C and Octave coherent psk modem code match, all tests passing yayyyyy
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Thu, 2 Apr 2015 06:25:41 +0000 (06:25 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Thu, 2 Apr 2015 06:25:41 +0000 (06:25 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@2101 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/octave/autotest.m
codec2-dev/octave/cohpsk.m
codec2-dev/octave/tcohpsk.m
codec2-dev/src/codec2_cohpsk.h
codec2-dev/src/cohpsk.c
codec2-dev/src/cohpsk_internal.h
codec2-dev/unittest/tcohpsk.c

index 0a772e40488f497372a65040b51b5319934bbecf..b6623d8a3d32d4c7b7a624f64104be260f7b3745 100644 (file)
@@ -53,13 +53,19 @@ function check(a, b, test_name, tol)
   end
 
   [m n] = size(a);
+  if m > n
+    ll = m;
+  else
+    ll = n;
+  end
+
   printf("%s", test_name);
   for i=1:(25-length(test_name))
     printf(".");
   end
   printf(": ");  
   
-  e = sum(sum(abs(a - b))/n);
+  e = sum(sum(abs(a - b))/ll);
   if e < tol
     printf("OK\n");
     passes++;
index 2207f3b2b4fee9a6a2f02b5f4dd67b7cacc341b4..2cfa41ce5ed47378e145d1f2b77ca8b769d59426 100644 (file)
@@ -224,9 +224,11 @@ function [rx_symb rx_bits amp_ phi_ EsNo_ cohpsk] = qpsk_symbols_to_bits(cohpsk,
     for c=1:Nc
       for r=1:Nsymbrow
         i = (c-1)*Nsymbrow + r;
-        rx_symb(i) = ct_symb_buf(2+r,c)*exp(-j*phi_(c));
+        rx_symb(r,c) = ct_symb_buf(2+r,c)*exp(-j*phi_(r,c));
+        %rx_symb(r,c) = ct_symb_buf(2+r,c);
         rx_symb_linear(i) = rx_symb(i);
         rx_bits((2*(i-1)+1):(2*i)) = qpsk_demod(rx_symb(r,c));
+        %printf("phi_ %d %d %f %f\n", r,c,real(exp(-j*phi_(r,c))), imag(exp(-j*phi_(r,c))));
       end
     end
 
@@ -483,11 +485,15 @@ function [next_sync cohpsk] = coarse_freq_offset_est(cohpsk, fdmdv, ch_fdm_frame
     sc = Ndft/Fs;
     bin_start = floor(f_start*sc+0.5)+1;
     bin_stop = floor(f_stop*sc+0.5)+1;
+
+    %printf("f_start: %f f_stop: %f sc: %f bin_start: %d bin_stop: %d\n", f_start, f_stop, sc, bin_start, bin_stop);
+
     x = bin_start-1:bin_stop-1;
     bin_est = x*T(bin_start:bin_stop)'/sum(T(bin_start:bin_stop));
-    cohpsk.f_est = bin_est/sc;
-    printf("bin_est: %f coarse freq est: %f\n", bin_est, cohpsk.f_est);
+    cohpsk.f_est = floor(bin_est/sc+0.5);
+    printf("coarse freq est: %f\n", cohpsk.f_est);
     next_sync = 1;
+    
   end
 
 endfunction
@@ -495,7 +501,7 @@ endfunction
 
 % returns index of start of frame and fine freq offset
 
-function [next_sync cohpsk] = frame_sync_fine_timing_est(cohpsk, ch_symb, sync, next_sync)
+function [next_sync cohpsk] = frame_sync_fine_freq_est(cohpsk, ch_symb, sync, next_sync)
   ct_symb_buf   = cohpsk.ct_symb_buf;
   Nct_sym_buf   = cohpsk.Nct_sym_buf;
   Rs            = cohpsk.Rs;
@@ -552,7 +558,7 @@ function [next_sync cohpsk] = frame_sync_fine_timing_est(cohpsk, ch_symb, sync,
       next_sync = 4;
     else
       next_sync = 0;
-      printf("  back to coarse freq offset ets...\n");
+      printf("  back to coarse freq offset est...\n");
     end
   end
 endfunction
@@ -571,8 +577,8 @@ function acohpsk = fine_freq_correct(acohpsk, sync, next_sync);
 
   if (next_sync == 4) || (sync == 4)
 
-    if next_sync == 4
-
+    if (next_sync == 4) && (sync == 2)
+      
       % first frame, we've just gotten sync so fine freq correct all Nsymbrowpilot+2 samples
 
       ct_symb_ff_buf = acohpsk.ct_symb_buf(acohpsk.ct+1:acohpsk.ct+acohpsk.Nsymbrowpilot+2,:);
@@ -582,14 +588,14 @@ function acohpsk = fine_freq_correct(acohpsk, sync, next_sync);
       end
 
     else
-      
+
       % second and subsequent frames, just fine freq correct the latest Nsymbrowpilot
 
-      ct_symb_ff_buf(1:2,:) = ct_symb_ff_buf(Nsymbrowpilot+1:Nsymbrowpilot+2,:);
-      ct_symb_ff_buf(3:Nsymbrowpilot+2,:) = acohpsk.ct_symb_buf(acohpsk.ct+3:acohpsk.ct+acohpsk.Nsymbrowpilot+2,:);
+      ct_symb_ff_buf(1:2,:) = ct_symb_ff_buf(acohpsk.Nsymbrowpilot+1:acohpsk.Nsymbrowpilot+2,:);
+      ct_symb_ff_buf(3:acohpsk.Nsymbrowpilot+2,:) = acohpsk.ct_symb_buf(acohpsk.ct+3:acohpsk.ct+acohpsk.Nsymbrowpilot+2,:);
       for r=3:acohpsk.Nsymbrowpilot+2
-        afdmdv.ff_phase *= afdmdv.ff_rect';
-        ct_symb_ff_buf(r,:) *= afdmdv.ff_phase;
+        acohpsk.ff_phase *= acohpsk.ff_rect';
+       ct_symb_ff_buf(r,:) *= acohpsk.ff_phase;
       end
 
     end
index f2f497cac3036295b4488d175e22d632fecd2283..f55113ab914f715f0e325069a154ae9e8c476151 100644 (file)
@@ -104,11 +104,13 @@ rx_phi_log = [];
 ch_symb_log = [];
 rx_symb_log = [];
 rx_bits_log = [];
+tx_bits_prev_log = [];
 noise_log = [];
 nerr_log = [];
 tx_baseband_log = [];
 tx_fdm_frame_log = [];
 ch_fdm_frame_log = [];
+rx_fdm_frame_bb_log = [];
 
 phase = 1;
 freq = exp(j*2*pi*foff/acohpsk.Rs);
@@ -123,6 +125,7 @@ rx_baseband_log = [];
 rx_fdm_frame_log = [];
 f_err_log = [];
 f_err_fail = 0;
+ct_symb_ff_log = [];
 
 phase_ch = 1;
 sync = 0;
@@ -208,7 +211,7 @@ for i=1:frames
   end
   mag = abs(fbb_phase_rx);
   fbb_phase_rx /= mag;
-  rx_fdm_frame_bb_log = [rx_fdm_log rx_fdm_frame_bb];
+  rx_fdm_frame_bb_log = [rx_fdm_frame_bb_log rx_fdm_frame_bb];
   
   % sample rate demod processing
 
@@ -232,13 +235,9 @@ for i=1:frames
 
   % coarse timing (frame sync) and initial fine freq est ---------------------------------------------
   
-  [next_sync acohpsk] = frame_sync_fine_timing_est(acohpsk, ch_symb, sync, next_sync);
-
-  if (i==1000)
-    xx
-  end
-
+  [next_sync acohpsk] = frame_sync_fine_freq_est(acohpsk, ch_symb, sync, next_sync);
   acohpsk = fine_freq_correct(acohpsk, sync, next_sync);
+  ct_symb_ff_log = [ct_symb_ff_log; acohpsk.ct_symb_ff_buf(1:acohpsk.Nsymbrowpilot,:)];
 
   if (sync == 4) || (next_sync == 4)  
     [rx_symb rx_bits amp_ phi_ EsNo_] = qpsk_symbols_to_bits(acohpsk, acohpsk.ct_symb_ff_buf);
@@ -246,17 +245,17 @@ for i=1:frames
     rx_amp_log = [rx_amp_log; amp_];
     rx_phi_log = [rx_phi_log; phi_];
     rx_bits_log = [rx_bits_log rx_bits];
+    tx_bits_prev_log = [tx_bits_prev_log prev_tx_bits2];
 
     % BER stats
 
-    if i > 2
-      error_positions = xor(prev_tx_bits2, rx_bits);
-      Nerrs  += sum(error_positions);
-      nerr_log = [nerr_log sum(error_positions)];
-     Tbits += length(error_positions);
-    end 
+    error_positions = xor(prev_tx_bits2, rx_bits);
+    Nerrs  += sum(error_positions);
+    nerr_log = [nerr_log sum(error_positions)];
+    Tbits += length(error_positions);
   end
 
+  %printf("f: %d sync: %d next_sync: %d\n", i, sync, next_sync);
   sync = sync_state_machine(sync, next_sync);
 
   prev_tx_bits2 = prev_tx_bits;
@@ -272,43 +271,42 @@ stem_sig_and_error(3, 211, real(tx_fdm_log_c(1:n)), real(tx_fdm_frame_log(1:n) -
 stem_sig_and_error(3, 212, imag(tx_fdm_log_c(1:n)), imag(tx_fdm_frame_log(1:n) - tx_fdm_frame_log_c(1:n)), 'tx fdm frame im', [1 n -10 10])
 stem_sig_and_error(4, 211, real(ch_fdm_frame_log_c(1:n)), real(ch_fdm_frame_log(1:n) - ch_fdm_frame_log_c(1:n)), 'ch fdm frame re', [1 n -10 10])
 stem_sig_and_error(4, 212, imag(ch_fdm_frame_log_c(1:n)), imag(ch_fdm_frame_log(1:n) - ch_fdm_frame_log_c(1:n)), 'ch fdm frame im', [1 n -10 10])
+stem_sig_and_error(5, 211, real(rx_fdm_frame_bb_log_c(1:n)), real(rx_fdm_frame_bb_log(1:n) - rx_fdm_frame_bb_log_c(1:n)), 'rx fdm frame bb re', [1 n -10 10])
+stem_sig_and_error(5, 212, imag(rx_fdm_frame_bb_log_c(1:n)), imag(rx_fdm_frame_bb_log(1:n) - rx_fdm_frame_bb_log_c(1:n)), 'rx fdm frame bb im', [1 n -10 10])
 
-if 0
-stem_sig_and_error(4, 211, real(ch_symb_log_c(1:n)), real(ch_symb_log(1:n) - ch_symb_log_c(1:n)), 'ch symb re', [1 n -2 2])
-stem_sig_and_error(4, 212, imag(ch_symb_log_c(1:n)), imag(ch_symb_log(1:n) - ch_symb_log_c(1:n)), 'ch symb im', [1 n -2 2])
-stem_sig_and_error(5, 211, rx_amp_log_c(1:n), rx_amp_log(1:n) - rx_amp_log_c(1:n), 'Amp Est', [1 n -1.5 1.5])
-stem_sig_and_error(5, 212, rx_phi_log_c(1:n), rx_phi_log(1:n) - rx_phi_log_c(1:n), 'Phase Est', [1 n -4 4])
-stem_sig_and_error(6, 211, real(rx_symb_log_c(1:n)), real(rx_symb_log(1:n) - rx_symb_log_c(1:n)), 'rx symb re', [1 n -1.5 1.5])
-stem_sig_and_error(6, 212, imag(rx_symb_log_c(1:n)), imag(rx_symb_log(1:n) - rx_symb_log_c(1:n)), 'rx symb im', [1 n -1.5 1.5])
-stem_sig_and_error(7, 111, rx_bits_log_c(1:n), rx_bits_log(1:n) - rx_bits_log_c(1:n), 'rx bits', [1 n -1.5 1.5])
-end
+[n m] = size(ch_symb_log);
+stem_sig_and_error(6, 211, real(ch_symb_log_c), real(ch_symb_log - ch_symb_log_c), 'ch symb re', [1 n -1.5 1.5])
+stem_sig_and_error(6, 212, imag(ch_symb_log_c), imag(ch_symb_log - ch_symb_log_c), 'ch symb im', [1 n -1.5 1.5])
+stem_sig_and_error(7, 211, real(ct_symb_ff_log_c), real(ct_symb_ff_log - ct_symb_ff_log_c), 'ct symb ff re', [1 n -1.5 1.5])
+stem_sig_and_error(7, 212, imag(ct_symb_ff_log_c), imag(ct_symb_ff_log - ct_symb_ff_log_c), 'ct symb ff im', [1 n -1.5 1.5])
+
+stem_sig_and_error(8, 211, rx_amp_log_c, rx_amp_log - rx_amp_log_c, 'Amp Est', [1 n -1.5 1.5])
+stem_sig_and_error(8, 212, rx_phi_log_c, rx_phi_log - rx_phi_log_c, 'Phase Est', [1 n -4 4])
+stem_sig_and_error(9, 211, real(rx_symb_log_c), real(rx_symb_log - rx_symb_log_c), 'rx symb re', [1 n -1.5 1.5])
+stem_sig_and_error(9, 212, imag(rx_symb_log_c), imag(rx_symb_log - rx_symb_log_c), 'rx symb im', [1 n -1.5 1.5])
+stem_sig_and_error(10, 111, rx_bits_log_c, rx_bits_log - rx_bits_log_c, 'rx bits', [1 n -1.5 1.5])
 
 check(tx_bits_log, tx_bits_log_c, 'tx_bits');
 check(tx_symb_log, tx_symb_log_c, 'tx_symb');
 check(tx_fdm_frame_log, tx_fdm_frame_log_c, 'tx_fdm_frame');
 check(ch_fdm_frame_log, ch_fdm_frame_log_c, 'ch_fdm_frame');
-
-if 0
-
-check(rx_baseband_log, rx_baseband_log_c, 'rx_baseband',0.01);
-check(rx_filt_log, rx_filt_log_c, 'rx_filt');
+check(rx_fdm_frame_bb_log, rx_fdm_frame_bb_log_c, 'rx_fdm_frame_bb', 0.01);
 check(ch_symb_log, ch_symb_log_c, 'ch_symb',0.01);
+check(ct_symb_ff_log, ct_symb_ff_log_c, 'ct_symb_ff',0.01);
 check(rx_amp_log, rx_amp_log_c, 'rx_amp_log',0.01);
-check(rx_phi_log, rx_phi_log_c, 'rx_phi_log');
+check(rx_phi_log, rx_phi_log_c, 'rx_phi_log',0.01);
 check(rx_symb_log, rx_symb_log_c, 'rx_symb',0.01);
 check(rx_bits_log, rx_bits_log_c, 'rx_bits');
-end
 
 % Determine bit error rate
 
 sz = length(tx_bits_log_c);
-Nerrs_c = sum(xor(tx_bits_log_c(framesize+1:sz-2*framesize), rx_bits_log_c(3*framesize+1:sz)));
-Tbits_c = sz - 2*framesize;
+Nerrs_c = sum(xor(tx_bits_prev_log, rx_bits_log_c));
+Tbits_c = length(tx_bits_prev_log);
 ber_c = Nerrs_c/Tbits_c;
 ber = Nerrs/Tbits;
 printf("EsNodB: %4.1f ber..: %3.2f Nerrs..: %d Tbits..: %d\n", EsNodB, ber, Nerrs, Tbits);
 printf("EsNodB: %4.1f ber_c: %3.2f Nerrs_c: %d Tbits_c: %d\n", EsNodB, ber_c, Nerrs_c, Tbits_c);
-printf("f_err std: %f  fails: %d\n", std(f_err_log), f_err_fail);
 
 % C header file of noise samples so C version gives extacly the same results
 
index 65de8299dd912fe7783ceaadaaa46c0de64773be..60acc0dd86cd94bdc81d528fe58b57e1021dee9e 100644 (file)
@@ -41,7 +41,8 @@ void cohpsk_destroy(struct COHPSK *coh);
 void bits_to_qpsk_symbols(COMP tx_symb[][COHPSK_NC], int tx_bits[], int nbits);
 void qpsk_symbols_to_bits(struct COHPSK *coh, int rx_bits[], COMP ct_symb_buf[][COHPSK_NC]);
 void coarse_freq_offset_est(struct COHPSK *coh, struct FDMDV *fdmdv, COMP ch_fdm_frame[], int sync, int *next_sync);
-void frame_sync_fine_timing_est(struct COHPSK *coh, COMP ch_symb[][COHPSK_NC], int sync, int *next_sync);
-int sync_state_machine(sync, next_sync);
+void frame_sync_fine_freq_est(struct COHPSK *coh, COMP ch_symb[][COHPSK_NC], int sync, int *next_sync);
+void fine_freq_correct(struct COHPSK *coh, int sync, int next_sync);
+int sync_state_machine(int sync, int next_sync);
 
 #endif
index 7818dc886040687af568f0c0383e9df86a9dad2f..89ec876494178082eb183ba1eab49e8f9066eb93 100644 (file)
@@ -105,6 +105,8 @@ struct COHPSK *cohpsk_create(void)
         }
     }
 
+    coh->ff_phase.real = 1.0; coh->ff_phase.imag = 0.0;
+
     return coh;
 }
 
@@ -193,10 +195,10 @@ void bits_to_qpsk_symbols(COMP tx_symb[][PILOTS_NC], int tx_bits[], int nbits)
 
 void qpsk_symbols_to_bits(struct COHPSK *coh, int rx_bits[], COMP ct_symb_buf[][COHPSK_NC])
 {
-    int   r, c, i;
-    COMP  corr, rot, pi_on_4;
+    int   p, r, c, i;
+    COMP  corr, rot, pi_on_4, phi_rect;
     float mag, phi_, amp_;
-    short sampling_points[] = {1, 2, 7, 8};
+    short sampling_points[] = {0, 1, 6, 7};
 
     pi_on_4.real = cosf(M_PI/4); pi_on_4.imag = sinf(M_PI/4);
    
@@ -206,14 +208,14 @@ void qpsk_symbols_to_bits(struct COHPSK *coh, int rx_bits[], COMP ct_symb_buf[][
 
     for(c=0; c<PILOTS_NC; c++) {
         corr.real = 0.0; corr.imag = 0.0; mag = 0.0;
-        for(r=0; r<2*NPILOTSFRAME; r++) {
-            corr = cadd(corr, fcmult(coh->pilot2[r][c], ct_symb_buf[sampling_points[r]][c]));
-            mag  += cabsolute(ct_symb_buf[sampling_points[r]][c]);
+        for(p=0; p<NPILOTSFRAME+2; p++) {
+            corr = cadd(corr, fcmult(coh->pilot2[p][c], ct_symb_buf[sampling_points[p]][c]));
+            mag  += cabsolute(ct_symb_buf[sampling_points[p]][c]);
         }
       
         phi_ = atan2f(corr.imag, corr.real);
-        amp_ =  mag/2*NPILOTSFRAME;
-        for(r=0; r<2*NPILOTSFRAME; r++) {
+        amp_ =  mag/(NPILOTSFRAME+2);
+        for(r=0; r<NSYMROW; r++) {
             coh->phi_[r][c] = phi_;
             coh->amp_[r][c] = amp_;
         }
@@ -222,16 +224,19 @@ void qpsk_symbols_to_bits(struct COHPSK *coh, int rx_bits[], COMP ct_symb_buf[][
     /* now correct phase of data symbols and make decn on bits */
 
     for(c=0; c<PILOTS_NC; c++) {
-        rot.real = cosf(coh->phi_[0][c]); rot.imag = -sinf(coh->phi_[0][c]);
+        phi_rect.real = cosf(coh->phi_[0][c]); phi_rect.imag = -sinf(coh->phi_[0][c]);
+        //rot.real = 1.0; rot.imag = 0.0;
         for (r=0; r<NSYMROW; r++) {
             i = c*NSYMROW + r;
-            coh->rx_symb[r][c] = cmult(ct_symb_buf[NPILOTSFRAME + r][c], rot);
+            coh->rx_symb[r][c] = cmult(ct_symb_buf[NPILOTSFRAME + r][c], phi_rect);
+            //printf("%d %d %f %f\n", r,c, coh->rx_symb[r][c].real, coh->rx_symb[r][c].imag);
+            //printf("phi_ %d %d %f %f\n", r,c, ct_symb_buf[NPILOTSFRAME + r][c].real, ct_symb_buf[NPILOTSFRAME + r][c].imag);
             rot = cmult(coh->rx_symb[r][c], pi_on_4);
             rx_bits[2*i+1] = rot.real < 0;
             rx_bits[2*i]   = rot.imag < 0;
         }
     }
-
+    
 }
 
 
@@ -260,13 +265,14 @@ void coarse_freq_offset_est(struct COHPSK *coh, struct FDMDV *fdmdv, COMP ch_fdm
         sc = (float)COARSE_FEST_NDFT/FS;
         bin_start = floorf(f_start*sc+0.5);
         bin_stop = floorf(f_stop*sc+0.5);
-        // printf("f_start: %f f_stop: %f sc: %f bin_start: %d bin_stop: %d\n",
-        //       f_start, f_stop, sc, bin_start, bin_stop);
+        //printf("f_start: %f f_stop: %f sc: %f bin_start: %d bin_stop: %d\n",
+        //        f_start, f_stop, sc, bin_start, bin_stop);
 
         for(i=0; i<NSYMROWPILOT*M; i++) {
             h = 0.5 - 0.5*cosf(2*M_PI*i/(NSYMROWPILOT*M-1));
             s[i] = fcmult(h, ch_fdm_frame[i]); 
         }
+        
         for (; i<COARSE_FEST_NDFT; i++) {
             s[i].real = 0.0;
             s[i].imag = 0.0;
@@ -277,16 +283,16 @@ void coarse_freq_offset_est(struct COHPSK *coh, struct FDMDV *fdmdv, COMP ch_fdm
         /* find centroid of signal energy inside search window */
 
         num = den = 0.0;
-        for(i=bin_start; i<bin_stop; i++) {
+        for(i=bin_start; i<=bin_stop; i++) {
             magsq = S[i].real*S[i].real + S[i].imag*S[i].imag;
-            num += (float)(i+1)*magsq;
+            num += (float)(i)*magsq;
             den += magsq;
         }
         bin_est = num/den;
-        coh->f_est = bin_est/sc;
+        coh->f_est = floor(bin_est/sc+0.5);
 
-        printf("bin_est: %f coarse freq est: %f\n", bin_est, coh->f_est);
-     
+        printf("coarse freq est: %f\n", coh->f_est);
+        
         *next_sync = 1;
     }
 }
@@ -298,14 +304,16 @@ void coarse_freq_offset_est(struct COHPSK *coh, struct FDMDV *fdmdv, COMP ch_fdm
   AUTHOR......: David Rowe                           
   DATE CREATED: April 2015
 
-  Returns an estimate of frequency offset, advances to next sync state.
+  Returns an estimate of frame sync (coarse timing) offset and fine
+  frequency offset, advances to next sync state if we have a reliable
+  match for frame sync.
 
   TODO: This is very stack heavy for an embedded uC.  Tweak algorthim to use
         a smaller DFT and test.
 
 \*---------------------------------------------------------------------------*/
 
-void frame_sync_fine_timing_est(struct COHPSK *coh, COMP ch_symb[][PILOTS_NC], int sync, int *next_sync)
+void frame_sync_fine_freq_est(struct COHPSK *coh, COMP ch_symb[][PILOTS_NC], int sync, int *next_sync)
 {
     int   sampling_points[] = {0, 1, 6, 7};
     int   r,c,i,p,t;
@@ -339,14 +347,14 @@ void frame_sync_fine_timing_est(struct COHPSK *coh, COMP ch_symb[][PILOTS_NC], i
                 corr.real = 0.0; corr.imag = 0.0; mag = 0.0;
                 for (c=0; c<PILOTS_NC; c++) {
                     for (p=0; p<NPILOTSFRAME+2; p++) {
-                        f_fine_rect.real = cosf(-f_fine*2.0*M_PI*(sampling_points[p]+1.0)/RS);
-                        f_fine_rect.imag = sinf(-f_fine*2.0*M_PI*(sampling_points[p]+1.0)/RS);
+                        f_fine_rect.real = cosf(f_fine*2.0*M_PI*(sampling_points[p]+1.0)/RS);
+                        f_fine_rect.imag = sinf(f_fine*2.0*M_PI*(sampling_points[p]+1.0)/RS);
                         f_corr = cmult(f_fine_rect, coh->ct_symb_buf[t+sampling_points[p]][c]);
                         corr = cadd(corr, fcmult(coh->pilot2[p][c], f_corr));
                         mag  += cabsolute(f_corr);
                     }
                 }
-                //printf("  f: %f  t: %d corr: %f %f\n", f_fine, t, real(corr), imag(corr));
+                //printf("  f: %f  t: %d corr: %f %f\n", f_fine, t, corr.real, corr.imag);
                 if (cabsolute(corr) > max_corr) {
                     max_corr = cabsolute(corr);
                     max_mag = mag;
@@ -357,8 +365,8 @@ void frame_sync_fine_timing_est(struct COHPSK *coh, COMP ch_symb[][PILOTS_NC], i
         }
 
 
-        coh->ff_rect.real = cosf(-coh->f_fine_est*2.0*M_PI/RS);
-        coh->ff_rect.imag = sinf(-coh->f_fine_est*2.0*M_PI/RS);
+        coh->ff_rect.real = cosf(coh->f_fine_est*2.0*M_PI/RS);
+        coh->ff_rect.imag = -sinf(coh->f_fine_est*2.0*M_PI/RS);
         printf("  fine freq f: %f max_corr: %f max_mag: %f ct: %d\n", coh->f_fine_est, max_corr, max_mag, coh->ct);
  
         if (max_corr/max_mag > 0.9) {
@@ -367,18 +375,83 @@ void frame_sync_fine_timing_est(struct COHPSK *coh, COMP ch_symb[][PILOTS_NC], i
         }
         else {
             *next_sync = 0;
-            printf("  back to coarse freq offset ets...\n");
+            printf("  back to coarse freq offset est...\n");
         }
-        //exit(0);
+        
     }
 }
 
 
-int sync_state_machine(sync, next_sync)
+/*---------------------------------------------------------------------------*\
+                                                       
+  FUNCTION....: fine_freq_correct()         
+  AUTHOR......: David Rowe                           
+  DATE CREATED: April 2015
+
+  Fine frequency correction of symbols at rate Rs.
+
+\*---------------------------------------------------------------------------*/
+
+void fine_freq_correct(struct COHPSK *coh, int sync, int next_sync) {
+    int   r,c;
+    float mag;
+
+  /*
+    We can decode first frame that we achieve sync.  Need to fine freq
+    correct all of it's symbols, including pilots.  From then on, just
+    correct new symbols into frame.  make copy, so if we lose sync we
+    havent fine freq corrected ct_symb_buf if next_sync == 4 correct
+    all 8 if sync == 2 correct latest 6.
+  */
+
+  if ((next_sync == 4) || (sync == 4)) {
+
+      if ((next_sync == 4) && (sync == 2)) {
+          
+          /* first frame, we've just gotten sync so fine freq correct all Nsymbrowpilot+2 samples */
+
+          for(r=0; r<NSYMROWPILOT+2; r++) {
+              coh->ff_phase = cmult(coh->ff_phase, cconj(coh->ff_rect));
+              for(c=0; c<PILOTS_NC; c++) {
+                  coh->ct_symb_ff_buf[r][c] = coh->ct_symb_buf[coh->ct+r][c];
+                  coh->ct_symb_ff_buf[r][c] = cmult(coh->ct_symb_ff_buf[r][c], coh->ff_phase);
+              }
+          }
+      }
+      else {
+          
+          /* second and subsequent frames, just fine freq correct the latest Nsymbrowpilot */
+
+          for(r=0; r<2; r++) {
+              for(c=0; c<PILOTS_NC; c++) {
+                  coh->ct_symb_ff_buf[r][c] = coh->ct_symb_ff_buf[r+NSYMROWPILOT][c];
+              }
+          }
+          
+          for(; r<NSYMROWPILOT+2; r++) {
+              coh->ff_phase = cmult(coh->ff_phase, cconj(coh->ff_rect));
+              for(c=0; c<PILOTS_NC; c++) {
+                  coh->ct_symb_ff_buf[r][c] = coh->ct_symb_buf[coh->ct+r][c];
+                  //printf("%d %d %f %f\n", r,c,coh->ct_symb_ff_buf[r][c].real, coh->ct_symb_ff_buf[r][c].imag);
+                  coh->ct_symb_ff_buf[r][c] = cmult(coh->ct_symb_ff_buf[r][c], coh->ff_phase);
+              }
+          }
+      }
+
+      mag = cabsolute(coh->ff_phase);
+      coh->ff_phase.real /= mag;
+      coh->ff_phase.imag /= mag;
+  }
+}
+
+
+int sync_state_machine(int sync, int next_sync)
 {
     if (sync == 1)
         next_sync = 2;
     sync = next_sync;
+
+    return sync;
 }
 
 
index d4b3175ce7f05d72c3a4283671fa10c1da6645af..4f5a7222064371bd1f1a1ef7e59277627f4d4906 100644 (file)
@@ -41,9 +41,11 @@ struct COHPSK {
     kiss_fft_cfg fft_coarse_fest;
     float        f_est;
     COMP         ct_symb_buf[NCT_SYMB_BUF][PILOTS_NC];
+    int          ct;                                 /* coarse timing offset in symbols                       */
     float        f_fine_est;
-    int          ct;
     COMP         ff_rect;
+    COMP         ff_phase;
+    COMP         ct_symb_ff_buf[NSYMROWPILOT+2][PILOTS_NC];
 };
 
 
index 350e4306182fb7f6e9f1e1852af26d0f8902f240..b0916083ef46e71ac9527f0a232126f0393e6c98 100644 (file)
@@ -68,7 +68,7 @@ int main(int argc, char *argv[])
     COMP           ch_fdm_frame_log[M*NSYMROWPILOT*FRAMES];
     COMP           rx_fdm_frame_bb_log[M*NSYMROWPILOT*FRAMES];
     COMP           ch_symb_log[NSYMROWPILOT*FRAMES][PILOTS_NC];
-
+    COMP           ct_symb_ff_log[NSYMROWPILOT*FRAMES][PILOTS_NC];
     float          rx_amp_log[NSYMROW*FRAMES][PILOTS_NC];
     float          rx_phi_log[NSYMROW*FRAMES][PILOTS_NC];
     COMP           rx_symb_log[NSYMROW*FRAMES][PILOTS_NC];
@@ -94,13 +94,12 @@ int main(int argc, char *argv[])
     int            rx_baseband_log_col_index = 0;
     COMP           rx_baseband_log[PILOTS_NC][(M+M/P)*NSYMROWPILOT*FRAMES];
 
-    int            ct;
-    int            sync, next_sync;
+    int            sync, next_sync, log_bits;
 
     coh = cohpsk_create();
     assert(coh != NULL);
 
-    log_r = log_data_r = noise_r = 0;
+    log_r = log_data_r = noise_r = log_bits = 0;
     ptest_bits_coh = (int*)test_bits_coh;
     ptest_bits_coh_end = (int*)test_bits_coh + sizeof(test_bits_coh)/sizeof(int);
 
@@ -196,14 +195,16 @@ int main(int argc, char *argv[])
 
         /* coarse timing (frame sync) and initial fine freq est */
   
-        frame_sync_fine_timing_est(coh, ch_symb, sync, &next_sync);
-
-        /* Coherent phase estimation and correction */
-
-        qpsk_symbols_to_bits(coh, rx_bits, ct_symb_buf + ct);
+        frame_sync_fine_freq_est(coh, ch_symb, sync, &next_sync);
+        fine_freq_correct(coh, sync, next_sync);
         
-        sync = sync_state_machine(sync, next_sync);
+        if ((sync == 4) || (next_sync == 4)) {
+           qpsk_symbols_to_bits(coh, rx_bits, coh->ct_symb_ff_buf);
+        }
 
+        //printf("f: %d sync: %d next_sync: %d\n", f, sync, next_sync);
+        sync = sync_state_machine(sync, next_sync);
+        
        /* --------------------------------------------------------*\
                               Log each vector 
        \*---------------------------------------------------------*/
@@ -217,24 +218,28 @@ int main(int argc, char *argv[])
             for(c=0; c<PILOTS_NC; c++) {
                tx_symb_log[log_r][c] = tx_symb[r][c]; 
                ch_symb_log[log_r][c] = ch_symb[r][c]; 
+               ct_symb_ff_log[log_r][c] = coh->ct_symb_ff_buf[r][c]; 
             }
         }
 
-       for(r=0; r<NSYMROW; r++, log_data_r++) {
-            for(c=0; c<PILOTS_NC; c++) {
-               rx_amp_log[log_data_r][c] = coh->amp_[r][c]; 
-               rx_phi_log[log_data_r][c] = coh->phi_[r][c]; 
-               rx_symb_log[log_data_r][c] = coh->rx_symb[r][c]; 
+        if ((sync == 4) || (next_sync == 4)) {
+
+           for(r=0; r<NSYMROW; r++, log_data_r++) {
+                for(c=0; c<PILOTS_NC; c++) {
+                    rx_amp_log[log_data_r][c] = coh->amp_[r][c]; 
+                    rx_phi_log[log_data_r][c] = coh->phi_[r][c]; 
+                    rx_symb_log[log_data_r][c] = coh->rx_symb[r][c]; 
+                }
             }
+            memcpy(&rx_bits_log[COHPSK_BITS_PER_FRAME*log_bits], rx_bits, sizeof(int)*COHPSK_BITS_PER_FRAME);
+            log_bits++;
         }
-       memcpy(&rx_bits_log[COHPSK_BITS_PER_FRAME*f], rx_bits, sizeof(int)*COHPSK_BITS_PER_FRAME);
 
        assert(log_r <= NSYMROWPILOT*FRAMES);
        assert(noise_r <= NSYMROWPILOT*M*FRAMES);
        assert(log_data_r <= NSYMROW*FRAMES);
     }
 
-
     /*---------------------------------------------------------*\
                Dump logs to Octave file for evaluation 
                       by tcohpsk.m Octave script
@@ -251,10 +256,11 @@ int main(int argc, char *argv[])
     octave_save_complex(fout, "rx_baseband_log_c", (COMP*)rx_baseband_log, PILOTS_NC, rx_baseband_log_col_index, (M+M/P)*FRAMES*NSYMROWPILOT);  
     octave_save_complex(fout, "rx_filt_log_c", (COMP*)rx_filt_log, PILOTS_NC, rx_filt_log_col_index, (P+1)*FRAMES*NSYMROWPILOT);  
     octave_save_complex(fout, "ch_symb_log_c", (COMP*)ch_symb_log, NSYMROWPILOT*FRAMES, PILOTS_NC, PILOTS_NC);  
-    octave_save_float(fout, "rx_amp_log_c", (float*)rx_amp_log, NSYMROW*FRAMES, PILOTS_NC, PILOTS_NC);  
-    octave_save_float(fout, "rx_phi_log_c", (float*)rx_phi_log, NSYMROW*FRAMES, PILOTS_NC, PILOTS_NC);  
-    octave_save_complex(fout, "rx_symb_log_c", (COMP*)rx_symb_log, NSYMROW*FRAMES, PILOTS_NC, PILOTS_NC);  
-    octave_save_int(fout, "rx_bits_log_c", rx_bits_log, 1, COHPSK_BITS_PER_FRAME*FRAMES);
+    octave_save_complex(fout, "ct_symb_ff_log_c", (COMP*)ct_symb_ff_log, NSYMROWPILOT*FRAMES, PILOTS_NC, PILOTS_NC);  
+    octave_save_float(fout, "rx_amp_log_c", (float*)rx_amp_log, log_data_r, PILOTS_NC, PILOTS_NC);  
+    octave_save_float(fout, "rx_phi_log_c", (float*)rx_phi_log, log_data_r, PILOTS_NC, PILOTS_NC);  
+    octave_save_complex(fout, "rx_symb_log_c", (COMP*)rx_symb_log, log_data_r, PILOTS_NC, PILOTS_NC);  
+    octave_save_int(fout, "rx_bits_log_c", rx_bits_log, 1, COHPSK_BITS_PER_FRAME*log_bits);
     fclose(fout);
 
     fdmdv_destroy(fdmdv);