From f4754dcb37fa08775ca7e4af4f1bb4ea294fabcc Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 16 Nov 2017 19:18:42 +0100 Subject: Restructure: Move fm_modulation from common code to 'libfm' --- .gitignore | 1 + configure.ac | 1 + src/Makefile.am | 2 +- src/amps/Makefile.am | 1 + src/anetz/Makefile.am | 1 + src/bnetz/Makefile.am | 1 + src/cnetz/Makefile.am | 1 + src/common/Makefile.am | 1 - src/common/fm_modulation.c | 382 -------------------------------------------- src/common/fm_modulation.h | 39 ----- src/common/fsk.h | 2 +- src/common/sdr.c | 2 +- src/jtacs/Makefile.am | 1 + src/libfm/Makefile.am | 6 + src/libfm/fm.c | 382 ++++++++++++++++++++++++++++++++++++++++++++ src/libfm/fm.h | 39 +++++ src/nmt/Makefile.am | 1 + src/r2000/Makefile.am | 1 + src/tacs/Makefile.am | 1 + src/test/Makefile.am | 5 + src/test/test_performance.c | 2 +- src/tv/Makefile.am | 1 + src/tv/main.c | 2 +- 23 files changed, 448 insertions(+), 427 deletions(-) delete mode 100644 src/common/fm_modulation.c delete mode 100644 src/common/fm_modulation.h create mode 100644 src/libfm/Makefile.am create mode 100644 src/libfm/fm.c create mode 100644 src/libfm/fm.h diff --git a/.gitignore b/.gitignore index 94039ad..6846aab 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ src/libtimer/libtimer.a src/libsamplerate/libsamplerate.a src/libscrambler/libscrambler.a src/libemphasis/libemphasis.a +src/libfm/libfm.a src/libfilter/libfilter.a src/libwave/libwave.a src/libfft/libfft.a diff --git a/configure.ac b/configure.ac index 82f5eae..db9c196 100644 --- a/configure.ac +++ b/configure.ac @@ -84,6 +84,7 @@ AC_OUTPUT( src/libsamplerate/Makefile src/libscrambler/Makefile src/libemphasis/Makefile + src/libfm/Makefile src/libfilter/Makefile src/libwave/Makefile src/libfft/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 5edcabe..f00125f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,3 @@ AUTOMAKE_OPTIONS = foreign -SUBDIRS = libgoertzel libjitter libsquelch libhagelbarger libdtmf libtimer libsamplerate libscrambler libemphasis libfilter libwave libfft common anetz bnetz cnetz nmt amps tacs jtacs r2000 tv test +SUBDIRS = libgoertzel libjitter libsquelch libhagelbarger libdtmf libtimer libsamplerate libscrambler libemphasis libfm libfilter libwave libfft common anetz bnetz cnetz nmt amps tacs jtacs r2000 tv test diff --git a/src/amps/Makefile.am b/src/amps/Makefile.am index 3e96124..3990e9a 100644 --- a/src/amps/Makefile.am +++ b/src/amps/Makefile.am @@ -33,6 +33,7 @@ amps_LDADD = \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ diff --git a/src/anetz/Makefile.am b/src/anetz/Makefile.am index 6864631..29b7f36 100644 --- a/src/anetz/Makefile.am +++ b/src/anetz/Makefile.am @@ -26,6 +26,7 @@ anetz_LDADD = \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ diff --git a/src/bnetz/Makefile.am b/src/bnetz/Makefile.am index 009ec07..55a7b36 100644 --- a/src/bnetz/Makefile.am +++ b/src/bnetz/Makefile.am @@ -21,6 +21,7 @@ bnetz_LDADD = \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ diff --git a/src/cnetz/Makefile.am b/src/cnetz/Makefile.am index e4df7ef..8962b94 100644 --- a/src/cnetz/Makefile.am +++ b/src/cnetz/Makefile.am @@ -24,6 +24,7 @@ cnetz_LDADD = \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libscrambler/libscrambler.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 52ee381..9e9908a 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -7,7 +7,6 @@ libcommon_a_SOURCES = \ debug.c \ sound_alsa.c \ compandor.c \ - fm_modulation.c \ fsk.c \ display_wave.c \ display_measurements.c diff --git a/src/common/fm_modulation.c b/src/common/fm_modulation.c deleted file mode 100644 index 93621c8..0000000 --- a/src/common/fm_modulation.c +++ /dev/null @@ -1,382 +0,0 @@ -/* FM modulation processing - * - * (C) 2017 by Andreas Eversberg - * All Rights Reserved - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include "sample.h" -#include "fm_modulation.h" - -//#define FAST_SINE - -/* init FM modulator */ -int fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitude) -{ - int i; - - memset(mod, 0, sizeof(*mod)); - mod->samplerate = samplerate; - mod->offset = offset; - mod->amplitude = amplitude; - - mod->ramp_length = samplerate * 0.001; - mod->ramp_tab = calloc(mod->ramp_length, sizeof(*mod->ramp_tab)); - if (!mod->ramp_tab) { - fprintf(stderr, "No mem!\n"); - return -ENOMEM; - } - mod->state = MOD_STATE_OFF; - - /* generate ramp up with ramp_length */ - for (i = 0; i < mod->ramp_length; i++) - mod->ramp_tab[i] = 0.5 - cos(M_PI * i / mod->ramp_length) / 2.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; -} - -void fm_mod_exit(fm_mod_t *mod) -{ - if (mod->ramp_tab) { - 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 */ -void fm_modulate_complex(fm_mod_t *mod, sample_t *frequency, uint8_t *power, int length, float *baseband) -{ - 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; - offset = mod->offset; - 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) { - case MOD_STATE_ON: - /* modulate */ - while (length) { - /* is power is not set, ramp down */ - if (!(*power)) { - mod->state = MOD_STATE_RAMP_DOWN; - break; - } - /* deviation is defined by the frequency value and the offset */ - 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 - } - break; - case MOD_STATE_RAMP_DOWN: - while (length) { - /* if power is set, ramp up */ - if (*power) { - mod->state = MOD_STATE_RAMP_UP; - break; - } - if (ramp == 0) { - mod->state = MOD_STATE_OFF; - break; - } - 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 - ramp--; - } - break; - case MOD_STATE_OFF: - while (length) { - /* if power is set, ramp up */ - if (*power) { - mod->state = MOD_STATE_RAMP_UP; - break; - } - frequency++; - power++; - length--; - baseband += 2; - } - break; - case MOD_STATE_RAMP_UP: - while (length) { - /* is power is not set, ramp down */ - if (!(*power)) { - mod->state = MOD_STATE_RAMP_DOWN; - break; - } - if (ramp == ramp_length - 1) { - mod->state = MOD_STATE_ON; - break; - } - /* deviation is defined by the frequency value and the offset */ - 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 - ramp++; - } - break; - } - if (length) - goto again; - - mod->phase = phase; - mod->ramp = ramp; -} - -/* init FM demodulator */ -int fm_demod_init(fm_demod_t *demod, double samplerate, double offset, double bandwidth) -{ - 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 - - /* 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; - } - - /* 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 - - return 0; -} - -void fm_demod_exit(fm_demod_t *demod) -{ - if (demod->sin_tab) { - free(demod->sin_tab); - demod->sin_tab = NULL; - } -} - -/* do frequency demodulation of baseband and write them to samples */ -void fm_demodulate_complex(fm_demod_t *demod, sample_t *frequency, int length, float *baseband, sample_t *I, sample_t *Q) -{ - double phase, rot, last_phase, dev, rate; - 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 - I[s] = i * _cos - q * _sin; - Q[s] = i * _sin + q * _cos; - } - demod->phase = phase; - iir_process(&demod->lp[0], I, length); - iir_process(&demod->lp[1], Q, length); - last_phase = demod->last_phase; - for (s = 0; s < length; s++) { - phase = atan2(Q[s], I[s]); - dev = (phase - last_phase) / 2 / M_PI; - last_phase = phase; - if (dev < -0.49) - dev += 1.0; - else if (dev > 0.49) - dev -= 1.0; - dev *= rate; - frequency[s] = dev; - } - demod->last_phase = last_phase; -} - -void fm_demodulate_real(fm_demod_t *demod, sample_t *frequency, int length, sample_t *baseband, sample_t *I, sample_t *Q) -{ - double phase, rot, last_phase, dev, rate; - 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 - I[s] = i * _cos; - Q[s] = i * _sin; - } - demod->phase = phase; - iir_process(&demod->lp[0], I, length); - iir_process(&demod->lp[1], Q, length); - last_phase = demod->last_phase; - for (s = 0; s < length; s++) { - phase = atan2(Q[s], I[s]); - dev = (phase - last_phase) / 2 / M_PI; - last_phase = phase; - if (dev < -0.49) - dev += 1.0; - else if (dev > 0.49) - dev -= 1.0; - dev *= rate; - frequency[s] = dev; - } - demod->last_phase = last_phase; -} - diff --git a/src/common/fm_modulation.h b/src/common/fm_modulation.h deleted file mode 100644 index 68f0bcd..0000000 --- a/src/common/fm_modulation.h +++ /dev/null @@ -1,39 +0,0 @@ -#include "../libfilter/iir_filter.h" - -enum fm_mod_state { - MOD_STATE_OFF, /* transmitter off, no IQ vector */ - MOD_STATE_ON, /* transmitter on, FM modulated IQ vector */ - MOD_STATE_RAMP_UP, /* use half cos to ramp up IQ vector */ - MOD_STATE_RAMP_DOWN, /* use half cos to ramp down IQ vector */ -}; - -typedef struct fm_mod { - double samplerate; /* sample rate of in and out */ - 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 */ - int ramp_length; /* number of values in ramp */ -} fm_mod_t; - -int fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitude); -void fm_mod_exit(fm_mod_t *mod); -void fm_modulate_complex(fm_mod_t *mod, sample_t *frequency, uint8_t *power, int num, float *baseband); - -typedef struct fm_demod { - double samplerate; /* sample rate of in and out */ - double phase; /* current rotation phase (used to shift) */ - 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); -void fm_demod_exit(fm_demod_t *demod); -void fm_demodulate_complex(fm_demod_t *demod, sample_t *frequency, int length, float *baseband, sample_t *I, sample_t *Q); -void fm_demodulate_real(fm_demod_t *demod, sample_t *frequency, int length, sample_t *baseband, sample_t *I, sample_t *Q); - diff --git a/src/common/fsk.h b/src/common/fsk.h index 723fe66..a7cc428 100644 --- a/src/common/fsk.h +++ b/src/common/fsk.h @@ -1,4 +1,4 @@ -#include "../common/fm_modulation.h" +#include "../libfm/fm.h" typedef struct ffsk { void *inst; diff --git a/src/common/sdr.c b/src/common/sdr.c index 01048ee..d7a445b 100644 --- a/src/common/sdr.c +++ b/src/common/sdr.c @@ -30,7 +30,7 @@ enum paging_signal; #include #include #include "sample.h" -#include "fm_modulation.h" +#include "../libfm/fm.h" #include "../libtimer/timer.h" #include "sender.h" #include "sdr_config.h" diff --git a/src/jtacs/Makefile.am b/src/jtacs/Makefile.am index 3c01af1..15a657b 100644 --- a/src/jtacs/Makefile.am +++ b/src/jtacs/Makefile.am @@ -19,6 +19,7 @@ jtacs_LDADD = \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ diff --git a/src/libfm/Makefile.am b/src/libfm/Makefile.am new file mode 100644 index 0000000..d78a28e --- /dev/null +++ b/src/libfm/Makefile.am @@ -0,0 +1,6 @@ +AM_CPPFLAGS = -Wall -Wextra -g $(all_includes) + +noinst_LIBRARIES = libfm.a + +libfm_a_SOURCES = \ + fm.c diff --git a/src/libfm/fm.c b/src/libfm/fm.c new file mode 100644 index 0000000..0e47d8a --- /dev/null +++ b/src/libfm/fm.c @@ -0,0 +1,382 @@ +/* FM modulation processing + * + * (C) 2017 by Andreas Eversberg + * All Rights Reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include "../common/sample.h" +#include "fm.h" + +//#define FAST_SINE + +/* init FM modulator */ +int fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitude) +{ + int i; + + memset(mod, 0, sizeof(*mod)); + mod->samplerate = samplerate; + mod->offset = offset; + mod->amplitude = amplitude; + + mod->ramp_length = samplerate * 0.001; + mod->ramp_tab = calloc(mod->ramp_length, sizeof(*mod->ramp_tab)); + if (!mod->ramp_tab) { + fprintf(stderr, "No mem!\n"); + return -ENOMEM; + } + mod->state = MOD_STATE_OFF; + + /* generate ramp up with ramp_length */ + for (i = 0; i < mod->ramp_length; i++) + mod->ramp_tab[i] = 0.5 - cos(M_PI * i / mod->ramp_length) / 2.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; +} + +void fm_mod_exit(fm_mod_t *mod) +{ + if (mod->ramp_tab) { + 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 */ +void fm_modulate_complex(fm_mod_t *mod, sample_t *frequency, uint8_t *power, int length, float *baseband) +{ + 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; + offset = mod->offset; + 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) { + case MOD_STATE_ON: + /* modulate */ + while (length) { + /* is power is not set, ramp down */ + if (!(*power)) { + mod->state = MOD_STATE_RAMP_DOWN; + break; + } + /* deviation is defined by the frequency value and the offset */ + 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 + } + break; + case MOD_STATE_RAMP_DOWN: + while (length) { + /* if power is set, ramp up */ + if (*power) { + mod->state = MOD_STATE_RAMP_UP; + break; + } + if (ramp == 0) { + mod->state = MOD_STATE_OFF; + break; + } + 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 + ramp--; + } + break; + case MOD_STATE_OFF: + while (length) { + /* if power is set, ramp up */ + if (*power) { + mod->state = MOD_STATE_RAMP_UP; + break; + } + frequency++; + power++; + length--; + baseband += 2; + } + break; + case MOD_STATE_RAMP_UP: + while (length) { + /* is power is not set, ramp down */ + if (!(*power)) { + mod->state = MOD_STATE_RAMP_DOWN; + break; + } + if (ramp == ramp_length - 1) { + mod->state = MOD_STATE_ON; + break; + } + /* deviation is defined by the frequency value and the offset */ + 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 + ramp++; + } + break; + } + if (length) + goto again; + + mod->phase = phase; + mod->ramp = ramp; +} + +/* init FM demodulator */ +int fm_demod_init(fm_demod_t *demod, double samplerate, double offset, double bandwidth) +{ + 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 + + /* 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; + } + + /* 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 + + return 0; +} + +void fm_demod_exit(fm_demod_t *demod) +{ + if (demod->sin_tab) { + free(demod->sin_tab); + demod->sin_tab = NULL; + } +} + +/* do frequency demodulation of baseband and write them to samples */ +void fm_demodulate_complex(fm_demod_t *demod, sample_t *frequency, int length, float *baseband, sample_t *I, sample_t *Q) +{ + double phase, rot, last_phase, dev, rate; + 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 + I[s] = i * _cos - q * _sin; + Q[s] = i * _sin + q * _cos; + } + demod->phase = phase; + iir_process(&demod->lp[0], I, length); + iir_process(&demod->lp[1], Q, length); + last_phase = demod->last_phase; + for (s = 0; s < length; s++) { + phase = atan2(Q[s], I[s]); + dev = (phase - last_phase) / 2 / M_PI; + last_phase = phase; + if (dev < -0.49) + dev += 1.0; + else if (dev > 0.49) + dev -= 1.0; + dev *= rate; + frequency[s] = dev; + } + demod->last_phase = last_phase; +} + +void fm_demodulate_real(fm_demod_t *demod, sample_t *frequency, int length, sample_t *baseband, sample_t *I, sample_t *Q) +{ + double phase, rot, last_phase, dev, rate; + 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 + I[s] = i * _cos; + Q[s] = i * _sin; + } + demod->phase = phase; + iir_process(&demod->lp[0], I, length); + iir_process(&demod->lp[1], Q, length); + last_phase = demod->last_phase; + for (s = 0; s < length; s++) { + phase = atan2(Q[s], I[s]); + dev = (phase - last_phase) / 2 / M_PI; + last_phase = phase; + if (dev < -0.49) + dev += 1.0; + else if (dev > 0.49) + dev -= 1.0; + dev *= rate; + frequency[s] = dev; + } + demod->last_phase = last_phase; +} + diff --git a/src/libfm/fm.h b/src/libfm/fm.h new file mode 100644 index 0000000..68f0bcd --- /dev/null +++ b/src/libfm/fm.h @@ -0,0 +1,39 @@ +#include "../libfilter/iir_filter.h" + +enum fm_mod_state { + MOD_STATE_OFF, /* transmitter off, no IQ vector */ + MOD_STATE_ON, /* transmitter on, FM modulated IQ vector */ + MOD_STATE_RAMP_UP, /* use half cos to ramp up IQ vector */ + MOD_STATE_RAMP_DOWN, /* use half cos to ramp down IQ vector */ +}; + +typedef struct fm_mod { + double samplerate; /* sample rate of in and out */ + 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 */ + int ramp_length; /* number of values in ramp */ +} fm_mod_t; + +int fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitude); +void fm_mod_exit(fm_mod_t *mod); +void fm_modulate_complex(fm_mod_t *mod, sample_t *frequency, uint8_t *power, int num, float *baseband); + +typedef struct fm_demod { + double samplerate; /* sample rate of in and out */ + double phase; /* current rotation phase (used to shift) */ + 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); +void fm_demod_exit(fm_demod_t *demod); +void fm_demodulate_complex(fm_demod_t *demod, sample_t *frequency, int length, float *baseband, sample_t *I, sample_t *Q); +void fm_demodulate_real(fm_demod_t *demod, sample_t *frequency, int length, sample_t *baseband, sample_t *I, sample_t *Q); + diff --git a/src/nmt/Makefile.am b/src/nmt/Makefile.am index a32875a..d36c727 100644 --- a/src/nmt/Makefile.am +++ b/src/nmt/Makefile.am @@ -31,6 +31,7 @@ nmt_LDADD = \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ diff --git a/src/r2000/Makefile.am b/src/r2000/Makefile.am index e6d9bc4..d122532 100644 --- a/src/r2000/Makefile.am +++ b/src/r2000/Makefile.am @@ -19,6 +19,7 @@ radiocom2000_LDADD = \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ diff --git a/src/tacs/Makefile.am b/src/tacs/Makefile.am index d0ae341..7f3afbf 100644 --- a/src/tacs/Makefile.am +++ b/src/tacs/Makefile.am @@ -20,6 +20,7 @@ tacs_LDADD = \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 62ca801..24666bb 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -19,6 +19,7 @@ test_filter_LDADD = \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ @@ -48,6 +49,7 @@ test_emphasis_LDADD = \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ @@ -67,6 +69,7 @@ test_dms_LDADD = \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ @@ -86,6 +89,7 @@ test_sms_LDADD = \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ $(top_builddir)/src/libemphasis/libemphasis.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ @@ -100,6 +104,7 @@ test_performance_LDADD = \ $(COMMON_LA) \ $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ diff --git a/src/test/test_performance.c b/src/test/test_performance.c index 175185c..100c050 100644 --- a/src/test/test_performance.c +++ b/src/test/test_performance.c @@ -5,7 +5,7 @@ #include #include "../common/sample.h" #include "../libfilter/iir_filter.h" -#include "../common/fm_modulation.h" +#include "../libfm/fm.h" #include "../common/debug.h" struct timeval start_tv, tv; diff --git a/src/tv/Makefile.am b/src/tv/Makefile.am index 3277ed4..e0e2cf2 100644 --- a/src/tv/Makefile.am +++ b/src/tv/Makefile.am @@ -17,6 +17,7 @@ osmotv_LDADD = \ $(top_builddir)/src/common/libimage.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libtimer/libtimer.a \ + $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ $(top_builddir)/src/libwave/libwave.a \ $(top_builddir)/src/libfft/libfft.a \ diff --git a/src/tv/main.c b/src/tv/main.c index 7440d0b..e997156 100644 --- a/src/tv/main.c +++ b/src/tv/main.c @@ -29,7 +29,7 @@ enum paging_signal; #include #include "../common/sample.h" #include "../libfilter/iir_filter.h" -#include "../common/fm_modulation.h" +#include "../libfm/fm.h" #include "../libwave/wave.h" #include "../common/img.h" #include "../common/debug.h" -- cgit v1.2.3