\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
\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
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
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