aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2022-12-16 10:18:19 +0100
committerAndreas Eversberg <jolly@eversberg.eu>2022-12-16 12:43:19 +0100
commitfd3b4dae5031a06345d9e8454cd33fb88a4b5c01 (patch)
treeebb073da38b94729c8e39d20e7b6579eb80013be /src
parent7609e98b8fbb540140f7e66784a24f5495e36f54 (diff)
FSK modulator improvements
1. Phase is now changed proportional to the time of the bit change, if it happens somewhere between samples. The amount of phase change per bit is now the same for all bits, no matter how many samples currently lay inside this bit. 2. IIR filter is removed, because it causes distortions. A cosine shape is now used to transit between phase change of F0 to F1 and vice versa. This limits the spectrum. This filter is optional.
Diffstat (limited to 'src')
-rw-r--r--src/bnetz/dsp.c2
-rw-r--r--src/datenklo/am791x.c2
-rw-r--r--src/libfsk/fsk.c167
-rw-r--r--src/libfsk/fsk.h10
-rw-r--r--src/nmt/dsp.c2
-rw-r--r--src/r2000/dsp.c4
6 files changed, 137 insertions, 50 deletions
diff --git a/src/bnetz/dsp.c b/src/bnetz/dsp.c
index 809cb53..5305183 100644
--- a/src/bnetz/dsp.c
+++ b/src/bnetz/dsp.c
@@ -420,7 +420,7 @@ void bnetz_set_dsp_mode(bnetz_t *bnetz, enum dsp_mode mode)
/* reset telegramm */
if (mode == DSP_MODE_TELEGRAMM && bnetz->dsp_mode != mode) {
bnetz->tx_telegramm = 0;
- fsk_mod_tx_reset(&bnetz->fsk_mod);
+ fsk_mod_reset(&bnetz->fsk_mod);
}
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "DSP mode %s -> %s\n", bnetz_dsp_mode_name(bnetz->dsp_mode), bnetz_dsp_mode_name(mode));
diff --git a/src/datenklo/am791x.c b/src/datenklo/am791x.c
index 146a779..b3164af 100644
--- a/src/datenklo/am791x.c
+++ b/src/datenklo/am791x.c
@@ -314,7 +314,7 @@ int send_sto(am791x_t *am791x, sample_t *sample, int length)
/* modulate STO */
phaseshift = am791x->sto_phaseshift65536;
- while (count < length && fsk->tx_bitpos < 1.0) {
+ while (count < length) {
sample[count++] = fsk->sin_tab[(uint16_t)phase];
phase += phaseshift;
if (phase >= 65536.0)
diff --git a/src/libfsk/fsk.c b/src/libfsk/fsk.c
index 6604de0..dcc437d 100644
--- a/src/libfsk/fsk.c
+++ b/src/libfsk/fsk.c
@@ -29,6 +29,12 @@
#define PI M_PI
+/* uncomment to see the modulated curve */
+//#define DEBUG_MODULATOR
+
+/* uncomment to see the shape of the filter */
+//#define DEBUG_MODULATOR_SHAPE
+
/*
* fsk = instance of fsk modem
* inst = instance of user
@@ -41,6 +47,7 @@
*/
int fsk_mod_init(fsk_mod_t *fsk, void *inst, int (*send_bit)(void *inst), int samplerate, double bitrate, double f0, double f1, double level, int ffsk, int filter)
{
+ double temp;
int i;
int rc;
@@ -49,7 +56,7 @@ int fsk_mod_init(fsk_mod_t *fsk, void *inst, int (*send_bit)(void *inst), int sa
memset(fsk, 0, sizeof(*fsk));
/* gen sine table with deviation */
- fsk->sin_tab = calloc(65536+16384, sizeof(*fsk->sin_tab));
+ fsk->sin_tab = calloc(65536, sizeof(*fsk->sin_tab));
if (!fsk->sin_tab) {
fprintf(stderr, "No mem!\n");
rc = -ENOMEM;
@@ -59,7 +66,6 @@ int fsk_mod_init(fsk_mod_t *fsk, void *inst, int (*send_bit)(void *inst), int sa
fsk->sin_tab[i] = sin((double)i / 65536.0 * 2.0 * PI) * level;
fsk->inst = inst;
- fsk->tx_bit = -1;
fsk->level = level;
fsk->send_bit = send_bit;
fsk->f0_deviation = (f0 - f1) / 2.0;
@@ -72,12 +78,12 @@ int fsk_mod_init(fsk_mod_t *fsk, void *inst, int (*send_bit)(void *inst), int sa
fsk->high_bit = 0;
}
- fsk->bits_per_sample = (double)bitrate / (double)samplerate;
- PDEBUG(DDSP, DEBUG_DEBUG, "Bitduration of %.4f bits per sample @ %d.\n", fsk->bits_per_sample, samplerate);
+ fsk->bits65536_per_sample = (double)bitrate / (double)samplerate * 65536.0;
+ PDEBUG(DDSP, DEBUG_DEBUG, "Bitduration of %.4f bits per sample @ %d.\n", fsk->bits65536_per_sample / 65536.0, samplerate);
fsk->phaseshift65536[0] = f0 / (double)samplerate * 65536.0;
- PDEBUG(DDSP, DEBUG_DEBUG, "F0 = %.0f Hz (phaseshift65536[0] = %.4f)\n", f0, fsk->phaseshift65536[0]);
fsk->phaseshift65536[1] = f1 / (double)samplerate * 65536.0;
+ PDEBUG(DDSP, DEBUG_DEBUG, "F0 = %.0f Hz (phaseshift65536[0] = %.4f)\n", f0, fsk->phaseshift65536[0]);
PDEBUG(DDSP, DEBUG_DEBUG, "F1 = %.0f Hz (phaseshift65536[1] = %.4f)\n", f1, fsk->phaseshift65536[1]);
/* use ffsk modulation, i.e. each bit has an integer number of
@@ -86,6 +92,12 @@ int fsk_mod_init(fsk_mod_t *fsk, void *inst, int (*send_bit)(void *inst), int sa
if (ffsk) {
double waves;
+ if (filter) {
+ PDEBUG(DDSP, DEBUG_ERROR, "Cannot use FFSK with filter.\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
PDEBUG(DDSP, DEBUG_DEBUG, "enable FFSK modulation mode\n");
fsk->ffsk = 1;
waves = (f0 / bitrate);
@@ -100,22 +112,39 @@ int fsk_mod_init(fsk_mod_t *fsk, void *inst, int (*send_bit)(void *inst), int sa
abort();
}
fsk->cycles_per_bit65536[1] = waves * 65536.0;
+ } else {
+ fsk->cycles_per_bit65536[0] = f0 / bitrate * 65536.0;
+ fsk->cycles_per_bit65536[1] = f1 / bitrate * 65536.0;
}
+ PDEBUG(DDSP, DEBUG_DEBUG, "F0 = %.0f Hz (cycles_per_bit65536[0] = %.4f)\n", f0, fsk->cycles_per_bit65536[0]);
+ PDEBUG(DDSP, DEBUG_DEBUG, "F1 = %.0f Hz (cycles_per_bit65536[1] = %.4f)\n", f1, fsk->cycles_per_bit65536[1]);
- /* if filter is enabled, add a band pass filter to smooth the spectrum of the tones
- * the bandwidth is twice the difference between f0 and f1
- */
+ /* if filter is enabled, use a cosine shaped curve to change the phase each sample */
if (filter) {
- double low = (f0 + f1) / 2.0 - fabs(f0 - f1);
- double high = (f0 + f1) / 2.0 + fabs(f0 - f1);
+ fsk->phase_tab_0_1 = calloc(65536 + 65536, sizeof(*fsk->sin_tab));
+ if (!fsk->phase_tab_0_1) {
+ fprintf(stderr, "No mem!\n");
+ rc = -ENOMEM;
+ goto error;
+ }
+ fsk->phase_tab_1_0 = fsk->phase_tab_0_1 + 65536;
+ for (i = 0; i < 65536; i++) {
+ temp = cos((double)i / 65536.0 * PI) / 2 + 0.5; /* half cosine going from 1 to 0 */
+ fsk->phase_tab_0_1[i] = temp * fsk->phaseshift65536[0] + (1.0 - temp) * fsk->phaseshift65536[1];
+ fsk->phase_tab_1_0[i] = temp * fsk->phaseshift65536[1] + (1.0 - temp) * fsk->phaseshift65536[0];
+#ifdef DEBUG_MODULATOR_SHAPE
+ fsk->phase_tab_0_1[i] = 1.0 - temp;
+ fsk->phase_tab_1_0[i] = temp;
+#endif
+ }
- PDEBUG(DDSP, DEBUG_DEBUG, "enable filter to smooth FSK transmission. (frequency rage %.0f .. %.0f)\n", low, high);
+ PDEBUG(DDSP, DEBUG_DEBUG, "Enable filter to smooth FSK transmission.\n");
fsk->filter = 1;
- /* use fourth order (2 iter) filter, since it is as fast as second order (1 iter) filter */
- iir_highpass_init(&fsk->lp[0], low, samplerate, 2);
- iir_lowpass_init(&fsk->lp[1], high, samplerate, 2);
}
+ /* must reset, because bit states must be initialized */
+ fsk_mod_reset(fsk);
+
return 0;
error:
@@ -132,6 +161,11 @@ void fsk_mod_cleanup(fsk_mod_t *fsk)
free(fsk->sin_tab);
fsk->sin_tab = NULL;
}
+ if (fsk->phase_tab_0_1) {
+ free(fsk->phase_tab_0_1);
+ fsk->phase_tab_0_1 = NULL;
+ fsk->phase_tab_1_0 = NULL;
+ }
}
/* modulate bits
@@ -154,12 +188,16 @@ int fsk_mod_send(fsk_mod_t *fsk, sample_t *sample, int length, int add)
/* get next bit */
if (fsk->tx_bit < 0) {
next_bit:
+ fsk->tx_last_bit = fsk->tx_bit;
fsk->tx_bit = fsk->send_bit(fsk->inst);
#ifdef DEBUG_MODULATOR
- printf("bit change to %d\n", fsk->tx_bit);
+ printf("bit change from %d to %d\n", fsk->tx_last_bit, fsk->tx_bit);
#endif
- if (fsk->tx_bit < 0)
+ if (fsk->tx_bit < 0) {
+ fsk_mod_reset(fsk);
goto done;
+ }
+ fsk->tx_bit &= 1;
/* correct phase when changing bit */
if (fsk->ffsk) {
/* round phase to nearest zero crossing */
@@ -167,40 +205,86 @@ next_bit:
phase = 32768.0;
else
phase = 0;
- /* set phase according to current position in bit */
- phase += fsk->tx_bitpos * fsk->cycles_per_bit65536[fsk->tx_bit & 1];
#ifdef DEBUG_MODULATOR
- printf("phase %.3f bitpos=%.6f\n", phase, fsk->tx_bitpos);
+ printf("phase %.3f bitpos=%.6f\n", phase / 65536.0, fsk->tx_bitpos65536 / 65536.0);
#endif
}
+ if (!fsk->filter) {
+ /* change phase forward to the current bit position */
+ phase += fsk->tx_bitpos65536 / 65536.0 * fsk->cycles_per_bit65536[fsk->tx_bit];
+ if (phase >= 65536.0)
+ phase -= 65536.0;
+ }
}
/* modulate bit */
- phaseshift = fsk->phaseshift65536[fsk->tx_bit & 1];
- while (count < length && fsk->tx_bitpos < 1.0) {
- if (add)
- sample[count++] += fsk->sin_tab[(uint16_t)phase];
- else
- sample[count++] = fsk->sin_tab[(uint16_t)phase];
+ if (!fsk->filter || fsk->tx_last_bit < 0 || fsk->tx_last_bit == fsk->tx_bit) {
+ /* without filtering or when there is no bit change */
+ phaseshift = fsk->phaseshift65536[fsk->tx_bit];
+ while (count < length && fsk->tx_bitpos65536 < 65536.0) {
+ if (add)
+ sample[count++] += fsk->sin_tab[(uint16_t)phase];
+ else
+ sample[count++] = fsk->sin_tab[(uint16_t)phase];
+#ifdef DEBUG_MODULATOR
+ printf("|%s| %d\n", debug_amplitude(fsk->sin_tab[(uint16_t)phase] / fsk->level), fsk->tx_bit);
+#endif
+#ifdef DEBUG_MODULATOR_SHAPE
+ printf("|%s| %d\n", debug_amplitude(fsk->tx_bit), fsk->tx_bit);
+#endif
+ phase += phaseshift;
+ if (phase >= 65536.0)
+ phase -= 65536.0;
+ fsk->tx_bitpos65536 += fsk->bits65536_per_sample;
+ }
+ } else if (fsk->tx_bit > fsk->tx_last_bit) {
+ /* with cosine shape filter, going from phase of 0 to phase of 1 */
+ while (count < length && fsk->tx_bitpos65536 < 65536.0) {
+ if (add)
+ sample[count++] += fsk->sin_tab[(uint16_t)phase];
+ else
+ sample[count++] = fsk->sin_tab[(uint16_t)phase];
+#ifdef DEBUG_MODULATOR
+ printf("|%s| 0->1\n", debug_amplitude(fsk->sin_tab[(uint16_t)phase] / fsk->level));
+#endif
+#ifdef DEBUG_MODULATOR_SHAPE
+ printf("|%s|0->1\n", debug_amplitude(fsk->phase_tab_0_1[(uint16_t)fsk->tx_bitpos65536]));
+#endif
+ phase += fsk->phase_tab_0_1[(uint16_t)fsk->tx_bitpos65536];
+ if (phase >= 65536.0)
+ phase -= 65536.0;
+ fsk->tx_bitpos65536 += fsk->bits65536_per_sample;
+ }
+ } else {
+ /* with cosine shape filter, going from phase of 1 to phase of 0 */
+ while (count < length && fsk->tx_bitpos65536 < 65536.0) {
+ if (add)
+ sample[count++] += fsk->sin_tab[(uint16_t)phase];
+ else
+ sample[count++] = fsk->sin_tab[(uint16_t)phase];
#ifdef DEBUG_MODULATOR
- printf("|%s|\n", debug_amplitude(fsk->sin_tab[(uint16_t)phase] / fsk->level));
+ printf("|%s|1->0\n", debug_amplitude(fsk->sin_tab[(uint16_t)phase] / fsk->level));
+#endif
+#ifdef DEBUG_MODULATOR_SHAPE
+ printf("|%s|1->0\n", debug_amplitude(fsk->phase_tab_1_0[(uint16_t)fsk->tx_bitpos65536]));
#endif
- phase += phaseshift;
- if (phase >= 65536.0)
- phase -= 65536.0;
- fsk->tx_bitpos += fsk->bits_per_sample;
+ phase += fsk->phase_tab_1_0[(uint16_t)fsk->tx_bitpos65536];
+ if (phase >= 65536.0)
+ phase -= 65536.0;
+ fsk->tx_bitpos65536 += fsk->bits65536_per_sample;
+ }
}
- if (fsk->tx_bitpos >= 1.0) {
- fsk->tx_bitpos -= 1.0;
+ if (fsk->tx_bitpos65536 >= 65536.0) {
+ fsk->tx_bitpos65536 -= 65536.0;
+ if (!fsk->filter) {
+ /* change phase back to the point when bit has changed */
+ phase -= fsk->tx_bitpos65536 / 65536.0 * fsk->cycles_per_bit65536[fsk->tx_bit];
+ if (phase < 0.0)
+ phase += 65536.0;
+ }
goto next_bit;
}
- /* post filter */
- if (fsk->filter) {
- iir_process(&fsk->lp[0], sample, length);
- iir_process(&fsk->lp[1], sample, length);
- }
-
done:
fsk->tx_phase65536 = phase;
@@ -208,11 +292,12 @@ done:
}
/* reset transmitter state, so we get a clean start */
-void fsk_mod_tx_reset(fsk_mod_t *fsk)
+void fsk_mod_reset(fsk_mod_t *fsk)
{
- fsk->tx_phase65536 = 0;
- fsk->tx_bitpos = 0;
+ fsk->tx_phase65536 = 0.0;
+ fsk->tx_bitpos65536 = 0.0;
fsk->tx_bit = -1;
+ fsk->tx_last_bit = -1;
}
/*
diff --git a/src/libfsk/fsk.h b/src/libfsk/fsk.h
index cb62170..da67f46 100644
--- a/src/libfsk/fsk.h
+++ b/src/libfsk/fsk.h
@@ -6,8 +6,10 @@
typedef struct fsk_mod {
void *inst;
int (*send_bit)(void *inst);
- double bits_per_sample; /* fraction of a bit per sample */
+ double bits65536_per_sample; /* fraction of a bit per sample */
double *sin_tab; /* sine table with correct peak level */
+ double *phase_tab_0_1; /* cosine shaped phase table (bit 0 to 1) */
+ double *phase_tab_1_0; /* cosine shaped phase table (bit 1 to 0) */
double phaseshift65536[2]; /* how much the phase of fsk synbol changes per sample */
double cycles_per_bit65536[2]; /* cycles of one bit */
double tx_phase65536; /* current transmit phase */
@@ -17,9 +19,9 @@ typedef struct fsk_mod {
double f1_deviation;
int low_bit, high_bit; /* a low or high deviation means which bit? */
int tx_bit; /* current transmitting bit (-1 if not set) */
- double tx_bitpos; /* current transmit position in bit */
+ int tx_last_bit; /* last transmitting bit (-1 if not set) */
+ double tx_bitpos65536; /* current transmit position in bit */
int filter; /* set, if filters are used */
- iir_filter_t lp[2]; /* filter to smooth transmission spectrum */
} fsk_mod_t;
typedef struct fsk_demod {
@@ -39,7 +41,7 @@ typedef struct fsk_demod {
int fsk_mod_init(fsk_mod_t *fsk, void *inst, int (*send_bit)(void *inst), int samplerate, double bitrate, double f0, double f1, double level, int coherent, int filter);
void fsk_mod_cleanup(fsk_mod_t *fsk);
int fsk_mod_send(fsk_mod_t *fsk, sample_t *sample, int length, int add);
-void fsk_mod_tx_reset(fsk_mod_t *fsk);
+void fsk_mod_reset(fsk_mod_t *fsk);
int fsk_demod_init(fsk_demod_t *fsk, void *inst, void (*receive_bit)(void *inst, int bit, double quality, double level), int samplerate, double bitrate, double f0, double f1, double bitadjust);
void fsk_demod_cleanup(fsk_demod_t *fsk);
void fsk_demod_receive(fsk_demod_t *fsk, sample_t *sample, int length);
diff --git a/src/nmt/dsp.c b/src/nmt/dsp.c
index 2d6e972..e63ae45 100644
--- a/src/nmt/dsp.c
+++ b/src/nmt/dsp.c
@@ -515,7 +515,7 @@ void nmt_set_dsp_mode(nmt_t *nmt, enum dsp_mode mode)
{
/* reset frame */
if (mode == DSP_MODE_FRAME && nmt->dsp_mode != mode) {
- fsk_mod_tx_reset(&nmt->fsk_mod);
+ fsk_mod_reset(&nmt->fsk_mod);
nmt->tx_frame_length = 0;
}
diff --git a/src/r2000/dsp.c b/src/r2000/dsp.c
index 79ae05b..bb3b97c 100644
--- a/src/r2000/dsp.c
+++ b/src/r2000/dsp.c
@@ -402,12 +402,12 @@ void r2000_set_dsp_mode(r2000_t *r2000, enum dsp_mode mode, int super)
/* reset telegramm */
if (mode == DSP_MODE_FRAME && r2000->dsp_mode != mode) {
r2000->tx_frame_length = 0;
- fsk_mod_tx_reset(&r2000->fsk_mod);
+ fsk_mod_reset(&r2000->fsk_mod);
}
if ((mode == DSP_MODE_AUDIO_TX || mode == DSP_MODE_AUDIO_TX_RX)
&& (r2000->dsp_mode != DSP_MODE_AUDIO_TX && r2000->dsp_mode != DSP_MODE_AUDIO_TX_RX)) {
r2000->super_tx_word_length = 0;
- fsk_mod_tx_reset(&r2000->super_fsk_mod);
+ fsk_mod_reset(&r2000->super_fsk_mod);
}
if (super >= 0) {