rx bits working OK
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Wed, 25 Apr 2012 02:16:09 +0000 (02:16 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Wed, 25 Apr 2012 02:16:09 +0000 (02:16 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@379 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/octave/README_fdmdv.txt
codec2-dev/octave/fdmdv.m
codec2-dev/octave/fdmdv_ut.m
codec2-dev/octave/tfdmdv.m
codec2-dev/src/fdmdv.c
codec2-dev/src/fdmdv.h
codec2-dev/src/fdmdv_internal.h
codec2-dev/unittest/tfdmdv.c

index d0a011dce92c0e9308ef51b57bb26ae511fe7e86..fb1b3eaf2e89e483bc78e8c2812754a0f5e4fe7b 100644 (file)
@@ -15,13 +15,22 @@ TODO
 [ ] test rx level sensitivity, i.e. 0 to 20dB attenuation
 [ ] try to run from shell script
 [ ] arb bit stream input to Octave mod and demod
+[ ] make fine freq indep of amplitude
+    + use angle rather than imag corrd
 [ ] C port and UT framework
-    [ ] doumnent how to use
+    [ ] document how to use
+    [ ] demo modem C test program
+    [ ] freq corr in func, state vars in struct
+    [ ] fine freq est in func, statevars
+    [ ] demod in func with all vars
+    [ ] mod in func with all vars
+    [ ] check with ch impairments    
+    [ ] test with freq offsets
 [ ] document use of fdmdv_ut and fdmdv_demod + PathSim
 [ ] block diagram
+    [ ] maybe in ascii art
 [ ] blog posts(s)
 [ ] Codec 2 web page update
-[ ] demo modem C test program
 
 Tests
 
index 6ce43b712d1a930674fc10aa50701dd3dcf564df..f7d44dae1a97f1b50ee89e2a59eef498e5e5fa6b 100644 (file)
@@ -637,7 +637,7 @@ endfunction
 
 % freq offset state machine.  Moves between acquire and track states based
 % on BPSK pilot sequence.  Freq offset estimator occasionally makes mistakes
-% when used continuously.  So we use it unit we have acquired the BPSK pilot,
+% when used continuously.  So we use it until we have acquired the BPSK pilot,
 % then switch to a more robust tracking algorithm.  If we lose sync we switch
 % back to acquire mode for fast-requisition.
 
index 0a20a42b9033bb8b5d4139acf3b0f97b342bb589..c99447af843c320dc1eb889a485316934bab7206 100644 (file)
@@ -30,7 +30,7 @@ rx_baseband_log = [];
 rx_bits_offset = zeros(Nc*Nb*2);
 prev_tx_symbols = ones(Nc+1,1);
 prev_rx_symbols = ones(Nc+1,1);
-f_err = 0;
+ferr = 0;
 foff = 0;
 foff_log = [];
 tx_baseband_log = [];
@@ -185,8 +185,8 @@ for f=1:frames
   else
     rx_symbols_log = [rx_symbols_log rx_symbols];
   endif
-  [rx_bits sync f_err] = qpsk_to_bits(prev_rx_symbols, rx_symbols, modulation);
-  foff -= 0.5*f_err;
+  [rx_bits sync ferr] = qpsk_to_bits(prev_rx_symbols, rx_symbols, modulation);
+  foff -= 0.5*ferr;
   prev_rx_symbols = rx_symbols;
   sync_log = [sync_log sync];
   
index 776bcc4ad394d8d973455fc288eb4359de94d3b8..0175f7a736d5ae682ca1b17006946ebaeb0ebd5d 100644 (file)
@@ -18,6 +18,7 @@ global fails;
 passes = fails = 0;
 frames = 25;
 prev_tx_symbols = ones(Nc+1,1);
+prev_rx_symbols = ones(Nc+1,1);
 
 % Octave outputs we want to collect for comparison to C version
 
@@ -37,6 +38,9 @@ rx_filt_log = [];
 env_log = [];
 rx_timing_log = [];
 rx_symbols_log = [];
+rx_bits_log = []; 
+ferr_log = [];
+sync_bit_log = [];  
 
 for f=1:frames
 
@@ -70,12 +74,21 @@ for f=1:frames
 
   rx_baseband = fdm_downconvert(rx_fdm, M);
   rx_baseband_log = [rx_baseband_log rx_baseband];
+
   rx_filt = rx_filter(rx_baseband, M);
   rx_filt_log = [rx_filt_log rx_filt];
+
   [rx_symbols rx_timing env] = rx_est_timing(rx_filt, rx_baseband, M);
   env_log = [env_log env];
+
   rx_timing_log = [rx_timing_log rx_timing];
   rx_symbols_log = [rx_symbols_log rx_symbols];
+
+  [rx_bits sync_bit ferr] = qpsk_to_bits(prev_rx_symbols, rx_symbols, 'dqpsk');
+  prev_rx_symbols = rx_symbols;
+  rx_bits_log = [rx_bits_log rx_bits]; 
+  ferr_log = [ferr_log ferr];
+  sync_bit_log = [sync_bit_log sync_bit];  
 end
 
 % Compare to the output from the C version
@@ -154,7 +167,7 @@ plot_sig_and_error(8, 212, imag(S2_log), imag(S2_log - S2_log_c), 'S2 imag' )
 plot_sig_and_error(9, 211, real(foff_log), real(foff_log - foff_log_c), 'Freq Offset' )
 plot_sig_and_error(9, 212, rx_timing_log, rx_timing_log - rx_timing_log_c, 'Rx Timing' )
 
-c=10;
+c=15;
 plot_sig_and_error(10, 211, real(rx_baseband_log(c,:)), real(rx_baseband_log(c,:) - rx_baseband_log_c(c,:)), 'Rx baseband real' )
 plot_sig_and_error(10, 212, imag(rx_baseband_log(c,:)), imag(rx_baseband_log(c,:) - rx_baseband_log_c(c,:)), 'Rx baseband imag' )
 
@@ -164,6 +177,13 @@ plot_sig_and_error(11, 212, imag(rx_filt_log(c,:)), imag(rx_filt_log(c,:) - rx_f
 plot_sig_and_error(12, 211, env_log, env_log - env_log_c, 'env' )
 plot_sig_and_error(12, 212, real(rx_symbols_log(c,:)), real(rx_symbols_log(c,:) - rx_symbols_log_c(c,:)), 'rx symbols' )
 
+st=10*28;
+en = 12*28;
+stem_sig_and_error(13, 211, rx_bits_log_c(st:en), rx_bits_log(st:en) - rx_bits_log_c(st:en), 'RX bits', [1 en-st -1.5 1.5])
+
+plot_sig_and_error(14, 211, ferr_log, ferr_log - ferr_log_c, 'Fine freq error' )
+stem_sig_and_error(14, 212, sync_bit_log_c, sync_bit_log - sync_bit_log_c, 'Sync bit', [1 n -1.5 1.5])
+
 % ---------------------------------------------------------------------------------------
 % AUTOMATED CHECKS ------------------------------------------
 % ---------------------------------------------------------------------------------------
@@ -198,10 +218,13 @@ check(pilot_baseband2_log, pilot_baseband2_log_c, 'pilot lpf2');
 check(S1_log, S1_log_c, 'S1');
 check(S2_log, S2_log_c, 'S2');
 check(foff_log, foff_log_c, 'rx_est_freq_offset');
-check(rx_baseband_log, rx_baseband_log_c, 'fdm_downconvert');
-check(rx_filt_log, rx_filt_log_c, 'fdm_downconvert');
+check(rx_baseband_log, rx_baseband_log_c, 'rx baseband');
+check(rx_filt_log, rx_filt_log_c, 'rx filt');
 check(env_log, env_log_c, 'env');
 check(rx_timing_log, rx_timing_log_c, 'rx_est_timing');
 check(rx_symbols_log, rx_symbols_log_c, 'rx_symbols');
+check(rx_bits_log, rx_bits_log_c, 'rx bits');
+check(ferr_log, ferr_log_c, 'fine freq error');
+check(sync_bit_log, sync_bit_log_c, 'sync bit');
 
 printf("\npasses: %d fails: %d\n", passes, fails);
index 4525a114b8fc3030c3b3df24e3ee6671cce7d051..a70ff11b850616632f69c4fecc4675c6eb68c0bd 100644 (file)
@@ -149,10 +149,17 @@ struct FDMDV *fdmdv_create(void)
        return NULL;
     
     f->current_test_bit = 0;
+    for(i=0; i<NTEST_BITS; i++)
+       f->rx_test_bits_mem[i] = 0;
+
     f->tx_pilot_bit = 0;
+
     for(c=0; c<NC+1; c++) {
        f->prev_tx_symbols[c].real = 1.0;
        f->prev_tx_symbols[c].imag = 0.0;
+       f->prev_rx_symbols[c].real = 1.0;
+       f->prev_rx_symbols[c].imag = 0.0;
+
        for(k=0; k<NFILTER; k++) {
            f->tx_filter_memory[c][k].real = 0.0;
            f->tx_filter_memory[c][k].imag = 0.0;
@@ -201,7 +208,7 @@ struct FDMDV *fdmdv_create(void)
 
     generate_pilot_lut(f->pilot_lut, &f->freq[NC]);
 
-    /* Freq Offset estimation */
+    /* freq Offset estimation states */
 
     for(i=0; i<NPILOTBASEBAND; i++) {
        f->pilot_baseband1[i].real = f->pilot_baseband2[i].real = 0.0;
@@ -834,7 +841,193 @@ float rx_est_timing(COMP rx_symbols[],
        for(k=s,j=0; k<s+NFILTER; k++,j++)
            rx_symbols[c] = cadd(rx_symbols[c], fcmult(gt_alpha5_root[j], rx_baseband_mem_timing[c][k]));
     }
-    printf("rx_symbols[0] = %f %f\n", rx_symbols[0].real, rx_symbols[0].imag);
        
     return rx_timing;
 }
+
+/*---------------------------------------------------------------------------*\
+                                                       
+  FUNCTION....: qpsk_to_bits()      
+  AUTHOR......: David Rowe                           
+  DATE CREATED: 24/4/2012
+
+  Convert DQPSK symbols back to an array of bits, extracts sync bit
+  from DBPSK pilot, and also uses pilot to estimate fine frequency
+  error.
+
+\*---------------------------------------------------------------------------*/
+
+float qpsk_to_bits(int rx_bits[], int *sync_bit, COMP prev_rx_symbols[], COMP rx_symbols[])
+{
+    int   c;
+    COMP  phase_difference[NC+1];
+    COMP  pi_on_4;
+    COMP  d;
+    int   msb, lsb;
+    float ferr;
+
+    pi_on_4.real = cos(PI/4.0);
+    pi_on_4.imag = sin(PI/4.0);
+
+    /* Extra 45 degree clockwise lets us use real and imag axis as
+       decision boundaries */
+
+    for(c=0; c<NC; c++)
+       phase_difference[c] = cmult(cmult(rx_symbols[c], cconj(prev_rx_symbols[c])), pi_on_4);
+                                   
+    /* map (Nc,1) DQPSK symbols back into an (1,Nc*Nb) array of bits */
+
+    for (c=0; c<NC; c++) {
+      d = phase_difference[c];
+      if ((d.real >= 0) && (d.imag >= 0)) {
+         msb = 0; lsb = 0;
+      }
+      if ((d.real < 0) && (d.imag >= 0)) {
+         msb = 0; lsb = 1;
+      }
+      if ((d.real < 0) && (d.imag < 0)) {
+         msb = 1; lsb = 0;
+      }
+      if ((d.real >= 0) && (d.imag < 0)) {
+         msb = 1; lsb = 1;
+      }
+      rx_bits[2*c] = msb;
+      rx_bits[2*c+1] = lsb;
+    }
+    /* Extract DBPSK encoded Sync bit */
+
+    phase_difference[NC] = cmult(rx_symbols[NC], cconj(prev_rx_symbols[NC]));
+    if (phase_difference[NC].real < 0) {
+      *sync_bit = 0;
+      ferr = phase_difference[NC].imag;
+    }
+    else {
+      *sync_bit = 1;
+      ferr = -phase_difference[NC].imag;
+    }
+
+    return ferr;
+}
+/*---------------------------------------------------------------------------*\
+                                                       
+  FUNCTION....: fdmdv_put_test_bits()       
+  AUTHOR......: David Rowe                           
+  DATE CREATED: 24/4/2012
+
+  Accepts nbits from rx and attempts to sync with test_bits sequence.
+  If sync OK measures bit errors.
+
+\*---------------------------------------------------------------------------*/
+
+void fdmdv_put_test_bits(struct FDMDV *f, int *sync, int *bit_errors, int rx_bits[])
+{
+    int   i,j;
+    float ber;
+
+    /* Append to our memory */
+
+    for(i=0,j=FDMDV_BITS_PER_FRAME; i<NTEST_BITS-FDMDV_BITS_PER_FRAME; i++)
+       f->rx_test_bits_mem[i] = f->rx_test_bits_mem[j];
+    for(i=NTEST_BITS-FDMDV_BITS_PER_FRAME,j=0; i<NTEST_BITS; i++)
+       f->rx_test_bits_mem[i] = rx_bits[j];
+    
+    /* see how many bit errors we get when checked against test sequence */
+       
+    *bit_errors = 0;
+    for(i=0; i<FDMDV_BITS_PER_FRAME; i++)
+       *bit_errors += test_bits[i] ^ f->rx_test_bits_mem[i];
+
+    /* if less than a thresh we are aligned and in sync with test sequence */
+
+    ber = *bit_errors/NTEST_BITS;
+  
+    *sync = 0;
+    if (ber < 0.2)
+       *sync = 1;
+}
+
+/*---------------------------------------------------------------------------*\
+                                                       
+  FUNCTION....: freq_state(()       
+  AUTHOR......: David Rowe                           
+  DATE CREATED: 24/4/2012
+
+  Freq offset state machine.  Moves between acquire and track states based
+  on BPSK pilot sequence.  Freq offset estimator occasionally makes mistakes
+  when used continuously.  So we use it until we have acquired the BPSK pilot,
+  then switch to a more robust tracking algorithm.  If we lose sync we switch
+  back to acquire mode for fast-requisition.
+
+\*---------------------------------------------------------------------------*/
+
+int freq_state(int sync_bit, int *state)
+{
+    int next_state, track;
+
+    /* acquire state, look for 6 symbol 010101 sequence from sync bit */
+
+    next_state = *state;
+    switch(*state) {
+    case 0:
+       if (sync_bit == 0)
+           next_state = 1;
+       break;
+    case 1:
+       if (sync_bit == 1)
+           next_state = 2;
+       else 
+           next_state = 0;
+       break;
+    case 2:
+       if (sync_bit == 0)
+           next_state = 3;
+       else 
+           next_state = 0;
+       break;
+    case 3:
+       if (sync_bit == 1)
+           next_state = 4;
+       else 
+           next_state = 0;
+       break;
+    case 4:
+       if (sync_bit == 0)
+           next_state = 5;
+       else 
+           next_state = 0;
+       break;
+    case 5:
+       if (sync_bit == 1)
+           next_state = 6;
+       else 
+           next_state = 0;
+       break;
+       
+       /* states 6 and above are track mode, make sure we keep
+          getting 0101 sync bit sequence */
+
+    case 6:
+       if (sync_bit == 0)
+           next_state = 7;
+       else 
+           next_state = 0;
+
+       break;
+    case 7:
+       if (sync_bit == 1)
+           next_state = 6;
+       else 
+           next_state = 0;
+       break;
+    }
+
+    *state = next_state;
+    if (*state >= 6)
+       track = 1;
+    else
+       track = 0;
+    return track;
+}
index 702dfc6f2135036e09e2ed75868e1cf3d258b2ab..755bc6a24937dfb0ae106c09d9767b6cc09b27fc 100644 (file)
@@ -56,7 +56,7 @@ void          fdmdv_mod(struct FDMDV *fdmdv_state, COMP tx_fdm[], int tx_bits[],
 void          fdmdv_demod(struct FDMDV *fdmdv_state, int rx_bits[], int *sync, float rx_fdm[], int *nin);
     
 void          fdmdv_get_test_bits(struct FDMDV *fdmdv_state, int tx_bits[]);
-void          fdmdv_put_test_bits(struct FDMDV *fdmdv_state, int rx_bits[]);
+void          fdmdv_put_test_bits(struct FDMDV *f, int *sync, int *bit_errors, int rx_bits[]);
     
 float         fdmdv_get_demod_stats(struct FDMDV *fdmdv_state, struct FDMDV_STATS *fdmdv_stats);
 void          fdmdv_get_waterfall_line(struct FDMDV *fdmdv_state, float magnitudes[], int *magnitude_points);
index eec78de01adc25897ac48065bd61f1b04f284d61..9fbedd909d905e87f1f5d8039efc2f9ec1643a1c 100644 (file)
@@ -71,6 +71,7 @@
 
 struct FDMDV {
     int  current_test_bit;
+    int  rx_test_bits_mem[NTEST_BITS];
 
     int  tx_pilot_bit;
     COMP prev_tx_symbols[NC+1];
@@ -93,6 +94,7 @@ struct FDMDV {
     COMP rx_filter_memory[NC+1][NFILTER];
     COMP rx_filter_mem_timing[NC+1][NT*P];
     COMP rx_baseband_mem_timing[NC+1][NFILTERTIMING];
+    COMP prev_rx_symbols[NC+1];
 };
 
 /*---------------------------------------------------------------------------*\
@@ -117,5 +119,7 @@ float rx_est_timing(COMP  rx_symbols[],
                   float env[],
                   COMP  rx_baseband_mem_timing[NC+1][NFILTERTIMING], 
                   int   nin);   
+float qpsk_to_bits(int rx_bits[], int *sync_bit, COMP prev_rx_symbols[], COMP rx_symbols[]);
+int freq_state(int sync_bit, int *state);
 
 #endif
index b7405f1556214510a87793a4e34e7a17cceb39d5..5141de3a07f95579d918bace8bb55d7a2934416d 100644 (file)
@@ -61,7 +61,10 @@ int main(int argc, char *argv[])
     float         rx_timing;
     float         env[NT*P];
     COMP          rx_symbols[NC+1];
-
+    int           rx_bits[FDMDV_BITS_PER_FRAME];
+    float         ferr;
+    int           sync_bit;
     int           tx_bits_log[FDMDV_BITS_PER_FRAME*FRAMES];
     COMP          tx_symbols_log[(NC+1)*FRAMES];
     COMP          tx_baseband_log[(NC+1)][M*FRAMES];
@@ -80,7 +83,10 @@ int main(int argc, char *argv[])
     float         env_log[NT*P*FRAMES];
     float         rx_timing_log[FRAMES];
     COMP          rx_symbols_log[NC+1][FRAMES];
-                         
+    int           rx_bits_log[FDMDV_BITS_PER_FRAME*FRAMES];
+    float         ferr_log[FRAMES];
+    int           sync_bit_log[FRAMES];
+
     FILE         *fout;
     int           f,c,i;
 
@@ -106,7 +112,7 @@ int main(int argc, char *argv[])
 
        /* demodulator ----------------------------------------*/
 
-       /* Freq offset estimation and correction */
+       /* freq offset estimation and correction */
 
        foff = rx_est_freq_offset(fdmdv, rx_fdm, nin);
 
@@ -121,10 +127,14 @@ int main(int argc, char *argv[])
            rx_fdm_fcorr[i].imag = 0.0;
        }
        
+       /* baseband processing */
+
        fdm_downconvert(rx_baseband, rx_fdm_fcorr, fdmdv->phase_rx, fdmdv->freq, nin);
        rx_filter(rx_filt, rx_baseband, fdmdv->rx_filter_memory, nin);
        rx_timing = rx_est_timing(rx_symbols, rx_filt, rx_baseband, fdmdv->rx_filter_mem_timing, env, fdmdv->rx_baseband_mem_timing, nin);       
-
+       ferr = qpsk_to_bits(rx_bits, &sync_bit, fdmdv->prev_rx_symbols, rx_symbols);
+       memcpy(fdmdv->prev_rx_symbols, rx_symbols, sizeof(COMP)*(NC+1));
+           
        /* save log of outputs ------------------------------------------------------*/
 
        memcpy(&tx_bits_log[FDMDV_BITS_PER_FRAME*f], tx_bits, sizeof(int)*FDMDV_BITS_PER_FRAME);
@@ -166,9 +176,16 @@ int main(int argc, char *argv[])
        rx_timing_log[f] = rx_timing;
        for(c=0; c<NC+1; c++)
            rx_symbols_log[c][f] = rx_symbols[c];
+       
+       /* qpsk_to_bits() */
+
+       memcpy(&rx_bits_log[FDMDV_BITS_PER_FRAME*f], rx_bits, sizeof(int)*FDMDV_BITS_PER_FRAME);
+       ferr_log[f] = ferr;
+       sync_bit_log[f] = sync_bit;
     }
 
-    /* dump logs to Octave file for evaluation by tfdmdv.m Octave script */
+
+    /* dump logs to Octave file for evaluation by tfdmdv.m Octave script ------------------------*/
 
     fout = fopen("tfdmdv_out.txt","wt");
     assert(fout != NULL);
@@ -190,6 +207,9 @@ int main(int argc, char *argv[])
     octave_save_float(fout, "env_log_c", env_log, 1, NT*P*FRAMES);  
     octave_save_float(fout, "rx_timing_log_c", rx_timing_log, 1, FRAMES);  
     octave_save_complex(fout, "rx_symbols_log_c", (COMP*)rx_symbols_log, (NC+1), FRAMES, FRAMES);  
+    octave_save_int(fout, "rx_bits_log_c", rx_bits_log, 1, FDMDV_BITS_PER_FRAME*FRAMES);
+    octave_save_float(fout, "ferr_log_c", ferr_log, 1, FRAMES);  
+    octave_save_int(fout, "sync_bit_log_c", sync_bit_log, 1, FRAMES);  
     fclose(fout);
 
     codec2_destroy(fdmdv);