Split FSK modem code into separate modulator and demodulator
This commit is contained in:
232
src/libfsk/fsk.c
232
src/libfsk/fsk.c
@@ -33,21 +33,18 @@
|
||||
* fsk = instance of fsk modem
|
||||
* inst = instance of user
|
||||
* send_bit() = function to be called whenever a new bit has to be sent
|
||||
* receive_bit() = function to be called whenever a new bit was received
|
||||
* samplerate = samplerate
|
||||
* bitrate = bits per second
|
||||
* f0, f1 = two frequencies for bit 0 and bit 1
|
||||
* level = level to modulate the frequencies
|
||||
* coherent = use coherent modulation (FFSK)
|
||||
* bitadjust = how much to adjust the sample clock when a bitchange was detected. (0 = nothing, don't use this, 0.5 full adjustment)
|
||||
*/
|
||||
int fsk_init(fsk_t *fsk, void *inst, int (*send_bit)(void *inst), void (*receive_bit)(void *inst, int bit, double quality, double level), int samplerate, double bitrate, double f0, double f1, double level, int coherent, double bitadjust)
|
||||
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)
|
||||
{
|
||||
double bandwidth;
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Setup FSK for Transceiver. (F0 = %.1f, F1 = %.1f, peak = %.1f)\n", f0, f1, level);
|
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Setup FSK for Transmitter. (F0 = %.1f, F1 = %.1f, peak = %.1f)\n", f0, f1, level);
|
||||
|
||||
memset(fsk, 0, sizeof(*fsk));
|
||||
|
||||
@@ -62,9 +59,6 @@ int fsk_init(fsk_t *fsk, void *inst, int (*send_bit)(void *inst), void (*receive
|
||||
fsk->sin_tab[i] = sin((double)i / 65536.0 * 2.0 * PI) * level;
|
||||
|
||||
fsk->inst = inst;
|
||||
fsk->rx_bit = -1;
|
||||
fsk->rx_bitadjust = bitadjust;
|
||||
fsk->receive_bit = receive_bit;
|
||||
fsk->tx_bit = -1;
|
||||
fsk->level = level;
|
||||
fsk->send_bit = send_bit;
|
||||
@@ -78,14 +72,6 @@ int fsk_init(fsk_t *fsk, void *inst, int (*send_bit)(void *inst), void (*receive
|
||||
fsk->high_bit = 0;
|
||||
}
|
||||
|
||||
/* calculate bandwidth */
|
||||
bandwidth = fabs(f0 - f1) * 2.0;
|
||||
|
||||
/* init fm demodulator */
|
||||
rc = fm_demod_init(&fsk->demod, (double)samplerate, (f0 + f1) / 2.0, bandwidth);
|
||||
if (rc < 0)
|
||||
goto error;
|
||||
|
||||
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);
|
||||
|
||||
@@ -118,19 +104,150 @@ int fsk_init(fsk_t *fsk, void *inst, int (*send_bit)(void *inst), void (*receive
|
||||
return 0;
|
||||
|
||||
error:
|
||||
fsk_cleanup(fsk);
|
||||
fsk_mod_cleanup(fsk);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Cleanup transceiver instance. */
|
||||
void fsk_cleanup(fsk_t *fsk)
|
||||
void fsk_mod_cleanup(fsk_mod_t *fsk)
|
||||
{
|
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Cleanup FSK for Transceiver.\n");
|
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Cleanup FSK for Transmitter.\n");
|
||||
|
||||
if (fsk->sin_tab) {
|
||||
free(fsk->sin_tab);
|
||||
fsk->sin_tab = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* modulate bits
|
||||
*
|
||||
* If first/next bit is required, callback function send_bit() is called.
|
||||
* If there is no (more) data to be transmitted, the callback functions shall
|
||||
* return -1. In this case, this function stops and returns the number of
|
||||
* samples that have been rendered so far, if any.
|
||||
*
|
||||
* For coherent mode (FSK), we round the phase on every bit change to the
|
||||
* next zero crossing. This prevents phase shifts due to rounding errors.
|
||||
*/
|
||||
int fsk_mod_send(fsk_mod_t *fsk, sample_t *sample, int length, int add)
|
||||
{
|
||||
int count = 0;
|
||||
double phase, phaseshift;
|
||||
|
||||
phase = fsk->tx_phase65536;
|
||||
|
||||
/* get next bit */
|
||||
if (fsk->tx_bit < 0) {
|
||||
next_bit:
|
||||
fsk->tx_bit = fsk->send_bit(fsk->inst);
|
||||
#ifdef DEBUG_MODULATOR
|
||||
printf("bit change to %d\n", fsk->tx_bit);
|
||||
#endif
|
||||
if (fsk->tx_bit < 0)
|
||||
goto done;
|
||||
/* correct phase when changing bit */
|
||||
if (fsk->coherent) {
|
||||
/* round phase to nearest zero crossing */
|
||||
if (phase > 16384.0 && phase < 49152.0)
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* 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];
|
||||
#ifdef DEBUG_MODULATOR
|
||||
printf("|%s|\n", debug_amplitude(fsk->sin_tab[(uint16_t)phase] / fsk->level));
|
||||
#endif
|
||||
phase += phaseshift;
|
||||
if (phase >= 65536.0)
|
||||
phase -= 65536.0;
|
||||
fsk->tx_bitpos += fsk->bits_per_sample;
|
||||
}
|
||||
if (fsk->tx_bitpos >= 1.0) {
|
||||
fsk->tx_bitpos -= 1.0;
|
||||
goto next_bit;
|
||||
}
|
||||
|
||||
done:
|
||||
fsk->tx_phase65536 = phase;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* reset transmitter state, so we get a clean start */
|
||||
void fsk_mod_tx_reset(fsk_mod_t *fsk)
|
||||
{
|
||||
fsk->tx_phase65536 = 0;
|
||||
fsk->tx_bitpos = 0;
|
||||
fsk->tx_bit = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* fsk = instance of fsk modem
|
||||
* inst = instance of user
|
||||
* receive_bit() = function to be called whenever a new bit was received
|
||||
* samplerate = samplerate
|
||||
* bitrate = bits per second
|
||||
* f0, f1 = two frequencies for bit 0 and bit 1
|
||||
* bitadjust = how much to adjust the sample clock when a bitchange was detected. (0 = nothing, don't use this, 0.5 full adjustment)
|
||||
*/
|
||||
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)
|
||||
{
|
||||
double bandwidth;
|
||||
int rc;
|
||||
|
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Setup FSK for Receiver. (F0 = %.1f, F1 = %.1f)\n", f0, f1);
|
||||
|
||||
memset(fsk, 0, sizeof(*fsk));
|
||||
|
||||
fsk->inst = inst;
|
||||
fsk->rx_bit = -1;
|
||||
fsk->rx_bitadjust = bitadjust;
|
||||
fsk->receive_bit = receive_bit;
|
||||
fsk->f0_deviation = (f0 - f1) / 2.0;
|
||||
fsk->f1_deviation = (f1 - f0) / 2.0;
|
||||
if (f0 < f1) {
|
||||
fsk->low_bit = 0;
|
||||
fsk->high_bit = 1;
|
||||
} else {
|
||||
fsk->low_bit = 1;
|
||||
fsk->high_bit = 0;
|
||||
}
|
||||
|
||||
/* calculate bandwidth */
|
||||
bandwidth = fabs(f0 - f1) * 2.0;
|
||||
|
||||
/* init fm demodulator */
|
||||
rc = fm_demod_init(&fsk->demod, (double)samplerate, (f0 + f1) / 2.0, bandwidth);
|
||||
if (rc < 0)
|
||||
goto error;
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
fsk_demod_cleanup(fsk);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Cleanup transceiver instance. */
|
||||
void fsk_demod_cleanup(fsk_demod_t *fsk)
|
||||
{
|
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Cleanup FSK for Receiver.\n");
|
||||
|
||||
fm_demod_exit(&fsk->demod);
|
||||
}
|
||||
@@ -150,7 +267,7 @@ void fsk_cleanup(fsk_t *fsk)
|
||||
* Therefore we change the sample counter only slightly, so bit slips may not
|
||||
* happen so quickly.
|
||||
*/
|
||||
void fsk_receive(fsk_t *fsk, sample_t *sample, int length)
|
||||
void fsk_demod_receive(fsk_demod_t *fsk, sample_t *sample, int length)
|
||||
{
|
||||
sample_t I[length], Q[length], frequency[length], f;
|
||||
int i;
|
||||
@@ -211,78 +328,3 @@ void fsk_receive(fsk_t *fsk, sample_t *sample, int length)
|
||||
}
|
||||
}
|
||||
|
||||
/* modulate bits
|
||||
*
|
||||
* If first/next bit is required, callback function send_bit() is called.
|
||||
* If there is no (more) data to be transmitted, the callback functions shall
|
||||
* return -1. In this case, this function stops and returns the number of
|
||||
* samples that have been rendered so far, if any.
|
||||
*
|
||||
* For coherent mode (FSK), we round the phase on every bit change to the
|
||||
* next zero crossing. This prevents phase shifts due to rounding errors.
|
||||
*/
|
||||
int fsk_send(fsk_t *fsk, sample_t *sample, int length, int add)
|
||||
{
|
||||
int count = 0;
|
||||
double phase, phaseshift;
|
||||
|
||||
phase = fsk->tx_phase65536;
|
||||
|
||||
/* get next bit */
|
||||
if (fsk->tx_bit < 0) {
|
||||
next_bit:
|
||||
fsk->tx_bit = fsk->send_bit(fsk->inst);
|
||||
#ifdef DEBUG_MODULATOR
|
||||
printf("bit change to %d\n", fsk->tx_bit);
|
||||
#endif
|
||||
if (fsk->tx_bit < 0)
|
||||
goto done;
|
||||
/* correct phase when changing bit */
|
||||
if (fsk->coherent) {
|
||||
/* round phase to nearest zero crossing */
|
||||
if (phase > 16384.0 && phase < 49152.0)
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* 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];
|
||||
#ifdef DEBUG_MODULATOR
|
||||
printf("|%s|\n", debug_amplitude(fsk->sin_tab[(uint16_t)phase] / fsk->level));
|
||||
#endif
|
||||
phase += phaseshift;
|
||||
if (phase >= 65536.0)
|
||||
phase -= 65536.0;
|
||||
fsk->tx_bitpos += fsk->bits_per_sample;
|
||||
}
|
||||
if (fsk->tx_bitpos >= 1.0) {
|
||||
fsk->tx_bitpos -= 1.0;
|
||||
goto next_bit;
|
||||
}
|
||||
|
||||
done:
|
||||
fsk->tx_phase65536 = phase;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* reset transmitter state, so we get a clean start */
|
||||
void fsk_tx_reset(fsk_t *fsk)
|
||||
{
|
||||
fsk->tx_phase65536 = 0;
|
||||
fsk->tx_bitpos = 0;
|
||||
fsk->tx_bit = -1;
|
||||
}
|
||||
|
||||
|
@@ -1,14 +1,12 @@
|
||||
#include "../libfm/fm.h"
|
||||
|
||||
typedef struct ffsk {
|
||||
typedef struct fsk_mod {
|
||||
void *inst;
|
||||
int (*send_bit)(void *inst);
|
||||
void (*receive_bit)(void *inst, int bit, double quality, double level);
|
||||
fm_demod_t demod;
|
||||
double bits_per_sample; /* fraction of a bit per sample */
|
||||
double *sin_tab; /* sine table with correct peak level */
|
||||
double phaseshift65536[2]; /* how much the phase of fsk synbol changes per sample */
|
||||
double cycles_per_bit65536[2]; /* cacles of one bit */
|
||||
double cycles_per_bit65536[2]; /* cycles of one bit */
|
||||
double tx_phase65536; /* current transmit phase */
|
||||
double level; /* level (amplitude) of signal */
|
||||
int coherent; /* set, if coherent TX mode */
|
||||
@@ -16,15 +14,27 @@ typedef struct ffsk {
|
||||
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) */
|
||||
int rx_bit; /* current receiving bit (-1 if not yet measured) */
|
||||
double tx_bitpos; /* current transmit position in bit */
|
||||
} fsk_mod_t;
|
||||
|
||||
typedef struct fsk_demod {
|
||||
void *inst;
|
||||
void (*receive_bit)(void *inst, int bit, double quality, double level);
|
||||
fm_demod_t demod;
|
||||
double bits_per_sample; /* fraction of a bit per sample */
|
||||
double f0_deviation; /* deviation of frequencies, relative to center */
|
||||
double f1_deviation;
|
||||
int low_bit, high_bit; /* a low or high deviation means which bit? */
|
||||
int rx_bit; /* current receiving bit (-1 if not yet measured) */
|
||||
double rx_bitpos; /* current receive position in bit (sampleclock) */
|
||||
double rx_bitadjust; /* how much does a bit change cause the sample clock to be adjusted in phase */
|
||||
} fsk_t;
|
||||
} fsk_demod_t;
|
||||
|
||||
int fsk_init(fsk_t *fsk, void *inst, int (*send_bit)(void *inst), void (*receive_bit)(void *inst, int bit, double quality, double level), int samplerate, double bitrate, double f0, double f1, double level, int coherent, double bitadjust);
|
||||
void fsk_cleanup(fsk_t *fsk);
|
||||
void fsk_receive(fsk_t *fsk, sample_t *sample, int length);
|
||||
int fsk_send(fsk_t *fsk, sample_t *sample, int length, int add);
|
||||
void fsk_tx_reset(fsk_t *fsk);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
|
Reference in New Issue
Block a user