aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2018-11-10 15:16:20 +0100
committerAndreas Eversberg <jolly@eversberg.eu>2018-11-10 15:18:28 +0100
commit32025915d564d999c33e73a4b6084d9df0dbd42a (patch)
tree718328859560d735f40d7a71ac3e75e0c339202e
parente8429166c3bfa5077d0dc353f345834e831f3e34 (diff)
Make run faster on ARM CPUs using fast math approximation
Use --fast-math to use sine/cosine tables and approximate atan2.
-rw-r--r--src/amps/amps_tacs_main.c7
-rw-r--r--src/anetz/main.c6
-rw-r--r--src/bnetz/main.c6
-rw-r--r--src/cnetz/main.c7
-rw-r--r--src/jolly/main.c5
-rw-r--r--src/libam/am.c104
-rw-r--r--src/libam/am.h8
-rw-r--r--src/libfm/fm.c356
-rw-r--r--src/libfm/fm.h5
-rw-r--r--src/libmobile/main_mobile.c11
-rw-r--r--src/libmobile/main_mobile.h1
-rw-r--r--src/nmt/main.c6
-rw-r--r--src/r2000/main.c6
-rw-r--r--src/radio/main.c16
-rw-r--r--src/test/test_dtmf.c4
-rw-r--r--src/test/test_performance.c24
-rw-r--r--src/tv/main.c6
17 files changed, 385 insertions, 193 deletions
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 <http://www.gnu.org/licenses/>.
*/
+#include <stdio.h>
#include <stdint.h>
+#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include <math.h>
#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 <name>\n");
+ printf(" --mncc-name <name>\n");
printf(" '/tmp/bsc_mncc' is used by default, give name to change socket to\n");
printf(" '/tmp/bsc_mncc_<name>'. (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 <prio>\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 <file>\n");
printf(" Write received audio to given wave file.\n");
printf(" --write-tx-wave <file>\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;
}