HRA = sim_in.ldpc_code;
[aNr aNc] = size(HRA);
rate = states.rate = (aNc-aNr)/aNc;
- assert(aNc == Nbitsperframe, "Dude: Num cols of LDPC HRA must == Nbitsperframe");
+ Ndatabitsperframe = Nbitsperframe;
+ assert(aNc == Ndatabitsperframe, "Dude: Num cols of LDPC HRA must == Nbitsperframe");
[H_rows, H_cols] = Mat2Hrows(HRA);
code_param.H_rows = H_rows;
code_param.H_cols = H_cols;
code_param.P_matrix = [];
code_param.data_bits_per_frame = length(code_param.H_cols) - length( code_param.P_matrix );
code_param.code_bits_per_frame = aNc;
- assert(aNr == Nbitsperframe*rate);
+ assert(aNr == Ndatabitsperframe*rate);
modulation = states.ldpc_modulation = 'QPSK';
mapping = states.ldpc_mapping = 'gray';
else
% uncoded mode
codeword = tx_data_bits(st:en);
+ if isfield(sim_in, "uw_debug")
+ codeword(states.uw_ind) = states.tx_uw;
+ end
end
tx_bits = [tx_bits codeword];
for b=1:2:Nbitsperframe
Nerrs_log = []; Nerrs_coded_log = [];
rx_bits = []; rx_np = []; rx_amp = [];
sig_var_log = []; noise_var_log = [];
-
+ uw_errors_log = [];
+
% reset some states for each EbNo simulation point
states.sample_point = states.timing_est = 1;
rx_bits = [rx_bits arx_bits]; rx_np = [rx_np arx_np]; rx_amp = [rx_amp arx_amp];
+ % note: only supported in ldpc_en = 0 Nc=17 atm, see debug_false_sync()
+
+ if isfield(sim_in, "uw_debug")
+ rx_uw = arx_bits(states.uw_ind);
+ uw_errors = sum(xor(states.tx_uw,rx_uw));
+ if verbose
+ printf("f: %d uw_errors: %d\n", f, uw_errors);
+ end
+ uw_errors_log = [uw_errors_log uw_errors];
+ end
+
timing_est_log = [timing_est_log states.timing_est];
delta_t_log = [delta_t_log states.delta_t];
foff_est_hz_log = [foff_est_hz_log states.foff_est_hz];
sim_out.per(nn) = Tpacketerrs/Tpackets;
end
end
+
+ sim_out.uw_errors_log = uw_errors_log;
% Optional plots, mostly used with run-single
sim_in.ldpc_en = 1;
sim_in.interleave_frames = 1;
-
%sim_in.diversity_en = 1;
sim_out = run_sim(sim_in);
endfunction
+% during development it was discovered demod could obtain a flase sync with no UW
+% errors at +/- 7Hz, approx the frame rate. This function is used to explore that
+
+function debug_false_sync(EbNodB = 100)
+ Ts = 0.018;
+ sim_in.Tcp = 0.002;
+ sim_in.Rs = 1/Ts; sim_in.bps = 2; sim_in.Nc = 17; sim_in.Ns = 8;
+
+ sim_in.Nsec = (sim_in.Ns+1)/sim_in.Rs; % one frame, make sure sim_in.interleave_frames = 1
+ sim_in.Nsec = 1;
+
+ sim_in.EbNodB = 40;
+ sim_in.verbose = 0;
+ sim_in.hf_en = 0;
+ sim_in.foff_hz = 0;
+ sim_in.dfoff_hz_per_sec = 0.00;
+ sim_in.sample_clock_offset_ppm = 0;
+ sim_in.gain = 1;
+
+ sim_in.timing_en = 0;
+ sim_in.foff_est_en = 0;
+ sim_in.phase_est_en = 1;
+
+ load HRA_112_112.txt
+ sim_in.ldpc_code = HRA_112_112;
+ sim_in.ldpc_en = 0;
+
+ %sim_in.interleave_frames = 1;
+ %sim_in.diversity_en = 1;
+
+ sim_in.uw_debug = 1;
+
+ foff = -25:0.5:25;
+ for f=1:length(foff)
+ sim_in.foff_hz = foff(f);
+ sim_out = run_sim(sim_in);
+ min_uw_errors(f) = min(sim_out.uw_errors_log(2:end-1));
+ printf("f: %4.2f %2d\n", foff(f), min_uw_errors(f));
+ end
+ figure(1); clf;
+ plot(foff, min_uw_errors);
+ title('UW errors versus freq offset');
+ xlabel('Freq Offset (Hz)');
+end
+
% ---------------------------------------------------------
% choose simulation to run here
%run_curves_estimators
%acquisition_histograms(fin_en=0, foff_hz=-15, EbNoAWGN=-1, EbNoHF=3)
%acquisition_test(Ntests=100, EbNodB=-1, foff_hz=-10, hf_en=0)
-sync_metrics('freq')
+%sync_metrics('freq')
%run_curves_snr
%acquisition_dev(Ntests=10, EbNodB=100, foff_hz=0)
%acquistion_curves
+
+debug_false_sync
Nerrs_coded_log = Nerrs_log = [];
error_positions = [];
Nerrs_coded = Nerrs_raw = zeros(1, interleave_frames);
-
- % 'prime' rx buf to get correct coarse timing (for now)
+ #{
+ % 'prime' rx buf to get correct coarse timing (for now)
+
prx = 1;
nin = Nsamperframe+2*(M+Ncp);
states.rxbuf(Nrxbuf-nin+1:Nrxbuf) = rx(prx:nin);
prx += nin;
-
+ #}
+
% main loop ----------------------------------------------------------------
for f=1:Nframes
if strcmp(states.sync_state,'search')
[timing_valid states] = ofdm_sync_search(states, rxbuf_in);
end
-
+
if strcmp(states.sync_state,'synced') || strcmp(states.sync_state,'trial')
[rx_bits states aphase_est_pilot_log arx_np arx_amp] = ofdm_demod(states, rxbuf_in);
- rx_uw = rx_bits(1:states.Nuwbits);
-
+ [rx_uw payload_syms payload_amps txt_bits] = disassemble_modem_frame(states, arx_np, arx_amp);
+
% we are in sync so log modem states
rx_np_log = [rx_np_log arx_np];
% discarding UW and txt symbols at start of each modem frame
rx_np(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_np(Nsymbolsperframe+1:Nsymbolsperinterleavedframe);
- rx_np(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_np(Nuwtxtsymbolsperframe+1:end);
+ rx_np(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = payload_syms;
rx_amp(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_amp(Nsymbolsperframe+1:Nsymbolsperinterleavedframe);
- rx_amp(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_amp(Nuwtxtsymbolsperframe+1:end);
+ rx_amp(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = payload_amps;
mean_amp = states.mean_amp;
% generate UW and txt symbols to prepend to every frame after LDPC encoding and interleaving
- tx_uw_tx_bits = [tx_uw zeros(1,Ntxtbits)];
- tx_uw_tx_symbols = [];
- for b=1:2:length(tx_uw_tx_bits)
- tx_uw_tx_symbols = [tx_uw_tx_symbols qpsk_mod(tx_uw_tx_bits(b:b+1))];
+ txt_bits = zeros(1,Ntxtbits);
+ txt_symbols = [];
+ for b=1:2:length(txt_bits)
+ txt_symbols = [txt_symbols qpsk_mod(txt_bits(b:b+1))];
end
atx = [];
for f=1:interleave_frames
st = (f-1)*code_param.code_bits_per_frame/bps+1; en = st + code_param.code_bits_per_frame/bps-1;
- atx = [atx ofdm_txframe( states, [tx_uw_tx_symbols tx_symbols(st:en)] ) ];
+ modem_frame = assemble_modem_frame_symbols(states, tx_symbols(st:en), txt_symbols);
+ atx = [atx ofdm_txframe(states, modem_frame) ];
end
-
+
tx = [];
for f=1:Nframes/interleave_frames
tx = [tx atx];
timing_valid = timing_mx > timing_mx_thresh;
if verbose > 1
- printf(" mx: %f timing_est: %d timing_valid: %d\n", timing_mx, t_est, timing_valid);
+ printf(" av_level: %f mx: %f timing_est: %d timing_valid: %d\n", av_level, timing_mx, t_est, timing_valid);
end
endfunction
% averaging metric was found to be really important for reliable acquisition at low SNRs
states.foff_metric = 0.9*states.foff_metric + 0.1*(conj(p1)*p2 + conj(p3)*p4);
- foff_est = Fs1*angle(states.foff_metric)/(2*pi);
+ foff_est = Fs1*angle(states.foff_metric)/(2*pi);
+
+ if states.verbose > 1
+ printf(" foff_metric: %f %f foff_est: %f\n", real(states.foff_metric), imag(states.foff_metric), foff_est);
+ end
+
endfunction
states.Nbitsperframe = (Ns-1)*Nc*bps;
states.Nrowsperframe = states.Nbitsperframe/(Nc*bps);
states.Nsamperframe = (states.Nrowsperframe+1)*(states.M+states.Ncp);
- states.Ntxtbits = 4; % reserve 4 bits/frame for auxillary text information
+ states.Ntxtbits = 4; % reserved bits/frame for auxillary text information
states.Nuwbits = (Ns-1)*bps - states.Ntxtbits;
- states.tx_uw = [1 0 0 1 0 1 0 0 1 0];
- assert(length(states.tx_uw) == states.Nuwbits);
+ % UW symbol placement, designed to get no false syncs and any freq
+ % offset. Use ofdm_dev.m, debug_false_sync() to test. Note we need
+ % to pair the UW bits so the fit into symbols. The LDPC decoder
+ % work on symbols so we can't break up any symbols into UW/LDPC
+ % bits.
+
+ states.uw_ind = states.uw_ind_sym = [];
+ for i=1:states.Nuwbits/2
+ states.uw_ind = [states.uw_ind 1+i*(Nc+1) 2+i*(Nc+1)];
+ states.uw_ind_sym = [states.uw_ind_sym i*(Nc+1)/2+1];
+ end
+ states.tx_uw = [0 0 0 0 0 0 0 0 0 0];
+ assert(length(states.tx_uw) == states.Nuwbits);
+ tx_uw_syms = [];
+ for b=1:2:states.Nuwbits
+ tx_uw_syms = [tx_uw_syms qpsk_mod(states.tx_uw(b:b+1))];
+ end
+ states.tx_uw_syms = tx_uw_syms;
+
% use this to scale tx output to 16 bit short. Adjusted by experiment
% to have same RMS power as FDMDV waveform
states.amp_scale = 2E5*1.1491/1.06;
- % this is used to scale input sto LDPC decoder to make it amplitude indep
+ % this is used to scale inputs to LDPC decoder to make it amplitude indep
states.mean_amp = 0;
[ft_est timing_valid timing_mx] = est_timing(states, rxbuf(st:en) .* exp(-j*woff_est*(st:en)), rate_fs_pilot_samples);
- % keep the freq est statistic updated in case we lose sync, not we supply it with uncorrected rxbuf
+ % keep the freq est statistic updated in case we lose sync, note
+ % we supply it with uncorrected rxbuf
+
+ [coarse_foff_est_hz states] = est_freq_offset(states, rxbuf(st:en), states.rate_fs_pilot_samples, ft_est);
- [unused_foff_est states] = est_freq_offset(states, rxbuf(st:en), states.rate_fs_pilot_samples, ft_est);
-
if timing_valid
timing_est = timing_est + ft_est - ceil(ftwindow_width/2);
states.sample_point = sample_point;
states.delta_t = delta_t;
states.foff_est_hz = foff_est_hz;
- states.coarse_foff_est_hz = coarse_foff_est_hz;
+ states.coarse_foff_est_hz = coarse_foff_est_hz; % just used for tofdm
+endfunction
+
+
+% assemble modem frame from UW, payload, and txt bits
+
+function modem_frame = assemble_modem_frame(states, payload_bits, txt_bits)
+ ofdm_load_const;
+
+ modem_frame = zeros(1,Nbitsperframe);
+ p = 1; u = 1;
+
+ for b=1:Nbitsperframe-Ntxtbits;
+ if (u <= Nuwbits) && (b == uw_ind(u))
+ modem_frame(b) = tx_uw(u++);
+ else
+ modem_frame(b) = payload_bits(p++);
+ end
+ end
+ t = 1;
+ for b=Nbitsperframe-Ntxtbits+1:Nbitsperframe
+ modem_frame(b) = txt_bits(t++);
+ end
+ assert(u == (Nuwbits+1));
+ assert(p = (length(payload_bits)+1));
+endfunction
+
+
+% assemble modem frame from UW, payload, and txt symbols
+
+function modem_frame = assemble_modem_frame_symbols(states, payload_syms, txt_syms)
+ ofdm_load_const;
+
+ Nsymsperframe = Nbitsperframe/bps;
+ Nuwsyms = Nuwbits/bps;
+ Ntxtsyms = Ntxtbits/bps;
+ modem_frame = zeros(1,Nsymsperframe);
+ p = 1; u = 1;
+
+ for s=1:Nsymsperframe-Ntxtsyms;
+ if (u <= Nuwsyms) && (s == uw_ind_sym(u))
+ modem_frame(s) = states.tx_uw_syms(u++);
+ else
+ modem_frame(s) = payload_syms(p++);
+ end
+ end
+ t = 1;
+ for s=Nsymsperframe-Ntxtsyms+1:Nsymsperframe
+ modem_frame(s) = txt_syms(t++);
+ end
+ assert(u == (Nuwsyms+1));
+ assert(p = (length(payload_syms)+1));
+endfunction
+
+
+% extract UW and txt bits, and payload symbols from a frame of modem symbols
+
+function [rx_uw payload_syms payload_amps txt_bits] = disassemble_modem_frame(states, modem_frame_syms, modem_frame_amps)
+ ofdm_load_const;
+
+ Nsymsperframe = Nbitsperframe/bps;
+ Nuwsyms = Nuwbits/bps;
+ Ntxtsyms = Ntxtbits/bps;
+ payload_syms = zeros(1,Nsymsperframe-Nuwsyms-Ntxtsyms);
+ payload_amps = zeros(1,Nsymsperframe-Nuwsyms-Ntxtsyms);
+ rx_uw_syms = zeros(1,Nuwsyms);
+ txt_syms = zeros(1,Ntxtsyms);
+ p = 1; u = 1;
+
+ for s=1:Nsymsperframe-Ntxtsyms;
+ if (u <= Nuwsyms) && (s == uw_ind_sym(u))
+ rx_uw_syms(u++) = modem_frame_syms(s);
+ else
+ payload_syms(p) = modem_frame_syms(s);
+ payload_amps(p++) = modem_frame_amps(s);
+ end
+ end
+ t = 1;
+ for s=Nsymsperframe-Ntxtsyms+1:Nsymsperframe
+ txt_syms(t++) = modem_frame_syms(s);
+ end
+ assert(u == (Nuwsyms+1));
+ assert(p = (Nsymsperframe+1));
+
+ % now demodulate UW and txt bits
+
+ rx_uw = zeros(1,Nuwbits);
+ txt_bits = zeros(1,Ntxtbits);
+
+ for s=1:Nuwsyms
+ rx_uw(2*s-1:2*s) = qpsk_demod(rx_uw_syms(s));
+ end
+ for s=1:Ntxtsyms
+ txt_bits(2*s-1:2*s) = qpsk_demod(txt_syms(s));
+ end
+
endfunction
% insert UW and txt bits
- tx_bits = [tx_uw zeros(1,Ntxtbits) codeword_raw];
+ %tx_bits = [tx_uw zeros(1,Ntxtbits) codeword_raw];
+ tx_bits = assemble_modem_frame(states, codeword_raw, zeros(1,Ntxtbits));
assert(Nbitsperframe == length(tx_bits));
endfunction
Nuwbits = states.Nuwbits;
Ntxtbits = states.Ntxtbits;
tx_uw = states.tx_uw;
+uw_ind = states.uw_ind;
+uw_ind_sym = states.uw_ind_sym;
W = states.W;
w = states.w;
%states.rxbuf(Nrxbuf-nin+1:Nrxbuf) = rx(prx:nin);
%prx += nin;
- states.verbose = 0;
+ states.verbose = 1;
Nerrs = 0; rx_uw = zeros(1,states.Nuwbits);
if strcmp(states.sync_state,'synced') || strcmp(states.sync_state,'trial')
[rx_bits states aphase_est_pilot_log arx_np arx_amp] = ofdm_demod(states, rxbuf_in);
- rx_uw = rx_bits(1:states.Nuwbits);
+ [rx_uw payload_syms payload_amps txt_bits] = disassemble_modem_frame(states, arx_np, arx_amp);
errors = xor(tx_bits, rx_bits);
Nerrs = sum(errors);
% make sure LDPC decoding is working OK
- assert(codeword == detected_data);
+ % assert(codeword == detected_data);
[m n] = size(symbol_likelihood);
symbol_likelihood_log = [symbol_likelihood_log; reshape(symbol_likelihood,m*n,1)];