File: ofdm_ldpc_rx.m

package info (click to toggle)
codec2 0.9.2-4
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 113,072 kB
  • sloc: ansic: 412,877; python: 4,004; sh: 1,540; objc: 817; asm: 683; makefile: 588
file content (324 lines) | stat: -rw-r--r-- 11,497 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
% ofdm_ldpc_rx.m
% David Rowe April 2017
%
% OFDM file based rx, with LDPC and interleaver, Octave version of src/ofdm_demod.c

function time_to_sync = ofdm_ldpc_rx(filename, mode="700D", interleave_frames = 1, error_pattern_filename, start_secs, len_secs=0)
  ofdm_lib;
  ldpc;
  gp_interleaver;
  more off;

  % init modem

  [bps Rs Tcp Ns Nc] = ofdm_init_mode(mode);
  states = ofdm_init(bps, Rs, Tcp, Ns, Nc);
  ofdm_load_const;
  states.verbose = 1;
  
  mod_order = 4; bps = 2; modulation = 'QPSK'; mapping = 'gray';
  demod_type = 0; decoder_type = 0; max_iterations = 100;

  EsNo = 3; % TODO: fixme
  printf("EsNo fixed at %f - need to est from channel\n", EsNo);
  
  % some constants used for assembling modem frames
  
  [code_param Nbitspercodecframe Ncodecframespermodemframe] = codec_to_frame_packing(states, mode);

  % load real samples from file

  Ascale= states.amp_scale/2.0;  % /2 as real signal has half amplitude
  frx=fopen(filename,"rb"); rx = fread(frx, Inf, "short")/Ascale; fclose(frx);
  if (nargin >= 5) printf("start_secs: %d\n", start_secs); rx = rx(start_secs*Fs+1:end); end
  if (nargin >= 6) printf("len_secs: %d\n", len_secs); rx = rx(1:len_secs*Fs); end
  Nsam = length(rx); Nframes = floor(Nsam/Nsamperframe);
  prx = 1;

  % 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 frame of bits that spans the entire interleaver
  %   frame.  Doesn't affect operation with the speech codec.
  
  codec_bits = round(ofdm_rand(code_param.data_bits_per_frame)/32767);
  [frame_bits bits_per_frame] = assemble_frame(states, code_param, mode, codec_bits, Ncodecframespermodemframe, Nbitspercodecframe);

  % Some handy constants, "frame" refers to modem frame less UW and
  % txt bits.
  
  Ncodedbitsperframe = code_param.coded_bits_per_frame;
  Nsymbolsperframe = code_param.coded_syms_per_frame;
  Nuwtxtsymbolsperframe = (Nuwbits+Ntxtbits)/bps;
  Nsymbolsperinterleavedframe = interleave_frames*Nsymbolsperframe;

  % buffers for interleaved frames

  rx_np = zeros(1, Nsymbolsperinterleavedframe);
  rx_amp = zeros(1, Nsymbolsperinterleavedframe);
  rx_uw = [];
  
  tx_bits = []; tx_frames = [];
  for f=1:interleave_frames
    tx_bits = [tx_bits codec_bits];
    tx_frames = [tx_frames frame_bits];
  end

  % used for rx frame sync on interleaved symbols - we demod the
  % entire interleaved frame to raw bits

  tx_symbols = [];
  for s=1:Nsymbolsperinterleavedframe
    tx_symbols = [tx_symbols qpsk_mod( tx_frames(2*(s-1)+1:2*s) )];
  end

  tx_symbols = gp_interleave(tx_symbols);

  tx_bits_raw = [];
  for s=1:Nsymbolsperinterleavedframe
    tx_bits_raw = [tx_bits_raw qpsk_demod(tx_symbols(s))];
  end

  % init logs and BER stats

  rx_bits = []; rx_np_log = []; timing_est_log = []; delta_t_log = []; foff_est_hz_log = [];
  phase_est_pilot_log = [];
  sig_var_log = []; noise_var_log = [];
  Terrs = Tbits = Terrs_coded = Tbits_coded = 0;
  Nerrs_coded_log = Nerrs_log = [];
  error_positions = [];
  Nerrs_coded = Nerrs_raw = zeros(1, interleave_frames);
  paritychecks = [0];
  time_to_sync = -1;
  
  #{
  % '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

    % insert samples at end of buffer, set to zero if no samples
    % available to disable phase estimation on future pilots on last
    % frame of simulation

    lnew = min(Nsam-prx,states.nin);
    rxbuf_in = zeros(1,states.nin);

    if lnew
      rxbuf_in(1:lnew) = rx(prx:prx+lnew-1);
    end
    prx += states.nin;

    % If looking for sync: check raw BER on frame just received
    % against all possible positions in the interleaver frame.

    % state machine(s) for modem and interleaver sync ------------------------------------

    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 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];
      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];
      sig_var_log = [sig_var_log states.sig_var];
      noise_var_log = [noise_var_log states.noise_var];
      
      % update sliding windows of rx-ed symbols and symbol amplitudes,
      % 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) = payload_syms;
      rx_amp(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_amp(Nsymbolsperframe+1:Nsymbolsperinterleavedframe);
      rx_amp(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = payload_amps;
           
      mean_amp = states.mean_amp;
      
      % de-interleave QPSK symbols and symbol amplitudes

      rx_np_de = gp_deinterleave(rx_np);
      rx_amp_de = gp_deinterleave(rx_amp);
      
      % 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,'search')
        Nerrs = 0;
        if strcmp(mode, "700D")
          % using LDPC decoder to obtain interleaver sync only supported for 700D so far
          st = 1; en = Ncodedbitsperframe/bps;
          [rx_codeword paritychecks] = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, rx_np_de(st:en)/mean_amp, min(EsNo,30), rx_amp_de(st:en)/mean_amp);
          Nerrs = code_param.data_bits_per_frame - max(paritychecks);
          %printf("Nerrs: %d\n", Nerrs);
        end
        
        % note we just go straight into sync if interleave_frames == 1
        
        if (Nerrs < 10) || (interleave_frames == 1)
          % sucessful(ish) decode!
          next_sync_state_interleaver = 'synced';
          states.frame_count_interleaver = interleave_frames;
        end
      end

      states.sync_state_interleaver = next_sync_state_interleaver;
            
      if strcmp(states.sync_state_interleaver,'synced') && (states.frame_count_interleaver == interleave_frames)
        states.frame_count_interleaver = 0;
        Nerrs_raw = Nerrs_coded = zeros(1, interleave_frames);

        %printf("decode!\n");
        
        % measure uncoded bit errors over interleaver frame

        rx_bits_raw = [];
        for s=1:Nsymbolsperinterleavedframe
          rx_bits_raw = [rx_bits_raw qpsk_demod(rx_np_de(s))];
        end
        for ff=1:interleave_frames
          st = (ff-1)*Ncodedbitsperframe+1; en = st+Ncodedbitsperframe-1;
          errors = xor(frame_bits, rx_bits_raw(st:en));
          Nerrs = sum(errors);
          Nerrs_log = [Nerrs_log Nerrs];
          Nerrs_raw(ff) += Nerrs;
          Tbits += Ncodedbitsperframe;
          Terrs += Nerrs;
        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

          if strcmp(mode, "700D")
            st = (ff-1)*Nsymbolsperframe+1; en = st + Nsymbolsperframe-1;
            [rx_codeword paritychecks] = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, rx_np_de(st:en)/mean_amp, min(EsNo,30), rx_amp_de(st:en)/mean_amp);
            arx_bits = rx_codeword(1:code_param.data_bits_per_frame);
            errors = xor(codec_bits, arx_bits);
            Nerrs  = sum(errors);
            Tbits_coded += code_param.data_bits_per_frame;
            rx_bits = [rx_bits arx_bits];
          end
          
          Nerrs_coded(ff) = Nerrs;
          Terrs_coded += Nerrs;
          Nerrs_coded_log = [Nerrs_coded_log Nerrs];
        end
      end
    end
    
    states = sync_state_machine(states, rx_uw);

    if states.verbose
      r = mod(states.frame_count_interleaver,  interleave_frames)+1;
      pcc = max(paritychecks);
      iter = 0;
      for i=1:length(paritychecks)
        if paritychecks(i) iter=i; end
      end
      printf("f: %3d st: %-6s euw: %2d %1d ist: %-6s eraw: %3d ecdd: %3d iter: %3d pcc: %3d foff: %4.1f nin: %d\n",
             f, states.last_sync_state, states.uw_errors, states.sync_counter, states.last_sync_state_interleaver,
             Nerrs_raw(r), Nerrs_coded(r), iter, pcc, states.foff_est_hz, states.nin);
      % detect a sucessful sync
      if (time_to_sync < 0) && (strcmp(states.sync_state,'synced') || strcmp(states.sync_state,'trial'))
        if (pcc > 80) && (iter != 100)
          time_to_sync = f*Nsamperframe/Fs;
        end
      end
    end

    % act on any events returned by modem sync state machine
    
    if states.sync_start
      Nerrs_raw = Nerrs_coded = zeros(1, interleave_frames);
      Nerrs_log = [];
      Terrs = Tbits = 0;
      Tpacketerrs = Tpackets = 0;
      Terrs_coded = Tbits_coded = 0;
      error_positions = Nerrs_coded_log = [];
    end
  end
  
  printf("Raw BER..: %5.4f Tbits: %5d Terrs: %5d\n", Terrs/(Tbits+1E-12), Tbits, Terrs);
  printf("Coded BER: %5.4f Tbits: %5d Terrs: %5d\n", Terrs_coded/(Tbits_coded+1E-12), Tbits_coded, Terrs_coded);

  if length(rx_np_log)
      figure(1); clf; 
      plot(rx_np_log,'+');
      mx = max(abs(rx_np_log));
      axis([-mx mx -mx mx]);
      title('Scatter');

      figure(2); clf;
      plot(phase_est_pilot_log,'g+', 'markersize', 5); 
      title('Phase est');
      axis([1 length(phase_est_pilot_log) -pi pi]);

      figure(3); clf;
      subplot(211)
      stem(delta_t_log)
      title('delta t');
      subplot(212)
      plot(timing_est_log);
      title('timing est');

      figure(4); clf;
      plot(foff_est_hz_log)
      mx = max(abs(foff_est_hz_log));
      axis([1 max(Nframes,2) -mx mx]);
      title('Fine Freq');
      ylabel('Hz')
  end
   
  if length(Nerrs_log) > 1
    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 errors/mode frame')
      axis([1 length(Nerrs_coded_log) 0 Nbitsperframe/2]);
    end
  end
  
  figure(6); clf;
  snr_estdB = 10*log10(sig_var_log) - 10*log10(noise_var_log) + 10*log10(Nc*Rs/3000);
  snr_smoothed_estdB = filter(0.1,[1 -0.9],snr_estdB);
  plot(snr_smoothed_estdB);
  title('Signal and Noise Power estimates');
  ylabel('SNR (dB)')

  figure(7); clf; plot_specgram(rx);
  if len_secs
    axis([0 len_secs 500 2500])
  end
  
  if (nargin == 4) && strlen(error_pattern_filename)
    fep = fopen(error_pattern_filename, "wb");
    fwrite(fep, error_positions, "uchar");
    fclose(fep);
  end
endfunction