diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/Makefile.am | 2 | ||||
-rw-r--r-- | src/common/ffsk.c | 256 | ||||
-rw-r--r-- | src/common/ffsk.h | 27 | ||||
-rw-r--r-- | src/common/fm_modulation.c | 123 | ||||
-rw-r--r-- | src/common/fm_modulation.h | 12 | ||||
-rw-r--r-- | src/common/fsk.c | 293 | ||||
-rw-r--r-- | src/common/fsk.h | 31 | ||||
-rw-r--r-- | src/common/sdr.c | 32 |
8 files changed, 456 insertions, 320 deletions
diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 92447dc..5b15507 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -24,7 +24,7 @@ libcommon_a_SOURCES = \ compandor.c \ fft.c \ fm_modulation.c \ - ffsk.c \ + fsk.c \ hagelbarger.c \ sender.c \ display_wave.c \ diff --git a/src/common/ffsk.c b/src/common/ffsk.c deleted file mode 100644 index fdbf255..0000000 --- a/src/common/ffsk.c +++ /dev/null @@ -1,256 +0,0 @@ -/* FFSK audio processing (NMT / Radiocom 2000) - * - * (C) 2017 by Andreas Eversberg <jolly@eversberg.eu> - * 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 <http://www.gnu.org/licenses/>. - */ - -#define CHAN ffsk->channel - -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <math.h> -#include "../common/sample.h" -#include "../common/debug.h" -#include "ffsk.h" - -#define PI M_PI - -#define BIT_RATE 1200 /* baud rate */ -#define FILTER_STEPS 0.1 /* step every 1/12000 sec */ - -/* two signaling tones */ -static double ffsk_freq[2] = { - 1800.0, - 1200.0, -}; - -static sample_t dsp_tone_bit[2][2][65536]; /* polarity, bit, phase */ - -/* global init for FFSK */ -void ffsk_global_init(double peak_fsk) -{ - int i; - double s; - - PDEBUG(DDSP, DEBUG_DEBUG, "Generating sine table for FFSK tones.\n"); - for (i = 0; i < 65536; i++) { - s = sin((double)i / 65536.0 * 2.0 * PI); - /* bit(1) 1 cycle */ - dsp_tone_bit[0][1][i] = s * peak_fsk; - dsp_tone_bit[1][1][i] = -s * peak_fsk; - /* bit(0) 1.5 cycles */ - s = sin((double)i / 65536.0 * 3.0 * PI); - dsp_tone_bit[0][0][i] = s * peak_fsk; - dsp_tone_bit[1][0][i] = -s * peak_fsk; - } -} - -/* Init FFSK */ -int ffsk_init(ffsk_t *ffsk, void *inst, void (*receive_bit)(void *inst, int bit, double quality, double level), int channel, int samplerate) -{ - sample_t *spl; - int i; - - /* a symbol rate of 1200 Hz, times check interval of FILTER_STEPS */ - if (samplerate < (double)BIT_RATE / (double)FILTER_STEPS) { - PDEBUG(DDSP, DEBUG_ERROR, "Sample rate must be at least 12000 Hz to process FSK+supervisory signal.\n"); - return -EINVAL; - } - - memset(ffsk, 0, sizeof(*ffsk)); - ffsk->inst = inst; - ffsk->receive_bit = receive_bit; - ffsk->channel = channel; - ffsk->samplerate = samplerate; - - ffsk->samples_per_bit = (double)ffsk->samplerate / (double)BIT_RATE; - ffsk->bits_per_sample = 1.0 / ffsk->samples_per_bit; - PDEBUG(DDSP, DEBUG_DEBUG, "Use %.4f samples for full bit duration @ %d.\n", ffsk->samples_per_bit, ffsk->samplerate); - - /* allocate ring buffers, one bit duration */ - ffsk->filter_size = floor(ffsk->samples_per_bit); /* buffer holds one bit (rounded down) */ - spl = calloc(1, ffsk->filter_size * sizeof(*spl)); - if (!spl) { - PDEBUG(DDSP, DEBUG_ERROR, "No memory!\n"); - ffsk_cleanup(ffsk); - return -ENOMEM; - } - ffsk->filter_spl = spl; - ffsk->filter_bit = -1; - - /* count symbols */ - for (i = 0; i < 2; i++) - audio_goertzel_init(&ffsk->goertzel[i], ffsk_freq[i], ffsk->samplerate); - ffsk->phaseshift65536 = 65536.0 / ffsk->samples_per_bit; - PDEBUG(DDSP, DEBUG_DEBUG, "fsk_phaseshift = %.4f\n", ffsk->phaseshift65536); - - return 0; -} - -/* Cleanup transceiver instance. */ -void ffsk_cleanup(ffsk_t *ffsk) -{ - PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Cleanup DSP for Transceiver.\n"); - - if (ffsk->filter_spl) { - free(ffsk->filter_spl); - ffsk->filter_spl = NULL; - } -} - -//#define DEBUG_MODULATOR -//#define DEBUG_FILTER -//#define DEBUG_QUALITY - -/* Filter one chunk of audio an detect tone, quality and loss of signal. - * The chunk is a window of 1/1200s. This window slides over audio stream - * and is processed every 1/12000s. (one step) */ -static inline void ffsk_decode_step(ffsk_t *ffsk, int pos) -{ - double level, result[2], softbit, quality; - int max; - sample_t *spl; - int bit; - - max = ffsk->filter_size; - spl = ffsk->filter_spl; - - level = audio_level(spl, max); - /* limit level to prevent division by zero */ - if (level < 0.001) - level = 0.001; - - audio_goertzel(ffsk->goertzel, spl, max, pos, result, 2); - - /* calculate soft bit from both frequencies */ - softbit = (result[1] / level - result[0] / level + 1.0) / 2.0; -//printf("%.3f: %.3f\n", level, softbit); - /* scale it, since both filters overlap by some percent */ -#define MIN_QUALITY 0.33 - softbit = (softbit - MIN_QUALITY) / (1.0 - MIN_QUALITY - MIN_QUALITY); -#ifdef DEBUG_FILTER -// printf("|%s", debug_amplitude(result[0]/level)); -// printf("|%s| low=%.3f high=%.3f level=%d\n", debug_amplitude(result[1]/level), result[0]/level, result[1]/level, (int)level); - printf("|%s| softbit=%.3f\n", debug_amplitude(softbit), softbit); -#endif - if (softbit > 1) - softbit = 1; - if (softbit < 0) - softbit = 0; - if (softbit > 0.5) - bit = 1; - else - bit = 0; - - if (ffsk->filter_bit != bit) { - /* If we have a bit change, move sample counter towards one half bit duration. - * We may have noise, so the bit change may be wrong or not at the correct place. - * This can cause bit slips. - * Therefore we change the sample counter only slightly, so bit slips may not - * happen so quickly. - * */ -#ifdef DEBUG_FILTER - puts("bit change"); -#endif - ffsk->filter_bit = bit; - if (ffsk->filter_sample < 5) - ffsk->filter_sample++; - if (ffsk->filter_sample > 5) - ffsk->filter_sample--; - } else if (--ffsk->filter_sample == 0) { - /* if sample counter bit reaches 0, we reset sample counter to one bit duration */ -#ifdef DEBUG_FILTER - puts("sample"); -#endif -// quality = result[bit] / level; - if (softbit > 0.5) - quality = softbit * 2.0 - 1.0; - else - quality = 1.0 - softbit * 2.0; -#ifdef DEBUG_QUALITY - printf("|%s| quality=%.2f ", debug_amplitude(softbit), quality); - printf("|%s|\n", debug_amplitude(quality)); -#endif - /* adjust level, so a peak level becomes 100% */ - ffsk->receive_bit(ffsk->inst, bit, quality, level / 0.63662); - ffsk->filter_sample = 10; - } -} - -void ffsk_receive(ffsk_t *ffsk, sample_t *sample, int length) -{ - sample_t *spl; - int max, pos; - double step, bps; - int i; - - /* write received samples to decode buffer */ - max = ffsk->filter_size; - pos = ffsk->filter_pos; - step = ffsk->filter_step; - bps = ffsk->bits_per_sample; - spl = ffsk->filter_spl; - for (i = 0; i < length; i++) { -#ifdef DEBUG_MODULATOR - printf("|%s|\n", debug_amplitude((double)samples[i] / 2333.0 /*fsk peak*/ / 2.0)); -#endif - /* write into ring buffer */ - spl[pos++] = sample[i]; - if (pos == max) - pos = 0; - /* if 1/10th of a bit duration is reached, decode buffer */ - step += bps; - if (step >= FILTER_STEPS) { - step -= FILTER_STEPS; - ffsk_decode_step(ffsk, pos); - } - } - ffsk->filter_step = step; - ffsk->filter_pos = pos; -} - -/* render frame */ -int ffsk_render_frame(ffsk_t *ffsk, const char *frame, int length, sample_t *sample) -{ - int bit, polarity; - double phaseshift, phase; - int count = 0, i; - - polarity = ffsk->polarity; - phaseshift = ffsk->phaseshift65536; - phase = ffsk->phase65536; - for (i = 0; i < length; i++) { - bit = (frame[i] == '1'); - do { - *sample++ = dsp_tone_bit[polarity][bit][(uint16_t)phase]; - count++; - phase += phaseshift; - } while (phase < 65536.0); - phase -= 65536.0; - /* flip polarity when we have 1.5 sine waves */ - if (bit == 0) - polarity = 1 - polarity; - } - ffsk->phase65536 = phase; - ffsk->polarity = polarity; - - /* return number of samples created for frame */ - return count; -} - diff --git a/src/common/ffsk.h b/src/common/ffsk.h deleted file mode 100644 index 84fc52a..0000000 --- a/src/common/ffsk.h +++ /dev/null @@ -1,27 +0,0 @@ -#include "../common/goertzel.h" - -typedef struct ffsk { - void *inst; - void (*receive_bit)(void *inst, int bit, double quality, double level); - int channel; /* channel number */ - int samplerate; /* current sample rate */ - double samples_per_bit; /* number of samples for one bit (1200 Baud) */ - double bits_per_sample; /* fraction of a bit per sample */ - goertzel_t goertzel[2]; /* filter for fsk decoding */ - int polarity; /* current polarity state of bit */ - sample_t *filter_spl; /* array to hold ring buffer for bit decoding */ - int filter_size; /* size of ring buffer */ - int filter_pos; /* position to write next sample */ - double filter_step; /* counts bit duration, to trigger decoding every 10th bit */ - int filter_bit; /* last bit state, so we detect a bit change */ - int filter_sample; /* count until it is time to sample bit */ - double phaseshift65536; /* how much the phase of fsk synbol changes per sample */ - double phase65536; /* current phase */ -} ffsk_t; - -void ffsk_global_init(double peak_fsk); -int ffsk_init(ffsk_t *ffsk, void *inst, void (*receive_bit)(void *inst, int bit, double quality, double level), int channel, int samplerate); -void ffsk_cleanup(ffsk_t *ffsk); -void ffsk_receive(ffsk_t *ffsk, sample_t *sample, int lenght); -int ffsk_render_frame(ffsk_t *ffsk, const char *frame, int length, sample_t *sample); - diff --git a/src/common/fm_modulation.c b/src/common/fm_modulation.c index aaf7e2c..2aa688a 100644 --- a/src/common/fm_modulation.c +++ b/src/common/fm_modulation.c @@ -23,13 +23,12 @@ #include <string.h> #include <math.h> #include "sample.h" -#include "iir_filter.h" #include "fm_modulation.h" //#define FAST_SINE /* init FM modulator */ -void fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitude) +int fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitude) { memset(mod, 0, sizeof(*mod)); mod->samplerate = samplerate; @@ -42,17 +41,27 @@ void fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitu mod->sin_tab = calloc(65536+16384, sizeof(*mod->sin_tab)); if (!mod->sin_tab) { fprintf(stderr, "No mem!\n"); - abort(); + 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; } -/* do frequency modulation of samples and add them to existing buff */ -void fm_modulate(fm_mod_t *mod, sample_t *samples, int num, float *buff) +void fm_mod_exit(fm_mod_t *mod) +{ + 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, int length, float *baseband) { double dev, rate, phase, offset; int s, ss; @@ -73,25 +82,25 @@ void fm_modulate(fm_mod_t *mod, sample_t *samples, int num, float *buff) #endif /* modulate */ - for (s = 0, ss = 0; s < num; s++) { - /* deviation is defined by the sample value and the offset */ - dev = offset + samples[s]; + for (s = 0, ss = 0; s < length; s++) { + /* deviation is defined by the frequency value and the offset */ + dev = offset + frequency[s]; #ifdef FAST_SINE phase += 65536.0 * dev / rate; if (phase < 0.0) phase += 65536.0; else if (phase >= 65536.0) phase -= 65536.0; - buff[ss++] += cos_tab[(uint16_t)phase]; - buff[ss++] += sin_tab[(uint16_t)phase]; + baseband[ss++] += cos_tab[(uint16_t)phase]; + baseband[ss++] += 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; - buff[ss++] += cos(phase) * amplitude; - buff[ss++] += sin(phase) * amplitude; + baseband[ss++] += cos(phase) * amplitude; + baseband[ss++] += sin(phase) * amplitude; #endif } @@ -99,7 +108,7 @@ void fm_modulate(fm_mod_t *mod, sample_t *samples, int num, float *buff) } /* init FM demodulator */ -void fm_demod_init(fm_demod_t *demod, double samplerate, double offset, double bandwidth) +int fm_demod_init(fm_demod_t *demod, double samplerate, double offset, double bandwidth) { memset(demod, 0, sizeof(*demod)); demod->samplerate = samplerate; @@ -119,21 +128,31 @@ void fm_demod_init(fm_demod_t *demod, double samplerate, double offset, double b demod->sin_tab = calloc(65536+16384, sizeof(*demod->sin_tab)); if (!demod->sin_tab) { fprintf(stderr, "No mem!\n"); - abort(); + 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 buff and write them to samples */ -void fm_demodulate(fm_demod_t *demod, sample_t *samples, int num, float *buff) +/* 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[num], Q[num], i, q; + sample_t i, q; int s, ss; #ifdef FAST_SINE double *sin_tab, *cos_tab; @@ -146,10 +165,10 @@ void fm_demodulate(fm_demod_t *demod, sample_t *samples, int num, float *buff) sin_tab = demod->sin_tab; cos_tab = demod->sin_tab + 16384; #endif - for (s = 0, ss = 0; s < num; s++) { + for (s = 0, ss = 0; s < length; s++) { phase += rot; - i = buff[ss++]; - q = buff[ss++]; + i = baseband[ss++]; + q = baseband[ss++]; #ifdef FAST_SINE if (phase < 0.0) phase += 65536.0; @@ -169,10 +188,66 @@ void fm_demodulate(fm_demod_t *demod, sample_t *samples, int num, float *buff) Q[s] = i * _sin + q * _cos; } demod->phase = phase; - iir_process(&demod->lp[0], I, num); - iir_process(&demod->lp[1], Q, num); + 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 < num; s++) { + for (s = 0; s < length; s++) { phase = atan2(Q[s], I[s]); dev = (phase - last_phase) / 2 / M_PI; last_phase = phase; @@ -181,7 +256,7 @@ void fm_demodulate(fm_demod_t *demod, sample_t *samples, int num, float *buff) else if (dev > 0.49) dev -= 1.0; dev *= rate; - samples[s] = dev; + frequency[s] = dev; } demod->last_phase = last_phase; } diff --git a/src/common/fm_modulation.h b/src/common/fm_modulation.h index 2cd571a..83e7db4 100644 --- a/src/common/fm_modulation.h +++ b/src/common/fm_modulation.h @@ -1,3 +1,4 @@ +#include "../common/iir_filter.h" typedef struct fm_mod { double samplerate; /* sample rate of in and out */ @@ -7,8 +8,9 @@ typedef struct fm_mod { double *sin_tab; /* sine/cosine table for modulation */ } fm_mod_t; -void fm_mod_init(fm_mod_t *mod, double samplerate, double offset, double amplitude); -void fm_modulate(fm_mod_t *mod, sample_t *samples, int num, float *buff); +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, int num, float *baseband); typedef struct fm_demod { double samplerate; /* sample rate of in and out */ @@ -19,6 +21,8 @@ typedef struct fm_demod { double *sin_tab; /* sine/cosine table rotation */ } fm_demod_t; -void fm_demod_init(fm_demod_t *demod, double samplerate, double offset, double bandwidth); -void fm_demodulate(fm_demod_t *demod, sample_t *samples, int num, float *buff); +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.c b/src/common/fsk.c new file mode 100644 index 0000000..fa0eaf8 --- /dev/null +++ b/src/common/fsk.c @@ -0,0 +1,293 @@ +/* FSK audio processing (coherent FSK modem) + * + * (C) 2017 by Andreas Eversberg <jolly@eversberg.eu> + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <math.h> +#include "../common/sample.h" +#include "../common/debug.h" +#include "fsk.h" + +#define PI M_PI + +/* + * 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) +{ + double bandwidth; + int i; + int rc; + + PDEBUG(DDSP, DEBUG_DEBUG, "Setup FSK for Transceiver. (F0 = %.1f, F1 = %.1f, peak = %.1f)\n", f0, f1, level); + + memset(fsk, 0, sizeof(*fsk)); + + /* gen sine table with deviation */ + fsk->sin_tab = calloc(65536+16384, sizeof(*fsk->sin_tab)); + if (!fsk->sin_tab) { + fprintf(stderr, "No mem!\n"); + rc = -ENOMEM; + goto error; + } + for (i = 0; i < 65536; i++) + 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; + 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); + + fsk->phaseshift65536[0] = f0 / (double)samplerate * 65536.0; + PDEBUG(DDSP, DEBUG_DEBUG, "phaseshift65536[0] = %.4f\n", fsk->phaseshift65536[0]); + fsk->phaseshift65536[1] = f1 / (double)samplerate * 65536.0; + PDEBUG(DDSP, DEBUG_DEBUG, "phaseshift65536[1] = %.4f\n", fsk->phaseshift65536[1]); + + /* use coherent modulation, i.e. each bit has an integer number of + * half waves and starts/ends at zero crossing + */ + if (coherent) { + double waves; + + fsk->coherent = 1; + waves = (f0 / bitrate); + if (fabs(round(waves * 2) - (waves * 2)) > 0.001) { + fprintf(stderr, "Failed to set coherent mode, half waves of F0 does not fit exactly into one bit, please fix!\n"); + abort(); + } + fsk->cycles_per_bit65536[0] = waves * 65536.0; + waves = (f1 / bitrate); + if (fabs(round(waves * 2) - (waves * 2)) > 0.001) { + fprintf(stderr, "Failed to set coherent mode, half waves of F1 does not fit exactly into one bit, please fix!\n"); + abort(); + } + fsk->cycles_per_bit65536[1] = waves * 65536.0; + } + + /* filter prevents emphasis to overshoot on bit change */ + iir_lowpass_init(&fsk->tx_filter, 4000.0, samplerate, 2); + + return 0; + +error: + fsk_cleanup(fsk); + return rc; +} + +/* Cleanup transceiver instance. */ +void fsk_cleanup(fsk_t *fsk) +{ + PDEBUG(DDSP, DEBUG_DEBUG, "Cleanup FSK for Transceiver.\n"); + + if (fsk->sin_tab) { + free(fsk->sin_tab); + fsk->sin_tab = NULL; + } + + fm_demod_exit(&fsk->demod); +} + +//#define DEBUG_MODULATOR +//#define DEBUG_FILTER + +/* Demodulates bits + * + * If bit is received, callback function send_bit() is called. + * + * We sample each bit 0.5 bits after polarity change. + * + * If we have a bit change, adjust sample counter towards one half bit duration. + * We may have noise, so the bit change may be wrong or not at the correct place. + * This can cause bit slips. + * 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) +{ + sample_t I[length], Q[length], frequency[length], f; + int i; + int bit; + double level, quality; + + /* demod samples to offset arround center frequency */ + fm_demodulate_real(&fsk->demod, frequency, length, sample, I, Q); + + for (i = 0; i < length; i++) { + f = frequency[i]; + if (f < 0) + bit = fsk->low_bit; + else + bit = fsk->high_bit; +#ifdef DEBUG_FILTER + printf("|%s| %.3f\n", debug_amplitude(f / fabs(fsk->f0_deviation)), f / fabs(fsk->f0_deviation)); +#endif + + + if (fsk->rx_bit != bit) { +#ifdef DEBUG_FILTER + puts("bit change"); +#endif + fsk->rx_bit = bit; + if (fsk->rx_bitpos < 0.5) { + fsk->rx_bitpos += fsk->rx_bitadjust; + if (fsk->rx_bitpos > 0.5) + fsk->rx_bitpos = 0.5; + } else + if (fsk->rx_bitpos > 0.5) { + fsk->rx_bitpos -= fsk->rx_bitadjust; + if (fsk->rx_bitpos < 0.5) + fsk->rx_bitpos = 0.5; + } + } + /* if bit counter reaches 1, we substract 1 and sample the bit */ + if (fsk->rx_bitpos >= 1.0) { + /* peak level is the length of I/Q vector + * since we filter out the unwanted modulation product, the vector is only half of length */ + level = sqrt(I[i] * I[i] + Q[i] * Q[i]) * 2.0; + /* quality is defined on how accurat the target frequency it hit + * if it is hit close to the center or close to double deviation from center, quality is close to 0 */ + if (bit == 0) + quality = 1.0 - fabs((f - fsk->f0_deviation) / fsk->f0_deviation); + else + quality = 1.0 - fabs((f - fsk->f1_deviation) / fsk->f1_deviation); + if (quality < 0) + quality = 0; +#ifdef DEBUG_FILTER + printf("sample (level=%.3f, quality=%.3f)\n", level / fsk->level, quality); +#endif + /* adjust the values, because this is best we can get from fm demodulator */ + fsk->receive_bit(fsk->inst, bit, quality / 0.95, level); + fsk->rx_bitpos -= 1.0; + } + fsk->rx_bitpos += fsk->bits_per_sample; + } +} + +/* 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; + + iir_process(&fsk->tx_filter, sample, count); + + 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; +} + diff --git a/src/common/fsk.h b/src/common/fsk.h new file mode 100644 index 0000000..1a1009a --- /dev/null +++ b/src/common/fsk.h @@ -0,0 +1,31 @@ +#include "../common/fm_modulation.h" + +typedef struct ffsk { + void *inst; + int (*send_bit)(void *inst); + void (*receive_bit)(void *inst, int bit, double quality, double level); + fm_demod_t demod; + iir_filter_t tx_filter; + 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 tx_phase65536; /* current transmit phase */ + double level; /* level (amplitude) of signal */ + int coherent; /* set, if coherent TX mode */ + 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 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 */ + 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; + +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); + diff --git a/src/common/sdr.c b/src/common/sdr.c index 7f465c4..41f78c8 100644 --- a/src/common/sdr.c +++ b/src/common/sdr.c @@ -26,7 +26,6 @@ #include <pthread.h> #include <unistd.h> #include "sample.h" -#include "iir_filter.h" #include "fm_modulation.h" #include "sender.h" #include "timer.h" @@ -229,13 +228,17 @@ void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_freq double tx_offset; tx_offset = sdr->chan[c].tx_frequency - tx_center_frequency; PDEBUG(DSDR, DEBUG_DEBUG, "Frequency #%d: TX offset: %.6f MHz\n", c, tx_offset / 1e6); - fm_mod_init(&sdr->chan[c].mod, samplerate, tx_offset, sdr->amplitude); + rc = fm_mod_init(&sdr->chan[c].mod, samplerate, tx_offset, sdr->amplitude); + if (rc < 0) + goto error; } if (sdr->paging_channel) { double tx_offset; tx_offset = sdr->chan[sdr->paging_channel].tx_frequency - tx_center_frequency; PDEBUG(DSDR, DEBUG_DEBUG, "Paging Frequency: TX offset: %.6f MHz\n", tx_offset / 1e6); - fm_mod_init(&sdr->chan[sdr->paging_channel].mod, samplerate, tx_offset, sdr->amplitude); + rc = fm_mod_init(&sdr->chan[sdr->paging_channel].mod, samplerate, tx_offset, sdr->amplitude); + if (rc < 0) + goto error; } /* show gain */ PDEBUG(DSDR, DEBUG_INFO, "Using gain: TX %.1f dB\n", sdr_tx_gain); @@ -286,7 +289,9 @@ void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_freq double rx_offset; rx_offset = sdr->chan[c].rx_frequency - rx_center_frequency; PDEBUG(DSDR, DEBUG_DEBUG, "Frequency #%d: RX offset: %.6f MHz\n", c, rx_offset / 1e6); - fm_demod_init(&sdr->chan[c].demod, samplerate, rx_offset, bandwidth); + rc = fm_demod_init(&sdr->chan[c].demod, samplerate, rx_offset, bandwidth); + if (rc < 0) + goto error; } /* show gain */ PDEBUG(DSDR, DEBUG_INFO, "Using gain: RX %.1f dB\n", sdr_rx_gain); @@ -513,7 +518,17 @@ void sdr_close(void *inst) wave_destroy_record(&sdr->wave_tx_rec); wave_destroy_playback(&sdr->wave_rx_play); wave_destroy_playback(&sdr->wave_tx_play); - free(sdr->chan); + if (sdr->chan) { + int c; + + for (c = 0; c < sdr->channels; c++) { + fm_mod_exit(&sdr->chan[c].mod); + fm_demod_exit(&sdr->chan[c].demod); + } + if (sdr->paging_channel) + fm_mod_exit(&sdr->chan[sdr->paging_channel].mod); + free(sdr->chan); + } free(sdr); sdr = NULL; } @@ -538,9 +553,9 @@ int sdr_write(void *inst, sample_t **samples, int num, enum paging_signal __attr for (c = 0; c < channels; c++) { /* switch to paging channel, if requested */ if (on[c] && sdr->paging_channel) - fm_modulate(&sdr->chan[sdr->paging_channel].mod, samples[c], num, buff); + fm_modulate_complex(&sdr->chan[sdr->paging_channel].mod, samples[c], num, buff); else - fm_modulate(&sdr->chan[c].mod, samples[c], num, buff); + fm_modulate_complex(&sdr->chan[c].mod, samples[c], num, buff); } } else { buff = (float *)samples; @@ -603,6 +618,7 @@ int sdr_read(void *inst, sample_t **samples, int num, int channels) { sdr_t *sdr = (sdr_t *)inst; float buffer[num * 2], *buff = NULL; + sample_t I[num], Q[num]; int count = 0; int c, s, ss; @@ -675,7 +691,7 @@ int sdr_read(void *inst, sample_t **samples, int num, int channels) if (channels) { for (c = 0; c < channels; c++) - fm_demodulate(&sdr->chan[c].demod, samples[c], count, buff); + fm_demodulate_complex(&sdr->chan[c].demod, samples[c], count, buff, I, Q); } return count; |