end\r
 \r
 \r
-% plots a BER cuvre for the decoder.  Takes a while to run, uses parallel cores\r
+% plots a BER curve for the decoder.  Takes a while to run, uses parallel cores\r
 \r
 function plot_curve\r
   num_cores = 4;              % set this to the number of cores you have\r
   fclose(fs);\r
 endfunction\r
 \r
+\r
+% Using simulated SSTV packet, generate complex fsk mod signals, 8-bit\r
+% unsigned IQ for feeding into demod chain\r
+#{\r
+todo: [X] uncoded BER\r
+          [X] octave fsk demod\r
+          [X] use C demod\r
+      [ ] compared unsigned 8 bit IQ to regular 16-bit\r
+          + modulate complex signal\r
+          + check BER\r
+          + feed into csdr stack\r
+      [ ] test with resampler\r
+      [ ] measure effect on PER with coding\r
+#}\r
+\r
+function [n_uncoded_errs n_uncoded_bits] = run_sstv_sim(sim_in, EbNodB)\r
+\r
+  frames = sim_in.frames;\r
+  c_demod = sim_in.c_demod;\r
+\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
+\r
+  % note fixed frame of bits used for BER testing\r
+\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
+  states.tx_real = 0;\r
+\r
+  % set up AWGN channel \r
+\r
+  EbNo = 10^(EbNodB/10);\r
+  variance = states.Fs/(states.Rs*EbNo*states.bitspersymbol);\r
+\r
+  % start simulation ----------------------------------------\r
+\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_real = sqrt(variance)*randn(length(tx),1);\r
+  noise_complex = sqrt(variance/2)*(randn(length(tx),1) + j*randn(length(tx),1));\r
+\r
+  % demodulate\r
+\r
+  if c_demod\r
+    if states.tx_real\r
+      rx = tx + noise_real;\r
+    else\r
+      rx = 2*real(tx) + noise_real;\r
+    end\r
+    SNRdB = 10*log10(var(tx)/var(noise_real));\r
+    rx_scaled = 1000*real(rx);\r
+    f = fopen("fsk_demod.raw","wb"); fwrite(f, rx_scaled, "short"); fclose(f);\r
+    system("../build_linux/src/fsk_demod 2X 8 9600 1200 fsk_demod.raw fsk_demod.bin");\r
+    f = fopen("fsk_demod.bin","rb"); rx_bit_stream = fread(f, "uint8")'; fclose(f);\r
+  else\r
+    if states.tx_real\r
+      rx = tx + noise_real;\r
+    else\r
+      rx = tx + noise_complex;\r
+    end\r
+    SNRdB = 10*log10(var(tx)/var(noise_complex));\r
+\r
+    % demodulate frame by frame using Octave demod\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
+  end\r
+\r
+  % state machine. Look for SSTV 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 include RS232 framing bits in uncoded error count\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
+        rx_frame_ind = i + 1;\r
+        n_uncoded_errs_this_frame = 0;\r
+        %printf("%d %s %s\n", i, state, next_state);\r
+      end\r
+    end\r
+    if strcmp(state, 'count errors')\r
+      n_uncoded_errs_this_frame += 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
+        n_uncoded_errs += n_uncoded_errs_this_frame;\r
+        printf("n_uncoded_errs_this_frame: %d\n", n_uncoded_errs_this_frame);\r
+        frame_rx232_rx = rx_bit_stream(rx_frame_ind:rx_frame_ind+nbits_frame-1);\r
+        %tx_codeword(start_frame_ind+1:start_frame_ind+10)\r
+        %frame_rx232_rx(1:10)\r
+        sstv_checksum(frame_rx232_rx);\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("EbNodB: %4.1f SNRdB: %4.1f n_uncoded_bits: %d n_uncoded_errs: %d BER: %4.3f\n", \r
+          EbNodB, SNRdB, n_uncoded_bits, n_uncoded_errs, uncoded_ber);  \r
+endfunction\r
+\r
 % Start simulation --------------------------------------------------------\r
 \r
 more off;\r
   f = fopen("sstv_sd.bin","wb"); fwrite(f, r, "float32"); fclose(f);\r
 end\r
 \r
+\r
 if demo == 9\r
   frames = 100;\r
   EbNodB = 11;\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
+  SNRdB = 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
 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
+  sim_in.frames = 3;\r
+  EbNodBvec = 9;\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
+  sim_in.c_demod = 0;\r
+  ber_octave = [];\r
+  for i = 1:length(EbNodBvec)\r
+    [n_uncoded_errs n_uncoded_bits] = run_sstv_sim(sim_in, EbNodBvec(i));\r
+    ber_octave(i) = n_uncoded_errs/n_uncoded_bits;\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
+  sim_in.c_demod = 1;\r
+  ber_c = [];\r
+  for i = 1:length(EbNodBvec)\r
+    [n_uncoded_errs n_uncoded_bits] = run_sstv_sim(sim_in, EbNodBvec(i));\r
+    ber_c(i) = n_uncoded_errs/n_uncoded_bits;\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
+  clf;\r
+  semilogy(EbNodBvec,  ber_octave, '+-;Octave demod;')\r
+  grid;\r
+  xlabel('Eb/No (dB)')\r
+  ylabel('BER')\r
+\r
+  hold on;\r
+  semilogy(EbNodBvec,  ber_c, 'g+-;C demod;')\r
+  legend("boxoff");\r
+  hold off;\r
 end\r
+\r