building up PER/BER tests
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 2 Oct 2016 18:10:39 +0000 (18:10 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 2 Oct 2016 18:10:39 +0000 (18:10 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@2882 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/octave/test_ldpc_fsk_lib.m

index 43a1348c29653d9b8a8ee4694ce1a87d467a9a33..19e27ddd7a216c25b586c6006de969b9723a1b9b 100644 (file)
@@ -196,7 +196,7 @@ function test_c_decoder
 \r
   f = fopen("data_out.bin","rb"); data_out = fread(f, "uint8")'; fclose(f);\r
   \r
-  Nerrs = Nerrs2 = zeros(1,frames);;\r
+  Nerrs = Nerrs2 = zeros(1,frames);\r
   for i=1:frames\r
 \r
     % Check C decoder\r
@@ -231,7 +231,20 @@ function test_c_decoder
 \r
 end\r
 \r
-\r
+% Saves a complex vector s to a file "filename" of IQ unsigned 8 bit\r
+% chars, same as RTLSDR format.\r
+\r
+function save_rtlsdr(filename, s)\r
+  mx = max(abs(s));\r
+  re = real(s); im = imag(s);\r
+  l = length(s);\r
+  iq = zeros(1,2*l);\r
+  iq(1:2:2*l) = 127 + re*(127/mx); \r
+  iq(2:2:2*l) = 127 + im*(127/mx); \r
+  fs = fopen(filename,"wb");\r
+  fwrite(fs,iq,"uchar");\r
+  fclose(fs);\r
+endfunction\r
 \r
 % Start simulation --------------------------------------------------------\r
 \r
@@ -264,9 +277,9 @@ ldpc_fsk_lib;
 randn('state',1);\r
 rand('state',1);\r
 \r
-% binary flags to run various demos, e.g. "15" to run 1 .. 8\r
+% ------------------ select which demo/test to run here ---------------\r
 \r
-demo = 8;\r
+demo = 10;\r
 \r
 if demo == 1\r
   printf("simple_ut....\n");\r
@@ -341,3 +354,293 @@ if demo == 8
   r = s + noise;\r
   f = fopen("sstv_sd.bin","wb"); fwrite(f, r, "float32"); fclose(f);\r
 end\r
+\r
+if demo == 9\r
+  frames = 100;\r
+  EbNodB = 11;\r
+\r
+  frame_rs232 = [];\r
+  for i=1:frames\r
+    frame_rs232 = [frame_rs232 gen_sstv_frame];\r
+  end\r
+\r
+  % Use C FSK modulator to generate modulated signal\r
+\r
+  f = fopen("sstv.bin","wb"); fwrite(f, frame_rs232, "char"); fclose(f);\r
+  system("../build_linux/src/fsk_mod 2 9600 1200 1200 2400 sstv.bin fsk_mod.raw");\r
+\r
+  % Add some channel noise here in Octave\r
+\r
+  f = fopen("fsk_mod.raw","rb"); tx = fread(f, "short")'; fclose(f); tx_pwr = var(tx);\r
+  Fs = 9600; Rs=1200; EbNolin = 10 ^ (EbNodB/10);\r
+  variance = (tx_pwr/2)*states.Fs/(states.Rs*EbNolin*states.bitspersymbol);\r
+  noise = sqrt(variance)*randn(1,length(tx)); \r
+  printf("SNRdB meas: %4.1f\n", 10*log10(var(tx)/var(noise)));\r
+  rx = tx + noise;\r
+  f = fopen("fsk_demod.raw","wb"); tx = fwrite(f, rx, "short"); fclose(f);\r
\r
+  % Demodulate using C modem and C de-framer/LDPC decoder\r
+\r
+  system("../build_linux/src/fsk_demod 2XS 8 9600 1200 fsk_demod.raw - | ../src/drs232_ldpc - dummy_out.bin");\r
+end\r
+\r
+\r
+% Using simulated SSTV packet, generate complex fsk mod signals, 8-bit\r
+% unsigned IQ for feeding into demod chain\r
+% todo: [ ] uncoded BER\r
+%       [ ] octave fsk demod\r
+%       [ ] compared unsigned 8 bit IQ to regular 16-bit\r
+%       [ ] run python dashboard\r
+%       [ ] compare measured Eb/No\r
+%       [ ] drs232_ldpc has built in test frame\r
+%           [ ] use test frame that comes with code?\r
+%           [ ] Octave code to generate\r
+%           [ ] print test results\r
+%       [ ] test with resampler\r
+\r
+if demo == 10\r
+% init LDPC code\r
+\r
+load('H2064_516_sparse.mat');\r
+HRA = full(HRA);  \r
+max_iterations = 100;\r
+decoder_type = 0;\r
+mod_order = 2;\r
+\r
+code_param = ldpc_init(HRA, mod_order);\r
+tx_codeword = gen_sstv_frame;\r
+\r
+% init FSK modem\r
+\r
+fsk_horus_as_a_lib = 1;\r
+fsk_horus;\r
+states         = fsk_horus_init_hbr(9600, 8, 1200, 2, length(tx_codeword));\r
+states.ftx     = [1200 2400];\r
+states.df(1:states.M) = 0;\r
+states.dA(1:states.M) = 1;\r
+\r
+% set up AWGN channel \r
+\r
+frames = 10;\r
+EbNodB = 9;\r
+EbNo = 10^(EbNodB/10);\r
+variance = states.Fs/(states.Rs*EbNo*states.bitspersymbol);\r
+\r
+% start simulation ----------------------------------------\r
+\r
+%tx_data = round(rand(1, code_param.data_bits_per_frame));\r
+%tx_codeword = ldpc_encode(code_param, tx_data);\r
+tx_bit_stream = [];\r
+for i=1:frames+1\r
+  tx_bit_stream = [tx_bit_stream tx_codeword];\r
+end\r
+\r
+% modulate and channel model\r
+\r
+tx = fsk_horus_mod(states, tx_bit_stream);\r
+noise = sqrt(variance)*randn(length(tx),1);\r
+rx = tx + noise;\r
+printf("SNRdB meas: %4.1f\n", 10*log10(var(tx)/var(noise)));\r
+\r
+% demodulate frame by frame\r
+\r
+st = 1;\r
+run_frames = floor(length(rx)/states.N);\r
+rx_bit_stream = [];\r
+rx_sd_stream = [];\r
+for f=1:run_frames\r
+\r
+  % extract nin samples from rx sample stream\r
+\r
+  nin = states.nin;\r
+  en = st + states.nin - 1;\r
+\r
+  if en <= length(rx) % due to nin variations its possible to overrun buffer\r
+    sf = rx(st:en);\r
+    st += nin;\r
+\r
+    % demodulate to stream of bits\r
+\r
+    states.f = [1200 2400];\r
+    [rx_bits states] = fsk_horus_demod(states, sf);\r
+    rx_bit_stream = [rx_bit_stream rx_bits];\r
+    rx_sd_stream = [rx_sd_stream states.rx_bits_sd];\r
+  end\r
+end\r
+\r
+#{\r
+% measure BER, there is an annoying one bit delay in rx\r
+% which means we waste a frame\r
+\r
+n_coded_bits = n_uncoded_bits = n_coded_errs = n_uncoded_errs = 0;\r
+for f=1:run_frames\r
+  st = (f-1)*states.nbit + 2; en = st+states.nbit-1;\r
+  if en < length(rx_bit_stream)\r
+    rx_codeword =  rx_bit_stream(st:en);\r
+    n_uncoded_errs += sum(xor(tx_codeword, rx_codeword));\r
+    n_uncoded_bits += code_param.symbols_per_frame;\r
+\r
+    #{\r
+    r = rx_sd_stream(st:en);\r
+    [detected_data Niters] = ldpc_decode(r, code_param, max_iterations, decoder_type);\r
+    coded_errors = sum(xor(detected_data(1:code_param.data_bits_per_frame), tx_data));\r
+    n_coded_errs += coded_errors;\r
+    n_coded_bits += code_param.data_bits_per_frame;\r
+    printf("f: %d Niters: %d coded_errors: %d\n", f, Niters, coded_errors);\r
+    #}\r
+  end\r
+end\r
+\r
+uncoded_ber = n_uncoded_errs/n_uncoded_bits;\r
+printf("n_uncoded_bits: %d n_uncoded_errs: %d BER: %4.3f\n", n_uncoded_bits, n_uncoded_errs, uncoded_ber);\r
+%coded_ber = n_coded_errs/n_coded_bits;\r
+%printf("n_coded_bits..: %d n_coded_errs..: %d BER: %4.3f\n", n_coded_bits, n_coded_errs, coded_ber);\r
+#}\r
+\r
+  % state machine. look for UW.  When found count bit errors over one frame of bits\r
+\r
+  state = "wait for uw";\r
+  start_uw_ind = 16*10+1; end_uw_ind = start_uw_ind + 2*10 - 1;\r
+  uw_rs232 = tx_codeword(start_uw_ind:end_uw_ind); luw = length(uw_rs232);\r
+  start_frame_ind =  end_uw_ind + 1;\r
+  nbits = length(rx_bit_stream);\r
+  uw_thresh = 0;\r
+  n_uncoded_errs = 0;\r
+  n_uncoded_bits = 0;\r
+\r
+  % might as well count uncoded errors use RS232 framing bits\r
+\r
+  nbits_frame = code_param.data_bits_per_frame*10/8;  \r
+\r
+  for i=luw:nbits\r
+    next_state = state;\r
+    if strcmp(state, 'wait for uw')\r
+      uw_errs = xor(rx_bit_stream(i-luw+1:i), uw_rs232);\r
+      if uw_errs <= uw_thresh\r
+        next_state = 'count errors';\r
+        tx_frame_ind = start_frame_ind;\r
+        %printf("%d %s %s\n", i, state, next_state);\r
+      end\r
+    end\r
+    if strcmp(state, 'count errors')\r
+      n_uncoded_errs += xor(rx_bit_stream(i), tx_codeword(tx_frame_ind));\r
+      n_uncoded_bits++;\r
+      tx_frame_ind++;\r
+      if tx_frame_ind == (start_frame_ind+nbits_frame)\r
+        next_state = 'wait for uw';\r
+      end\r
+    end\r
+    state = next_state;\r
+  end\r
+\r
+uncoded_ber = n_uncoded_errs/n_uncoded_bits;\r
+printf("n_uncoded_bits: %d n_uncoded_errs: %d BER: %4.3f\n", n_uncoded_bits, n_uncoded_errs, uncoded_ber);\r
+  \r
+#{\r
+  frames = 2;\r
+  EbNodB = 100;\r
+\r
+  % init LPDC code - we need code_param.symbols_per_frame to init fsk modem,\r
+  % which is actually unused as we aren't running the fsk modem lol\r
+\r
+  load('H2064_516_sparse.mat');\r
+  HRA = full(HRA);  \r
+  max_iterations = 100; decoder_type = 0; mod_order = 2;\r
+  code_param = ldpc_init(HRA, mod_order);\r
+\r
+  % init 8x oversampled FSK modulator\r
+\r
+  fsk_horus_as_a_lib = 1;\r
+  fsk_horus;\r
+  states = fsk_horus_init_hbr(9600, 8, 1200, 2, code_param.symbols_per_frame);\r
+  states.ftx = [1200 2400];\r
+  states.tx_real = 0;\r
+\r
+  % Generate some SSTV frames, note it's the same frame repeated which\r
+  % isn't ideal for testing the LDPC code but good for uncoded BER\r
+  % testing.  For testing PER best to send frames of random payload data\r
+  % and measure PER based on checksum/LDPC decoder convergence.\r
+\r
+  printf("generating LPDC encoded frames...\n");\r
+  aframe_rs232 = gen_sstv_frame;\r
+  frames_rs232 = [];\r
+  for i=1:frames\r
+    frames_rs232 = [frames_rs232 aframe_rs232];\r
+  end\r
+  nbits = length(frame_rs232); bit_rate = 115200; Nsecs = nbits/bit_rate;\r
+  printf("%d frames, %d bits, %3.1f seconds at %d bit/s\n", frames, nbits, Nsecs, bit_rate);\r
+\r
+  % FSK modulate and add noise\r
+\r
+  printf("fsk mod and AWGN noise...\n");\r
+  tx = fsk_horus_mod(states, frame_rs232);\r
+\r
+  EbNolin = 10 ^ (EbNodB/10);\r
+  tx_pwr = var(tx);\r
+  variance = (tx_pwr)*states.Fs/(states.Rs*EbNolin*states.bitspersymbol);\r
+  noise = sqrt(variance/2)*(randn(length(tx),1) + j*randn(length(tx),1)); \r
+  rx = tx + noise;\r
+\r
+  % Octave demodulator \r
+\r
+  printf("fsk demod ....\n");\r
+  st = 1;\r
+  run_frames = floor(length(rx)/states.N);\r
+  rx_bit_stream = [];\r
+  rx_sd_stream = [];\r
+  for f=1:run_frames\r
+\r
+    % extract nin samples from rx sample stream\r
+\r
+    nin = states.nin;\r
+    en = st + states.nin - 1;\r
+\r
+    if en <= length(rx) % due to nin variations its possible to overrun buffer\r
+      sf = rx(st:en);\r
+      st += nin;\r
+\r
+      % demodulate to stream of bits\r
+\r
+      states.f = [1200 2400];\r
+      [rx_bits states] = fsk_horus_demod(states, sf);\r
+      rx_bit_stream = [rx_bit_stream rx_bits];\r
+      rx_sd_stream = [rx_sd_stream states.rx_bits_sd];\r
+    end\r
+  end\r
+\r
+  % arrange into 10 bit columns\r
+\r
+  % look for SSTV packet UW\r
+\r
+  uw_rs232 = aframe_rs232(16*10+1:18*10); luw = length(uw_rs232);\r
+  nbits = length(rx_bit_stream);\r
+  uw_score = zeros(1, nbits);\r
+  for i=1:nbits-luw\r
+    errs = xor(rx_bit_stream(i:i+luw-1), uw_rs232);\r
+    uw_score(i) = sum(errs);\r
+  end\r
+  figure(1)\r
+  clf\r
+  plot(uw_score)\r
+\r
+  % pass through drs232 to provide UW sync \r
+\r
+#}\r
+#{\r
+  % determine raw BER from rx_frames\r
+\r
+  % read in test frame output from drs232_ldpc, determine raw BER\r
+\r
+\r
+  % Use Octave demodulator to check uncoded BER and PER.  Use UW to sync.\r
+  % Idea - how abt using C code for this?  Or just copy state machine logic\r
+  % here.  Wld need drs232_ldpc to have known test frame.  Hmmm... that is a \r
+  % great idea for testing ... especially repeats across different rx set-ups.ñ\r
\r
+  printf("save IQ to disk...\n");\r
+  figure(1);\r
+  subplot(211); plot(real(rx(1:1000)));\r
+  subplot(212); plot(imag(rx(1:1000)));\r
+  save_hackrf("fsk_modiq.raw", rx);\r
+#}\r
+end\r