ofdm_ldpc_tx & rx working with one interleaver frame, and UW sync, need to add EsNo...
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Thu, 12 Apr 2018 20:59:09 +0000 (20:59 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Thu, 12 Apr 2018 20:59:09 +0000 (20:59 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@3471 01035d8c-6547-0410-b346-abe4f91aad63

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

index aff1898b51b448801016fa67467e29e1d796770c..9af0d138f7fadaa7702f4713417caa313187bbf0 100644 (file)
@@ -73,7 +73,7 @@ function [codeword s] = ldpc_enc(data, code_param)
 endfunction
 
 
-function detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, r, EsNo, fading)
+function [detected_data errors] = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, r, EsNo, fading)
     if nargin == 6
       fading = ones(1, length(r));
     end
@@ -87,8 +87,8 @@ function detected_data = ldpc_dec(code_param, max_iterations, demod_type, decode
         
     input_decoder_c = bit_likelihood(1:code_param.code_bits_per_frame);
         
-    x_hat= MpDecode( -input_decoder_c, code_param.H_rows, code_param.H_cols, ...
-                     max_iterations, decoder_type, 1, 1);
+    [x_hat errors] = MpDecode( -input_decoder_c, code_param.H_rows, code_param.H_cols, ...
+                              max_iterations, decoder_type, 1, 1);
     detected_data = x_hat(max_iterations,:);
 endfunction
 
index 4f0614ebfee33b4547b1a7aec217c288e0cfa0a8..01c2684d0ff66c90b1a96ed94350f449f9596f7d 100644 (file)
@@ -19,7 +19,7 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename)
 
   % init modem
 
-  Ts = 0.018; Tcp = 0.002; Rs = 1/Ts; bps = 2; Nc = 16; Ns = 8;
+  Ts = 0.018; Tcp = 0.002; Rs = 1/Ts; bps = 2; Nc = 17; Ns = 8;
   states = ofdm_init(bps, Rs, Tcp, Ns, Nc);
   ofdm_load_const;
   states.verbose = 1;
@@ -29,12 +29,13 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename)
   mod_order = 4; bps = 2; modulation = 'QPSK'; mapping = 'gray';
   demod_type = 0; decoder_type = 0; max_iterations = 100;
 
-  EsNo = 10; % TODO: fixme
-
+  EsNo = 1; % TODO: fixme
+  printf("EsNo fixed at %f - need to est from channel\n", EsNo);
+  
   init_cml('/home/david/Desktop/cml/');
   load HRA_112_112.txt
   [code_param framesize rate] = ldpc_init_user(HRA_112_112, modulation, mod_order, mapping);
-  assert(Nbitsperframe == code_param.code_bits_per_frame);
+  assert(Nbitsperframe == (code_param.code_bits_per_frame + states.Nuwbits + states.Ntxtbits));
 
   % load real samples from file
 
@@ -45,11 +46,14 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename)
 
   % buffers for interleaved frames
 
-  Nsymbolsperframe = code_param.code_bits_per_frame/bps
-  Nsymbolsperinterleavedframe = interleave_frames*Nsymbolsperframe
+  Ncodedbitsperframe = code_param.code_bits_per_frame;
+  Nsymbolsperframe = code_param.code_bits_per_frame/bps;
+  Nuwtxtsymbolsperframe = (Nuwbits+Ntxtbits)/bps;
+  Nsymbolsperinterleavedframe = interleave_frames*Nsymbolsperframe;
   rx_np = zeros(1, Nsymbolsperinterleavedframe);
   rx_amp = zeros(1, Nsymbolsperinterleavedframe);
-
+  rx_uw = [];
+  
   % OK generate tx frame for BER calcs
 
   rand('seed', 100);
@@ -84,7 +88,8 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename)
   Nbitspervocframe = 28;
   Nerrs_coded_log = Nerrs_log = [];
   error_positions = [];
-
+  Nerrs = Nerrs_coded = 0;
+  
   % 'prime' rx buf to get correct coarse timing (for now)
 
   prx = 1;
@@ -113,138 +118,113 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename)
     [rx_bits_raw states aphase_est_pilot_log arx_np arx_amp] = ofdm_demod(states, rxbuf_in);
     frame_count++;
 
-    % update sliding windows of rx-ed symbols and symbol amplitudes
-
-    rx_np(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_np(Nsymbolsperframe+1:Nsymbolsperinterleavedframe);
-    rx_np(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_np;
-    rx_amp(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_amp(Nsymbolsperframe+1:Nsymbolsperinterleavedframe);
-    rx_amp(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_amp;
-
-    printf("f: %d state: %s frame_count: %d\n", f, state, frame_count);
-
     % If looking for sync: check raw BER on frame just received
     % against all possible positions in the interleaver frame.
 
-    % iterate state machine ------------------------------------
-
-    next_state = state;
-    if strcmp(state,'searching')  
-
-      % If looking for sync: check raw BER on frame just received
-      % against all possible positions in the interleaver frame.
-
-      for ff=1:interleave_frames
-        st = (ff-1)*Nbitsperframe+1; en = st + Nbitsperframe - 1;
-        errors = xor(tx_bits_raw(st:en), rx_bits_raw);
-        Nerrs = sum(errors); 
-        printf("  ff: %d Nerrs: %d\n", ff, Nerrs);
-        if Nerrs/Nbitsperframe < 0.1
-          next_state = 'synced';
-          % make sure we get an interleave frame with correct freq offset
-          % note this introduces a lot of delay, a better idea would be to
-          % run demod again from interleave_frames back with now-known freq offset
-          frame_count = ff - interleave_frames;
-        end
-      end
-    end
+    % state machine(s) for modem and interleaver sync ------------------------------------
 
-    if strcmp(state,'synced')  
-      if Nerrs/Nbitsperframe > 0.2
-        %next_state = 'searching';
-      end
-    end
-
-    state = next_state;
-
-    if strcmp(state,'searching') 
-
-      % still searching? Attempt coarse timing estimate (i.e. detect start of frame)
-
-      st = M+Ncp + Nsamperframe + 1; en = st + 2*Nsamperframe; 
-      [ct_est foff_est] = coarse_sync(states, states.rxbuf(st:en), states.rate_fs_pilot_samples);
-      if states.verbose
-        printf("  Nerrs: %d ct_est: %4d foff_est: %3.1f\n", Nerrs, ct_est, foff_est);
-      end
-
-      % calculate number of samples we need on next buffer to get into sync
-     
-      states.nin = Nsamperframe + ct_est - 1;
-
-      % reset modem states
-
-      states.sample_point = states.timing_est = 1;
-      states.foff_est_hz = foff_est;
+    if strcmp(states.sync_state,'searching') 
+      [timing_valid states] = ofdm_sync_search(states, rxbuf_in);
     end
     
-    if strcmp(state,'synced')
-
-      % we are in sync so log states
+    if strcmp(states.sync_state,'synced') || strcmp(states.sync_state,'trial_sync')
+      [rx_bits states aphase_est_pilot_log arx_np arx_amp] = ofdm_demod(states, rxbuf_in);
+      rx_uw = rx_bits(1:states.Nuwbits);
+      
+      % we are in sync so log modem states
 
       rx_np_log = [rx_np_log arx_np];
       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];
       phase_est_pilot_log = [phase_est_pilot_log; aphase_est_pilot_log];
-    end
 
-    if strcmp(state,'synced') && (frame_count == interleave_frames)
+      % update sliding windows of rx-ed symbols and symbol amplitudes,
+      % discarding UW and txt symbols at start of each modem frame
 
-      % de-interleave QPSK symbols
+      rx_np(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_np(Nsymbolsperframe+1:Nsymbolsperinterleavedframe);
+      rx_np(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_np(Nuwtxtsymbolsperframe+1:end);
+      rx_amp(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_amp(Nsymbolsperframe+1:Nsymbolsperinterleavedframe);
+      rx_amp(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_amp(Nuwtxtsymbolsperframe+1:end);
 
-      arx_np = gp_deinterleave(rx_np);
-      arx_amp = gp_deinterleave(rx_amp);
+      % 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)
+        
+        % de-interleave QPSK symbols and symbol amplitudes
 
-      % measure uncoded bit errors per modem frame
+        arx_np = gp_deinterleave(rx_np);
+        arx_amp = gp_deinterleave(rx_amp);
 
-      rx_bits_raw = [];
-      for s=1:Nsymbolsperinterleavedframe
-        rx_bits_raw = [rx_bits_raw qpsk_demod(rx_np(s))];
-      end
-      for ff=1:interleave_frames
-        st = (ff-1)*Nbitsperframe+1; en = st+Nbitsperframe-1;
-        errors = xor(tx_bits_raw(st:en), rx_bits_raw(st:en));
-        Nerrs = sum(errors);
-        if Nerrs/Nbitsperframe < 0.2
+        % measure uncoded bit errors over interleaver frame
+
+        rx_bits_raw = [];
+        for s=1:Nsymbolsperinterleavedframe
+          rx_bits_raw = [rx_bits_raw qpsk_demod(rx_np(s))];
+        end
+        for ff=1:interleave_frames
+          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 += Nbitsperframe;
+          Tbits += Ncodedbitsperframe;
+        end
+        
+        % LDPC decode
+        %  note: ldpc_errors can be used to measure raw BER
+        %        std CML library doesn't have an indication of convergence
+
+        rx_bits = [];
+        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)];          
         end
-      end
-
-      % LDPC decode
-
-      rx_bits = [];
-      for ff=1:interleave_frames
-        st = (ff-1)*Nbitsperframe/bps+1; en = st + Nbitsperframe/bps - 1;
-        rx_codeword = 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)];
-      end
 
-      errors_coded = xor(tx_bits, rx_bits);
-      Nerrs_coded = sum(errors_coded);
-      if Nerrs/Nbitsperframe < 0.2
-        Terrs_coded += Nerrs_coded;
-        Tbits_coded += code_param.data_bits_per_frame*interleave_frames;
-        error_positions = [error_positions errors_coded];
-
-        % measure packet errors based on Codec 2 packet size
-
-        Nvocframes = floor(code_param.data_bits_per_frame*interleave_frames/Nbitspervocframe);
-        for fv=1:Nvocframes
-          st = (fv-1)*Nbitspervocframe + 1;
-          en = st + Nbitspervocframe - 1;
-          Nvocpacketerrs = sum(xor(tx_bits(st:en), rx_bits(st:en)));
-          if Nvocpacketerrs
-            Tpacketerrs++;
+        errors_coded = xor(tx_bits, rx_bits);
+        Nerrs_coded = sum(errors_coded);
+        if Nerrs_coded < 0.2
+          Terrs_coded += Nerrs_coded;
+          Tbits_coded += code_param.data_bits_per_frame*interleave_frames;
+          error_positions = [error_positions errors_coded];
+        
+          % measure packet errors based on Codec 2 packet size
+
+          Nvocframes = floor(code_param.data_bits_per_frame*interleave_frames/Nbitspervocframe);
+          for fv=1:Nvocframes
+            st = (fv-1)*Nbitspervocframe + 1;
+            en = st + Nbitspervocframe - 1;
+            Nvocpacketerrs = sum(xor(tx_bits(st:en), rx_bits(st:en)));
+            if Nvocpacketerrs
+              Tpacketerrs++;
+            end
+            Tpackets++;
+            Nerrs_coded_log = [Nerrs_coded_log Nvocpacketerrs];
           end
-          Tpackets++;
-          Nerrs_coded_log = [Nerrs_coded_log Nvocpacketerrs];
         end
       end
-      printf("  Nerrs_coded: %d\n", Nerrs_coded);
+    end
+    
+    states = sync_state_machine(states, rx_uw);
 
-      frame_count = 0;
+    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);
     end
+
+    % act on any events returned by modem sync state machine
+    
+    if states.sync_start
+      Nerrs_log = [];
+      Terrs = Tbits = frame_count = 0;
+      Tpacketerrs = Tpackets = 0;
+      Terrs_coded = Tbits_coded = 0;
+      error_positions = Nerrs_coded_log = [];
+    end
+
   end
 
   printf("Coded BER: %5.4f Tbits: %5d Terrs: %5d PER: %5.4f Tpacketerrs: %5d Tpackets: %5d\n", 
@@ -253,12 +233,12 @@ function ofdm_ldpc_rx(filename, interleave_frames = 1, error_pattern_filename)
 
   figure(1); clf; 
   plot(rx_np_log,'+');
-  mx = max(abs(rx_np_log))
+  mx = max(abs(rx_np_log));
   axis([-mx mx -mx mx]);
   title('Scatter');
 
   figure(2); clf;
-  plot(phase_est_pilot_log(:,2:Nc+1),'g+', 'markersize', 5); 
+  plot(phase_est_pilot_log,'g+', 'markersize', 5); 
   title('Phase est');
   axis([1 length(phase_est_pilot_log) -pi pi]);  
 
index 187b21cdb99eab1572e534b634a0de3e24c84fda..bcebb39f3d36c1b51b832d8cdca5a750ff5a4853 100644 (file)
@@ -7,11 +7,11 @@
 #{
   Examples:
  
-  i) 4 frame interleaver, 10 seconds, AWGN channel at Eb/No=3dB
+  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);
 
-  ii) 4 frame interleaver, 10 seconds, HF channel at Eb/No=6dB
+  ii) 4 frame interleaver, 10 seconds, HF channel at (coded) Eb/No=6dB
 
     ofdm_ldpc_tx('hf_ebno_6dB_700d.raw', 4, 10, 6, 'hf');
 #}
@@ -70,17 +70,25 @@ function ofdm_ldpc_tx(filename, Nsec, interleave_frames = 1, EbNodB=100, channel
     atx_bits = round(rand(1,code_param.data_bits_per_frame));
     tx_bits = [tx_bits atx_bits];
     codeword = LdpcEncode(atx_bits, code_param.H_rows, code_param.P_matrix);
-    for b=1:2:Nbitsperframe
+    for b=1:2:code_param.code_bits_per_frame
       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)];
+  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))];
+  end
   
   atx = [];
   for f=1:interleave_frames
-    st = (f-1)*Nbitsperframe/bps+1; en = st + Nbitsperframe/bps-1;
-    atx = [atx ofdm_txframe(states, tx_symbols(st:en))];
+    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)] ) ];
   end
  
   tx = [];
@@ -126,7 +134,7 @@ function ofdm_ldpc_tx(filename, Nsec, interleave_frames = 1, EbNodB=100, channel
   variance = 1/(M*EsNo/2);
   woffset = 2*pi*freq_offset_Hz/Fs;
 
-  SNRdB = EbNodB + 10*log10(700/3000);
+  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);
 
   % set up HF model ---------------------------------------------------------------
@@ -174,7 +182,7 @@ function ofdm_ldpc_tx(filename, Nsec, interleave_frames = 1, EbNodB=100, channel
 
   noise = sqrt(variance/2)*0.5*randn(1,Nsam);
   rx = real(rx) + noise;
-  printf("measured SNR: %3.2f dB\n", 10*log10(var(real(tx))/var(noise))+10*log10(4000) - 10*log10(3000));
+  printf("measured SNR: %3.2f dB\n", 10*log10(var(real(tx))/var(noise)) + 10*log10(4000) - 10*log10(3000));
 
   if rx_filter
     % ssb rx filter