From d2528082e28ef041c3280d6d5923c6688290ff3e Mon Sep 17 00:00:00 2001 From: drowe67 Date: Fri, 1 Aug 2014 11:01:42 +0000 Subject: [PATCH] ported rate Q rx filtering to C, tfdmdv tests out OK, demod seems to run much faster git-svn-id: https://svn.code.sf.net/p/freetel/code@1776 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/octave/fdmdv.m | 14 ++-- codec2-dev/octave/fdmdv_demod.m | 9 +++ codec2-dev/octave/fdmdv_ut.m | 6 +- codec2-dev/octave/tfdmdv.m | 23 ++++--- codec2-dev/src/fdmdv.c | 117 ++++++++++++++++++++++++++++---- codec2-dev/src/fdmdv_internal.h | 18 ++++- codec2-dev/src/rxdec_coeff.h | 35 ++++++++++ codec2-dev/stm32/Makefile | 2 +- codec2-dev/unittest/tfdmdv.c | 12 +++- 9 files changed, 196 insertions(+), 40 deletions(-) create mode 100644 codec2-dev/src/rxdec_coeff.h diff --git a/codec2-dev/octave/fdmdv.m b/codec2-dev/octave/fdmdv.m index 23febbca..486cf733 100644 --- a/codec2-dev/octave/fdmdv.m +++ b/codec2-dev/octave/fdmdv.m @@ -254,6 +254,8 @@ function tx_fdm = fdm_upconvert(tx_filt) mag = abs(phase_tx(c)); phase_tx(c) /= mag; end + mag = abs(fbb_phase_tx); + fbb_phase_tx /= mag; endfunction @@ -344,6 +346,8 @@ end % Combined down convert and rx filter, more memory efficient but less intuitive design +% TODO: Decimate mem update and downconversion, this will save some more CPU and memory +% note phase would have to advance 4 times as fast function rx_filt = down_convert_and_rx_filter(rx_fdm, nin, dec_rate) global Nc; @@ -1047,16 +1051,16 @@ endfunction % Saves rx decimation filter coeffs to a text file in the form of a C array function rxdec_file(filename) - global rxdec; + global rxdec_coeff; global Nrxdec; f=fopen(filename,"wt"); fprintf(f,"/* Generated by rxdec_file() Octave function */\n\n"); - fprintf(f,"const float rxdec[]={\n"); - for m=1:Nfilter-1 - fprintf(f," %g,\n",rxdec(m)); + fprintf(f,"const float rxdec_coeff[]={\n"); + for m=1:Nrxdec-1 + fprintf(f," %g,\n",rxdec_coeff(m)); endfor - fprintf(f," %g\n};\n",rxdec(Nrxdecr)); + fprintf(f," %g\n};\n",rxdec_coeff(Nrxdec)); fclose(f); endfunction diff --git a/codec2-dev/octave/fdmdv_demod.m b/codec2-dev/octave/fdmdv_demod.m index 704ac231..65f0acaa 100644 --- a/codec2-dev/octave/fdmdv_demod.m +++ b/codec2-dev/octave/fdmdv_demod.m @@ -89,6 +89,15 @@ function fdmdv_demod(rawfilename, nbits, NumCarriers, errorpatternfilename, symb S=fft(spec_mem.*hanning(Nspec)',Nspec); SdB = 0.9*SdB + 0.1*20*log10(abs(S)); + % shift down to complex baseband + + for i=1:nin + fbb_phase_rx = fbb_phase_rx*fbb_rect'; + rx_fdm(i) = rx_fdm(i)*fbb_phase_rx; + end + mag = abs(fbb_phase_rx); + fbb_phase_rx /= mag; + % frequency offset estimation and correction [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, nin); diff --git a/codec2-dev/octave/fdmdv_ut.m b/codec2-dev/octave/fdmdv_ut.m index 0d7772e9..d46a4291 100644 --- a/codec2-dev/octave/fdmdv_ut.m +++ b/codec2-dev/octave/fdmdv_ut.m @@ -175,6 +175,8 @@ for f=1:frames fbb_phase_rx = fbb_phase_rx*fbb_rect'; rx_fdm(i) = rx_fdm(i)*fbb_phase_rx; end + mag = abs(fbb_phase_rx); + fbb_phase_rx /= mag; % frequency offset estimation and correction, need to call rx_est_freq_offset even in sync % mode to keep states updated @@ -195,10 +197,6 @@ for f=1:frames end rx_fdm_filter = rxdec_filter(rx_fdm, M); - - % TODO: Decimate to rate Q at this point, this will save some more CPU - % in down_convert_and_rx_filter - rx_filt = down_convert_and_rx_filter(rx_fdm_filter, M, M/Q); [rx_symbols rx_timing] = rx_est_timing(rx_filt, M); diff --git a/codec2-dev/octave/tfdmdv.m b/codec2-dev/octave/tfdmdv.m index 2ad4c2b4..bba5a7ab 100644 --- a/codec2-dev/octave/tfdmdv.m +++ b/codec2-dev/octave/tfdmdv.m @@ -64,7 +64,7 @@ noise_est_log = []; % adjust this if the screen is getting a bit cluttered global no_plot_list; -no_plot_list = [1 2 3 4 5 6 7 8 16]; +no_plot_list = []; for f=1:frames @@ -92,7 +92,16 @@ for f=1:frames channel = channel(nin+1:channel_count); channel_count -= nin; - % demodulator + % demodulator -------------------------------------------- + + % shift down to complex baseband + + for i=1:nin + fbb_phase_rx = fbb_phase_rx*fbb_rect'; + rx_fdm(i) = rx_fdm(i)*fbb_phase_rx; + end + mag = abs(fbb_phase_rx); + fbb_phase_rx /= mag; [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, nin); @@ -119,14 +128,8 @@ for f=1:frames rx_fdm_fcorr(i) = rx_fdm(i)*foff_phase_rect; end -if 1 - % more memory efficient but more complex - rx_filt = down_convert_and_rx_filter(rx_fdm_fcorr, nin); -else - rx_baseband = fdm_downconvert(rx_fdm_corr,nin); - rx_baseband_log = [rx_baseband_log rx_baseband]; - rx_filt = rx_filter(rx_baseband, nin); -end + rx_fdm_filter = rxdec_filter(rx_fdm_fcorr, nin); + rx_filt = down_convert_and_rx_filter(rx_fdm_filter, nin, M/Q); rx_filt_log = [rx_filt_log rx_filt]; diff --git a/codec2-dev/src/fdmdv.c b/codec2-dev/src/fdmdv.c index cd117d77..d16b3184 100644 --- a/codec2-dev/src/fdmdv.c +++ b/codec2-dev/src/fdmdv.c @@ -40,6 +40,7 @@ #include "fdmdv_internal.h" #include "codec2_fdmdv.h" #include "rn.h" +#include "rxdec_coeff.h" #include "test_bits.h" #include "pilot_coeff.h" #include "kiss_fft.h" @@ -182,9 +183,17 @@ struct FDMDV * fdmdv_create(int Nc) } fdmdv_set_fsep(f, FSEP); - f->freq[Nc].real = cosf(2.0*PI*FDMDV_FCENTRE/FS); - f->freq[Nc].imag = sinf(2.0*PI*FDMDV_FCENTRE/FS); - f->freq_pol[Nc] = 2.0*PI*FDMDV_FCENTRE/FS; + f->freq[Nc].real = cosf(2.0*PI*0.0/FS); + f->freq[Nc].imag = sinf(2.0*PI*0.0/FS); + f->freq_pol[Nc] = 2.0*PI*0.0/FS; + + f->fbb_rect.real = cosf(2.0*PI*FDMDV_FCENTRE/FS); + f->fbb_rect.imag = sinf(2.0*PI*FDMDV_FCENTRE/FS); + f->fbb_pol = 2.0*PI*FDMDV_FCENTRE/FS; + f->fbb_phase_tx.real = 1.0; + f->fbb_phase_tx.imag = 0.0; + f->fbb_phase_rx.real = 1.0; + f->fbb_phase_rx.imag = 0.0; /* Generate DBPSK pilot Look Up Table (LUT) */ @@ -202,6 +211,11 @@ struct FDMDV * fdmdv_create(int Nc) f->pilot_lut_index = 0; f->prev_pilot_lut_index = 3*M; + for(i=0; irxdec_lpf_mem[i].real = 0.0; + f->rxdec_lpf_mem[i].imag = 0.0; + } + for(i=0; ipilot_lpf1[i].real = f->pilot_lpf2[i].real = 0.0; f->pilot_lpf1[i].imag = f->pilot_lpf2[i].imag = 0.0; @@ -302,17 +316,18 @@ void fdmdv_set_fsep(struct FDMDV *f, float fsep) { float carrier_freq; f->fsep = fsep; + /* Set up frequency of each carrier */ for(c=0; cNc/2; c++) { - carrier_freq = (-f->Nc/2 + c)*f->fsep + FDMDV_FCENTRE; + carrier_freq = (-f->Nc/2 + c)*f->fsep; f->freq[c].real = cosf(2.0*PI*carrier_freq/FS); f->freq[c].imag = sinf(2.0*PI*carrier_freq/FS); f->freq_pol[c] = 2.0*PI*carrier_freq/FS; } for(c=f->Nc/2; cNc; c++) { - carrier_freq = (-f->Nc/2 + c + 1)*f->fsep + FDMDV_FCENTRE; + carrier_freq = (-f->Nc/2 + c + 1)*f->fsep; f->freq[c].real = cosf(2.0*PI*carrier_freq/FS); f->freq[c].imag = sinf(2.0*PI*carrier_freq/FS); f->freq_pol[c] = 2.0*PI*carrier_freq/FS; @@ -448,7 +463,8 @@ void tx_filter(COMP tx_baseband[NC+1][M], int Nc, COMP tx_symbols[], COMP tx_fil \*---------------------------------------------------------------------------*/ -void fdm_upconvert(COMP tx_fdm[], int Nc, COMP tx_baseband[NC+1][M], COMP phase_tx[], COMP freq[]) +void fdm_upconvert(COMP tx_fdm[], int Nc, COMP tx_baseband[NC+1][M], COMP phase_tx[], COMP freq[], + COMP *fbb_phase, COMP fbb_rect) { int i,c; COMP two = {2.0, 0.0}; @@ -485,6 +501,13 @@ void fdm_upconvert(COMP tx_fdm[], int Nc, COMP tx_baseband[NC+1][M], COMP phase_ tx_fdm[i] = cadd(tx_fdm[i], pilot); } + /* shift whole thing up to carrier freq */ + + for (i=0; ireal /= mag; + fbb_phase->imag /= mag; } /*---------------------------------------------------------------------------*\ @@ -534,7 +561,7 @@ void fdmdv_mod(struct FDMDV *fdmdv, COMP tx_fdm[], int tx_bits[], int *sync_bit) TIMER_SAMPLE_AND_LOG(tx_filter_start, mod_start, " bits_to_dqpsk_symbols"); tx_filter(tx_baseband, fdmdv->Nc, tx_symbols, fdmdv->tx_filter_memory); TIMER_SAMPLE_AND_LOG(fdm_upconvert_start, tx_filter_start, " tx_filter"); - fdm_upconvert(tx_fdm, fdmdv->Nc, tx_baseband, fdmdv->phase_tx, fdmdv->freq); + fdm_upconvert(tx_fdm, fdmdv->Nc, tx_baseband, fdmdv->phase_tx, fdmdv->freq, &fdmdv->fbb_phase_tx, fdmdv->fbb_rect); TIMER_SAMPLE_AND_LOG2(fdm_upconvert_start, " fdm_upconvert"); *sync_bit = fdmdv->tx_pilot_bit; @@ -892,6 +919,58 @@ void rx_filter(COMP rx_filt[NC+1][P+1], int Nc, COMP rx_baseband[NC+1][M+M/P], C assert(j <= (P+1)); /* check for any over runs */ } + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: rxdec_filter() + AUTHOR......: David Rowe + DATE CREATED: 31 July 2014 + + +/- 1000Hz low pass filter, allows us to filter at rate Q to save CPU load. + +\*---------------------------------------------------------------------------*/ + +void rxdec_filter(COMP rx_fdm_filter[], COMP rx_fdm[], COMP rxdec_lpf_mem[], int nin) { + int i,j,k; + + for(i=0; ifbb_phase_rx, *nin); + /* freq offset estimation and correction */ TIMER_SAMPLE(demod_start); @@ -1401,8 +1489,9 @@ void fdmdv_demod(struct FDMDV *fdmdv, int rx_bits[], /* baseband processing */ - down_convert_and_rx_filter(rx_filt, fdmdv->Nc, rx_fdm_fcorr, fdmdv->rx_fdm_mem, fdmdv->phase_rx, fdmdv->freq, - fdmdv->freq_pol, *nin); + rxdec_filter(rx_fdm_filter, rx_fdm_fcorr, fdmdv->rxdec_lpf_mem, *nin); + down_convert_and_rx_filter(rx_filt, fdmdv->Nc, rx_fdm_filter, fdmdv->rx_fdm_mem, fdmdv->phase_rx, fdmdv->freq, + fdmdv->freq_pol, *nin, M/Q); TIMER_SAMPLE_AND_LOG(rx_est_timing_start, down_convert_and_rx_filter_start, " down_convert_and_rx_filter"); fdmdv->rx_timing = rx_est_timing(rx_symbols, fdmdv->Nc, rx_filt, fdmdv->rx_filter_mem_timing, env, *nin); TIMER_SAMPLE_AND_LOG(qpsk_to_bits_start, rx_est_timing_start, " rx_est_timing"); diff --git a/codec2-dev/src/fdmdv_internal.h b/codec2-dev/src/fdmdv_internal.h index d542e5e6..b66ee9ef 100644 --- a/codec2-dev/src/fdmdv_internal.h +++ b/codec2-dev/src/fdmdv_internal.h @@ -53,7 +53,9 @@ #define FSEP 75 /* Default separation between carriers (Hz) */ #define NT 5 /* number of symbols we estimate timing over */ -#define P 4 /* oversample factor used for initial rx symbol filtering */ +#define P 4 /* oversample factor used for initial rx symbol filtering output */ +#define Q (M/4) /* oversample factor used for initial rx symbol filtering input */ +#define NRXDEC 31 /* number of taps in the rx decimation filter */ #define NPILOT_LUT (4*M) /* number of pilot look up table samples */ #define NPILOTCOEFF 30 /* number of FIR filter coeffs in LP filter */ @@ -111,6 +113,13 @@ struct FDMDV { COMP S1[MPILOTFFT]; COMP S2[MPILOTFFT]; + /* baseband to low IF carrier states */ + + COMP fbb_rect; + float fbb_pol; + COMP fbb_phase_tx; + COMP fbb_phase_rx; + /* freq offset correction states */ float foff; @@ -118,6 +127,7 @@ struct FDMDV { /* Demodulator */ + COMP rxdec_lpf_mem[NRXDEC-1+M]; COMP rx_fdm_mem[NFILTER+M]; COMP phase_rx[NC+1]; COMP rx_filter_mem_timing[NC+1][NT*P]; @@ -155,16 +165,18 @@ struct FDMDV { void bits_to_dqpsk_symbols(COMP tx_symbols[], int Nc, COMP prev_tx_symbols[], int tx_bits[], int *pilot_bit, int old_qpsk_mapping); void tx_filter(COMP tx_baseband[NC+1][M], int Nc, COMP tx_symbols[], COMP tx_filter_memory[NC+1][NSYM]); -void fdm_upconvert(COMP tx_fdm[], int Nc, COMP tx_baseband[NC+1][M], COMP phase_tx[], COMP freq_tx[]); +void fdm_upconvert(COMP tx_fdm[], int Nc, COMP tx_baseband[NC+1][M], COMP phase_tx[], COMP freq_tx[], + COMP *fbb_phase, COMP fbb_rect); void generate_pilot_fdm(COMP *pilot_fdm, int *bit, float *symbol, float *filter_mem, COMP *phase, COMP *freq); void generate_pilot_lut(COMP pilot_lut[], COMP *pilot_freq); float rx_est_freq_offset(struct FDMDV *f, COMP rx_fdm[], int nin); void lpf_peak_pick(float *foff, float *max, COMP pilot_baseband[], COMP pilot_lpf[], kiss_fft_cfg fft_pilot_cfg, COMP S[], int nin); void fdm_downconvert(COMP rx_baseband[NC+1][M+M/P], int Nc, COMP rx_fdm[], COMP phase_rx[], COMP freq[], int nin); +void rxdec_filter(COMP rx_fdm_filter[], COMP rx_fdm[], COMP rxdec_lpf_mem[], int nin); void rx_filter(COMP rx_filt[NC+1][P+1], int Nc, COMP rx_baseband[NC+1][M+M/P], COMP rx_filter_memory[NC+1][NFILTER], int nin); void down_convert_and_rx_filter(COMP rx_filt[NC+1][P+1], int Nc, COMP rx_fdm[], COMP rx_fdm_mem[], COMP phase_rx[], COMP freq[], - float freq_pol[], int nin); + float freq_pol[], int nin, int dec_rate); float rx_est_timing(COMP rx_symbols[], int Nc, COMP rx_filt[NC+1][P+1], COMP rx_filter_mem_timing[NC+1][NT*P], diff --git a/codec2-dev/src/rxdec_coeff.h b/codec2-dev/src/rxdec_coeff.h new file mode 100644 index 00000000..a08cf9fe --- /dev/null +++ b/codec2-dev/src/rxdec_coeff.h @@ -0,0 +1,35 @@ +/* Generated by rxdec_file() Octave function */ + +const float rxdec_coeff[]={ + -0.00125472, + -0.00204605, + -0.0019897, + 0.000163906, + 0.00490937, + 0.00986375, + 0.0096718, + -0.000480351, + -0.019311, + -0.0361822, + -0.0341251, + 0.000827866, + 0.0690577, + 0.152812, + 0.222115, + 0.249004, + 0.222115, + 0.152812, + 0.0690577, + 0.000827866, + -0.0341251, + -0.0361822, + -0.019311, + -0.000480351, + 0.0096718, + 0.00986375, + 0.00490937, + 0.000163906, + -0.0019897, + -0.00204605, + -0.00125472 +}; diff --git a/codec2-dev/stm32/Makefile b/codec2-dev/stm32/Makefile index fcaea9a1..89386cc5 100644 --- a/codec2-dev/stm32/Makefile +++ b/codec2-dev/stm32/Makefile @@ -13,7 +13,7 @@ SIZE=$(BINPATH)/arm-none-eabi-size ################################################### -CFLAGS = -std=gnu99 -O2 -g -Wall -Tstm32_flash.ld -DSTM32F4XX -DCORTEX_M4 +CFLAGS = -std=gnu99 -O3 --param max-unroll-times=200 -g -Wall -Tstm32_flash.ld -DSTM32F4XX -DCORTEX_M4 CFLAGS += -mlittle-endian -mthumb -mthumb-interwork -nostartfiles -mcpu=cortex-m4 ifeq ($(FLOAT_TYPE), hard) diff --git a/codec2-dev/unittest/tfdmdv.c b/codec2-dev/unittest/tfdmdv.c index af962fc6..438fb957 100644 --- a/codec2-dev/unittest/tfdmdv.c +++ b/codec2-dev/unittest/tfdmdv.c @@ -56,6 +56,7 @@ int main(int argc, char *argv[]) float foff_coarse; int nin, next_nin; COMP rx_fdm_fcorr[M+M/P]; + COMP rx_fdm_filter[M+M/P]; COMP rx_baseband[NC+1][M+M/P]; COMP rx_filt[NC+1][P+1]; float rx_timing; @@ -115,7 +116,7 @@ int main(int argc, char *argv[]) bits_to_dqpsk_symbols(tx_symbols, FDMDV_NC, fdmdv->prev_tx_symbols, tx_bits, &fdmdv->tx_pilot_bit, 0); memcpy(fdmdv->prev_tx_symbols, tx_symbols, sizeof(COMP)*(FDMDV_NC+1)); tx_filter(tx_baseband, FDMDV_NC, tx_symbols, fdmdv->tx_filter_memory); - fdm_upconvert(tx_fdm, FDMDV_NC, tx_baseband, fdmdv->phase_tx, fdmdv->freq); + fdm_upconvert(tx_fdm, FDMDV_NC, tx_baseband, fdmdv->phase_tx, fdmdv->freq, &fdmdv->fbb_phase_tx, fdmdv->fbb_rect); /* --------------------------------------------------------*\ Channel @@ -149,6 +150,10 @@ int main(int argc, char *argv[]) Demodulator \*---------------------------------------------------------*/ + /* shift down to complex baseband */ + + fdmdv_freq_shift(rx_fdm, rx_fdm, -FDMDV_FCENTRE, &fdmdv->fbb_phase_rx, nin); + /* freq offset estimation and correction */ foff_coarse = rx_est_freq_offset(fdmdv, rx_fdm, nin); @@ -161,8 +166,9 @@ int main(int argc, char *argv[]) /* baseband processing */ - down_convert_and_rx_filter(rx_filt, fdmdv->Nc, rx_fdm_fcorr, fdmdv->rx_fdm_mem, fdmdv->phase_rx, fdmdv->freq, - fdmdv->freq_pol, nin); + rxdec_filter(rx_fdm_filter, rx_fdm_fcorr, fdmdv->rxdec_lpf_mem, nin); + down_convert_and_rx_filter(rx_filt, fdmdv->Nc, rx_fdm_filter, fdmdv->rx_fdm_mem, fdmdv->phase_rx, fdmdv->freq, + fdmdv->freq_pol, nin, M/Q); rx_timing = rx_est_timing(rx_symbols, FDMDV_NC, rx_filt, fdmdv->rx_filter_mem_timing, env, nin); foff_fine = qpsk_to_bits(rx_bits, &sync_bit, FDMDV_NC, fdmdv->phase_difference, fdmdv->prev_rx_symbols, rx_symbols, 0); -- 2.25.1