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