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.
This commit is contained in:
Andreas Eversberg 2022-12-16 10:18:19 +01:00
parent 7609e98b8f
commit fd3b4dae50
6 changed files with 137 additions and 50 deletions

View File

@ -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));

View File

@ -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)

View File

@ -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|\n", debug_amplitude(fsk->sin_tab[(uint16_t)phase] / fsk->level));
printf("|%s| %d\n", debug_amplitude(fsk->sin_tab[(uint16_t)phase] / fsk->level), fsk->tx_bit);
#endif
phase += phaseshift;
if (phase >= 65536.0)
phase -= 65536.0;
fsk->tx_bitpos += fsk->bits_per_sample;
#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|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 += 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;
}
/*

View File

@ -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);

View File

@ -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;
}

View File

@ -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) {