From: drowe67 Date: Wed, 2 May 2012 08:15:50 +0000 (+0000) Subject: C and Octave versions of fdmdv_demod giving same results with real world signals... X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=974909dcdd6a1bb769512739b150f6476e8df9b0;p=freetel-svn-tracking.git C and Octave versions of fdmdv_demod giving same results with real world signals with clock slip, added clock slip to unittest/tfdmdv and found a few small but tricky bugs. Still need to add some instrumentation to C version git-svn-id: https://svn.code.sf.net/p/freetel/code@390 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2-dev/octave/README_fdmdv.txt b/codec2-dev/octave/README_fdmdv.txt index e9e45202..23a10bae 100644 --- a/codec2-dev/octave/README_fdmdv.txt +++ b/codec2-dev/octave/README_fdmdv.txt @@ -57,7 +57,9 @@ TODO $ ./fdmdv_get_test_bits - 14000 | ./fdmdv_mod - - | ./fdmdv_demod - - demod_dump.txt | ./fdmdv_put_test_bits - [ ] PAPR idea - + automatically weak phases to reduce PAPR, e.g. slow variations in freq... + + automatically tweak phases to reduce PAPR, e.g. slow variations in freq... +[ ] implement SNR and ppm measurements +[ ] add help to each octave script & C program Tests @@ -67,3 +69,4 @@ Tests [ ] mod_dqpsk_good_4dB_8008hz.raw [ ] mod_dqpsk_moderate_4dB_8008hz.raw [ ] mod_dqpsk_moderate_4dB_7992hz.raw +[ ] time .... diff --git a/codec2-dev/octave/fdmdv_demod.m b/codec2-dev/octave/fdmdv_demod.m index 7a21d0dc..b30b497c 100644 --- a/codec2-dev/octave/fdmdv_demod.m +++ b/codec2-dev/octave/fdmdv_demod.m @@ -50,15 +50,16 @@ function fdmdv_demod(rawfilename, nbits, pngname) % obtain nin samples of the test input signal for i=1:nin - rx_fdm(i) = fread(fin, 1, "short")/gain; + rx_fdm(i) = fread(fin, 1, "short")/gain; end - + rx_fdm_log = [rx_fdm_log rx_fdm(1:nin)]; % 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); [foff_coarse S1 S2] = rx_est_freq_offset(rx_fdm, pilot, prev_pilot, nin); + if track == 0 foff = foff_coarse; end @@ -76,6 +77,7 @@ function fdmdv_demod(rawfilename, nbits, pngname) rx_filt = rx_filter(rx_baseband, nin); [rx_symbols rx_timing] = rx_est_timing(rx_filt, rx_baseband, nin); + rx_timing_log = [rx_timing_log rx_timing]; nin = M; if rx_timing > 2*M/P diff --git a/codec2-dev/octave/tfdmdv.m b/codec2-dev/octave/tfdmdv.m index 34216ee3..d554f411 100644 --- a/codec2-dev/octave/tfdmdv.m +++ b/codec2-dev/octave/tfdmdv.m @@ -22,6 +22,9 @@ prev_rx_symbols = ones(Nc+1,1); foff_phase_rect = 1; coarse_fine = 0; fest_state = 0; +channel = []; +channel_count = 0; +next_nin = M; % Octave outputs we want to collect for comparison to C version @@ -46,6 +49,7 @@ rx_symbols_log = []; rx_bits_log = []; sync_bit_log = []; coarse_fine_log = []; +nin_log = []; for f=1:frames @@ -61,13 +65,29 @@ for f=1:frames tx_fdm = fdm_upconvert(tx_baseband); tx_fdm_log = [tx_fdm_log tx_fdm]; - rx_fdm = real(tx_fdm); + % channel + + nin = next_nin; + %nin = 120; + %nin = M; + %if (f == 3) + % nin = 120; + %elseif (f == 4) + % nin = 200; + %else + % nin = M; + %end + channel = [channel real(tx_fdm)]; + channel_count += M; + rx_fdm = channel(1:nin); + channel = channel(nin+1:channel_count); + channel_count -= nin; % demodulator - [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, M); + [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, nin); - [foff_coarse S1 S2] = rx_est_freq_offset(rx_fdm, pilot, prev_pilot, M); + [foff_coarse S1 S2] = rx_est_freq_offset(rx_fdm, pilot, prev_pilot, nin); if coarse_fine == 0 foff = foff_coarse; end @@ -82,23 +102,32 @@ for f=1:frames foff_rect = exp(j*2*pi*foff/Fs); - for i=1:M + for i=1:nin foff_phase_rect *= foff_rect'; rx_fdm_fcorr(i) = rx_fdm(i)*foff_phase_rect; end - rx_baseband = fdm_downconvert(rx_fdm_fcorr, M); + rx_baseband = fdm_downconvert(rx_fdm_fcorr, nin); rx_baseband_log = [rx_baseband_log rx_baseband]; - rx_filt = rx_filter(rx_baseband, M); + rx_filt = rx_filter(rx_baseband, nin); rx_filt_log = [rx_filt_log rx_filt]; - [rx_symbols rx_timing env] = rx_est_timing(rx_filt, rx_baseband, M); + [rx_symbols rx_timing env] = rx_est_timing(rx_filt, rx_baseband, nin); env_log = [env_log env]; rx_timing_log = [rx_timing_log rx_timing]; rx_symbols_log = [rx_symbols_log rx_symbols]; + next_nin = M; + if rx_timing > 2*M/P + next_nin += M/P; + end + if rx_timing < 0; + next_nin -= M/P; + end + nin_log = [nin_log nin]; + [rx_bits sync_bit foff_fine] = qpsk_to_bits(prev_rx_symbols, rx_symbols, 'dqpsk'); prev_rx_symbols = rx_symbols; rx_bits_log = [rx_bits_log rx_bits]; @@ -174,11 +203,13 @@ plot_sig_and_error(4, 212, imag(pilot_lut_c), imag(pilot_lut - pilot_lut_c), 'pi % rx_est_freq_offset() -plot_sig_and_error(5, 211, real(pilot_baseband1_log), real(pilot_baseband1_log - pilot_baseband1_log_c), 'pilot baseband1 real' ) -plot_sig_and_error(5, 212, real(pilot_baseband2_log), real(pilot_baseband2_log - pilot_baseband2_log_c), 'pilot baseband2 real' ) +st=1; en = 3*Npilotbaseband; +plot_sig_and_error(5, 211, real(pilot_baseband1_log(st:en)), real(pilot_baseband1_log(st:en) - pilot_baseband1_log_c(st:en)), 'pilot baseband1 real' ) +plot_sig_and_error(5, 212, real(pilot_baseband2_log(st:en)), real(pilot_baseband2_log(st:en) - pilot_baseband2_log_c(st:en)), 'pilot baseband2 real' ) -plot_sig_and_error(6, 211, real(pilot_lpf1_log), real(pilot_lpf1_log - pilot_lpf1_log_c), 'pilot lpf1 real' ) -plot_sig_and_error(6, 212, real(pilot_lpf2_log), real(pilot_lpf2_log - pilot_lpf2_log_c), 'pilot lpf2 real' ) +st=1; en = 3*Npilotlpf; +plot_sig_and_error(6, 211, real(pilot_lpf1_log(st:en)), real(pilot_lpf1_log(st:en) - pilot_lpf1_log_c(st:en)), 'pilot lpf1 real' ) +plot_sig_and_error(6, 212, real(pilot_lpf2_log(st:en)), real(pilot_lpf2_log(st:en) - pilot_lpf2_log_c(st:en)), 'pilot lpf2 real' ) plot_sig_and_error(7, 211, real(S1_log), real(S1_log - S1_log_c), 'S1 real' ) plot_sig_and_error(7, 212, imag(S1_log), imag(S1_log - S1_log_c), 'S1 imag' ) @@ -199,7 +230,8 @@ plot_sig_and_error(11, 212, imag(rx_baseband_log(c,:)), imag(rx_baseband_log(c,: plot_sig_and_error(12, 211, real(rx_filt_log(c,:)), real(rx_filt_log(c,:) - rx_filt_log_c(c,:)), 'Rx filt real' ) plot_sig_and_error(12, 212, imag(rx_filt_log(c,:)), imag(rx_filt_log(c,:) - rx_filt_log_c(c,:)), 'Rx filt imag' ) -plot_sig_and_error(13, 211, env_log, env_log - env_log_c, 'env' ) +st=1; en=3*Nt*P; +plot_sig_and_error(13, 211, env_log(st:en), env_log(st:en) - env_log_c(st:en), 'env' ) stem_sig_and_error(13, 212, real(rx_symbols_log(c,:)), real(rx_symbols_log(c,:) - rx_symbols_log_c(c,:)), 'rx symbols' ) st=10*28; @@ -208,6 +240,7 @@ plot_sig_and_error(14, 211, rx_timing_log, rx_timing_log - rx_timing_log_c, 'Rx stem_sig_and_error(14, 212, sync_bit_log_c, sync_bit_log - sync_bit_log_c, 'Sync bit', [1 n -1.5 1.5]) stem_sig_and_error(15, 211, rx_bits_log_c(st:en), rx_bits_log(st:en) - rx_bits_log_c(st:en), 'RX bits', [1 en-st -1.5 1.5]) +stem_sig_and_error(15, 212, nin_log_c, nin_log - nin_log_c, 'nin') % --------------------------------------------------------------------------------------- % AUTOMATED CHECKS ------------------------------------------ @@ -253,5 +286,6 @@ check(rx_symbols_log, rx_symbols_log_c, 'rx_symbols'); check(rx_bits_log, rx_bits_log_c, 'rx bits'); check(sync_bit_log, sync_bit_log_c, 'sync bit'); check(coarse_fine_log, coarse_fine_log_c, 'coarse_fine'); +check(nin_log, nin_log_c, 'nin'); printf("\npasses: %d fails: %d\n", passes, fails); diff --git a/codec2-dev/src/fdmdv.c b/codec2-dev/src/fdmdv.c index 096dbd8c..f710e6bf 100644 --- a/codec2-dev/src/fdmdv.c +++ b/codec2-dev/src/fdmdv.c @@ -120,7 +120,8 @@ struct FDMDV *fdmdv_create(void) float carrier_freq; assert(FDMDV_BITS_PER_FRAME == NC*NB); - assert(FDMDV_SAMPLES_PER_FRAME == M); + assert(FDMDV_NOM_SAMPLES_PER_FRAME == M); + assert(FDMDV_MAX_SAMPLES_PER_FRAME == (M+M/P)); f = (struct FDMDV*)malloc(sizeof(struct FDMDV)); if (f == NULL) @@ -700,7 +701,7 @@ void fdm_downconvert(COMP rx_baseband[NC+1][M+M/P], COMP rx_fdm[], COMP phase_rx /* maximum number of input samples to demod */ - assert(nin < (M+M/P)); + assert(nin <= (M+M/P)); /* Nc/2 tones below centre freq */ @@ -713,15 +714,15 @@ void fdm_downconvert(COMP rx_baseband[NC+1][M+M/P], COMP rx_fdm[], COMP phase_rx /* Nc/2 tones above centre freq */ for (c=NC/2; c M) rx_timing -= M; if (rx_timing < -M) @@ -1100,7 +1103,9 @@ void fdmdv_demod(struct FDMDV *fdmdv, int rx_bits[], int *sync_bit, float rx_fdm /* freq offset estimation and correction */ + foff_coarse = rx_est_freq_offset(fdmdv, rx_fdm, *nin); + if (fdmdv->coarse_fine == COARSE) fdmdv->foff = foff_coarse; freq_shift(rx_fdm_fcorr, rx_fdm, fdmdv->foff, &fdmdv->foff_rect, &fdmdv->foff_phase_rect, *nin); @@ -1110,6 +1115,17 @@ void fdmdv_demod(struct FDMDV *fdmdv, int rx_bits[], int *sync_bit, float rx_fdm fdm_downconvert(rx_baseband, rx_fdm_fcorr, fdmdv->phase_rx, fdmdv->freq, *nin); rx_filter(rx_filt, rx_baseband, fdmdv->rx_filter_memory, *nin); fdmdv->rx_timing = rx_est_timing(rx_symbols, rx_filt, rx_baseband, fdmdv->rx_filter_mem_timing, env, fdmdv->rx_baseband_mem_timing, *nin); + + /* adjust number of input samples to keep timing within bounds */ + + *nin = M; + + if (fdmdv->rx_timing > 2*M/P) + *nin += M/P; + + if (fdmdv->rx_timing < 0) + *nin -= M/P; + foff_fine = qpsk_to_bits(rx_bits, sync_bit, fdmdv->phase_difference, fdmdv->prev_rx_symbols, rx_symbols); memcpy(fdmdv->prev_rx_symbols, rx_symbols, sizeof(COMP)*(NC+1)); @@ -1132,18 +1148,26 @@ void fdmdv_demod(struct FDMDV *fdmdv, int rx_bits[], int *sync_bit, float rx_fdm void fdmdv_get_demod_stats(struct FDMDV *fdmdv, struct FDMDV_STATS *fdmdv_stats) { int c; + COMP pi_on_4; + + pi_on_4.real = cos(PI/4.0); + pi_on_4.imag = sin(PI/4.0); fdmdv_stats->snr = 0.0; /* TODO - implement SNR estimation */ fdmdv_stats->fest_coarse_fine = fdmdv->coarse_fine; fdmdv_stats->foff = fdmdv->foff; - fdmdv_stats->rx_timing = fdmdv->rx_timing/M; + fdmdv_stats->rx_timing = fdmdv->rx_timing; fdmdv_stats->clock_offset = 0.0; /* TODO - implement clock offset estimation */ assert((NC+1) == FDMDV_NSYM); - for(c=0; crx_symbols[c] = fdmdv->phase_difference[c]; } + + /* place pilots somewhere convenient on scatter diagram */ + + fdmdv_stats->rx_symbols[NC] = cmult(fdmdv->phase_difference[NC], pi_on_4); } diff --git a/codec2-dev/src/fdmdv.h b/codec2-dev/src/fdmdv.h index 34634962..0f8a0a96 100644 --- a/codec2-dev/src/fdmdv.h +++ b/codec2-dev/src/fdmdv.h @@ -41,10 +41,12 @@ extern "C" { #include "comp.h" -#define FDMDV_BITS_PER_FRAME 28 /* odd/even frames 56 bits, 1400 bit/s */ -#define FDMDV_SAMPLES_PER_FRAME 160 /* 8000 Hz sample rate */ -#define FDMDV_SCALE 1000 /* suggested scaling for 16 bit shorts */ -#define FDMDV_NSYM 15 +#define FDMDV_BITS_PER_FRAME 28 /* 20ms frames, 1400 bit/s */ +#define FDMDV_NOM_SAMPLES_PER_FRAME 160 /* modulator output samples/frame and nominal demod samples/frame */ + /* at 8000 Hz sample rate */ +#define FDMDV_MAX_SAMPLES_PER_FRAME 200 /* max demod samples/frame, use this to allocate storage */ +#define FDMDV_SCALE 1000 /* suggested scaling for 16 bit shorts */ +#define FDMDV_NSYM 15 struct FDMDV; @@ -53,7 +55,7 @@ struct FDMDV_STATS { COMP rx_symbols[FDMDV_NSYM]; /* latest received symbols, for scatter plot */ int fest_coarse_fine; /* freq est state, 0-coarse 1-fine */ float foff; /* estimated freq offset in Hz */ - float rx_timing; /* timing offset -1..1 as fraction of symbol period */ + float rx_timing; /* estimated optimum timing offset in samples */ float clock_offset; /* Estimated tx/rx sample clock offset in ppm */ }; diff --git a/codec2-dev/src/fdmdv_demod.c b/codec2-dev/src/fdmdv_demod.c index ce44536a..cfb2667a 100644 --- a/codec2-dev/src/fdmdv_demod.c +++ b/codec2-dev/src/fdmdv_demod.c @@ -53,8 +53,8 @@ int main(int argc, char *argv[]) char packed_bits[BYTES_PER_CODEC_FRAME]; int rx_bits[FDMDV_BITS_PER_FRAME]; int codec_bits[2*FDMDV_BITS_PER_FRAME]; - float rx_fdm[FDMDV_SAMPLES_PER_FRAME]; - short rx_fdm_scaled[FDMDV_SAMPLES_PER_FRAME]; + float rx_fdm[FDMDV_MAX_SAMPLES_PER_FRAME]; + short rx_fdm_scaled[FDMDV_MAX_SAMPLES_PER_FRAME]; int i, bit, byte, c; int nin; int sync_bit; @@ -91,12 +91,12 @@ int main(int argc, char *argv[]) fdmdv = fdmdv_create(); frames = 0; state = 0; - nin = FDMDV_SAMPLES_PER_FRAME; + nin = FDMDV_NOM_SAMPLES_PER_FRAME; while(fread(rx_fdm_scaled, sizeof(short), nin, fin) == nin) { - for(i=0; itx_filter_memory); fdm_upconvert(tx_fdm, tx_baseband, fdmdv->phase_tx, fdmdv->freq); + /* --------------------------------------------------------*\ + Channel + \*---------------------------------------------------------*/ + + nin = next_nin; + /* + if (f == 2) + nin = 120; + if (f == 3) + nin = 200; + if ((f !=2) && (f != 3)) + nin = M; + */ + /* add M tx samples to end of buffer */ + + assert((channel_count + M) < CHANNEL_BUF_SIZE); for(i=0; irx_filter_mem_timing, env, fdmdv->rx_baseband_mem_timing, nin); foff_fine = qpsk_to_bits(rx_bits, &sync_bit, fdmdv->phase_difference, fdmdv->prev_rx_symbols, rx_symbols); memcpy(fdmdv->prev_rx_symbols, rx_symbols, sizeof(COMP)*(NC+1)); + + next_nin = M; + + if (rx_timing > 2*M/P) + next_nin += M/P; + + if (rx_timing < 0) + next_nin -= M/P; + fdmdv->coarse_fine = freq_state(sync_bit, &fdmdv->fest_state); fdmdv->foff -= TRACK_COEFF*foff_fine; @@ -164,15 +206,16 @@ int main(int argc, char *argv[]) /* rx filtering */ for(c=0; c