freq offset est and alg developnment coming along nicely
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 20 Jun 2014 06:27:15 +0000 (06:27 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 20 Jun 2014 06:27:15 +0000 (06:27 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@1695 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/octave/fdmdv.m
codec2-dev/octave/fdmdv_ut_freq_off.m

index 7fdabd4e5299a003fc67bda66813e1a5291f32a3..7c6aea49a3c7999f76d66a75e07270ecb9eea021 100644 (file)
@@ -89,6 +89,8 @@ global m8_binary_to_gray = [
                              bin2dec("100")
                            ];
 
+% temp logging stuff
+
 % Functions ----------------------------------------------------
 
 
@@ -208,7 +210,7 @@ function tx_fdm = fdm_upconvert(tx_filt)
   for i=1:M
     phase_tx(c) = phase_tx(c) * freq(c);
     pilot(i) = 2*tx_filt(c,i)*phase_tx(c);
-    tx_fdm(i) = tx_fdm(i) + pilot(i);
+    tx_fdm(i) = tx_fdm(i) + pilot(i);  
   end
  
   % Scale such that total Carrier power C of real(tx_fdm) = Nc.  This
@@ -313,10 +315,9 @@ function [foff imax pilot_lpf_out S] = lpf_peak_pick(pilot_baseband, pilot_lpf,
   j = Npilotcoeff+1;
   for i = Npilotlpf-nin+1:Npilotlpf
     pilot_lpf(i) = pilot_baseband(j-Npilotcoeff+1:j) * pilot_coeff';
-    %pilot_lpf(i) = pilot_baseband(j-Npilotcoeff+1);
     j++;
   end
-
+  
   % decimate to improve DFT resolution, window and DFT
 
   Mpilot = Fs/(2*200);  % calc decimation rate given new sample rate is twice LPF freq
@@ -327,7 +328,7 @@ function [foff imax pilot_lpf_out S] = lpf_peak_pick(pilot_baseband, pilot_lpf,
 
   % peak pick and convert to Hz
 
-  [imax ix] = max(S);
+  [imax ix] = max(abs(S));
   r = 2*200/Mpilotfft;     % maps FFT bin to frequency in Hz
   
   if ix > Mpilotfft/2
@@ -373,6 +374,7 @@ function [foff S1 S2] = rx_est_freq_offset(rx_fdm, pilot, pilot_prev, nin)
   else
     foff = foff2;
   end  
+  foff = foff1;
 endfunction
 
 
@@ -676,8 +678,6 @@ function [sync bit_errors error_pattern] = put_test_bits(test_bits, rx_bits)
   endif
 endfunction
 
-
-
 % Generate M samples of DBPSK pilot signal for Freq offset estimation
 
 function [pilot_fdm bit symbol filter_mem phase] = generate_pilot_fdm(bit, symbol, filter_mem, phase, freq)
@@ -1049,17 +1049,22 @@ 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-1, 200/(Fs/2))'; % 200Hz LPF
-global Npilotbaseband = Npilotcoeff + M + M/P;          % number of pilot baseband samples reqd for pilot LPF
-global Npilotlpf      = 4*M;                            % number of samples we DFT pilot over, pilot est window
+global Npilotcoeff;                                      % number of pilot LPF coeffs
+       Npilotcoeff    = 300;                             % number of pilot LPF coeffs
+global pilot_coeff;
+       pilot_coeff    = fir1(Npilotcoeff-1, 200/(Fs/2))';% 200Hz LPF
+global Npilotbaseband = Npilotcoeff + M + M/P;           % number of pilot baseband samples reqd for pilot LPF
+global Npilotlpf;                                        % number of samples we DFT pilot over, pilot est window
+       Npilotlpf      = 16*M;
 
 % 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;
+global pilot_lut_index;
+       pilot_lut_index = 1;
+global prev_pilot_lut_index;
+       prev_pilot_lut_index = 3*M+1;
 
 % Freq offset estimator states 
 
index c9541cb76750d08ba0d06f8c09e919a182553fd6..f118dd349fa5ff06d44718e96893aeb8656e6959 100644 (file)
@@ -10,6 +10,8 @@
 % [ ] sweep of different delays
 % [ ] sweep of Eb/No
 % [ ] sweep of freq offsets
+% [ ] step change in foff
+%     + time to respond
 % [ ] plot/print pass fail/relevant stats
 %      + variance
 %      + histogram of freq ests?
@@ -20,7 +22,7 @@ hf_sim; % load hf sim code
 % ---------------------------------------------------------------------
 % Eb/No calculations.  We need to work out Eb/No for each FDM carrier.
 % Total power is sum of power in all FDM carriers.  These calcs set the
-% Eb/No of the data carriers.
+% Eb/No of the data carriers, Eb/No of pilot will be higher.
 % ---------------------------------------------------------------------
 
 function [Nsd SNR] = calc_Nsd_from_EbNo(EbNo_dB)
@@ -55,6 +57,28 @@ function [Nsd SNR] = calc_Nsd_from_EbNo(EbNo_dB)
   SNR = CNo_dB - 10*log10(B) + 10*log10((Nc+4)/Nc);
 end
 
+% we keep a m sample buffer in sample_memory
+% update sample_memory with n samples each time this function is called
+% outputs one nfft2 slice of spectrogram in dB.  Good idea to make nfft2 a power of 2
+
+function [S, states_out] = spectrogram_update(samples, n, states_in)
+  sample_memory = states_in.sample_memory;
+  m             = states_in.m;
+  nfft2         = states_in.nfft2;
+  lower_clip_dB = states_in.lower_clip_dB;
+  dec           = states_in.dec;
+
+  sample_memory(1:m-n)   = sample_memory(n+1:m);
+  sample_memory(m-n+1:m) = samples;
+
+  F = fft(sample_memory .* hanning(m)', 2*nfft2);
+  S = 20*log10(abs(F(1:dec:nfft2))/(nfft2));
+  S(find(S < lower_clip_dB)) = lower_clip_dB;    % clip lower limit
+
+  states_out = states_in;
+  states_out.sample_memory = sample_memory;
+end
+
 % ------------------------------------------------------------
 
 function sim_out = freq_off_est_test(sim_in)
@@ -77,7 +101,27 @@ function sim_out = freq_off_est_test(sim_in)
   allowable_error = sim_in.allowable_error;
   foff_hz  = sim_in.foff_hz;
   hf_sim   = sim_in.hf_sim;
-  hf_delay = floor(sim_in.hf_delay_ms*Fs);
+  hf_delay = floor(sim_in.hf_delay_ms*Fs/1000);
+
+  % work out gain for HF model
+  % e = sum((g*s)^2) = g*g*sum(s^2) = N, g = sqrt(N/sum(s^2))
+  % compute so e=N
+
+  s1 = spread(1:frames*M);
+  s2 = [zeros(hf_delay,1); spread_2ms(1:frames*M)];
+  s2 = s2(1:frames*M);
+
+  p = (s1+s2)'*(s1+s2);
+  hf_gain = sqrt(frames*M/p);
+  p2 = (hf_gain*(s1+s2))'*(hf_gain*(s1+s2));
+
+  % spectrogram states
+
+  spec_states.m             = 4*M;
+  spec_states.nfft2         = 2 ^ ceil(log2(spec_states.m/2));
+  spec_states.dec           = 4;
+  spec_states.sample_memory = zeros(1, spec_states.m);
+  spec_states.lower_clip_dB = -30;
 
   % ---------------------------------------------------------------------
   % Main loop 
@@ -102,6 +146,8 @@ function sim_out = freq_off_est_test(sim_in)
     phase_offset = 1;
     freq_offset = exp(j*2*pi*foff_hz/Fs);
     foff_phase = 1;
+    Nmedian = 25;
+    foff_median=zeros(1,Nmedian);
 
     % hf sim states
     
@@ -109,6 +155,12 @@ function sim_out = freq_off_est_test(sim_in)
     sum_sig   = 0;
     sum_noise = 0;
 
+    % state machine
+    state = 0;
+    fest_current = 0;
+    fdelta = 5;
+    candidate_thresh = 10;
+
     for f=1:frames
 
       % ------------------- Modulator -------------------
@@ -135,12 +187,14 @@ function sim_out = freq_off_est_test(sim_in)
 
       if hf_sim
         path1 = tx_fdm .* conj(spread(f*M+1:f*M+M)');
+
+        path2(1:hf_delay) = path2(M+1:hf_delay+M);
         path2(hf_delay+1:hf_delay+M) = tx_fdm .* conj(spread_2ms(f*M+1:f*M+M)');
 
         tx_fdm = hf_gain*(path1 + path2(1:M));
       end
       sum_sig += tx_fdm * tx_fdm';
-
+      
       rx_fdm = real(tx_fdm);
 
       % AWGN noise
@@ -162,15 +216,51 @@ function sim_out = freq_off_est_test(sim_in)
 
       [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = ...
           get_pilot(pilot_lut_index, prev_pilot_lut_index, M); 
-      [foff_coarse S1 S2] = rx_est_freq_offset(rx_fdm_delay, pilot, prev_pilot, M);
+      [foff_est S1 S2] = rx_est_freq_offset(rx_fdm_delay, pilot, prev_pilot, M);
       pilot_lpf1_log = [pilot_lpf1_log pilot_lpf1(Npilotlpf-M+1:Npilotlpf)];
       S1_log(f,:) = fftshift(S1);
+     
+      % raw estimate
+      
+      foff_log(ne,f) = foff_est;
+      maxcf_log(ne,f) = max(abs(S1));
+
+      % median filter post-processed
+
+      foff_median(1:Nmedian-1) = foff_median(2:Nmedian);
+      foff_median(Nmedian) = foff_est;
+      foff_median_log(ne,f) = foff_coarse = median(foff_median);
+
+      % state machine post-processed
+
+      next_state = state;
+      if state == 0
+        if abs(foff_est - fest_current) > fdelta
+          fest_candidate = foff_est;
+          candidate_count = 0; 
+          next_state = 1;
+        end
+      end
+      if state == 1
+         if abs(foff_est - fest_candidate) > fdelta
+           next_state = 0;
+         end
+         candidate_count++; 
+         if candidate_count > candidate_thresh
+           fest_current = fest_candidate;
+           next_state = 1;
+        end
+      end
+      state = next_state;
+      foff_statemach_log(ne,f) = fest_current;
 
-      foff_log(ne,f) = foff_coarse;
-
-      if (f > startup_delay) && (abs(foff_coarse - foff_hz) < allowable_error)
+      if (f > startup_delay) && (abs(foff_est - foff_hz) < allowable_error)
         hits++;
       end
+
+      if length(EbNovec) == 1
+        [spectrogram(f,:) spec_states] = spectrogram_update(rx_fdm, M, spec_states);
+      end
     end
 
     % results for this EbNo value
@@ -179,6 +269,8 @@ function sim_out = freq_off_est_test(sim_in)
     sim_out.hits = hits;
     sim_out.hits_percent = 100*sim_out.hits/(frames-startup_delay);
     sim_out.SNRvec(ne) = SNR;
+    sim_out.tx_fdm_log = tx_fdm_log;
+    sim_out.rx_fdm_log = rx_fdm_log;
 
     % noise we have measures is 4000 Hz wide, we want noise in 3000 Hz BW
 
@@ -192,21 +284,43 @@ function sim_out = freq_off_est_test(sim_in)
     if length(EbNovec) == 1
       figure(1)
       clf;
+      subplot(311)
       plot(foff_log(ne,:))
+      axis([1 frames -200 200]);
+      ylabel("Freq offset estimate")
+      subplot(312)
+      plot(foff_median_log(ne,:))
+      axis([1 frames -200 200]);
+      ylabel("Freq offset estimate")
+      subplot(313)
+      plot(foff_statemach_log(ne,:))
+      axis([1 frames -200 200]);
       xlabel("Frames")
       ylabel("Freq offset estimate")
+      grid;
 
       figure(2)
       clf;
-      hist(foff_log(ne,:));
+      plot(maxcf_log(ne,:))
+      axis([1 frames -0 300]);
+      xlabel("Frames")
+      ylabel("max(abs(S1))")
+      grid;
 
       figure(3)
       [n m] = size(S1_log);
-      mesh(-200+400*(0:m-1)/256,1:n,abs(S1_log(:,:)))
+      mesh(-200+400*(0:m-1)/256,1:n,abs(S1_log(:,:)));
+      xlabel('Freq (Hz)'); ylabel('Frame num'); zlabel("max(abs(S1))")
 
       figure(4)
-      clf;
-      spec(rx_fdm_log,8000);
+      clf
+      [n m] = size(spectrogram);
+      lower = floor(500*m/4000); upper = floor(2500*m/4000);
+      mesh(lower:upper,1:n,spectrogram(:,lower:upper));
+      xlabel('Freq (Hz)'); ylabel('Frame num'); zlabel('Amplitude (dB)');
+
+      sim_out.spec = spectrogram;
+      sim_out.tx_fdm_log = spectrogram;
     end
   end
 end
@@ -215,63 +329,77 @@ end
 % Run Automated Tests
 % ---------------------------------------------------------------------
 
-more off;
+figure(5); h=freqz(pilot_coeff,1,4000); plot(20*log10(abs(h(1:1000)))); grid
 
-% Test 2 - range of Eb/No (SNRs) in multipath channel
+more off;
 
-sim_in.EbNovec = 0:10;
-sim_in.delay = 0;
+sim_in.EbNovec = 3;
 sim_in.hf_sim = 1;
 sim_in.hf_delay_ms = 2;
+sim_in.delay = M/2;
 sim_in.frames = Rs*10;
-sim_in.foff_hz = 0;
+sim_in.foff_hz = 50;
 sim_in.startup_delay = 10;
 sim_in.allowable_error = 5;
 
 sim_out = freq_off_est_test(sim_in);
 
-figure(5)
-clf
-subplot(211)
-plot(sim_in.EbNovec,sim_out.foff_sd)
-hold on;
-plot(sim_in.EbNovec,sim_out.foff_sd,'+')
-hold off;
-xlabel("Eb/No (dB)")
-ylabel("Std Dev")
-axis([(min(sim_in.EbNovec)-1) (max(sim_in.EbNovec)+1) -1 10]);
-
-if 0
- Test 1 - range of Eb/No (SNRs) in AWGN channel
-
-sim_in.EbNovec = 0:10;
-sim_in.delay = M/2;
-sim_in.frames = 20;
-sim_in.foff_hz = 0;
-sim_in.startup_delay = 10;
-sim_in.allowable_error = 5;
+% Test 1 - range of Eb/No (SNRs) in AWGN channel
+
+function test1
+  sim_in.EbNovec = 0:10;
+  sim_in.delay = M/2;
+  sim_in.frames = 20;
+  sim_in.foff_hz = 50;
+  sim_in.startup_delay = 10;
+  sim_in.allowable_error = 5;
+
+  sim_out = freq_off_est_test(sim_in);
+
+  figure(4)
+  clf
+  subplot(211)
+  plot(sim_in.EbNovec,sim_out.foff_sd)
+  hold on;
+  plot(sim_in.EbNovec,sim_out.foff_sd,'+')
+  hold off;
+  xlabel("Eb/No (dB)")
+  ylabel("Std Dev")
+  axis([(min(sim_in.EbNovec)-1) (max(sim_in.EbNovec)+1) -1 10]);
+
+  subplot(212)
+  plot(sim_out.SNRvec,sim_out.foff_sd)
+  hold on;
+  plot(sim_out.SNRvec,sim_out.foff_sd,'+')
+  hold off;
+  xlabel("SNR (dB)")
+  ylabel("Std Dev")
+  axis([(min(sim_out.SNRvec)-1)  (max(sim_out.SNRvec)+1) -1 10]);
+end
 
-sim_out = freq_off_est_test(sim_in);
+% Test 2 - range of Eb/No (SNRs) in multipath channel
 
-figure(4)
-clf
-subplot(211)
-plot(sim_in.EbNovec,sim_out.foff_sd)
-hold on;
-plot(sim_in.EbNovec,sim_out.foff_sd,'+')
-hold off;
-xlabel("Eb/No (dB)")
-ylabel("Std Dev")
-axis([(min(sim_in.EbNovec)-1) (max(sim_in.EbNovec)+1) -1 10]);
-
-subplot(212)
-plot(sim_out.SNRvec,sim_out.foff_sd)
-hold on;
-plot(sim_out.SNRvec,sim_out.foff_sd,'+')
-hold off;
-xlabel("SNR (dB)")
-ylabel("Std Dev")
-axis([(min(sim_out.SNRvec)-1)  (max(sim_out.SNRvec)+1) -1 10]);
-
-% Test 2 - range of Eb/No (SNRs) in AWGN channel
+function test2
+  sim_in.EbNovec = 0:10;
+  sim_in.delay = 2;
+  sim_in.hf_sim = 0;
+  sim_in.hf_delay_ms = 2;
+  sim_in.frames = Rs*10;
+  sim_in.foff_hz = 0;
+  sim_in.startup_delay = 10;
+  sim_in.allowable_error = 5;
+
+  sim_out = freq_off_est_test(sim_in);
+
+  figure(5)
+  clf
+  subplot(211)
+  plot(sim_in.EbNovec,sim_out.foff_sd)
+  hold on;
+  plot(sim_in.EbNovec,sim_out.foff_sd,'+')
+  hold off;
+  xlabel("Eb/No (dB)")
+  ylabel("Std Dev")
+  axis([(min(sim_in.EbNovec)-1) (max(sim_in.EbNovec)+1) -1 10]);
 end
+