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:
parent
7609e98b8f
commit
fd3b4dae50
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
157
src/libfsk/fsk.c
157
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,21 +112,38 @@ 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);
|
||||
|
||||
PDEBUG(DDSP, DEBUG_DEBUG, "enable filter to smooth FSK transmission. (frequency rage %.0f .. %.0f)\n", low, high);
|
||||
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);
|
||||
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.\n");
|
||||
fsk->filter = 1;
|
||||
}
|
||||
|
||||
/* must reset, because bit states must be initialized */
|
||||
fsk_mod_reset(fsk);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -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 (!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
|
||||
#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_bitpos += fsk->bits_per_sample;
|
||||
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_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;
|
||||
}
|
||||
if (fsk->tx_bitpos >= 1.0) {
|
||||
fsk->tx_bitpos -= 1.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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue