first pass interleaver sync working
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 15 Apr 2018 00:53:53 +0000 (00:53 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 15 Apr 2018 00:53:53 +0000 (00:53 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@3490 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/octave/ldpc.m
codec2-dev/octave/ofdm_ldpc_rx.m
codec2-dev/octave/ofdm_ldpc_tx.m
codec2-dev/octave/ofdm_lib.m
codec2-dev/octave/ofdm_tx.m

index 908f0f17c49ec5935681fcbe1b9c1077d677d291..d337394e4ed89ca36d54a67b9a7d2ccf36ef5c52 100644 (file)
@@ -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
 
 
index 1fa5fcb13a14af1ca1aaeb5566718ecacebe92ec..bbe04efe08591049c1d19af04532a5fc715400b2 100644 (file)
@@ -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");
index 55e4154a1cbd4c0f28d1e24ddc2af83e2d405fbb..098518a5dd269ce09f40dcb7ad0c925749c38391 100644 (file)
@@ -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 ---------------------------------------------------------------
 
index 05644be3bb093842bb6466e3e10e7abc2f5a20df..63ab4b6dfcf9a6f2f1333e8435820cb63f7ba35a 100644 (file)
@@ -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
index 9571d788edc53bafe618f48177a797ab22fdb46d..11fa112ec88faccac7361189937e102197fd8a90 100644 (file)
@@ -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;