global P = 4; % oversample factor used for rx symbol filtering
global Nfilter = Nsym*M;
global Nfiltertiming = M+Nfilter+M;
+alpha = 0.5;
% root raised cosine (Root Nyquist) filter
-global gt_alpha5_root = gen_rn_coeffs(alpha, Rs, Nsym, M);
-
-% Initialise ----------------------------------------------------
-
-global pilot_bit;
-pilot_bit = 0; % current value of pilot bit
-
-global tx_filter_memory;
-tx_filter_memory = zeros(Nc+1, Nfilter);
-global rx_filter_memory;
-rx_filter_memory = zeros(Nc+1, Nfilter);
-
-% phasors used for up and down converters
-
-global freq;
-freq = zeros(Nc+1,1);
-for c=1:Nc/2
- carrier_freq = (-Nc/2 - 1 + c)*Fsep + Fcentre;
- freq(c) = exp(j*2*pi*carrier_freq/Fs);
-end
-for c=Nc/2+1:Nc
- carrier_freq = (-Nc/2 + c)*Fsep + Fcentre;
- freq(c) = exp(j*2*pi*carrier_freq/Fs);
-end
-
-freq(Nc+1) = exp(j*2*pi*Fcentre/Fs);
-
-% Spread initial FDM carrier phase out as far as possible. This
-% helped PAPR for a few dB. We don't need to adjust rx phase as DQPSK
-% takes care of that.
-
-global phase_tx;
-%phase_tx = ones(Nc+1,1);
-phase_tx = exp(j*2*pi*(0:Nc)/(Nc+1));
-global phase_rx;
-phase_rx = ones(Nc+1,1);
-
-% Freq offset estimator constants
-
-global Mpilotfft = 256;
-global Npilotcoeff = 30; % number of pilot LPF coeffs
-global pilot_coeff = fir1(Npilotcoeff, 200/(Fs/2))'; % 200Hz LPF
-global Npilotbaseband = Npilotcoeff + 4*M; % number of pilot baseband samples reqd for pilot LPF
-global Npilotlpf = 4*M; % number of samples we DFT pilot over, pilot est window
-
-% Freq offset estimator states
-
-global pilot_baseband1;
-global pilot_baseband2;
-pilot_baseband1 = zeros(1, Npilotbaseband); % pilot baseband samples
-pilot_baseband2 = zeros(1, Npilotbaseband); % pilot baseband samples
-global pilot_lpf1
-global pilot_lpf2
-pilot_lpf1 = zeros(1, Npilotlpf); % LPF pilot samples
-pilot_lpf2 = zeros(1, Npilotlpf); % LPF pilot samples
-
-% Timing estimator states
-
-global rx_filter_mem_timing;
-rx_filter_mem_timing = zeros(Nc+1, Nt*P);
-global rx_baseband_mem_timing;
-rx_baseband_mem_timing = zeros(Nc+1, Nfiltertiming);
-
-% Test bit stream constants
-
-global Ntest_bits = Nc*Nb*4; % length of test sequence
-global test_bits = rand(1,Ntest_bits) > 0.5;
-
-% Test bit stream state variables
-
-global current_test_bit = 1;
-current_test_bit = 1;
-global rx_test_bits_mem;
-rx_test_bits_mem = zeros(1,Ntest_bits);
+global gt_alpha5_root = gen_rn_coeffs(alpha, T, Rs, Nsym, M);
% Functions ----------------------------------------------------
% is periodic in 4M samples we can then use this vector as a look up table
% for pilot signsl generation at the demod.
-function pilot_lut = generate_pilot_lut
+function pilot_lut = generate_pilot_lut()
global Nc;
global Nfilter;
global M;
endfunction
+% grab next pilot samples for freq offset estimation at demod
+
+function [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, nin)
+ global M;
+ global pilot_lut;
+
+ for i=1:nin
+ pilot(i) = pilot_lut(pilot_lut_index);
+ pilot_lut_index++;
+ if pilot_lut_index > 4*M
+ pilot_lut_index = 1;
+ end
+ prev_pilot(i) = pilot_lut(prev_pilot_lut_index);
+ prev_pilot_lut_index++;
+ if prev_pilot_lut_index > 4*M
+ prev_pilot_lut_index = 1;
+ end
+ end
+endfunction
+
+
+
% Change the sample rate by a small amount, for example 1000ppm (ratio
% = 1.001). Always returns nout samples in buf_out, but uses a
% variable number of input samples nin to accomodate the change in
end
endfunction
+% Initialise ----------------------------------------------------
+
+global pilot_bit;
+pilot_bit = 0; % current value of pilot bit
+
+global tx_filter_memory;
+tx_filter_memory = zeros(Nc+1, Nfilter);
+global rx_filter_memory;
+rx_filter_memory = zeros(Nc+1, Nfilter);
+
+% phasors used for up and down converters
+
+global freq;
+freq = zeros(Nc+1,1);
+for c=1:Nc/2
+ carrier_freq = (-Nc/2 - 1 + c)*Fsep + Fcentre;
+ freq(c) = exp(j*2*pi*carrier_freq/Fs);
+end
+for c=Nc/2+1:Nc
+ carrier_freq = (-Nc/2 + c)*Fsep + Fcentre;
+ freq(c) = exp(j*2*pi*carrier_freq/Fs);
+end
+
+freq(Nc+1) = exp(j*2*pi*Fcentre/Fs);
+
+% Spread initial FDM carrier phase out as far as possible. This
+% helped PAPR for a few dB. We don't need to adjust rx phase as DQPSK
+% takes care of that.
+
+global phase_tx;
+%phase_tx = ones(Nc+1,1);
+phase_tx = exp(j*2*pi*(0:Nc)/(Nc+1));
+global phase_rx;
+phase_rx = ones(Nc+1,1);
+
+% Freq offset estimator constants
+
+global Mpilotfft = 256;
+global Npilotcoeff = 30; % number of pilot LPF coeffs
+global pilot_coeff = fir1(Npilotcoeff, 200/(Fs/2))'; % 200Hz LPF
+global Npilotbaseband = Npilotcoeff + 4*M; % number of pilot baseband samples reqd for pilot LPF
+global Npilotlpf = 4*M; % number of samples we DFT pilot over, pilot est window
+
+% pilot LUT, used for copy of pilot at rx
+
+global pilot_lut;
+pilot_lut = generate_pilot_lut();
+pilot_lut_index = 1;
+prev_pilot_lut_index = 3*M+1;
+
+% Freq offset estimator states
+
+global pilot_baseband1;
+global pilot_baseband2;
+pilot_baseband1 = zeros(1, Npilotbaseband); % pilot baseband samples
+pilot_baseband2 = zeros(1, Npilotbaseband); % pilot baseband samples
+global pilot_lpf1
+global pilot_lpf2
+pilot_lpf1 = zeros(1, Npilotlpf); % LPF pilot samples
+pilot_lpf2 = zeros(1, Npilotlpf); % LPF pilot samples
+
+% Timing estimator states
+
+global rx_filter_mem_timing;
+rx_filter_mem_timing = zeros(Nc+1, Nt*P);
+global rx_baseband_mem_timing;
+rx_baseband_mem_timing = zeros(Nc+1, Nfiltertiming);
+
+% Test bit stream constants
+
+global Ntest_bits = Nc*Nb*4; % length of test sequence
+global test_bits = rand(1,Ntest_bits) > 0.5;
+
+% Test bit stream state variables
+
+global current_test_bit = 1;
+current_test_bit = 1;
+global rx_test_bits_mem;
+rx_test_bits_mem = zeros(1,Ntest_bits);
+
+
prev_rx_symbols = ones(Nc+1,1);
foff_phase = 1;
- % pilot LUT, used for copy of pilot at rx
-
- pilot_lut = generate_pilot_lut;
- pilot_lut_index = 1;
- prev_pilot_lut_index = 3*M+1;
-
% BER stats
total_bit_errors = 0;
nin = M; % timing correction for sample rate differences
foff = 0;
track_log = [];
- track = 1;
+ track = 0;
fest_state = 0;
% Main loop ----------------------------------------------------
% frequency offset estimation and correction
- for i=1:nin
- pilot(i) = pilot_lut(pilot_lut_index);
- pilot_lut_index++;
- if pilot_lut_index > 4*M
- pilot_lut_index = 1;
- end
- prev_pilot(i) = pilot_lut(prev_pilot_lut_index);
- prev_pilot_lut_index++;
- if prev_pilot_lut_index > 4*M
- prev_pilot_lut_index = 1;
- end
- end
+ [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, nin);
foff_coarse = rx_est_freq_offset(rx_fdm, pilot, prev_pilot, nin);
if track == 0
foff = foff_coarse;
track_log = [track_log track];
% count bit errors if we find a test frame
- % Allow 15 frames for filter memories to fill and time est to settle
[test_frame_sync bit_errors] = put_test_bits(rx_bits);
if (test_frame_sync == 1)
title('timing offset (samples)');
subplot(212)
plot(xt, foff_log)
+ hold on;
+ plot(xt, track_log*75, 'r');
+ hold off;
title('Freq offset (Hz)');
grid
axis([0 secs 0 1.5]);
title('Test Frame Sync')
- figure(5)
- clf;
- plot(xt, track_log);
- axis([0 secs 0 1.5]);
endfunction
test_frame_sync_log = [];
test_frame_sync_state = 0;
-% pilot look up table, used for copy of pilot at rx
-
-pilot_lut = generate_pilot_lut;
-pilot_lut_index = 1;
-prev_pilot_lut_index = 3*M+1;
-
% fixed delay simuation
Ndelay = M+20;
B = 3000;
SNR = CNo_dB - 10*log10(B);
+% freq offset simulation states
+
phase_offset = 1;
freq_offset = exp(j*2*pi*Foff_hz/Fs);
foff_phase = 1;
t = 0;
+foff = 0;
+fest_state = 0;
+track = 0;
+track_log = [];
% ---------------------------------------------------------------------
% Main loop
% Demodulator
% -------------------
- % frequency offset estimation and correction
+ % frequency offset estimation and correction, need to call rx_est_freq_offset even in track
+ % mode to keep states updated
- for i=1:M
- pilot(i) = pilot_lut(pilot_lut_index);
- pilot_lut_index++;
- if pilot_lut_index > 4*M
- pilot_lut_index = 1;
- end
- prev_pilot(i) = pilot_lut(prev_pilot_lut_index);
- prev_pilot_lut_index++;
- if prev_pilot_lut_index > 4*M
- prev_pilot_lut_index = 1;
- end
+ [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, M);
+ foff_course = rx_est_freq_offset(rx_fdm_delay, pilot, prev_pilot, M);
+ if track == 0
+ foff = foff_course;
end
- %foff = rx_est_freq_offset(rx_fdm_delay, pilot, prev_pilot, M);
foff_log = [ foff_log foff ];
- %foff = 0;
foff_rect = exp(j*2*pi*foff/Fs);
for i=1:M
prev_rx_symbols = rx_symbols;
sync_log = [sync_log sync];
+ % freq est state machine
+
+ [track fest_state] = freq_state(sync, fest_state);
+ track_log = [track_log track];
+
% count bit errors if we find a test frame
% Allow 15 frames for filter memories to fill and time est to settle
[test_frame_sync bit_errors] = put_test_bits(rx_bits);
- if ((test_frame_sync == 1) && (f > 15))
+ if test_frame_sync == 1
total_bit_errors = total_bit_errors + bit_errors;
total_bits = total_bits + Ntest_bits;
bit_errors_log = [bit_errors_log bit_errors];
+ else
+ bit_errors_log = [bit_errors_log 0];
end
% test frame sync state machine, just for more informative plots
title('timing offset (samples)');
subplot(212)
plot(foff_log)
+hold on;
+plot(track_log*75, 'r');
+hold off;
title('Freq offset (Hz)');
figure(3)