% decimation filter
f.Nrxdec = 31;
- f.rxdec_coeff = fir1(f.Nrxdec-1, 0.25);
+ % fir1() output appears to have changed from when coeffs used in C port were used
+ %f.rxdec_coeff = fir1(f.Nrxdec-1, 0.25);
+ f.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];
+
f.rxdec_lpf_mem = zeros(1,f.Nrxdec-1+M);
f.Q=M/4;
f.Mpilotfft = 256;
f.Npilotcoeff = 30;
- f.pilot_coeff = fir1(f.Npilotcoeff-1, 200/(Fs/2))'; % 200Hz LPF
+
+ % here's how to make this filter from scratch, however it appeared to change over different
+ % octave versions so have hard coded to version used for C port
+ %f.pilot_coeff = fir1(f.Npilotcoeff-1, 200/(Fs/2))'; % 200Hz LPF
+ f.pilot_coeff = [0.00223001 0.00301037 0.00471258 0.0075934 0.0118145 0.0174153 ...
+ 0.0242969 0.0322204 0.0408199 0.0496286 0.0581172 0.0657392 ...
+ 0.0719806 0.0764066 0.0787022 0.0787022 0.0764066 0.0719806 ...
+ 0.0657392 0.0581172 0.0496286 0.0408199 0.0322204 0.0242969 ...
+ 0.0174153 0.0118145 0.0075934 0.00471258 0.00301037 0.00223001];
+
f.Npilotbaseband = f.Npilotcoeff + M + M/P; % number of pilot baseband samples
f.Npilotlpf = 4*M; % reqd for pilot LPF
% number of symbols we DFT pilot over
pilot_lpf(1:Npilotlpf-nin) = pilot_lpf(nin+1:Npilotlpf);
k = Npilotbaseband-nin+1;;
for i = Npilotlpf-nin+1:Npilotlpf
- pilot_lpf(i) = pilot_baseband(k-Npilotcoeff+1:k) * pilot_coeff;
+ pilot_lpf(i) = pilot_baseband(k-Npilotcoeff+1:k) * pilot_coeff';
k++;
end
% Estimate frequency offset of FDM signal using BPSK pilot. This is quite
% sensitive to pilot tone level wrt other carriers
-function [foff S1 S2] = rx_est_freq_offset(f, rx_fdm, pilot, pilot_prev, nin, do_fft)
+function [foff S1 S2 f] = rx_est_freq_offset(f, rx_fdm, pilot, pilot_prev, nin, do_fft)
M = f.M;
Npilotbaseband = f.Npilotbaseband;
pilot_baseband1 = f.pilot_baseband1;
function [rx_bits sync_bit f_err phase_difference] = psk_to_bits(f, prev_rx_symbols, rx_symbols, modulation)
Nc = f.Nc;
Nb = f.Nb;
+
m4_binary_to_gray = [
bin2dec("00")
bin2dec("01")
% returns nbits from a repeating sequence of random data
function [bits f] = get_test_bits(f, nbits)
-
+
for i=1:nbits
bits(i) = f.test_bits(f.current_test_bit++);
% Octave script that tests the C port of the FDMDV modem. This script loads
% the output of unittest/tfdmdv.c and compares it to the output of the
% reference versions of the same functions written in Octave.
+%
+% Usage:
+%
+% 1/ In codec2-dev/CMakeLists.txt, ensure set(CMAKE_BUILD_TYPE "Debug"), to
+% enable building the C unittests. Build codec2-dev as per
+% codec2-dev/README.
+%
+% 2/ Run the C side from the Octave directory:
+%
+% codec2-dev/octave$ ../build_linux/unittest/tfdmdv
+% codec2-dev/octave$ ls -l tfdmdv_out.txt
+% -rw-rw-r-- 1 david david 3419209 Aug 27 10:05 tfdmdv_out.txt
+%
+% 3/ Run the Octave side (this script):
+%
+% octave:1> tfdmdv
+%
+
%
% Copyright David Rowe 2012
% This program is distributed under the terms of the GNU General Public License
% Generate reference vectors using Octave implementation of FDMDV modem
-passes = fails = 0;
+global passes = fails = 0;
frames = 35;
prev_tx_symbols = ones(Nc+1,1); prev_tx_symbols(Nc+1) = 2;
prev_rx_symbols = ones(Nc+1,1);
foff_coarse_log = [];
foff_fine_log = [];
foff_log = [];
-rx_baseband_log = [];
+rx_fdm_filter_log = [];
rx_filt_log = [];
env_log = [];
rx_timing_log = [];
% adjust this if the screen is getting a bit cluttered
-no_plot_list = [1 2 3 4 5 6 7 8 11 12 13 14 15 16];
+global no_plot_list = [1 2 3 4 5 6 7 8 12 13 14 15 16];
for fr=1:frames
[tx_symbols f] = bits_to_psk(f, prev_tx_symbols, tx_bits, 'dqpsk');
prev_tx_symbols = tx_symbols;
tx_symbols_log = [tx_symbols_log tx_symbols];
- [tx_baseband ] = tx_filter(f, tx_symbols);
+ [tx_baseband f] = tx_filter(f, tx_symbols);
tx_baseband_log = [tx_baseband_log tx_baseband];
- tx_fdm = fdm_upconvert(f, tx_baseband);
+ [tx_fdm f] = fdm_upconvert(f, tx_baseband);
tx_fdm_log = [tx_fdm_log tx_fdm];
% channel
nin = next_nin;
- %nin = M; % when debugging good idea to uncomment this to "open loop"
+ % nin = M; % when debugging good idea to uncomment this to "open loop"
channel = [channel real(tx_fdm)];
channel_count += M;
mag = abs(f.fbb_phase_rx);
f.fbb_phase_rx /= mag;
- [pilot prev_pilot f.pilot_lut_index f.prev_pilot_lut_index] = get_pilot(f, f.pilot_lut_index, f.prev_pilot_lut_index, nin);
- [foff_coarse S1 S2] = rx_est_freq_offset(f, rx_fdm, pilot, prev_pilot, nin, !sync);
+ % sync = 0; % when debugging good idea to uncomment this to "open loop"
- %sync = 0; % when debugging good idea to uncomment this to "open loop"
+ [pilot prev_pilot f.pilot_lut_index f.prev_pilot_lut_index] = get_pilot(f, f.pilot_lut_index, f.prev_pilot_lut_index, nin);
+ [foff_coarse S1 S2 f] = rx_est_freq_offset(f, rx_fdm, pilot, prev_pilot, nin, !sync);
if sync == 0
foff = foff_coarse;
[rx_fdm_filter f] = rxdec_filter(f, rx_fdm_fcorr, nin);
[rx_filt f] = down_convert_and_rx_filter(f, rx_fdm_filter, nin, M/Q);
-
+ #{
+ for i=1:5
+ printf("[%d] rx_fdm_fcorr: %f %f rx_fdm_filter: %f %f\n", i,
+ real(rx_fdm_fcorr(i)), imag(rx_fdm_fcorr(i)), real(rx_fdm_filter(i)), imag(rx_fdm_filter(i)));
+ end
+ for i=1:5
+ printf("[%d] rx_fdm_fcorr: %f %f rxdec_lpf_mem: %f %f\n", i,
+ real(rx_fdm_fcorr(i)), imag(rx_fdm_fcorr(i)), real(f.rxdec_lpf_mem(i)), imag(f.rxdec_lpf_mem(i)));
+ end
+ #}
rx_filt_log = [rx_filt_log rx_filt];
+ rx_fdm_filter_log = [rx_fdm_filter_log rx_fdm_filter];
[rx_symbols rx_timing env f] = rx_est_timing(f, rx_filt, nin);
env_log = [env_log env];
% Compare to the output from the C version
-load ../build_src/unittest/tfdmdv_out.txt
+load tfdmdv_out.txt
% ---------------------------------------------------------------------------------------
% generate_pilot_lut()
-plot_sig_and_error(4, 211, real(pilot_lut_c), real(pilot_lut - pilot_lut_c), 'pilot lut real')
-plot_sig_and_error(4, 212, imag(pilot_lut_c), imag(pilot_lut - pilot_lut_c), 'pilot lut imag')
+plot_sig_and_error(4, 211, real(pilot_lut_c), real(f.pilot_lut - pilot_lut_c), 'pilot lut real')
+plot_sig_and_error(4, 212, imag(pilot_lut_c), imag(f.pilot_lut - pilot_lut_c), 'pilot lut imag')
% rx_est_freq_offset()
-st=1; en = 5*Npilotbaseband;
+st=1; en = 5*f.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' )
-st=1; en = 5*Npilotlpf;
+st=1; en = 5*f.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(10, 211, foff_log, foff_log - foff_log_c, 'Freq Offset' )
plot_sig_and_error(10, 212, sync_log, sync_log - sync_log_c, 'Sync & Freq Est Coarse(0) Fine(1)', [1 frames -1.5 1.5] )
-c=1;
-if 0
-plot_sig_and_error(11, 211, real(rx_baseband_log(c,:)), real(rx_baseband_log(c,:) - rx_baseband_log_c(c,:)), 'Rx baseband real' )
-plot_sig_and_error(11, 212, imag(rx_baseband_log(c,:)), imag(rx_baseband_log(c,:) - rx_baseband_log_c(c,:)), 'Rx baseband imag' )
-end
+plot_sig_and_error(11, 211, real(rx_fdm_filter_log), real(rx_fdm_filter_log - rx_fdm_filter_log_c), 'Rx dec filter real' )
+plot_sig_and_error(11, 212, imag(rx_fdm_filter_log), imag(rx_fdm_filter_log - rx_fdm_filter_log_c), 'Rx dec filter imag' )
+c=1;
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(16, 211, sig_est_log(c,:), sig_est_log(c,:) - sig_est_log_c(c,:), 'sig est for SNR' )
plot_sig_and_error(16, 212, noise_est_log(c,:), noise_est_log(c,:) - noise_est_log_c(c,:), 'noise est for SNR' )
-f=12;
+fr=12;
-stem_sig_and_error(13, 211, real(rx_symbols_log(:,f)), real(rx_symbols_log(:,f) - rx_symbols_log_c(:,f)), 'rx symbols real' )
-stem_sig_and_error(13, 212, imag(rx_symbols_log(:,f)), imag(rx_symbols_log(:,f) - rx_symbols_log_c(:,f)), 'rx symbols imag' )
+stem_sig_and_error(13, 211, real(rx_symbols_log(:,fr)), real(rx_symbols_log(:,fr) - rx_symbols_log_c(:,fr)), 'rx symbols real' )
+stem_sig_and_error(13, 212, imag(rx_symbols_log(:,fr)), imag(rx_symbols_log(:,fr) - rx_symbols_log_c(:,fr)), 'rx symbols imag' )
-stem_sig_and_error(17, 211, real(phase_difference_log(:,f)), real(phase_difference_log(:,f) - phase_difference_log_c(:,f)), 'phase difference real' )
-stem_sig_and_error(17, 212, imag(phase_difference_log(:,f)), imag(phase_difference_log(:,f) - phase_difference_log_c(:,f)), 'phase difference imag' )
+stem_sig_and_error(17, 211, real(phase_difference_log(:,fr)), real(phase_difference_log(:,fr) - phase_difference_log_c(:,fr)), 'phase difference real' )
+stem_sig_and_error(17, 212, imag(phase_difference_log(:,fr)), imag(phase_difference_log(:,fr) - phase_difference_log_c(:,fr)), 'phase difference imag' )
check(tx_bits_log, tx_bits_log_c, 'tx_bits');
check(tx_symbols_log, tx_symbols_log_c, 'tx_symbols');
check(tx_fdm_log, tx_fdm_log_c, 'tx_fdm');
-check(pilot_lut, pilot_lut_c, 'pilot_lut');
-check(pilot_coeff, pilot_coeff_c, 'pilot_coeff');
+check(f.pilot_lut, pilot_lut_c, 'pilot_lut');
+check(f.pilot_coeff, pilot_coeff_c, 'pilot_coeff');
check(pilot_baseband1_log, pilot_baseband1_log_c, 'pilot lpf1');
check(pilot_baseband2_log, pilot_baseband2_log_c, 'pilot lpf2');
check(S1_log, S1_log_c, 'S1');
check(foff_coarse_log, foff_coarse_log_c, 'foff_coarse');
check(foff_fine_log, foff_fine_log_c, 'foff_fine');
check(foff_log, foff_log_c, 'foff');
-%check(rx_baseband_log, rx_baseband_log_c, 'rx baseband');
-check(rx_filt_log, rx_filt_log_c, 'rx filt');
+check(rx_fdm_filter_log, rx_fdm_filter_log_c, 'rxdec filter');
+check(rx_filt_log, rx_filt_log_c, 'rx filt', 2E-3);
check(env_log, env_log_c, 'env');
check(rx_timing_log, rx_timing_log_c, 'rx_timing');
-check(rx_symbols_log, rx_symbols_log_c, 'rx_symbols');
+check(rx_symbols_log, rx_symbols_log_c, 'rx_symbols', 2E-3);
check(rx_bits_log, rx_bits_log_c, 'rx bits');
check(sync_bit_log, sync_bit_log_c, 'sync bit');
check(sync_log, sync_log_c, 'sync');
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;
float env[NT*P];
COMP S2_log[MPILOTFFT*FRAMES];
float foff_coarse_log[FRAMES];
float foff_log[FRAMES];
- COMP rx_baseband_log[(NC+1)][(M+M/P)*FRAMES];
- int rx_baseband_log_col_index;
+ COMP rx_fdm_filter_log[(M+M/P)*FRAMES];
+ int rx_fdm_filter_log_index;
COMP rx_filt_log[NC+1][(P+1)*FRAMES];
int rx_filt_log_col_index;
float env_log[NT*P*FRAMES];
next_nin = M;
channel_count = 0;
- rx_baseband_log_col_index = 0;
+ rx_fdm_filter_log_index = 0;
rx_filt_log_col_index = 0;
printf("sizeof FDMDV states: %zd bytes\n", sizeof(struct FDMDV));
nin = next_nin;
- //nin = M; // when debugging good idea to uncomment this to "open loop"
+ // nin = M; // when debugging good idea to uncomment this to "open loop"
/* add M tx samples to end of buffer */
/* freq offset estimation and correction */
- //fdmdv->sync = 0; // when debugging good idea to uncomment this to "open loop"
+ // fdmdv->sync = 0; // when debugging good idea to uncomment this to "open loop"
foff_coarse = rx_est_freq_offset(fdmdv, rx_fdm, nin, !fdmdv->sync);
/* baseband processing */
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, M);
memcpy(&S2_log[f*MPILOTFFT], fdmdv->S2, sizeof(COMP)*MPILOTFFT);
foff_coarse_log[f] = foff_coarse;
foff_log[f] = fdmdv->foff;
-
- /* rx down conversion */
-
- for(c=0; c<NC+1; c++) {
- for(i=0; i<nin; i++)
- rx_baseband_log[c][rx_baseband_log_col_index + i] = rx_baseband[c][i];
- }
- rx_baseband_log_col_index += nin;
-
+
/* rx filtering */
+ for(i=0; i<nin; i++)
+ rx_fdm_filter_log[rx_fdm_filter_log_index + i] = rx_fdm_filter[i];
+ rx_fdm_filter_log_index += nin;
+
for(c=0; c<NC+1; c++) {
for(i=0; i<(P*nin)/M; i++)
rx_filt_log[c][rx_filt_log_col_index + i] = rx_filt[c][i];
octave_save_complex(fout, "S2_log_c", S2_log, 1, MPILOTFFT*FRAMES, MPILOTFFT*FRAMES);
octave_save_float(fout, "foff_log_c", foff_log, 1, FRAMES, FRAMES);
octave_save_float(fout, "foff_coarse_log_c", foff_coarse_log, 1, FRAMES, FRAMES);
- octave_save_complex(fout, "rx_baseband_log_c", (COMP*)rx_baseband_log, (FDMDV_NC+1), rx_baseband_log_col_index, (M+M/P)*FRAMES);
+ octave_save_complex(fout, "rx_fdm_filter_log_c", (COMP*)rx_fdm_filter_log, 1, rx_fdm_filter_log_index, rx_fdm_filter_log_index);
octave_save_complex(fout, "rx_filt_log_c", (COMP*)rx_filt_log, (FDMDV_NC+1), rx_filt_log_col_index, (P+1)*FRAMES);
octave_save_float(fout, "env_log_c", env_log, 1, NT*P*FRAMES, NT*P*FRAMES);
octave_save_float(fout, "rx_timing_log_c", rx_timing_log, 1, FRAMES, FRAMES);