From f827d888821f42f8964c95e9d66c275d75984d01 Mon Sep 17 00:00:00 2001 From: drowe67 Date: Tue, 8 May 2018 10:38:50 +0000 Subject: [PATCH] found some freq offsets that caused false syncs. Wrote ofdm_dev function to explore false syncs, designed better UW and position of UW in modem frame to remove false sync issue. Refactored ofdm_tx, ofdm_rx, ofdm_ldpc_tx, ofdm_ldpc_rx to support new UW placement, all working OK git-svn-id: https://svn.code.sf.net/p/freetel/code@3584 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/octave/ofdm_dev.m | 74 ++++++++++++++- codec2-dev/octave/ofdm_ldpc_rx.m | 18 ++-- codec2-dev/octave/ofdm_ldpc_tx.m | 13 +-- codec2-dev/octave/ofdm_lib.m | 141 +++++++++++++++++++++++++--- codec2-dev/octave/ofdm_load_const.m | 2 + codec2-dev/octave/ofdm_rx.m | 4 +- codec2-dev/octave/tofdm.m | 2 +- 7 files changed, 221 insertions(+), 33 deletions(-) diff --git a/codec2-dev/octave/ofdm_dev.m b/codec2-dev/octave/ofdm_dev.m index 1d47f882..7c8be03b 100644 --- a/codec2-dev/octave/ofdm_dev.m +++ b/codec2-dev/octave/ofdm_dev.m @@ -112,14 +112,15 @@ function [sim_out rx states] = run_sim(sim_in) HRA = sim_in.ldpc_code; [aNr aNc] = size(HRA); rate = states.rate = (aNc-aNr)/aNc; - assert(aNc == Nbitsperframe, "Dude: Num cols of LDPC HRA must == Nbitsperframe"); + Ndatabitsperframe = Nbitsperframe; + assert(aNc == Ndatabitsperframe, "Dude: Num cols of LDPC HRA must == Nbitsperframe"); [H_rows, H_cols] = Mat2Hrows(HRA); code_param.H_rows = H_rows; code_param.H_cols = H_cols; code_param.P_matrix = []; code_param.data_bits_per_frame = length(code_param.H_cols) - length( code_param.P_matrix ); code_param.code_bits_per_frame = aNc; - assert(aNr == Nbitsperframe*rate); + assert(aNr == Ndatabitsperframe*rate); modulation = states.ldpc_modulation = 'QPSK'; mapping = states.ldpc_mapping = 'gray'; @@ -200,6 +201,9 @@ function [sim_out rx states] = run_sim(sim_in) else % uncoded mode codeword = tx_data_bits(st:en); + if isfield(sim_in, "uw_debug") + codeword(states.uw_ind) = states.tx_uw; + end end tx_bits = [tx_bits codeword]; for b=1:2:Nbitsperframe @@ -294,7 +298,8 @@ function [sim_out rx states] = run_sim(sim_in) Nerrs_log = []; Nerrs_coded_log = []; rx_bits = []; rx_np = []; rx_amp = []; sig_var_log = []; noise_var_log = []; - + uw_errors_log = []; + % reset some states for each EbNo simulation point states.sample_point = states.timing_est = 1; @@ -328,6 +333,17 @@ function [sim_out rx states] = run_sim(sim_in) rx_bits = [rx_bits arx_bits]; rx_np = [rx_np arx_np]; rx_amp = [rx_amp arx_amp]; + % note: only supported in ldpc_en = 0 Nc=17 atm, see debug_false_sync() + + if isfield(sim_in, "uw_debug") + rx_uw = arx_bits(states.uw_ind); + uw_errors = sum(xor(states.tx_uw,rx_uw)); + if verbose + printf("f: %d uw_errors: %d\n", f, uw_errors); + end + uw_errors_log = [uw_errors_log uw_errors]; + end + timing_est_log = [timing_est_log states.timing_est]; delta_t_log = [delta_t_log states.delta_t]; foff_est_hz_log = [foff_est_hz_log states.foff_est_hz]; @@ -463,6 +479,8 @@ function [sim_out rx states] = run_sim(sim_in) sim_out.per(nn) = Tpacketerrs/Tpackets; end end + + sim_out.uw_errors_log = uw_errors_log; % Optional plots, mostly used with run-single @@ -573,7 +591,6 @@ function run_single(EbNodB = 100, error_pattern_filename); sim_in.ldpc_en = 1; sim_in.interleave_frames = 1; - %sim_in.diversity_en = 1; sim_out = run_sim(sim_in); @@ -1199,6 +1216,51 @@ function sync_metrics(x_axis = 'EbNo') endfunction +% during development it was discovered demod could obtain a flase sync with no UW +% errors at +/- 7Hz, approx the frame rate. This function is used to explore that + +function debug_false_sync(EbNodB = 100) + Ts = 0.018; + sim_in.Tcp = 0.002; + sim_in.Rs = 1/Ts; sim_in.bps = 2; sim_in.Nc = 17; sim_in.Ns = 8; + + sim_in.Nsec = (sim_in.Ns+1)/sim_in.Rs; % one frame, make sure sim_in.interleave_frames = 1 + sim_in.Nsec = 1; + + sim_in.EbNodB = 40; + sim_in.verbose = 0; + sim_in.hf_en = 0; + sim_in.foff_hz = 0; + sim_in.dfoff_hz_per_sec = 0.00; + sim_in.sample_clock_offset_ppm = 0; + sim_in.gain = 1; + + sim_in.timing_en = 0; + sim_in.foff_est_en = 0; + sim_in.phase_est_en = 1; + + load HRA_112_112.txt + sim_in.ldpc_code = HRA_112_112; + sim_in.ldpc_en = 0; + + %sim_in.interleave_frames = 1; + %sim_in.diversity_en = 1; + + sim_in.uw_debug = 1; + + foff = -25:0.5:25; + for f=1:length(foff) + sim_in.foff_hz = foff(f); + sim_out = run_sim(sim_in); + min_uw_errors(f) = min(sim_out.uw_errors_log(2:end-1)); + printf("f: %4.2f %2d\n", foff(f), min_uw_errors(f)); + end + figure(1); clf; + plot(foff, min_uw_errors); + title('UW errors versus freq offset'); + xlabel('Freq Offset (Hz)'); +end + % --------------------------------------------------------- % choose simulation to run here @@ -1214,7 +1276,9 @@ init_cml('~/cml/'); %run_curves_estimators %acquisition_histograms(fin_en=0, foff_hz=-15, EbNoAWGN=-1, EbNoHF=3) %acquisition_test(Ntests=100, EbNodB=-1, foff_hz=-10, hf_en=0) -sync_metrics('freq') +%sync_metrics('freq') %run_curves_snr %acquisition_dev(Ntests=10, EbNodB=100, foff_hz=0) %acquistion_curves + +debug_false_sync diff --git a/codec2-dev/octave/ofdm_ldpc_rx.m b/codec2-dev/octave/ofdm_ldpc_rx.m index 4fedb11d..fe658ab6 100644 --- a/codec2-dev/octave/ofdm_ldpc_rx.m +++ b/codec2-dev/octave/ofdm_ldpc_rx.m @@ -93,14 +93,16 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) Nerrs_coded_log = Nerrs_log = []; error_positions = []; Nerrs_coded = Nerrs_raw = zeros(1, interleave_frames); - - % 'prime' rx buf to get correct coarse timing (for now) + #{ + % 'prime' rx buf to get correct coarse timing (for now) + prx = 1; nin = Nsamperframe+2*(M+Ncp); states.rxbuf(Nrxbuf-nin+1:Nrxbuf) = rx(prx:nin); prx += nin; - + #} + % main loop ---------------------------------------------------------------- for f=1:Nframes @@ -125,11 +127,11 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) if strcmp(states.sync_state,'search') [timing_valid states] = ofdm_sync_search(states, rxbuf_in); end - + if strcmp(states.sync_state,'synced') || strcmp(states.sync_state,'trial') [rx_bits states aphase_est_pilot_log arx_np arx_amp] = ofdm_demod(states, rxbuf_in); - rx_uw = rx_bits(1:states.Nuwbits); - + [rx_uw payload_syms payload_amps txt_bits] = disassemble_modem_frame(states, arx_np, arx_amp); + % we are in sync so log modem states rx_np_log = [rx_np_log arx_np]; @@ -144,9 +146,9 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) % discarding UW and txt symbols at start of each modem frame rx_np(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_np(Nsymbolsperframe+1:Nsymbolsperinterleavedframe); - rx_np(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_np(Nuwtxtsymbolsperframe+1:end); + rx_np(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = payload_syms; rx_amp(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_amp(Nsymbolsperframe+1:Nsymbolsperinterleavedframe); - rx_amp(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_amp(Nuwtxtsymbolsperframe+1:end); + rx_amp(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = payload_amps; mean_amp = states.mean_amp; diff --git a/codec2-dev/octave/ofdm_ldpc_tx.m b/codec2-dev/octave/ofdm_ldpc_tx.m index 071106a8..0f97502c 100644 --- a/codec2-dev/octave/ofdm_ldpc_tx.m +++ b/codec2-dev/octave/ofdm_ldpc_tx.m @@ -83,18 +83,19 @@ function ofdm_ldpc_tx(filename, interleave_frames = 1, Nsec, EbNodB=100, channel % generate UW and txt symbols to prepend to every frame after LDPC encoding and interleaving - tx_uw_tx_bits = [tx_uw zeros(1,Ntxtbits)]; - tx_uw_tx_symbols = []; - for b=1:2:length(tx_uw_tx_bits) - tx_uw_tx_symbols = [tx_uw_tx_symbols qpsk_mod(tx_uw_tx_bits(b:b+1))]; + txt_bits = zeros(1,Ntxtbits); + txt_symbols = []; + for b=1:2:length(txt_bits) + txt_symbols = [txt_symbols qpsk_mod(txt_bits(b:b+1))]; end atx = []; for f=1:interleave_frames st = (f-1)*code_param.code_bits_per_frame/bps+1; en = st + code_param.code_bits_per_frame/bps-1; - atx = [atx ofdm_txframe( states, [tx_uw_tx_symbols tx_symbols(st:en)] ) ]; + modem_frame = assemble_modem_frame_symbols(states, tx_symbols(st:en), txt_symbols); + atx = [atx ofdm_txframe(states, modem_frame) ]; end - + tx = []; for f=1:Nframes/interleave_frames tx = [tx atx]; diff --git a/codec2-dev/octave/ofdm_lib.m b/codec2-dev/octave/ofdm_lib.m index cb115212..b3de59ce 100644 --- a/codec2-dev/octave/ofdm_lib.m +++ b/codec2-dev/octave/ofdm_lib.m @@ -74,7 +74,7 @@ function [t_est timing_valid timing_mx] = est_timing(states, rx, rate_fs_pilot_s timing_valid = timing_mx > timing_mx_thresh; if verbose > 1 - printf(" mx: %f timing_est: %d timing_valid: %d\n", timing_mx, t_est, timing_valid); + printf(" av_level: %f mx: %f timing_est: %d timing_valid: %d\n", av_level, timing_mx, t_est, timing_valid); end endfunction @@ -108,7 +108,12 @@ function [foff_est states] = est_freq_offset(states, rx, rate_fs_pilot_samples, % averaging metric was found to be really important for reliable acquisition at low SNRs states.foff_metric = 0.9*states.foff_metric + 0.1*(conj(p1)*p2 + conj(p3)*p4); - foff_est = Fs1*angle(states.foff_metric)/(2*pi); + foff_est = Fs1*angle(states.foff_metric)/(2*pi); + + if states.verbose > 1 + printf(" foff_metric: %f %f foff_est: %f\n", real(states.foff_metric), imag(states.foff_metric), foff_est); + end + endfunction @@ -137,17 +142,34 @@ function states = ofdm_init(bps, Rs, Tcp, Ns, Nc) states.Nbitsperframe = (Ns-1)*Nc*bps; states.Nrowsperframe = states.Nbitsperframe/(Nc*bps); states.Nsamperframe = (states.Nrowsperframe+1)*(states.M+states.Ncp); - states.Ntxtbits = 4; % reserve 4 bits/frame for auxillary text information + states.Ntxtbits = 4; % reserved bits/frame for auxillary text information states.Nuwbits = (Ns-1)*bps - states.Ntxtbits; - states.tx_uw = [1 0 0 1 0 1 0 0 1 0]; - assert(length(states.tx_uw) == states.Nuwbits); + % UW symbol placement, designed to get no false syncs and any freq + % offset. Use ofdm_dev.m, debug_false_sync() to test. Note we need + % to pair the UW bits so the fit into symbols. The LDPC decoder + % work on symbols so we can't break up any symbols into UW/LDPC + % bits. + + states.uw_ind = states.uw_ind_sym = []; + for i=1:states.Nuwbits/2 + states.uw_ind = [states.uw_ind 1+i*(Nc+1) 2+i*(Nc+1)]; + states.uw_ind_sym = [states.uw_ind_sym i*(Nc+1)/2+1]; + end + states.tx_uw = [0 0 0 0 0 0 0 0 0 0]; + assert(length(states.tx_uw) == states.Nuwbits); + tx_uw_syms = []; + for b=1:2:states.Nuwbits + tx_uw_syms = [tx_uw_syms qpsk_mod(states.tx_uw(b:b+1))]; + end + states.tx_uw_syms = tx_uw_syms; + % use this to scale tx output to 16 bit short. Adjusted by experiment % to have same RMS power as FDMDV waveform states.amp_scale = 2E5*1.1491/1.06; - % this is used to scale input sto LDPC decoder to make it amplitude indep + % this is used to scale inputs to LDPC decoder to make it amplitude indep states.mean_amp = 0; @@ -392,10 +414,11 @@ function [rx_bits states aphase_est_pilot_log rx_np rx_amp] = ofdm_demod(states, [ft_est timing_valid timing_mx] = est_timing(states, rxbuf(st:en) .* exp(-j*woff_est*(st:en)), rate_fs_pilot_samples); - % keep the freq est statistic updated in case we lose sync, not we supply it with uncorrected rxbuf + % keep the freq est statistic updated in case we lose sync, note + % we supply it with uncorrected rxbuf + + [coarse_foff_est_hz states] = est_freq_offset(states, rxbuf(st:en), states.rate_fs_pilot_samples, ft_est); - [unused_foff_est states] = est_freq_offset(states, rxbuf(st:en), states.rate_fs_pilot_samples, ft_est); - if timing_valid timing_est = timing_est + ft_est - ceil(ftwindow_width/2); @@ -576,7 +599,102 @@ function [rx_bits states aphase_est_pilot_log rx_np rx_amp] = ofdm_demod(states, states.sample_point = sample_point; states.delta_t = delta_t; states.foff_est_hz = foff_est_hz; - states.coarse_foff_est_hz = coarse_foff_est_hz; + states.coarse_foff_est_hz = coarse_foff_est_hz; % just used for tofdm +endfunction + + +% assemble modem frame from UW, payload, and txt bits + +function modem_frame = assemble_modem_frame(states, payload_bits, txt_bits) + ofdm_load_const; + + modem_frame = zeros(1,Nbitsperframe); + p = 1; u = 1; + + for b=1:Nbitsperframe-Ntxtbits; + if (u <= Nuwbits) && (b == uw_ind(u)) + modem_frame(b) = tx_uw(u++); + else + modem_frame(b) = payload_bits(p++); + end + end + t = 1; + for b=Nbitsperframe-Ntxtbits+1:Nbitsperframe + modem_frame(b) = txt_bits(t++); + end + assert(u == (Nuwbits+1)); + assert(p = (length(payload_bits)+1)); +endfunction + + +% assemble modem frame from UW, payload, and txt symbols + +function modem_frame = assemble_modem_frame_symbols(states, payload_syms, txt_syms) + ofdm_load_const; + + Nsymsperframe = Nbitsperframe/bps; + Nuwsyms = Nuwbits/bps; + Ntxtsyms = Ntxtbits/bps; + modem_frame = zeros(1,Nsymsperframe); + p = 1; u = 1; + + for s=1:Nsymsperframe-Ntxtsyms; + if (u <= Nuwsyms) && (s == uw_ind_sym(u)) + modem_frame(s) = states.tx_uw_syms(u++); + else + modem_frame(s) = payload_syms(p++); + end + end + t = 1; + for s=Nsymsperframe-Ntxtsyms+1:Nsymsperframe + modem_frame(s) = txt_syms(t++); + end + assert(u == (Nuwsyms+1)); + assert(p = (length(payload_syms)+1)); +endfunction + + +% extract UW and txt bits, and payload symbols from a frame of modem symbols + +function [rx_uw payload_syms payload_amps txt_bits] = disassemble_modem_frame(states, modem_frame_syms, modem_frame_amps) + ofdm_load_const; + + Nsymsperframe = Nbitsperframe/bps; + Nuwsyms = Nuwbits/bps; + Ntxtsyms = Ntxtbits/bps; + payload_syms = zeros(1,Nsymsperframe-Nuwsyms-Ntxtsyms); + payload_amps = zeros(1,Nsymsperframe-Nuwsyms-Ntxtsyms); + rx_uw_syms = zeros(1,Nuwsyms); + txt_syms = zeros(1,Ntxtsyms); + p = 1; u = 1; + + for s=1:Nsymsperframe-Ntxtsyms; + if (u <= Nuwsyms) && (s == uw_ind_sym(u)) + rx_uw_syms(u++) = modem_frame_syms(s); + else + payload_syms(p) = modem_frame_syms(s); + payload_amps(p++) = modem_frame_amps(s); + end + end + t = 1; + for s=Nsymsperframe-Ntxtsyms+1:Nsymsperframe + txt_syms(t++) = modem_frame_syms(s); + end + assert(u == (Nuwsyms+1)); + assert(p = (Nsymsperframe+1)); + + % now demodulate UW and txt bits + + rx_uw = zeros(1,Nuwbits); + txt_bits = zeros(1,Ntxtbits); + + for s=1:Nuwsyms + rx_uw(2*s-1:2*s) = qpsk_demod(rx_uw_syms(s)); + end + for s=1:Ntxtsyms + txt_bits(2*s-1:2*s) = qpsk_demod(txt_syms(s)); + end + endfunction @@ -622,7 +740,8 @@ function [tx_bits payload_data_bits codeword] = create_ldpc_test_frame % insert UW and txt bits - tx_bits = [tx_uw zeros(1,Ntxtbits) codeword_raw]; + %tx_bits = [tx_uw zeros(1,Ntxtbits) codeword_raw]; + tx_bits = assemble_modem_frame(states, codeword_raw, zeros(1,Ntxtbits)); assert(Nbitsperframe == length(tx_bits)); endfunction diff --git a/codec2-dev/octave/ofdm_load_const.m b/codec2-dev/octave/ofdm_load_const.m index bfcb636e..7499d50e 100644 --- a/codec2-dev/octave/ofdm_load_const.m +++ b/codec2-dev/octave/ofdm_load_const.m @@ -16,6 +16,8 @@ timing_mx_thresh = 0.25; Nuwbits = states.Nuwbits; Ntxtbits = states.Ntxtbits; tx_uw = states.tx_uw; +uw_ind = states.uw_ind; +uw_ind_sym = states.uw_ind_sym; W = states.W; w = states.w; diff --git a/codec2-dev/octave/ofdm_rx.m b/codec2-dev/octave/ofdm_rx.m index 98412551..0a450d53 100644 --- a/codec2-dev/octave/ofdm_rx.m +++ b/codec2-dev/octave/ofdm_rx.m @@ -43,7 +43,7 @@ function ofdm_rx(filename, error_pattern_filename) %states.rxbuf(Nrxbuf-nin+1:Nrxbuf) = rx(prx:nin); %prx += nin; - states.verbose = 0; + states.verbose = 1; Nerrs = 0; rx_uw = zeros(1,states.Nuwbits); @@ -69,7 +69,7 @@ function ofdm_rx(filename, error_pattern_filename) if strcmp(states.sync_state,'synced') || strcmp(states.sync_state,'trial') [rx_bits states aphase_est_pilot_log arx_np arx_amp] = ofdm_demod(states, rxbuf_in); - rx_uw = rx_bits(1:states.Nuwbits); + [rx_uw payload_syms payload_amps txt_bits] = disassemble_modem_frame(states, arx_np, arx_amp); errors = xor(tx_bits, rx_bits); Nerrs = sum(errors); diff --git a/codec2-dev/octave/tofdm.m b/codec2-dev/octave/tofdm.m index c570b610..68c64a9f 100644 --- a/codec2-dev/octave/tofdm.m +++ b/codec2-dev/octave/tofdm.m @@ -155,7 +155,7 @@ for f=1:Nframes % make sure LDPC decoding is working OK - assert(codeword == detected_data); + % assert(codeword == detected_data); [m n] = size(symbol_likelihood); symbol_likelihood_log = [symbol_likelihood_log; reshape(symbol_likelihood,m*n,1)]; -- 2.25.1