reasonable results on fading channels for C version of modem, still testing
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Wed, 27 May 2015 07:57:46 +0000 (07:57 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Wed, 27 May 2015 07:57:46 +0000 (07:57 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@2153 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/octave/tcohpsk.m
codec2-dev/octave/test_cohpsk_ch.m [new file with mode: 0644]
codec2-dev/src/cohpsk.c
codec2-dev/unittest/test_cohpsk_ch.c

index ee6eb3149a4ba42e383c2878ca83a186623e1704..b0b4a1ea9f1026ab2d4ef04265f2ebb9a21d6b1e 100644 (file)
@@ -56,9 +56,9 @@ randn('state',1);
 
 % select which test  ----------------------------------------------------------
 
-test = 'compare to c';
+%test = 'compare to c';
 %test = 'awgn';
-%test = 'fading';
+test = 'fading';
 
 % some parameters that can be over ridden, e.g. to disable parts of modem
 
@@ -84,27 +84,27 @@ end
 % should be BER around 0.015 to 0.02
 
 if strcmp(test, 'awgn')
-  frames = 100;
+  frames = 10;
   foff =  0;
   dfoff = -0/Fs;
   EsNodB = 8;
   fading_en = 0;
   hf_delay_ms = 2;
   compare_with_c = 0;
-  sample_rate_ppm = -1500;
+  sample_rate_ppm = 0;
 end
 
 % Similar to AWGN - should be BER around 0.015 to 0.02
 
 if strcmp(test, 'fading');
   frames = 100;
-  foff = -53.1;
+  foff = 55;
   dfoff = 0.0/Fs;
   EsNodB = 12;
   fading_en = 1;
   hf_delay_ms = 2;
   compare_with_c = 0;
-  sample_rate_ppm = -100;
+  sample_rate_ppm = 0;
 end
 
 EsNo = 10^(EsNodB/10);
@@ -228,6 +228,7 @@ ptx_bits_coh = 1;
 
 Nerrs = Tbits = 0;
 prev_tx_bits = prev_tx_bits2 = [];
+error_positions_hist = zeros(1,framesize);
 
 phase_ch = 1;
 sync = initial_sync;
@@ -482,6 +483,7 @@ for f=1:frames;
       Nerrs  += sum(error_positions);
       nerr_log = [nerr_log sum(error_positions)];
       Tbits += length(error_positions);
+      error_positions_hist += error_positions;
     end
     printf("\r  [%d]", f);
   end
@@ -659,8 +661,15 @@ else
   clf
   h = freqz(b,a,Fs/2);
   plot(20*log10(abs(h)))
-  axis([1 Fs/2 -50 0])
+  axis([1 Fs/2 -20 0])
   grid
+  title('SSB tx filter')
+
+  figure(9)
+  clf
+  plot(error_positions_hist)    
+  title('histogram of bit errors')                               
+
 end
 
 
@@ -686,3 +695,24 @@ function write_noise_file(uvnoise_log)
 
   fclose(f);
 endfunction
+
+
+% function to write float fading samples for use by C programs
+
+function write_noise_file(raw_file_name, Fs, len_samples)
+  [spread spread_2ms hf_gain] = init_hf_model(Fs, len_samples);
+ hf_gain
+  % interleave real imag samples
+
+  inter = zeros(1,len_samples*4);
+  inter(1:4) = hf_gain;
+  for i=1:len_samples
+    inter(i*4+1) = real(spread(i));
+    inter(i*4+2) = imag(spread(i));
+    inter(i*4+3) = real(spread_2ms(i));
+    inter(i*4+4) = imag(spread_2ms(i));
+  end
+  f = fopen(raw_file_name,"wb");
+  fwrite(f, inter, "float32");
+  fclose(f);
+endfunction
diff --git a/codec2-dev/octave/test_cohpsk_ch.m b/codec2-dev/octave/test_cohpsk_ch.m
new file mode 100644 (file)
index 0000000..7344664
--- /dev/null
@@ -0,0 +1,21 @@
+% test_cohpsk_ch.m
+% David Rowe May 2015
+%
+% Plot outputs from test_coh_psk_ch.c
+
+Nc=7; Nd=2;
+
+load ../build_linux/unittest/test_cohpsk_ch_out.txt
+  
+figure(3)
+clf;
+
+% plot combined signals to show diversity gains
+
+combined = rx_symb_log_c(:,1:Nc);
+for d=2:Nd
+  combined += rx_symb_log_c(:, (d-1)*Nc+1:d*Nc);
+end
+plot(combined*exp(j*pi/4)/sqrt(Nd),'+')
+title('Scatter');
+axis([-2 2 -2 2])
index 8806e52671423faf04e9e7b13f8af39004a56149..2c880f81a8b76a4c0602cea2b928302de47b87f1 100644 (file)
@@ -627,8 +627,8 @@ void cohpsk_mod(struct COHPSK *coh, COMP tx_fdm[], int tx_bits[])
     for(r=0; r<NSYMROWPILOT; r++) {
         for(c=0; c<COHPSK_NC*ND; c++) 
             tx_onesym[c] = tx_symb[r][c];         
-        tx_filter_and_upconvert(&tx_fdm[r*COHPSK_M], fdmdv->Nc , tx_onesym, fdmdv->tx_filter_memory, 
-                                fdmdv->phase_tx, fdmdv->freq, &fdmdv->fbb_phase_tx, fdmdv->fbb_rect);
+        tx_filter_and_upconvert_coh(&tx_fdm[r*COHPSK_M], COHPSK_NC*ND , tx_onesym, fdmdv->tx_filter_memory, 
+                                    fdmdv->phase_tx, fdmdv->freq, &fdmdv->fbb_phase_tx, fdmdv->fbb_rect);
     }
 }
 
index cf4d6bbc1996fd0e3e00e603e89ae460b015e983..f304eaeca3032f25deb4250203e4aa0f42309d34 100644 (file)
 #include "octave.h"
 #include "comp_prim.h"
 #include "noise_samples.h"
+#include "cohpsk_defs.h"
+#include "cohpsk_internal.h"
 
-#define FS          8000
 #define FRAMES      100
-#define FOFF_HZ     10.5
-#define ES_NO_DB     8.0
+#define SYNC_FRAMES 12                    /* sync state uses up extra log storage as we reprocess several times */
+#define FRAMESL     (SYNC_FRAMES*FRAMES)  /* worst case is every frame is out of sync                           */
+
+#define FOFF_HZ      0.0
+#define ES_NO_DB     80.0
 #define HF_DELAY_MS  2.0
-#define HF_GAIN      1.423599
+
+#define CH_BUF_SZ (4*COHPSK_SAMPLES_PER_FRAME)
 
 #define FADING_FILE_NAME "../../raw/fading_samples.float"
 
@@ -53,7 +58,11 @@ int main(int argc, char *argv[])
     int            tx_bits[COHPSK_BITS_PER_FRAME];
     COMP           tx_fdm[COHPSK_SAMPLES_PER_FRAME];
     COMP           ch_fdm[COHPSK_SAMPLES_PER_FRAME];
+    COMP           ch_buf[CH_BUF_SZ];
     int            rx_bits[COHPSK_BITS_PER_FRAME];
+    float          rx_amp_log[NSYMROW*FRAMES][COHPSK_NC*ND];
+    float          rx_phi_log[NSYMROW*FRAMES][COHPSK_NC*ND];
+    COMP           rx_symb_log[NSYMROW*FRAMES][COHPSK_NC*ND];
                                             
     int            f, r, i;
     int           *ptest_bits_coh, *ptest_bits_coh_end, *ptest_bits_coh_rx;
@@ -64,12 +73,21 @@ int main(int argc, char *argv[])
     float          EsNo, variance;
     COMP           scaled_noise;
     float          EsNodB, foff_hz;
-    int            fading_en, nhfdelay, ret, nin;
+    int            fading_en, nhfdelay, ret, nin_frame;
+    float          hf_gain;
     COMP          *ch_fdm_delay, aspread, aspread_2ms, delayed, direct;
-    FILE          *ffading;
+    FILE          *ffading, *fout;
+    int            ch_buf_n;
+    float          tx_pwr, rx_pwr, noise_pwr;
+    int            error_positions_hist[COHPSK_BITS_PER_FRAME];
+    int            log_data_r, c, j, tmp;
+
+    for(i=0; i<COHPSK_BITS_PER_FRAME; i++)
+        error_positions_hist[i] = 0;
 
     EsNodB = ES_NO_DB;
     foff_hz =  FOFF_HZ;
+    fading_en = 0;
     if (argc == 4) {
         EsNodB = atof(argv[1]);
         foff_hz = atof(argv[2]);
@@ -80,18 +98,27 @@ int main(int argc, char *argv[])
     coh = cohpsk_create();
     assert(coh != NULL);
 
+    coh->ch_symb_log_col_sz = COHPSK_NC*ND;
+    coh->ch_symb_log = (COMP *)malloc(sizeof(COMP)*NSYMROWPILOT*FRAMESL*coh->ch_symb_log_col_sz);
+
     ptest_bits_coh = ptest_bits_coh_rx = (int*)test_bits_coh;
     ptest_bits_coh_end = (int*)test_bits_coh + sizeof(test_bits_coh)/sizeof(int);
+    
     phase_ch.real = 1.0; phase_ch.imag = 0.0; 
     noise_r = 0; 
     noise_end = sizeof(noise)/sizeof(COMP);
-    
+    ch_buf_n = 0;
+
+    log_data_r = 0;
+
     /*  each carrier has power = 2, total power 2Nc, total symbol rate
         NcRs, noise BW B=Fs Es/No = (C/Rs)/(N/B), N = var =
         2NcFs/NcRs(Es/No) = 2Fs/Rs(Es/No) */
 
     EsNo = pow(10.0, EsNodB/10.0);
     variance = 2.0*COHPSK_FS/(COHPSK_RS*EsNo);
+    
+    tx_pwr = rx_pwr = noise_pwr = 0.0;
 
     /* init HF fading model */
 
@@ -101,19 +128,23 @@ int main(int argc, char *argv[])
             printf("Can't find fading file: %s\n", FADING_FILE_NAME);
             exit(1);
         }
-        nhfdelay = floor(HF_DELAY_MS*FS/1000);
+        nhfdelay = floor(HF_DELAY_MS*COHPSK_FS/1000);
         ch_fdm_delay = (COMP*)malloc((nhfdelay+COHPSK_SAMPLES_PER_FRAME)*sizeof(COMP));
         assert(ch_fdm_delay != NULL);
         for(i=0; i<nhfdelay+COHPSK_SAMPLES_PER_FRAME; i++) {
             ch_fdm_delay[i].real = 0.0;
             ch_fdm_delay[i].imag = 0.0;
         }
+
+        /* first values are HF gains */
+
+        for (i=0; i<4; i++)
+            ret = fread(&hf_gain, sizeof(float), 1, ffading);
+        printf("hf_gain: %f\n", hf_gain);
     }
 
     /* Main Loop ---------------------------------------------------------------------*/
 
-    nin = COHPSK_SAMPLES_PER_FRAME;
-
     for(f=0; f<FRAMES; f++) {
         
        /* --------------------------------------------------------*\
@@ -124,9 +155,15 @@ int main(int argc, char *argv[])
         ptest_bits_coh += COHPSK_BITS_PER_FRAME;
         if (ptest_bits_coh >= ptest_bits_coh_end) {
             ptest_bits_coh = (int*)test_bits_coh;
+            //fprintf(stderr, "  [%d] tx test bits wrap\n", f);            
         }
 
        cohpsk_mod(coh, tx_fdm, tx_bits);
+        cohpsk_clip(tx_fdm);
+        
+        for(r=0; r<COHPSK_SAMPLES_PER_FRAME; r++) {
+            tx_pwr += pow(tx_fdm[r].real, 2.0) + pow(tx_fdm[r].imag, 2.0);
+        }
 
        /* --------------------------------------------------------*\
                                  Channel
@@ -142,8 +179,8 @@ int main(int argc, char *argv[])
 
             for(i=0; i<nhfdelay; i++)
                 ch_fdm_delay[i] = ch_fdm_delay[i+COHPSK_SAMPLES_PER_FRAME];
-            for(; i<COHPSK_SAMPLES_PER_FRAME; i++)
-                ch_fdm_delay[i] = ch_fdm[i];
+            for(j=0; j<COHPSK_SAMPLES_PER_FRAME; i++, j++)
+                ch_fdm_delay[i] = ch_fdm[j];
 
             /* combine direct and delayed paths, both multiplied by
                "spreading" (doppler) functions */
@@ -157,65 +194,118 @@ int main(int argc, char *argv[])
                 
                 direct    = cmult(aspread, ch_fdm[i]);
                 delayed   = cmult(aspread_2ms, ch_fdm_delay[i]);
-                ch_fdm[i] = fcmult(HF_GAIN, cadd(direct, delayed));
+                ch_fdm[i] = fcmult(hf_gain, cadd(direct, delayed));
             }
         }
 
+        for(r=0; r<COHPSK_SAMPLES_PER_FRAME; r++) {
+            rx_pwr += pow(ch_fdm[r].real, 2.0) + pow(ch_fdm[r].imag, 2.0);
+        }
+
         /* AWGN noise ------------------------------------------*/
 
         for(r=0; r<COHPSK_SAMPLES_PER_FRAME; r++) {
             scaled_noise = fcmult(sqrt(variance), noise[noise_r]);
             ch_fdm[r] = cadd(ch_fdm[r], scaled_noise);
+            noise_pwr += pow(noise[noise_r].real, 2.0) + pow(noise[noise_r].imag, 2.0);
             noise_r++;
-            if (noise_r > noise_end)
+            if (noise_r > noise_end) {
                 noise_r = 0;
+                //fprintf(stderr, "  [%d] noise wrap\n", f);            
+            }
+               
         }
 
+        /* buffer so we can let demod Fs offset code do it's thing */
+        
+        memcpy(&ch_buf[ch_buf_n], ch_fdm, sizeof(COMP)*COHPSK_SAMPLES_PER_FRAME);
+        ch_buf_n += COHPSK_SAMPLES_PER_FRAME;
+        assert(ch_buf_n < CH_BUF_SZ);
+
+        // add SAMPLES to end
+        // subtract nin from beginning
        /* --------------------------------------------------------*\
                                  Demod
        \*---------------------------------------------------------*/
 
-       cohpsk_demod(coh, rx_bits, &reliable_sync_bit, ch_fdm, &nin);
+        /* locks timing to avoid complications when we know there is
+           no Fs offset */
 
+        tmp = nin_frame;
+       cohpsk_demod(coh, rx_bits, &reliable_sync_bit, ch_buf, &tmp);
+        ch_buf_n -= nin_frame;
+        assert(ch_buf_n >= 0);
+        if (ch_buf_n)
+            memcpy(ch_buf, &ch_buf[nin_frame], sizeof(COMP)*ch_buf_n);
+        nin_frame = tmp;
+
+        //fprintf(stderr, "  [%d] nin_frame: %d\n", f, nin_frame);            
         errors = 0;
         for(i=0; i<COHPSK_BITS_PER_FRAME; i++) {
             errors += (rx_bits[i] & 0x1) ^ ptest_bits_coh_rx[i];
+            if (state == 1) {
+                if ((rx_bits[i] & 0x1) ^ ptest_bits_coh_rx[i])
+                    error_positions_hist[i]++;
+            }
         }
-
+        
         /* state logic to sync up to test data */
 
         next_state = state;
-
+        
         if (state == 0) {
-            if (reliable_sync_bit && (errors == 0)) {
+            if (reliable_sync_bit && (errors < 4)) {
                 next_state = 1;
                 ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME;
                 nerrors = errors;
                 nbits = COHPSK_BITS_PER_FRAME;
-                fprintf(stderr, "  test data sync\n");            
-
+                //fprintf(stderr, "  [%d] test data sync nerrors: %d\n", f, nerrors);            
             }
         }
 
         if (state == 1) {
             nerrors += errors;
             nbits   += COHPSK_BITS_PER_FRAME;
+            //fprintf(stderr, "  [%d] test data sync errors: %d\n", f, errors);            
             ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME;
             if (ptest_bits_coh_rx >= ptest_bits_coh_end) {
                 ptest_bits_coh_rx = (int*)test_bits_coh;
+                //fprintf(stderr, "  [%d] rx test bits wrap\n", f);                         
             }
-        }
 
+            for(r=0; r<NSYMROW; r++, log_data_r++) {
+                for(c=0; c<COHPSK_NC*ND; 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]; 
+                }
+            }
+        }
+        
         state = next_state;
     }
-    
+            
     printf("%4.3f %d %d\n", (float)nerrors/nbits, nbits, nerrors);
-
+    printf("tx var: %f noise var: %f rx var: %f\n", 
+           tx_pwr/(FRAMES*COHPSK_SAMPLES_PER_FRAME), 
+           noise_pwr/(FRAMES*COHPSK_SAMPLES_PER_FRAME),
+           rx_pwr/(FRAMES*COHPSK_SAMPLES_PER_FRAME) 
+           );
     if (fading_en) {
         free(ch_fdm_delay);
         fclose(ffading);
     }
     cohpsk_destroy(coh);
+        
+    //for(i=0; i<COHPSK_BITS_PER_FRAME; i++)
+    //        printf("%d %d\n", i, error_positions_hist[i]);
+
+    fout = fopen("test_cohpsk_ch_out.txt","wt");
+    octave_save_complex(fout, "ch_symb_log_c", (COMP*)coh->ch_symb_log, coh->ch_symb_log_r, COHPSK_NC*ND, COHPSK_NC*ND);  
+    octave_save_float(fout, "rx_amp_log_c", (float*)rx_amp_log, log_data_r, COHPSK_NC*ND, COHPSK_NC*ND);  
+    octave_save_float(fout, "rx_phi_log_c", (float*)rx_phi_log, log_data_r, COHPSK_NC*ND, COHPSK_NC*ND);  
+    octave_save_complex(fout, "rx_symb_log_c", (COMP*)rx_symb_log, log_data_r, COHPSK_NC*ND, COHPSK_NC*ND);  
+    fclose(fout);
 
     return 0;
 }