From 32025915d564d999c33e73a4b6084d9df0dbd42a Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 10 Nov 2018 15:16:20 +0100 Subject: Make run faster on ARM CPUs using fast math approximation Use --fast-math to use sine/cosine tables and approximate atan2. --- src/amps/amps_tacs_main.c | 7 +- src/anetz/main.c | 6 + src/bnetz/main.c | 6 +- src/cnetz/main.c | 7 +- src/jolly/main.c | 5 + src/libam/am.c | 104 ++++++++++--- src/libam/am.h | 8 +- src/libfm/fm.c | 356 ++++++++++++++++++++++++-------------------- src/libfm/fm.h | 5 +- src/libmobile/main_mobile.c | 11 +- src/libmobile/main_mobile.h | 1 + src/nmt/main.c | 6 +- src/r2000/main.c | 6 +- src/radio/main.c | 16 ++ src/test/test_dtmf.c | 4 + src/test/test_performance.c | 24 ++- src/tv/main.c | 6 + 17 files changed, 385 insertions(+), 193 deletions(-) (limited to 'src') diff --git a/src/amps/amps_tacs_main.c b/src/amps/amps_tacs_main.c index df1dca0..a4eef2f 100644 --- a/src/amps/amps_tacs_main.c +++ b/src/amps/amps_tacs_main.c @@ -27,6 +27,7 @@ #include "../libdebug/debug.h" #include "../libmobile/call.h" #include "../liboptions/options.h" +#include "../libfm/fm.h" #include "amps.h" #include "dsp.h" #include "frame.h" @@ -329,7 +330,8 @@ int main_amps_tacs(int argc, char *argv[]) print_image(); sid_stations(sid); - /* init functions */ + /* inits */ + fm_init(fast_math); dsp_init(); init_frame(); @@ -400,6 +402,9 @@ fail: while (sender_head) amps_destroy(sender_head); + /* exits */ + fm_exit(); + return 0; } diff --git a/src/anetz/main.c b/src/anetz/main.c index 35fc036..bc28897 100644 --- a/src/anetz/main.c +++ b/src/anetz/main.c @@ -29,6 +29,7 @@ #include "../libtimer/timer.h" #include "../libmobile/call.h" #include "../liboptions/options.h" +#include "../libfm/fm.h" #include "freiton.h" #include "besetztton.h" #include "anetz.h" @@ -176,6 +177,8 @@ int main(int argc, char *argv[]) if (!loopback) print_image(); + /* inits */ + fm_init(fast_math); dsp_init(); anetz_init(); @@ -196,6 +199,9 @@ fail: while (sender_head) anetz_destroy(sender_head); + /* exits */ + fm_exit(); + return 0; } diff --git a/src/bnetz/main.c b/src/bnetz/main.c index d60ba88..2222bff 100644 --- a/src/bnetz/main.c +++ b/src/bnetz/main.c @@ -176,7 +176,8 @@ int main(int argc, char *argv[]) if (!loopback) print_image(); - /* init functions */ + /* inits */ + fm_init(fast_math); dsp_init(); bnetz_init(); @@ -204,6 +205,9 @@ fail: while(sender_head) bnetz_destroy(sender_head); + /* exits */ + fm_exit(); + return 0; } diff --git a/src/cnetz/main.c b/src/cnetz/main.c index a4fca5f..021eccb 100644 --- a/src/cnetz/main.c +++ b/src/cnetz/main.c @@ -29,6 +29,7 @@ #include "../anetz/freiton.h" #include "../anetz/besetztton.h" #include "../liboptions/options.h" +#include "../libfm/fm.h" #include "cnetz.h" #include "database.h" #include "sysinfo.h" @@ -459,7 +460,8 @@ int main(int argc, char *argv[]) if (!loopback) print_image(); - /* init functions */ + /* inits */ + fm_init(fast_math); scrambler_init(); if (futln_sperre_start >= 0) { teilnehmergruppensperre = futln_sperre_start; @@ -561,6 +563,9 @@ fail: while (sender_head) cnetz_destroy(sender_head); + /* exits */ + fm_exit(); + return 0; } diff --git a/src/jolly/main.c b/src/jolly/main.c index 424b091..ac25191 100644 --- a/src/jolly/main.c +++ b/src/jolly/main.c @@ -182,6 +182,8 @@ int main(int argc, char *argv[]) goto fail; } + /* inits */ + fm_init(fast_math); init_voice(samplerate); dsp_init(); @@ -202,6 +204,9 @@ fail: while (sender_head) jolly_destroy(sender_head); + /* exits */ + fm_exit(); + return 0; } diff --git a/src/libam/am.c b/src/libam/am.c index 9c8bf58..e9367d9 100644 --- a/src/libam/am.c +++ b/src/libam/am.c @@ -17,12 +17,55 @@ * along with this program. If not, see . */ +#include #include +#include #include +#include #include #include "../libsample/sample.h" #include "am.h" +static int has_init = 0; +static int fast_math = 0; +static float *sin_tab = NULL, *cos_tab = NULL; + +/* global init */ +int am_init(int _fast_math) +{ + fast_math = _fast_math; + + if (fast_math) { + int i; + + sin_tab = calloc(65536+16384, sizeof(*sin_tab)); + if (!sin_tab) { + fprintf(stderr, "No mem!\n"); + return -ENOMEM; + } + cos_tab = sin_tab + 16384; + + /* generate sine and cosine */ + for (i = 0; i < 65536+16384; i++) + sin_tab[i] = sin(2.0 * M_PI * (double)i / 65536.0); + } + + has_init = 1; + + return 0; +} + +/* global exit */ +void am_exit(void) +{ + if (sin_tab) { + free(sin_tab); + sin_tab = cos_tab = NULL; + } + + has_init = 0; +} + #define CARRIER_FILTER 30.0 /* Amplitude modulation in SDR: @@ -36,7 +79,10 @@ int am_mod_init(am_mod_t *mod, double samplerate, double offset, double gain, do memset(mod, 0, sizeof(*mod)); mod->gain = gain; mod->bias = bias; - mod->phasestep = 2.0 * M_PI * offset / samplerate; + if (fast_math) + mod->rot = 65536.0 * offset / samplerate; + else + mod->rot = 2.0 * M_PI * offset / samplerate; return 0; } @@ -49,20 +95,30 @@ void am_modulate_complex(am_mod_t *mod, sample_t *amplitude, int num, float *bas { int s; double vector; - double phasestep = mod->phasestep; + double rot = mod->rot; double phase = mod->phase; double gain = mod->gain; double bias = mod->bias; for (s = 0; s < num; s++) { vector = *amplitude++ * gain + bias; - *baseband++ = cos(phase) * vector; - *baseband++ = sin(phase) * vector; - phase += phasestep; - if (phase < 0.0) - phase += 2.0 * M_PI; - else if (phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; + if (fast_math) { + *baseband++ += cos_tab[(uint16_t)phase] * vector; + *baseband++ += sin_tab[(uint16_t)phase] * vector; + phase += rot; + if (phase < 0.0) + phase += 65536.0; + else if (phase >= 65536.0) + phase -= 65536.0; + } else { + *baseband++ = cos(phase) * vector; + *baseband++ = sin(phase) * vector; + phase += rot; + if (phase < 0.0) + phase += 2.0 * M_PI; + else if (phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + } } mod->phase = phase; @@ -73,7 +129,10 @@ int am_demod_init(am_demod_t *demod, double samplerate, double offset, double ba { memset(demod, 0, sizeof(*demod)); demod->gain = gain; - demod->phasestep = 2 * M_PI * -offset / samplerate; + if (fast_math) + demod->rot = 65536.0 * -offset / samplerate; + else + demod->rot = 2 * M_PI * -offset / samplerate; /* use fourth order (2 iter) filter, since it is as fast as second order (1 iter) filter */ iir_lowpass_init(&demod->lp[0], bandwidth, samplerate, 2); @@ -93,7 +152,7 @@ void am_demod_exit(am_demod_t __attribute__((unused)) *demod) void am_demodulate_complex(am_demod_t *demod, sample_t *amplitude, int length, float *baseband, sample_t *I, sample_t *Q, sample_t *carrier) { int s, ss; - double phasestep = demod->phasestep; + double rot = demod->rot; double phase = demod->phase; double gain = demod->gain; double i, q; @@ -103,13 +162,22 @@ void am_demodulate_complex(am_demod_t *demod, sample_t *amplitude, int length, f for (s = 0, ss = 0; s < length; s++) { i = baseband[ss++]; q = baseband[ss++]; - _sin = sin(phase); - _cos = cos(phase); - phase += phasestep; - if (phase < 0.0) - phase += 2.0 * M_PI; - else if (phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; + phase += rot; + if (fast_math) { + if (phase < 0.0) + phase += 65536.0; + else if (phase >= 65536.0) + phase -= 65536.0; + _sin = sin_tab[(uint16_t)phase]; + _cos = cos_tab[(uint16_t)phase]; + } else { + if (phase < 0.0) + phase += 2.0 * M_PI; + else if (phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + _sin = sin(phase); + _cos = cos(phase); + } I[s] = i * _cos - q * _sin; Q[s] = i * _sin + q * _cos; } diff --git a/src/libam/am.h b/src/libam/am.h index e9e9889..6bebe2c 100644 --- a/src/libam/am.h +++ b/src/libam/am.h @@ -1,7 +1,10 @@ #include "../libfilter/iir_filter.h" +int am_init(int fast_math); +void am_exit(void); + typedef struct am_mod { - double phasestep; /* angle to rotate vector per sample */ + double rot; /* angle to rotate vector per sample */ double phase; /* current phase */ double gain; /* gain to be multiplied to amplitude */ double bias; /* DC offset to add (carrier amplitude) */ @@ -12,9 +15,8 @@ void am_mod_exit(am_mod_t *mod); void am_modulate_complex(am_mod_t *mod, sample_t *amplitude, int num, float *baseband); typedef struct am_demod { - double phasestep; /* angle to rotate vector per sample */ + double rot; /* angle to rotate vector per sample */ double phase; /* current rotation phase (used to shift) */ - double last_phase; /* last phase of FM (used to demodulate) */ iir_filter_t lp[3]; /* filters received IQ signal/carrier */ double gain; /* gain to be expected from amplitude */ double bias; /* DC offset to be expected (carrier amplitude) */ diff --git a/src/libfm/fm.c b/src/libfm/fm.c index a006990..48b4f11 100644 --- a/src/libfm/fm.c +++ b/src/libfm/fm.c @@ -26,13 +26,56 @@ #include "../libsample/sample.h" #include "fm.h" -//#define FAST_SINE +static int has_init = 0; +static int fast_math = 0; +static float *sin_tab = NULL, *cos_tab = NULL; + +/* global init */ +int fm_init(int _fast_math) +{ + fast_math = _fast_math; + + if (fast_math) { + int i; + + sin_tab = calloc(65536+16384, sizeof(*sin_tab)); + if (!sin_tab) { + fprintf(stderr, "No mem!\n"); + return -ENOMEM; + } + cos_tab = sin_tab + 16384; + + /* generate sine and cosine */ + for (i = 0; i < 65536+16384; i++) + sin_tab[i] = sin(2.0 * M_PI * (double)i / 65536.0); + } + + has_init = 1; + + return 0; +} + +/* global exit */ +void fm_exit(void) +{ + if (sin_tab) { + free(sin_tab); + sin_tab = cos_tab = NULL; + } + + has_init = 0; +} /* init FM modulator */ int fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitude) { int i; + if (!has_init) { + fprintf(stderr, "libfm was not initialized, plese fix!\n"); + abort(); + } + memset(mod, 0, sizeof(*mod)); mod->samplerate = samplerate; mod->offset = offset; @@ -51,19 +94,6 @@ int fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitud mod->ramp_tab[i] = 0.5 - cos(M_PI * i / mod->ramp_length) / 2.0; mod->ramp_tab[0] = mod->ramp_tab[1] / 2.0; /* never be 0 */ -#ifdef FAST_SINE - mod->sin_tab = calloc(65536+16384, sizeof(*mod->sin_tab)); - if (!mod->sin_tab) { - fprintf(stderr, "No mem!\n"); - fm_mod_exit(mod); - return -ENOMEM; - } - - /* generate sine and cosine */ - for (i = 0; i < 65536+16384; i++) - mod->sin_tab[i] = sin(2.0 * M_PI * (double)i / 65536.0) * amplitude; -#endif - return 0; } @@ -73,10 +103,6 @@ void fm_mod_exit(fm_mod_t *mod) free(mod->ramp_tab); mod->ramp_tab = NULL; } - if (mod->sin_tab) { - free(mod->sin_tab); - mod->sin_tab = NULL; - } } /* do frequency modulation of samples and add them to existing baseband */ @@ -85,11 +111,7 @@ void fm_modulate_complex(fm_mod_t *mod, sample_t *frequency, uint8_t *power, int double dev, rate, phase, offset; int ramp, ramp_length; double *ramp_tab; -#ifdef FAST_SINE - double *sin_tab, *cos_tab; -#else double amplitude; -#endif rate = mod->samplerate; phase = mod->phase; @@ -97,12 +119,7 @@ void fm_modulate_complex(fm_mod_t *mod, sample_t *frequency, uint8_t *power, int ramp = mod->ramp; ramp_length = mod->ramp_length; ramp_tab = mod->ramp_tab; -#ifdef FAST_SINE - sin_tab = mod->sin_tab; - cos_tab = mod->sin_tab + 16384; -#else amplitude = mod->amplitude; -#endif again: switch (mod->state) { @@ -118,23 +135,23 @@ again: dev = offset + *frequency++; power++; length--; -#ifdef FAST_SINE - phase += 65536.0 * dev / rate; - if (phase < 0.0) - phase += 65536.0; - else if (phase >= 65536.0) - phase -= 65536.0; - *baseband++ += cos_tab[(uint16_t)phase]; - *baseband++ += sin_tab[(uint16_t)phase]; -#else - phase += 2.0 * M_PI * dev / rate; - if (phase < 0.0) - phase += 2.0 * M_PI; - else if (phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; - *baseband++ += cos(phase) * amplitude; - *baseband++ += sin(phase) * amplitude; -#endif + if (fast_math) { + phase += 65536.0 * dev / rate; + if (phase < 0.0) + phase += 65536.0; + else if (phase >= 65536.0) + phase -= 65536.0; + *baseband++ += cos_tab[(uint16_t)phase] * amplitude; + *baseband++ += sin_tab[(uint16_t)phase] * amplitude; + } else { + phase += 2.0 * M_PI * dev / rate; + if (phase < 0.0) + phase += 2.0 * M_PI; + else if (phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + *baseband++ += cos(phase) * amplitude; + *baseband++ += sin(phase) * amplitude; + } } break; case MOD_STATE_RAMP_DOWN: @@ -151,23 +168,23 @@ again: dev = offset + *frequency++; power++; length--; -#ifdef FAST_SINE - phase += 65536.0 * dev / rate; - if (phase < 0.0) - phase += 65536.0; - else if (phase >= 65536.0) - phase -= 65536.0; - *baseband++ += cos_tab[(uint16_t)phase] * ramp_tab[ramp]; - *baseband++ += sin_tab[(uint16_t)phase] * ramp_tab[ramp]; -#else - phase += 2.0 * M_PI * dev / rate; - if (phase < 0.0) - phase += 2.0 * M_PI; - else if (phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; - *baseband++ += cos(phase) * amplitude * ramp_tab[ramp]; - *baseband++ += sin(phase) * amplitude * ramp_tab[ramp]; -#endif + if (fast_math) { + phase += 65536.0 * dev / rate; + if (phase < 0.0) + phase += 65536.0; + else if (phase >= 65536.0) + phase -= 65536.0; + *baseband++ += cos_tab[(uint16_t)phase] * amplitude * ramp_tab[ramp]; + *baseband++ += sin_tab[(uint16_t)phase] * amplitude * ramp_tab[ramp]; + } else { + phase += 2.0 * M_PI * dev / rate; + if (phase < 0.0) + phase += 2.0 * M_PI; + else if (phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + *baseband++ += cos(phase) * amplitude * ramp_tab[ramp]; + *baseband++ += sin(phase) * amplitude * ramp_tab[ramp]; + } ramp--; } break; @@ -186,23 +203,23 @@ again: * we still continue with a carrier, but it has very low amplitude. * the low amplitude is set in ramp_tab[0] */ -#ifdef FAST_SINE - phase += 65536.0 * dev / rate; - if (phase < 0.0) - phase += 65536.0; - else if (phase >= 65536.0) - phase -= 65536.0; - *baseband++ += cos_tab[(uint16_t)phase] * ramp_tab[ramp]; - *baseband++ += sin_tab[(uint16_t)phase] * ramp_tab[ramp]; -#else - phase += 2.0 * M_PI * dev / rate; - if (phase < 0.0) - phase += 2.0 * M_PI; - else if (phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; - *baseband++ += cos(phase) * amplitude * ramp_tab[ramp]; - *baseband++ += sin(phase) * amplitude * ramp_tab[ramp]; -#endif + if (fast_math) { + phase += 65536.0 * dev / rate; + if (phase < 0.0) + phase += 65536.0; + else if (phase >= 65536.0) + phase -= 65536.0; + *baseband++ += cos_tab[(uint16_t)phase] * amplitude * ramp_tab[ramp]; + *baseband++ += sin_tab[(uint16_t)phase] * amplitude * ramp_tab[ramp]; + } else { + phase += 2.0 * M_PI * dev / rate; + if (phase < 0.0) + phase += 2.0 * M_PI; + else if (phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + *baseband++ += cos(phase) * amplitude * ramp_tab[ramp]; + *baseband++ += sin(phase) * amplitude * ramp_tab[ramp]; + } } break; case MOD_STATE_RAMP_UP: @@ -220,23 +237,23 @@ again: dev = offset + *frequency++; power++; length--; -#ifdef FAST_SINE - phase += 65536.0 * dev / rate; - if (phase < 0.0) - phase += 65536.0; - else if (phase >= 65536.0) - phase -= 65536.0; - *baseband++ += cos_tab[(uint16_t)phase] * ramp_tab[ramp]; - *baseband++ += sin_tab[(uint16_t)phase] * ramp_tab[ramp]; -#else - phase += 2.0 * M_PI * dev / rate; - if (phase < 0.0) - phase += 2.0 * M_PI; - else if (phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; - *baseband++ += cos(phase) * amplitude * ramp_tab[ramp]; - *baseband++ += sin(phase) * amplitude * ramp_tab[ramp]; -#endif + if (fast_math) { + phase += 65536.0 * dev / rate; + if (phase < 0.0) + phase += 65536.0; + else if (phase >= 65536.0) + phase -= 65536.0; + *baseband++ += cos_tab[(uint16_t)phase] * amplitude * ramp_tab[ramp]; + *baseband++ += sin_tab[(uint16_t)phase] * amplitude * ramp_tab[ramp]; + } else { + phase += 2.0 * M_PI * dev / rate; + if (phase < 0.0) + phase += 2.0 * M_PI; + else if (phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + *baseband++ += cos(phase) * amplitude * ramp_tab[ramp]; + *baseband++ += sin(phase) * amplitude * ramp_tab[ramp]; + } ramp++; } break; @@ -251,41 +268,62 @@ again: /* init FM demodulator */ int fm_demod_init(fm_demod_t *demod, double samplerate, double offset, double bandwidth) { + if (!has_init) { + fprintf(stderr, "libfm was not initialized, plese fix!\n"); + abort(); + } + memset(demod, 0, sizeof(*demod)); demod->samplerate = samplerate; -#ifdef FAST_SINE - demod->rot = 65536.0 * -offset / samplerate; -#else - demod->rot = 2 * M_PI * -offset / samplerate; -#endif + + if (fast_math) + demod->rot = 65536.0 * -offset / samplerate; + else + demod->rot = 2 * M_PI * -offset / samplerate; /* use fourth order (2 iter) filter, since it is as fast as second order (1 iter) filter */ iir_lowpass_init(&demod->lp[0], bandwidth / 2.0, samplerate, 2); iir_lowpass_init(&demod->lp[1], bandwidth / 2.0, samplerate, 2); -#ifdef FAST_SINE - int i; - - demod->sin_tab = calloc(65536+16384, sizeof(*demod->sin_tab)); - if (!demod->sin_tab) { - fprintf(stderr, "No mem!\n"); - return -ENOMEM; - } + return 0; +} - /* generate sine and cosine */ - for (i = 0; i < 65536+16384; i++) - demod->sin_tab[i] = sin(2.0 * M_PI * (double)i / 65536.0); -#endif +void fm_demod_exit(fm_demod_t __attribute__ ((unused)) *demod) +{ +} - return 0; +static inline float fast_tan(float z) +{ + const float n1 = 0.97239411f; + const float n2 = -0.19194795f; + return (n1 + n2 * z * z) * z; } -void fm_demod_exit(fm_demod_t *demod) +static inline float fast_atan2(float y, float x) { - if (demod->sin_tab) { - free(demod->sin_tab); - demod->sin_tab = NULL; + if (x != 0.0) { + if (fabsf(x) > fabsf(y)) { + const float z = y / x; + if (x > 0.0) /* atan2(y,x) = atan(y/x) if x > 0 */ + return fast_tan(z); + else if (y >= 0.0) /* atan2(y,x) = atan(y/x) + PI if x < 0, y >= 0 */ + return fast_tan(z) + M_PI; + else /* atan2(y,x) = atan(y/x) - PI if x < 0, y < 0 */ + return fast_tan(z) - M_PI; + } else { /* Use property atan(y/x) = PI/2 - atan(x/y) if |y/x| > 1 */ + const float z = x / y; + if (y > 0.0) /* atan2(y,x) = PI/2 - atan(x/y) if |y/x| > 1, y > 0 */ + return -fast_tan(z) + M_PI_2; + else /* atan2(y,x) = -PI/2 - atan(x/y) if |y/x| > 1, y < 0 */ + return -fast_tan(z) - M_PI_2; + } + } else { + if (y > 0.0) /* x = 0, y > 0 */ + return M_PI_2; + else if (y < 0.0) /* x = 0, y < 0 */ + return -M_PI_2; } + return 0.0; /* x,y = 0. return 0, because NaN would harm further processing */ } /* do frequency demodulation of baseband and write them to samples */ @@ -295,36 +333,29 @@ void fm_demodulate_complex(fm_demod_t *demod, sample_t *frequency, int length, f double _sin, _cos; sample_t i, q; int s, ss; -#ifdef FAST_SINE - double *sin_tab, *cos_tab; -#endif rate = demod->samplerate; phase = demod->phase; rot = demod->rot; -#ifdef FAST_SINE - sin_tab = demod->sin_tab; - cos_tab = demod->sin_tab + 16384; -#endif for (s = 0, ss = 0; s < length; s++) { phase += rot; i = baseband[ss++]; q = baseband[ss++]; -#ifdef FAST_SINE - if (phase < 0.0) - phase += 65536.0; - else if (phase >= 65536.0) - phase -= 65536.0; - _sin = sin_tab[(uint16_t)phase]; - _cos = cos_tab[(uint16_t)phase]; -#else - if (phase < 0.0) - phase += 2.0 * M_PI; - else if (phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; - _sin = sin(phase); - _cos = cos(phase); -#endif + if (fast_math) { + if (phase < 0.0) + phase += 65536.0; + else if (phase >= 65536.0) + phase -= 65536.0; + _sin = sin_tab[(uint16_t)phase]; + _cos = cos_tab[(uint16_t)phase]; + } else { + if (phase < 0.0) + phase += 2.0 * M_PI; + else if (phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + _sin = sin(phase); + _cos = cos(phase); + } I[s] = i * _cos - q * _sin; Q[s] = i * _sin + q * _cos; } @@ -333,7 +364,10 @@ void fm_demodulate_complex(fm_demod_t *demod, sample_t *frequency, int length, f iir_process(&demod->lp[1], Q, length); last_phase = demod->last_phase; for (s = 0; s < length; s++) { - phase = atan2(Q[s], I[s]); + if (fast_math) + phase = fast_atan2(Q[s], I[s]); + else + phase = atan2(Q[s], I[s]); dev = (phase - last_phase) / 2 / M_PI; last_phase = phase; if (dev < -0.49) @@ -352,35 +386,28 @@ void fm_demodulate_real(fm_demod_t *demod, sample_t *frequency, int length, samp double _sin, _cos; sample_t i; int s, ss; -#ifdef FAST_SINE - double *sin_tab, *cos_tab; -#endif rate = demod->samplerate; phase = demod->phase; rot = demod->rot; -#ifdef FAST_SINE - sin_tab = demod->sin_tab; - cos_tab = demod->sin_tab + 16384; -#endif for (s = 0, ss = 0; s < length; s++) { phase += rot; i = baseband[ss++]; -#ifdef FAST_SINE - if (phase < 0.0) - phase += 65536.0; - else if (phase >= 65536.0) - phase -= 65536.0; - _sin = sin_tab[(uint16_t)phase]; - _cos = cos_tab[(uint16_t)phase]; -#else - if (phase < 0.0) - phase += 2.0 * M_PI; - else if (phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; - _sin = sin(phase); - _cos = cos(phase); -#endif + if (fast_math) { + if (phase < 0.0) + phase += 65536.0; + else if (phase >= 65536.0) + phase -= 65536.0; + _sin = sin_tab[(uint16_t)phase]; + _cos = cos_tab[(uint16_t)phase]; + } else { + if (phase < 0.0) + phase += 2.0 * M_PI; + else if (phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + _sin = sin(phase); + _cos = cos(phase); + } I[s] = i * _cos; Q[s] = i * _sin; } @@ -389,7 +416,10 @@ void fm_demodulate_real(fm_demod_t *demod, sample_t *frequency, int length, samp iir_process(&demod->lp[1], Q, length); last_phase = demod->last_phase; for (s = 0; s < length; s++) { - phase = atan2(Q[s], I[s]); + if (fast_math) + phase = fast_atan2(Q[s], I[s]); + else + phase = atan2(Q[s], I[s]); dev = (phase - last_phase) / 2 / M_PI; last_phase = phase; if (dev < -0.49) diff --git a/src/libfm/fm.h b/src/libfm/fm.h index 68f0bcd..b87a662 100644 --- a/src/libfm/fm.h +++ b/src/libfm/fm.h @@ -1,5 +1,8 @@ #include "../libfilter/iir_filter.h" +int fm_init(int fast_math); +void fm_exit(void); + enum fm_mod_state { MOD_STATE_OFF, /* transmitter off, no IQ vector */ MOD_STATE_ON, /* transmitter on, FM modulated IQ vector */ @@ -12,7 +15,6 @@ typedef struct fm_mod { double offset; /* offset to calculated center frequency */ double amplitude; /* how much amplitude to add to the buff */ double phase; /* current phase of FM (used to shift and modulate ) */ - double *sin_tab; /* sine/cosine table for modulation */ enum fm_mod_state state;/* state of transmit power */ double *ramp_tab; /* half cosine ramp up */ int ramp; /* current ramp position */ @@ -29,7 +31,6 @@ typedef struct fm_demod { double rot; /* rotation step per sample to shift rx frequency (used to shift) */ double last_phase; /* last phase of FM (used to demodulate) */ iir_filter_t lp[2]; /* filters received IQ signal */ - double *sin_tab; /* sine/cosine table rotation */ } fm_demod_t; int fm_demod_init(fm_demod_t *demod, double samplerate, double offset, double bandwidth); diff --git a/src/libmobile/main_mobile.c b/src/libmobile/main_mobile.c index 97d6f34..9cf0d74 100644 --- a/src/libmobile/main_mobile.c +++ b/src/libmobile/main_mobile.c @@ -41,6 +41,7 @@ #include "../libsdr/sdr_config.h" #endif #include "../liboptions/options.h" +#include "../libfm/fm.h" #define DEFAULT_LO_OFFSET -1000000.0 @@ -69,6 +70,7 @@ static int send_patterns = 1; static int release_on_disconnect = 1; int loopback = 0; int rt_prio = 1; +int fast_math = 0; const char *write_tx_wave = NULL; const char *write_rx_wave = NULL; const char *read_tx_wave = NULL; @@ -133,7 +135,7 @@ void main_mobile_print_help(const char *arg0, const char *ext_usage) printf(" use one combined control+voice channel and one voice channels.\n"); printf(" -m --mncc-sock\n"); printf(" Disable built-in call contol and offer socket (to LCR)\n"); - printf(" --mncc-name \n"); + printf(" --mncc-name \n"); printf(" '/tmp/bsc_mncc' is used by default, give name to change socket to\n"); printf(" '/tmp/bsc_mncc_'. (Useful to run multiple networks.)\n"); printf(" -t --tones 0 | 1\n"); @@ -143,6 +145,8 @@ void main_mobile_print_help(const char *arg0, const char *ext_usage) printf(" Loopback test: 1 = internal | 2 = external | 3 = echo\n"); printf(" -r --realtime \n"); printf(" Set prio: 0 to diable, 99 for maximum (default = %d)\n", rt_prio); + printf(" --fast-math\n"); + printf(" Use fast math approximation for slow CPU / ARM based systems.\n"); printf(" --write-rx-wave \n"); printf(" Write received audio to given wave file.\n"); printf(" --write-tx-wave \n"); @@ -181,6 +185,7 @@ void main_mobile_print_hotkeys(void) #define OPT_READ_TX_WAVE 1004 #define OPT_CALL_SAMPLERATE 1005 #define OPT_MNCC_NAME 1006 +#define OPT_FAST_MATH 1007 #define OPT_LIMESDR 1100 #define OPT_LIMESDR_MINI 1101 @@ -206,6 +211,7 @@ void main_mobile_add_options(void) option_add('t', "tones", 1); option_add('l', "loopback", 1); option_add('r', "realtime", 1); + option_add(OPT_FAST_MATH, "fast-math", 0); option_add(OPT_WRITE_RX_WAVE, "write-rx-wave", 1); option_add(OPT_WRITE_TX_WAVE, "write-tx-wave", 1); option_add(OPT_READ_RX_WAVE, "read-rx-wave", 1); @@ -307,6 +313,9 @@ int main_mobile_handle_options(int short_option, int argi, char **argv) case 'r': rt_prio = atoi(argv[argi]); break; + case OPT_FAST_MATH: + fast_math = 1; + break; case OPT_WRITE_RX_WAVE: write_rx_wave = strdup(argv[argi]); break; diff --git a/src/libmobile/main_mobile.h b/src/libmobile/main_mobile.h index 4d5dffc..0edf9ba 100644 --- a/src/libmobile/main_mobile.h +++ b/src/libmobile/main_mobile.h @@ -14,6 +14,7 @@ extern int do_de_emphasis; extern double rx_gain; extern int loopback; extern int rt_prio; +extern int fast_math; extern const char *write_rx_wave; extern const char *write_tx_wave; extern const char *read_rx_wave; diff --git a/src/nmt/main.c b/src/nmt/main.c index 1d3eb2c..68ef122 100644 --- a/src/nmt/main.c +++ b/src/nmt/main.c @@ -381,7 +381,8 @@ int main(int argc, char *argv[]) if (!loopback) print_image(); - /* init functions */ + /* inits */ + fm_init(fast_math); rc = init_frame(); if (rc < 0) { fprintf(stderr, "Failed to setup frames. Quitting!\n"); @@ -419,6 +420,9 @@ fail: while (sender_head) nmt_destroy(sender_head); + /* exits */ + fm_exit(); + return 0; } diff --git a/src/r2000/main.c b/src/r2000/main.c index 425affd..cf30690 100644 --- a/src/r2000/main.c +++ b/src/r2000/main.c @@ -335,7 +335,8 @@ int main(int argc, char *argv[]) if (!loopback && crins != 3) print_image(); - /* init functions */ + /* inits */ + fm_init(fast_math); dsp_init(); /* SDR always requires emphasis */ @@ -373,6 +374,9 @@ fail: while (sender_head) r2000_destroy(sender_head); + /* exits */ + fm_exit(); + return 0; } diff --git a/src/radio/main.c b/src/radio/main.c index 89b221c..acc430e 100644 --- a/src/radio/main.c +++ b/src/radio/main.c @@ -44,6 +44,7 @@ void *sender_head = NULL; int use_sdr = 0; int num_kanal = 1; /* only one channel used for debugging */ int rt_prio = 1; +int fast_math = 0; void *get_sender_by_empfangsfrequenz() { return NULL; } @@ -140,6 +141,8 @@ void print_help(const char *arg0) printf(" -S --stereo\n"); printf(" Enables stereo carrier for frequency modulated UHF broadcast.\n"); printf(" It uses the 'Pilot-tone' system.\n"); + printf(" --fast-math\n"); + printf(" Use fast math approximation for slow CPU / ARM based systems.\n"); printf(" --limesdr\n"); printf(" Auto-select several required options for LimeSDR\n"); printf(" --limesdr-mini\n"); @@ -147,6 +150,7 @@ void print_help(const char *arg0) sdr_config_print_help(); } +#define OPT_FAST_MATH 1007 #define OPT_LIMESDR 1100 #define OPT_LIMESDR_MINI 1101 @@ -166,6 +170,7 @@ static void add_options(void) option_add('I', "modulation-index", 1); option_add('E', "emphasis", 1); option_add('S', "stereo", 0); + option_add(OPT_FAST_MATH, "fast-math", 0); option_add(OPT_LIMESDR, "limesdr", 0); option_add(OPT_LIMESDR_MINI, "limesdr-mini", 0); sdr_config_add_options(); @@ -236,6 +241,9 @@ static int handle_options(int short_option, int argi, char **argv) case 'S': stereo = 1; break; + case OPT_FAST_MATH: + fast_math = 1; + break; case OPT_LIMESDR: { char *argv_lime[] = { argv[0], @@ -297,6 +305,10 @@ int main(int argc, char *argv[]) exit(0); } + /* global inits */ + fm_init(fast_math); + am_init(fast_math); + rc = sdr_configure(samplerate); if (rc < 0) return rc; @@ -482,6 +494,10 @@ error: sdr_close(sdr); radio_exit(&radio); + /* global exits */ + fm_exit(); + am_exit(); + return 0; } diff --git a/src/test/test_dtmf.c b/src/test/test_dtmf.c index 8f56e5c..6640c59 100644 --- a/src/test/test_dtmf.c +++ b/src/test/test_dtmf.c @@ -63,6 +63,8 @@ int main(void) int f, i; double target; + fm_init(0); + dtmf_decode_init(&dtmf_dec, NULL, recv_digit, SAMPLERATE, db2level(0), db2level(-30.0)); for (f = 0; f < 8; f++) { @@ -109,6 +111,8 @@ int main(void) dtmf_decode_exit(&dtmf_dec); + fm_exit(); + return 0; } diff --git a/src/test/test_performance.c b/src/test/test_performance.c index 5732b8b..2f9b062 100644 --- a/src/test/test_performance.c +++ b/src/test/test_performance.c @@ -22,7 +22,7 @@ int tot_samples; duration = (double)tv.tv_sec + (double)tv.tv_usec / 1e6; \ duration -= (double)start_tv.tv_sec + (double)start_tv.tv_usec / 1e6; \ tot_samples += samples; \ - if (duration >= 0.5) \ + if (duration >= 2) \ break; \ } \ printf("%s: %.3f mega samples/sec\n", what, (double)tot_samples / duration / 1e6); \ @@ -39,15 +39,35 @@ iir_filter_t lp; int main(void) { memset(power, 1, sizeof(power)); + + fm_init(0); + fm_mod_init(&mod, 50000, 0, 0.333); T_START() fm_modulate_complex(&mod, samples, power, SAMPLES, buff); T_STOP("FM modulate", SAMPLES) + fm_mod_exit(&mod); fm_demod_init(&demod, 50000, 0, 10000.0); T_START() fm_demodulate_complex(&demod, samples, SAMPLES, buff, I, Q); T_STOP("FM demodulate", SAMPLES) + fm_demod_exit(&demod); + + fm_exit(); + fm_init(1); + + fm_mod_init(&mod, 50000, 0, 0.333); + T_START() + fm_modulate_complex(&mod, samples, power, SAMPLES, buff); + T_STOP("FM modulate (fast math)", SAMPLES) + fm_mod_exit(&mod); + + fm_demod_init(&demod, 50000, 0, 10000.0); + T_START() + fm_demodulate_complex(&demod, samples, SAMPLES, buff, I, Q); + T_STOP("FM demodulate (fast math)", SAMPLES) + fm_demod_exit(&demod); iir_lowpass_init(&lp, 10000.0 / 2.0, 50000, 1); T_START() @@ -64,6 +84,8 @@ int main(void) iir_process(&lp, samples, SAMPLES); T_STOP("low-pass filter (eigth order)", SAMPLES) + fm_exit(); + return 0; } diff --git a/src/tv/main.c b/src/tv/main.c index f632a24..ab68d40 100644 --- a/src/tv/main.c +++ b/src/tv/main.c @@ -473,6 +473,9 @@ int main(int argc, char *argv[]) exit(0); } + /* inits */ + fm_init(0); + if (!wave_file) { #ifdef HAVE_SDR rc = sdr_configure(samplerate); @@ -499,6 +502,9 @@ int main(int argc, char *argv[]) return -EINVAL; } + /* exits */ + fm_exit(); + return 0; } -- cgit v1.2.3