\r
% unpack bytes to bits and LPDC encode\r
\r
- mask = 2.^(0:7); % LSB to MSB\r
+ mask = 2.^(7:-1:0); % MSB to LSB unpacking to match python tx code.\r
unpacked_data = [];\r
for b=1:length(data)\r
unpacked_data = [unpacked_data bitand(data(b), mask) > 0];\r
end\r
- codeword = ldpc_encode(code_param, unpacked_data);\r
+ codeword = [ldpc_encode(code_param, unpacked_data) 0 0 0 0]; % pad with 0s to get integer number of bytes\r
+\r
+ % pack back into bytes to match python code \r
+\r
+ lpacked_codeword = length(codeword)/8\r
+ packed_codeword = zeros(1,lpacked_codeword);\r
+ for b=1:lpacked_codeword\r
+ st = (b-1)*8 + 1;\r
+ packed_codeword(b) = sum(codeword(st:st+7) .* mask);\r
+ end\r
\r
- % generate unpacked header bits\r
+ % generate header bits\r
\r
header = [hex2dec('55')*ones(1,16) hex2dec('ab') hex2dec('cd') hex2dec('ef') hex2dec('01')];\r
- unpacked_header = [];\r
- for b=1:length(header)\r
- unpacked_header = [unpacked_header bitand(header(b), mask) > 0];\r
+\r
+ % now construct entire unpacked frame\r
+\r
+ packed_frame = [header packed_codeword];\r
+ mask = 2.^(0:7); % LSB to MSB packing for header\r
+ lpacked_frame = length(packed_frame);\r
+ frame = [];\r
+ for b=1:lpacked_frame\r
+ frame = [frame bitand(packed_frame(b), mask) > 0];\r
end\r
- frame = [unpacked_header codeword 0 0 0 0]; % integer number of bytes\r
\r
% insert rs232 framing bits\r
\r
for b=1:8:length(frame)\r
frame_rs232 = [frame_rs232 0 frame(b:b+7) 1];\r
end\r
+\r
+ %printf("codeword: %d unpacked_header: %d frame: %d frame_rs232: %d \n", length(codeword), length(unpacked_header), length(frame), length(frame_rs232));\r
endfunction\r
\r
\r
% note fixed frame of bits used for BER testing\r
\r
tx_codeword = gen_sstv_frame;\r
-\r
+ \r
% init FSK modem\r
\r
fsk_horus_as_a_lib = 1;\r
states.df(1:states.M) = 0;\r
states.dA(1:states.M) = 1;\r
states.tx_real = 0; % Octave fsk_mod generates complex valued output\r
+ % so we can simulate rtl_sdr complex ouput\r
\r
% Set up simulated tx tones to sit in the middle of cdsr passband\r
\r
\r
tx_bit_stream = [];\r
for i=1:frames\r
+ % uncomment for different data on each frame\r
+ %tx_codeword = gen_sstv_frame;\r
tx_bit_stream = [tx_bit_stream tx_codeword];\r
end\r
\r
+ printf("%d bits at %d bit/s is a %3.1f second run\n", length(tx_bit_stream), 115200,length(tx_bit_stream)/115200);\r
+ \r
% modulate and channel model\r
\r
tx = fsk_horus_mod(states, tx_bit_stream);\r
\r
% demodulate to stream of bits\r
\r
- states.f = [f1 f2];\r
+ states.f = [f1 f2]; % note that for Octave demod we cheat and use known tone frequencies\r
+ % allows us to determine if freq offset estimation in C demod is a problem\r
+\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
\r
endfunction\r
\r
+\r
+% Function to test flight mode software. Takes a rx stream of\r
+% demodulated bits, and locates frames using UW detection. Extracts\r
+% data and parity bits. Uses data bits to generate parity bits here\r
+% and compare.\r
+\r
+function compare_parity_bits(rx_bit_stream)\r
+ nframes = 2;\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
+ % generate frame, this will have random bits not related to\r
+ % rx_stream, however we just use it for the UW\r
+\r
+ tx_codeword = gen_sstv_frame;\r
+ l = length(tx_codeword);\r
+ printf("expected rs232 frames codeword length: %d\n", l);\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 + 4*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 = nframes*l;\r
+ uw_thresh = 5;\r
+ n_uncoded_errs = 0;\r
+ n_uncoded_bits = 0;\r
+ n_packets_rx = 0;\r
+ last_i = 0;\r
+\r
+ % might as well include RS232 framing bits in uncoded error count\r
+\r
+ uw_errs = luw*ones(1, nbits);\r
+ for i=luw:nbits\r
+ uw_errs(i) = sum(xor(rx_bit_stream(i-luw+1:i), uw_rs232));\r
+ end\r
+\r
+ frame_start = find(uw_errs < 6)+1;\r
+ nframes = length(frame_start);\r
+ for i=1:nframes\r
+\r
+ % double check UW OK\r
+\r
+ st_uw = frame_start(i) - luw; en_uw = frame_start(i) - 1;\r
+ uw_err_check = sum(xor(rx_bit_stream(st_uw:en_uw), uw_rs232));\r
+ printf("uw_err_check: %d\n", uw_err_check);\r
+\r
+ % strip off rs232 start/stop bits\r
+\r
+ nbits_rs232 = (256+2+65)*10;\r
+ nbits = (256+2+65)*8\r
+ nbits_byte = 10;\r
+ rx_codeword = zeros(1,nbits);\r
+ pdb = 1;\r
+\r
+ for k=1:nbits_byte:nbits_rs232\r
+ for l=1:8\r
+ rx_codeword(pdb) = rx_bit_stream(frame_start(i)-1+k+l);\r
+ pdb++;\r
+ end\r
+ end\r
+ assert(pdb == (nbits+1));\r
+ \r
+ data_bits = rx_codeword(1:256*8);\r
+ checksum_bits = rx_codeword(256*8+1:258*8);\r
+ parity_bits = rx_codeword(258*8+1:258*8+516);\r
+ padding_bits = rx_codeword(258*8+516+1:258*8+516+1);\r
+\r
+ % stopped here as we found bug lol!\r
+ end\r
+\r
+ figure(1); clf;\r
+ plot(uw_errs);\r
+ title('Unique Word Hamming Distance')\r
+\r
+endfunction\r
+\r
+\r
% Start simulation --------------------------------------------------------\r
\r
more off;\r
\r
if demo == 11\r
sim_in.frames = 100;\r
- EbNodB = 13;\r
+ EbNodB = 7;\r
sim_in.demod_type = 5;\r
run_sstv_sim(sim_in, EbNodB);\r
end\r
+\r
+\r
+% Compare parity bits from an off-air stream of demodulated bits\r
+\r
+if demo == 12\r
+ f = fopen("fsk_demod.bin","rb"); rx_bit_stream = fread(f, "uint8")'; fclose(f);\r
+\r
+ compare_parity_bits(rx_bit_stream);\r
+end\r