From: drowe67 Date: Sun, 15 Apr 2018 00:53:53 +0000 (+0000) Subject: first pass interleaver sync working X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=7d4a7e0bf2a1db408c9ca68b78b588c1af3099ca;p=freetel-svn-tracking.git first pass interleaver sync working git-svn-id: https://svn.code.sf.net/p/freetel/code@3490 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2-dev/octave/ldpc.m b/codec2-dev/octave/ldpc.m index 908f0f17..d337394e 100644 --- a/codec2-dev/octave/ldpc.m +++ b/codec2-dev/octave/ldpc.m @@ -73,7 +73,7 @@ function [codeword s] = ldpc_enc(data, code_param) endfunction -function [detected_data errors] = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, r, EsNo, fading) +function [detected_data paritychecks] = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, r, EsNo, fading) if nargin == 6 fading = ones(1, length(r)); end @@ -87,9 +87,10 @@ function [detected_data errors] = ldpc_dec(code_param, max_iterations, demod_typ input_decoder_c = bit_likelihood(1:code_param.code_bits_per_frame); - [x_hat errors] = MpDecode( -input_decoder_c, code_param.H_rows, code_param.H_cols, ... + [x_hat paritychecks] = MpDecode( -input_decoder_c, code_param.H_rows, code_param.H_cols, ... max_iterations, decoder_type, 1, 1); - detected_data = x_hat(max_iterations,:); + [mx mx_ind] = max(paritychecks); + detected_data = x_hat(mx_ind,:); endfunction diff --git a/codec2-dev/octave/ofdm_ldpc_rx.m b/codec2-dev/octave/ofdm_ldpc_rx.m index 1fa5fcb1..bbe04efe 100644 --- a/codec2-dev/octave/ofdm_ldpc_rx.m +++ b/codec2-dev/octave/ofdm_ldpc_rx.m @@ -55,7 +55,10 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) rx_uw = []; % OK generate tx frame for BER calcs - + % We just use a single test frame of bits as it makes interleaver sync + % easier than using a test fram eof bits that spans the entire interleaver + % frame. Doesn't affect operation with the speech codec operation. + rand('seed', 1); atx_bits = round(rand(1,code_param.data_bits_per_frame)); tx_bits = []; tx_codewords = []; @@ -88,7 +91,7 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) Nbitspervocframe = 28; Nerrs_coded_log = Nerrs_log = []; error_positions = []; - Nerrs = Nerrs_coded = 0; + Nerrs_raw = Nerrs_coded = 0; % 'prime' rx buf to get correct coarse timing (for now) @@ -97,8 +100,6 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) states.rxbuf(Nrxbuf-nin+1:Nrxbuf) = rx(prx:nin); prx += nin; - state = 'searching'; frame_count = 0; - % main loop ---------------------------------------------------------------- for f=1:Nframes @@ -115,9 +116,6 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) end prx += states.nin; - [rx_bits_raw states aphase_est_pilot_log arx_np arx_amp] = ofdm_demod(states, rxbuf_in); - frame_count++; - % If looking for sync: check raw BER on frame just received % against all possible positions in the interleaver frame. @@ -147,10 +145,31 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) rx_amp(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_amp(Nsymbolsperframe+1:Nsymbolsperinterleavedframe); rx_amp(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_amp(Nuwtxtsymbolsperframe+1:end); - % just single frame for now, so trival interlave sync - % TODO: work out a way to get interleaver sync - - if (mod(frame_count,interleave_frames) == 0) + % Interleaver Sync: + % Needs to work on any data + % Use indication of LDPC convergence, may need to patch CML code for that + % Attempt a decode on every frame, when it converges we have sync + + next_sync_state_interleaver = states.sync_state_interleaver; + + if strcmp(states.sync_state_interleaver,'searching') + arx_np = gp_deinterleave(rx_np); + arx_amp = gp_deinterleave(rx_amp); + st = 1; en = Ncodedbitsperframe/bps; + [rx_codeword parity_checks] = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, arx_np(st:en), min(EsNo,30), arx_amp(st:en)); + if find(parity_checks == code_param.data_bits_per_frame) + % sucessful decode! + next_sync_state_interleaver = 'synced'; + states.frame_count_interleaver = interleave_frames; + end + end + + states.sync_state_interleaver = next_sync_state_interleaver; + + Nerrs_raw = Nerrs_coded = 0; + if strcmp(states.sync_state_interleaver,'synced') && (states.frame_count_interleaver == interleave_frames) + states.frame_count_interleaver = 0; + printf("decode!\n"); % de-interleave QPSK symbols and symbol amplitudes @@ -167,10 +186,11 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) st = (ff-1)*Ncodedbitsperframe+1; en = st+Ncodedbitsperframe-1; errors = xor(tx_bits_raw(st:en), rx_bits_raw(st:en)); Nerrs = sum(errors); - Terrs += Nerrs; Nerrs_log = [Nerrs_log Nerrs]; - Tbits += Ncodedbitsperframe; + Nerrs_raw += Nerrs; end + Tbits += Ncodedbitsperframe*interleave_frames; + Terrs += Nerrs_raw; % LDPC decode % note: ldpc_errors can be used to measure raw BER @@ -180,12 +200,12 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) for ff=1:interleave_frames st = (ff-1)*Ncodedbitsperframe/bps+1; en = st + Ncodedbitsperframe/bps - 1; [rx_codeword ldpc_errors] = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, arx_np(st:en), min(EsNo,30), arx_amp(st:en)); - rx_bits = [rx_bits rx_codeword(1:code_param.data_bits_per_frame)]; + rx_bits = [rx_bits rx_codeword(1:code_param.data_bits_per_frame)]; end errors_coded = xor(tx_bits, rx_bits); Nerrs_coded = sum(errors_coded); - if Nerrs_coded < 0.2 + if Nerrs_coded/(code_param.data_bits_per_frame*interleave_frames) < 0.2 Terrs_coded += Nerrs_coded; Tbits_coded += code_param.data_bits_per_frame*interleave_frames; error_positions = [error_positions errors_coded]; @@ -211,15 +231,16 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) states = sync_state_machine(states, rx_uw); if states.verbose - printf("f: %2d state: %-10s uw_errors: %2d %1d Nerrs: %3d Nerrs_coded: %3d foff: %3.1f\n", - f, states.last_sync_state, states.uw_errors, states.sync_counter, Nerrs, Nerrs_coded, states.foff_est_hz); + printf("f: %2d st: %-10s uw_errs: %2d inter_st: %-10s inter_fr: %d %1d Nerrs_raw: %3d Nerrs_coded: %3d foff: %4.1f\n", + f, states.last_sync_state, states.uw_errors, states.last_sync_state_interleaver, states.frame_count_interleaver, + states.sync_counter, Nerrs_raw, Nerrs_coded, states.foff_est_hz); end % act on any events returned by modem sync state machine if states.sync_start Nerrs_log = []; - Terrs = Tbits = frame_count = 0; + Terrs = Tbits = 0; Tpacketerrs = Tpackets = 0; Terrs_coded = Tbits_coded = 0; error_positions = Nerrs_coded_log = []; @@ -227,9 +248,9 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) end - printf("Coded BER: %5.4f Tbits: %5d Terrs: %5d PER: %5.4f Tpacketerrs: %5d Tpackets: %5d\n", - Terrs_coded/Tbits_coded, Tbits_coded, Terrs_coded, Tpacketerrs/Tpackets, Tpacketerrs, Tpackets); - printf("Raw BER..: %5.4f Tbits: %5d Terrs: %5d\n", Terrs/Tbits, Tbits, Terrs); + printf("Coded BER: %5.4f Tbits: %5d Terrs: %5d\n", Terrs_coded/(Tbits_coded+1E-12), Tbits_coded, Terrs_coded); + printf("Codec PER: %5.4f Tpkts: %5d Terrs: %5d\n", Tpacketerrs/(Tpackets+1E-12), Tpackets, Tpacketerrs); + printf("Raw BER..: %5.4f Tbits: %5d Terrs: %5d\n", Terrs/(Tbits+1E-12), Tbits, Terrs); figure(1); clf; plot(rx_np_log,'+'); @@ -257,16 +278,20 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename) title('Fine Freq'); ylabel('Hz') - figure(5); clf; - subplot(211) - stem(Nerrs_log); - title('Uncoded errrors/modem frame') - axis([1 length(Nerrs_log) 0 Nbitsperframe*rate/2]); - subplot(212) - stem(Nerrs_coded_log); - title('Coded errrors/vocoder frame') - axis([1 length(Nerrs_coded_log) 0 Nbitspervocframe/2]); - + if length(Nerrs_log) + figure(5); clf; + subplot(211) + stem(Nerrs_log); + title('Uncoded errrors/modem frame') + axis([1 length(Nerrs_log) 0 Nbitsperframe*rate/2]); + if length(Nerrs_coded_log) + subplot(212) + stem(Nerrs_coded_log); + title('Coded errrors/vocoder frame') + axis([1 length(Nerrs_coded_log) 0 Nbitspervocframe/2]); + end + end + if nargin == 3 fep = fopen(error_pattern_filename, "wb"); fwrite(fep, error_positions, "short"); diff --git a/codec2-dev/octave/ofdm_ldpc_tx.m b/codec2-dev/octave/ofdm_ldpc_tx.m index 55e4154a..098518a5 100644 --- a/codec2-dev/octave/ofdm_ldpc_tx.m +++ b/codec2-dev/octave/ofdm_ldpc_tx.m @@ -9,7 +9,7 @@ i) 4 frame interleaver, 10 seconds, AWGN channel at (coded) Eb/No=3dB - octave:4> ofdm_ldpc_tx('awgn_ebno_3dB_700d.raw',4, 10,3); + octave:4> ofdm_ldpc_tx('awgn_ebno_3dB_700d.raw', 4, 10,3); ii) 4 frame interleaver, 10 seconds, HF channel at (coded) Eb/No=6dB @@ -32,7 +32,7 @@ #} -function ofdm_ldpc_tx(filename, Nsec, interleave_frames = 1, EbNodB=100, channel='awgn', freq_offset_Hz=0) +function ofdm_ldpc_tx(filename, interleave_frames = 1, Nsec, EbNodB=100, channel='awgn', freq_offset_Hz=0) ofdm_lib; ldpc; gp_interleaver; @@ -69,9 +69,9 @@ function ofdm_ldpc_tx(filename, Nsec, interleave_frames = 1, EbNodB=100, channel % as per create_ldpc_test_frame rand('seed', 1); - atx_bits = round(rand(1,code_param.data_bits_per_frame)); tx_bits = tx_symbols = []; + atx_bits = round(rand(1,code_param.data_bits_per_frame)); for f=1:interleave_frames tx_bits = [tx_bits atx_bits]; codeword = LdpcEncode(atx_bits, code_param.H_rows, code_param.P_matrix); @@ -79,9 +79,8 @@ function ofdm_ldpc_tx(filename, Nsec, interleave_frames = 1, EbNodB=100, channel tx_symbols = [tx_symbols qpsk_mod(codeword(b:b+1))]; end end - tx_symbols = gp_interleave(tx_symbols); - + % generate UW and txt symbols to prepend to every frame after LDPC encoding and interleaving tx_uw_tx_bits = [zeros(1,Nuwbits) zeros(1,Ntxtbits)]; @@ -140,7 +139,8 @@ function ofdm_ldpc_tx(filename, Nsec, interleave_frames = 1, EbNodB=100, channel woffset = 2*pi*freq_offset_Hz/Fs; SNRdB = EbNodB + 10*log10(Nc*bps*Rs*rate/3000); - printf("EbNo: %3.1f dB SNR(3k) est: %3.1f dB foff: %3.1fHz ", EbNodB, SNRdB, freq_offset_Hz); + printf("EbNo: %3.1f dB SNR(3k) est: %3.1f dB foff: %3.1fHz inter_frms: %d ", + EbNodB, SNRdB, freq_offset_Hz, interleave_frames); % set up HF model --------------------------------------------------------------- diff --git a/codec2-dev/octave/ofdm_lib.m b/codec2-dev/octave/ofdm_lib.m index 05644be3..63ab4b6d 100644 --- a/codec2-dev/octave/ofdm_lib.m +++ b/codec2-dev/octave/ofdm_lib.m @@ -198,10 +198,12 @@ function states = ofdm_init(bps, Rs, Tcp, Ns, Nc) states.sync_state = states.last_sync_state = 'searching'; states.uw_errors = 0; states.sync_counter = 0; - states.sync_frame_count = 0; + states.frame_count = 0; states.sync_start = 0; states.sync_end = 0; - + states.sync_state_interleaver = 'searching'; + states.frame_count_interleaver = 0; + % LDPC code is optionally enabled states.rate = 1.0; @@ -614,6 +616,7 @@ function states = sync_state_machine(states, rx_uw) if strcmp(states.sync_state,'synced') || strcmp(states.sync_state,'trial_sync') states.frame_count++; + states.frame_count_interleaver++; % during trial sync we don't tolerate errors so much, once we have synced up % we are willing to wait out a fade @@ -623,18 +626,21 @@ function states = sync_state_machine(states, rx_uw) end if strcmp(states.sync_state,'synced') sync_counter_thresh = 6; + uw_thresh = 2; else - sync_counter_thresh = 3; + sync_counter_thresh = 2; + uw_thresh = 1; end % freq offset est may be too far out, and has aliases every 1/Ts, so % we use a Unique Word to get a really solid indication of sync. states.uw_errors = sum(rx_uw); - if (states.uw_errors > 2) + if (states.uw_errors > uw_thresh) states.sync_counter++; if states.sync_counter == sync_counter_thresh next_state = 'searching'; + states.sync_state_interleaver = 'searching'; end else states.sync_counter = 0; @@ -642,5 +648,6 @@ function states = sync_state_machine(states, rx_uw) end states.last_sync_state = states.sync_state; + states.last_sync_state_interleaver = states.sync_state_interleaver; states.sync_state = next_state; endfunction diff --git a/codec2-dev/octave/ofdm_tx.m b/codec2-dev/octave/ofdm_tx.m index 9571d788..11fa112e 100644 --- a/codec2-dev/octave/ofdm_tx.m +++ b/codec2-dev/octave/ofdm_tx.m @@ -16,6 +16,8 @@ ofdm_tx('hf_ebno_6dB_700d.raw', 10, 6, 'hf'); #} +% Note EbNodB is for payload data bits, so will be 10log10(rate) higher than +% raw EbNodB used in ofdm_tx() at uncoded bit rate function ofdm_tx(filename, Nsec, EbNodB=100, channel='awgn', freq_offset_Hz=0, dfoff_hz_per_sec = 0) ofdm_lib;