% Frequency shift each modem carrier down to Nc+1 baseband signals
-function rx_baseband = fdm_downconvert(rx_fdm, nin)
- global Fs;
- global M;
- global Nc;
- global Fsep;
- global phase_rx;
- global freq;
-
- rx_baseband = zeros(1,nin);
+function [rx_baseband fdmdv] = fdm_downconvert(fdmdv, rx_fdm, nin)
+ Fs = fdmdv.Fs;
+ M = fdmdv.M;
+ Nc = fdmdv.Nc;
+ phase_rx = fdmdv.phase_rx;
+ freq = fdmdv.freq;
- % Nc/2 tones below centre freq
+ rx_baseband = zeros(Nc+1,nin);
- for c=1:Nc/2
- for i=1:nin
- phase_rx(c) = phase_rx(c) * freq(c);
- rx_baseband(c,i) = rx_fdm(i)*phase_rx(c)';
- end
- end
-
- % Nc/2 tones above centre freq
-
- for c=Nc/2+1:Nc
+ for c=1:Nc+1
for i=1:nin
phase_rx(c) = phase_rx(c) * freq(c);
rx_baseband(c,i) = rx_fdm(i)*phase_rx(c)';
end
end
- % Pilot
-
- c = Nc+1;
- for i=1:nin
- phase_rx(c) = phase_rx(c) * freq(c);
- rx_baseband(c,i) = rx_fdm(i)*phase_rx(c)';
- end
-
+ fdmdv.phase_rx = phase_rx;
endfunction
% Receive filter each baseband signal at oversample rate P
-function rx_filt = rx_filter(rx_baseband, nin)
- global Nc;
- global M;
- global P;
- global rx_filter_memory;
- global Nfilter;
- global gt_alpha5_root;
+function [rx_filt fdmdv] = rx_filter(fdmdv, rx_baseband, nin)
+ Nc = fdmdv.Nc;
+ M = fdmdv.M;
+ P = fdmdv.P;
+ rx_filter_memory = fdmdv.rx_filter_memory;
+ Nfilter = fdmdv.Nfilter;
+ gt_alpha5_root = fdmdv.gt_alpha5_root;
rx_filt = zeros(Nc+1,nin*P/M);
rx_filter_memory(:,1:Nfilter-N) = rx_filter_memory(:,1+N:Nfilter);
j+=1;
end
+
+ fdmdv.rx_filter_memory = rx_filter_memory;
endfunction
% LP filter +/- 1000 Hz, allows us to perfrom rx filtering at a lower rate saving CPU
-function rx_fdm_filter = rxdec_filter(rx_fdm, nin)
- global M;
- global Nrxdec;
- global rxdec_coeff;
- global rxdec_lpf_mem;
+function [rx_fdm_filter fdmdv] = rxdec_filter(fdmdv, rx_fdm, nin)
+ M = fdmdv.M;
+ Nrxdec = fdmdv.Nrxdec;
+ rxdec_coeff = fdmdv.rxdec_coeff;
+ rxdec_lpf_mem = fdmdv.rxdec_lpf_mem;
rxdec_lpf_mem(1:Nrxdec-1+M-nin) = rxdec_lpf_mem(nin+1:Nrxdec-1+M);
rxdec_lpf_mem(Nrxdec-1+M-nin+1:Nrxdec-1+M) = rx_fdm(1:nin);
for i=1:nin
rx_fdm_filter(i) = rxdec_lpf_mem(i:Nrxdec-1+i) * rxdec_coeff;
end
+
+ fdmdv.rxdec_lpf_mem = rxdec_lpf_mem;
end
% TODO: Decimate mem update and downconversion, this will save some more CPU and memory
% note phase would have to advance 4 times as fast
-function rx_filt = down_convert_and_rx_filter(rx_fdm, nin, dec_rate)
- global Nc;
- global M;
- global P;
- global rx_fdm_mem;
- global phase_rx;
- global freq;
- global freq_pol;
- global Nfilter;
- global gt_alpha5_root;
- global Q;
+function [rx_filt fdmdv] = down_convert_and_rx_filter(fdmdv, rx_fdm, nin, dec_rate)
+ Nc = fdmdv.Nc;
+ M = fdmdv.M;
+ P = fdmdv.P;
+ rx_fdm_mem = fdmdv.rx_fdm_mem;
+ phase_rx = fdmdv.phase_rx;
+ freq = fdmdv.freq;
+ freq_pol = fdmdv.freq_pol;
+ Nfilter = fdmdv.Nfilter;
+ gt_alpha5_root = fdmdv.gt_alpha5_root;
+ Q = fdmdv.Q;
% update memory of rx_fdm
k+=1;
end
end
+
+ fdmdv.phase_rx = phase_rx;
+ fdmdv.rx_fdm_mem = rx_fdm_mem;
endfunction
% Estimate optimum timing offset, re-filter receive symbols
-function [rx_symbols rx_timing_M env] = rx_est_timing(rx_filt, nin)
- global M;
- global Nt;
- global Nc;
- global rx_filter_mem_timing;
- global P;
- global Nfilter;
- global Nfiltertiming;
- global gt_alpha5_root;
+function [rx_symbols rx_timing_M env fdmdv] = rx_est_timing(fdmdv, rx_filt, nin)
+ M = fdmdv.M;
+ Nt = fdmdv.Nt;
+ Nc = fdmdv.Nc;
+ rx_filter_mem_timing = fdmdv.rx_filter_mem_timing;
+ P = fdmdv.P;
+ Nfilter = fdmdv.Nfilter;
+ Nfiltertiming = fdmdv.Nfiltertiming;
% nin adjust
% --------------------------------
% rx_symbols = rx_filter_mem_timing(:,high_sample+1);
rx_timing_M = norm_rx_timing*M;
+
+ fdmdv.rx_filter_mem_timing = rx_filter_mem_timing;
endfunction
fdmdv.Fs = 8000;
fdmdv.Nc = Nc-1;
-fdmdv.M = Fs/Rs;
+M = fdmdv.M = Fs/Rs;
fdmdv.tx_filter_memory = zeros(fdmdv.Nc+1, Nfilter);
fdmdv.Nfilter = Nfilter;
fdmdv.gt_alpha5_root = gt_alpha5_root;
fdmdv.Fsep = 75;
-fdmdv.phase_tx = exp(j*2*pi*(0:Nc)/(Nc+1));
+fdmdv.phase_tx = ones(fdmdv.Nc+1,1);
freq_hz = Fsep*( -Nc/2 - 0.5 + (1:Nc) );
-fdmdv.freq = exp(j*2*pi*freq_hz/Fs);
+fdmdv.freq_pol = 2*pi*freq_hz/Fs;
+fdmdv.freq = exp(j*fdmdv.freq_pol);
Fcentre = 1500;
fdmdv.fbb_rect = exp(j*2*pi*Fcentre/Fs);
fdmdv.fbb_phase_tx = 1;
+fdmdv.Nrxdec = 31;
+fdmdv.rxdec_coeff = fir1(fdmdv.Nrxdec-1, 0.25)';
+fdmdv.rxdec_lpf_mem = zeros(1,fdmdv.Nrxdec-1+M);
+
+P = fdmdv.P = 4;
+fdmdv.phase_rx = ones(fdmdv.Nc+1,1);
+fdmdv.Nsym = 6;
+fdmdv.Nfilter = fdmdv.Nsym*fdmdv.M;
+fdmdv.rx_fdm_mem = zeros(1,fdmdv.Nfilter + fdmdv.M);
+Q = fdmdv.Q = fdmdv.M/4;
+
+fdmdv.Nt = 5;
+fdmdv.rx_filter_mem_timing = zeros(fdmdv.Nc+1, fdmdv.Nt*fdmdv.P);
+fdmdv.Nfiltertiming = fdmdv.M + fdmdv.Nfilter + fdmdv.M;
+
+fdmdv.rx_filter_memory = zeros(fdmdv.Nc+1, fdmdv.Nfilter);
+
+rx_filt_log = [];
+rx_fdm_filter_log = [];
+rx_baseband_log = [];
+
+fbb_phase_rx = 1;
+
+% frame of just pilots ofr coarse sync
+
+tx_bits = zeros(1,framesize);
+[tx_symb_pilot tx_bits prev_tx_sym] = bits_to_qpsk_symbols(sim_in, tx_bits, [], []);
+for r=1:(sim_in.Ns+1):sim_in.Nsymbrowpilot
+ tx_symb_pilot(r+1:r+sim_in.Ns,:) = zeros(sim_in.Ns, sim_in.Nc);
+end
+
+ct_symb_buf = zeros(2*sim_in.Nsymbrowpilot, sim_in.Nc);
+
+% main loop --------------------------------------------------------------------
+
for i=1:frames
tx_bits = tx_bits_coh(ptx_bits_coh:ptx_bits_coh+framesize-1);
ptx_bits_coh += framesize;
tx_bits_log = [tx_bits_log tx_bits];
[tx_symb tx_bits prev_tx_sym] = bits_to_qpsk_symbols(sim_in, tx_bits, [], []);
+ %tx_symb = tx_symb_pilot;
tx_symb_log = [tx_symb_log; tx_symb];
+ tx_fdm_frame = [];
for r=1:sim_in.Nsymbrowpilot
- [tx_baseband fdmdv] = tx_filter(fdmdv, rot90(tx_symb(r,:),1));
+ tx_onesymb = tx_symb(r,:);
+ [tx_baseband fdmdv] = tx_filter(fdmdv, tx_onesymb);
tx_baseband_log = [tx_baseband_log tx_baseband];
[tx_fdm fdmdv] = fdm_upconvert(fdmdv, tx_baseband);
- tx_fdm_log = [tx_fdm_log tx_fdm];
+ tx_fdm_frame = [tx_fdm_frame tx_fdm];
end
+ tx_fdm_log = [tx_fdm_log tx_fdm_frame];
+ nin = M;
+
+ % shift frame down to complex baseband
+
+ rx_fdm_frame_bb = zeros(1, sim_in.Nsymbrowpilot*M);
+ for r=1:sim_in.Nsymbrowpilot*M
+ fbb_phase_rx = fbb_phase_rx*fdmdv.fbb_rect';
+ rx_fdm_frame_bb(r) = tx_fdm_frame(r)*fbb_phase_rx;
+ end
+ mag = abs(fbb_phase_rx);
+ fbb_phase_rx /= mag;
+
+ ch_symb = zeros(sim_in.Nsymbrowpilot, Nc);
+ for r=1:sim_in.Nsymbrowpilot
+ %[rx_fdm_filter fdmdv] = rxdec_filter(fdmdv, rx_fdm_frame_bb(1+(r-1)*M:r*M), nin);
+ %rx_fdm_filter_log = [rx_fdm_filter_log rx_fdm_filter];
+ %[rx_filt fdmdv] = down_convert_and_rx_filter(fdmdv, rx_fdm_filter, nin, M/Q);
+
+ [rx_baseband fdmdv] = fdm_downconvert(fdmdv, rx_fdm_frame_bb(1+(r-1)*M:r*M), nin);
+ rx_baseband_log = [rx_baseband_log rx_baseband];
+ [rx_filt fdmdv] = rx_filter(fdmdv, rx_baseband, nin);
+
+ rx_filt_log = [rx_filt_log rx_filt];
+
+ [rx_onesym rx_timing env fdmdv] = rx_est_timing(fdmdv, rx_filt, nin);
+ ch_symb(r,:) = rx_onesym;
+ end
+
+if 0
noise = sqrt(variance*0.5)*(randn(sim_in.Nsymbrowpilot,sim_in.Nc) + j*randn(sim_in.Nsymbrowpilot,sim_in.Nc));
noise_log = [noise_log; noise];
ch_symb(r,:) = tx_symb(r,:)*phase + noise(r,:);
end
phase = phase/abs(phase);
+end
ch_symb_log = [ch_symb_log; ch_symb];
- [rx_symb rx_bits rx_symb_linear amp_linear amp_ phi_ EsNo_ prev_sym_rx sim_in] = qpsk_symbols_to_bits(sim_in, ch_symb, []);
+ % coarse timing
+
+ ct_symb_buf(1:sim_in.Nsymbrowpilot,:) = ct_symb_buf(sim_in.Nsymbrowpilot+1:2*sim_in.Nsymbrowpilot,:);
+ ct_symb_buf(sim_in.Nsymbrowpilot+1:2*sim_in.Nsymbrowpilot,:) = ch_symb;
+
+ max_corr = 0;
+ for t=0:sim_in.Nsymbrowpilot-1
+ corr = sum(sum(rot90(ct_symb_buf(t+1:t+sim_in.Nsymbrowpilot,:),1) * tx_symb_pilot));
+ if corr > max_corr
+ max_corr = corr;
+ ct = t;
+ end
+ end
+ %printf("max_corr: %f ct: %d\n", max_corr, ct);
+
+ [rx_symb rx_bits rx_symb_linear amp_linear amp_ phi_ EsNo_ prev_sym_rx sim_in] = qpsk_symbols_to_bits(sim_in, ct_symb_buf(ct+1:ct+sim_in.Nsymbrowpilot,:), []);
rx_symb_log = [rx_symb_log; rx_symb];
rx_amp_log = [rx_amp_log; amp_];
rx_phi_log = [rx_phi_log; phi_];
% BER stats
- if i > 2
- error_positions = xor(prev_tx_bits, rx_bits);
+ if i > 3
+ error_positions = xor(prev_tx_bits2, rx_bits);
Nerrs += sum(error_positions);
nerr_log = [nerr_log sum(error_positions)];
Tbits += length(error_positions);
end
+ prev_tx_bits2 = prev_tx_bits;
prev_tx_bits = tx_bits;
end