Fixed FSK EbNodB estimation; started hooking up FSK statistic generation
authorbaobrien <baobrien@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 21 Feb 2016 04:38:01 +0000 (04:38 +0000)
committerbaobrien <baobrien@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 21 Feb 2016 04:38:01 +0000 (04:38 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@2706 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/octave/tfsk.m
codec2-dev/src/fmfsk.c
codec2-dev/src/fmfsk.h
codec2-dev/src/freedv_api.c
codec2-dev/src/freedv_rx.c
codec2-dev/src/fsk.c
codec2-dev/src/fsk.h

index a84b60ba6fd19919ade4b7d9bf5a4c26c7c5ff04..69379f22fcc42332e02e47db972507dadbf59041 100644 (file)
@@ -230,6 +230,7 @@ function test_stats = fsk_demod_xt(Fs,Rs,f1,fsp,mod,tname,M=2)
 
     % Much larger tolerances on unimportant statistics
     pass = vcompare(o_ppm   ,     t_ppm,      'ppm',      tname,.02,11) && pass;
+    pass = vcompare(o_EbNodB   ,     t_EbNodB,      'EbNodB',      tname,.02,11) && pass;
     
     assert(pass);
     diffpass = sum(xor(obits,bits'))<4;
@@ -548,10 +549,10 @@ function pass = test_fsk_battery()
     assert(pass)
     pass = pass && test_mod_horuscfgm4_randbits;
     assert(pass)
-    pass = pass && test_drift_var(4);
-    assert(pass)
     pass = pass && test_drift_var(2);
     assert(pass)
+    pass = pass && test_drift_var(4);
+    assert(pass)
     if pass
         printf("***** All tests passed! *****\n");
     end
index 8e6b8ca3970e09c308b877f371e8ed3c13121da4..93f377c0b41c0b850816646818b5fa772736cac4 100644 (file)
@@ -151,7 +151,7 @@ void fmfsk_demod(struct FMFSK *fmfsk, uint8_t rx_bits[],float fmfsk_in[]){
     COMP phi_ft,dphi_ft;    /* Phase and delta-phase for fine timing estimator */
     float t;
     COMP x;                 /* Magic fine timing angle */
-    float norm_rx_timing;
+    float norm_rx_timing,old_norm_rx_timing,d_norm_rx_timing,appm;
     int rx_timing,sample_offset;
     int next_nin;
     float apeven,apodd;     /* Approx. prob of even or odd stream being correct */
@@ -209,6 +209,18 @@ void fmfsk_demod(struct FMFSK *fmfsk, uint8_t rx_bits[],float fmfsk_in[]){
     norm_rx_timing =  atan2f(x.imag,x.real)/(2*M_PI) - .42;
     rx_timing = (int)lroundf(norm_rx_timing*(float)Ts);
     
+    old_norm_rx_timing = fmfsk->norm_rx_timing;
+    fmfsk->norm_rx_timing = norm_rx_timing;
+    
+    /* Estimate sample clock offset */
+    d_norm_rx_timing = norm_rx_timing - old_norm_rx_timing;
+    
+    /* Filter out big jumps in due to nin change */
+    if(fabsf(d_norm_rx_timing) < .2){
+        appm = 1e6*d_norm_rx_timing/(float)nsym;
+        fmfsk->ppm = .9*fmfsk->ppm + .1*appm;
+    }
+    
     /* Figure out how far offset the sample points are */
     sample_offset = (Ts/2)+Ts+rx_timing-1;
     
index d34915248a85e919f85816332112c916af8b0ede..1573f248bbc1b52d1dbf1731d5869f7386f26333 100644 (file)
@@ -50,6 +50,11 @@ struct FMFSK{
     int lodd;           /* Last integrated sample for odd bitstream generation */
     float * oldsamps;   /* Memory of old samples to make clock-offset-tolerance possible */
     
+    /* Stats generated by demod */
+    float norm_rx_timing; /* RX Timing, used to calculate clock offset */
+    int ppm;                   /* Clock offset in parts-per-million */
+    
+    
 };
 
 /*
index f3362350958334a3ab4ec4852f27854b5f14ab65..0c20ba32f2edbbd6e561d1f6db05593f6ce6dc73 100644 (file)
@@ -168,6 +168,9 @@ struct freedv *freedv_open(int mode) {
         f->modem_sample_rate = 48000;
         /* Malloc something to appease freedv_init and freedv_destroy */
         f->codec_bits = malloc(1);
+        
+        /* Set up the stats */
+        fsk_setup_modem_stats(f->fsk,&(f->stats));
     }
     
     if (mode == FREEDV_MODE_2400B) {
@@ -643,7 +646,6 @@ int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]) {
     float rx_float[f->n_max_modem_samples];
     int i;
     int nin = freedv_nin(f);
-
     assert(nin <= f->n_max_modem_samples);
     /* FSK RX happens in real floats, so convert to those and call their demod here */
     if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) ){
@@ -669,9 +671,14 @@ int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]) {
 int freedv_floatrx(struct freedv *f, short speech_out[], float demod_in[]) {
     assert(f != NULL);
     COMP rx_fdm[f->n_max_modem_samples];
+    uint8_t vc_bits[2];
+    short vc_bit;
     int  i;
-    int nin = freedv_nin(f);
-
+    int nin = freedv_nin(f);    
+    int n_ascii;
+    char ascii_out;
+    float Rs;
+    
     assert(nin <= f->n_max_modem_samples);
     
     /* FSK RX happens in real floats, so demod for those goes here */
@@ -679,18 +686,28 @@ int freedv_floatrx(struct freedv *f, short speech_out[], float demod_in[]) {
         if(f->mode == FREEDV_MODE_2400A){
             fsk_demod(f->fsk,(uint8_t*)f->tx_bits,demod_in);
             f->nin = fsk_nin(f->fsk);
-            f->stats.snr_est = f->fsk->EbNodB;
-            f->stats.clock_offset = f->fsk->ppm;
         }else{            
             fmfsk_demod(f->fmfsk,(uint8_t*)f->tx_bits,demod_in);
             f->nin = fmfsk_nin(f->fmfsk);
+            f->stats.clock_offset = f->fsk->ppm;
         }
-        /* TODO: Protocol and varicode bits */
-        if(fvhff_deframe_bits(f->deframer,f->packed_codec_bits,NULL,NULL,(uint8_t*)f->tx_bits)){
+        /* TODO: Protocol bits */
+        if(fvhff_deframe_bits(f->deframer,f->packed_codec_bits,NULL,vc_bits,(uint8_t*)f->tx_bits)){
+            /* Decode varicode text */
+            for(i=0; i<2; i++){
+                /* Note: deframe_bits spits out bits in uint8_ts while varicode_decode expects shorts */
+                vc_bit = vc_bits[i];
+                n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, &vc_bit, 1, 1);
+                if (n_ascii && (f->freedv_put_next_rx_char != NULL)) {
+                    (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out);
+                }
+            }
             /* Decode the codec data */
             codec2_decode(f->codec2,speech_out,f->packed_codec_bits);
             f->sync = 1;
             f->stats.sync = 1;
+            
+            
         } else {
             /* Fill with silence */
             for(i=0;i<f->n_speech_samples;i++){
index da3e7d68b0d6ef5469e497acd7b7313721f7998d..3e4b514e7b72d8d2ece89c04a48a078dac28237c 100644 (file)
@@ -48,7 +48,7 @@ struct my_callback_state {
 void my_put_next_rx_char(void *callback_state, char c) {
     struct my_callback_state* pstate = (struct my_callback_state*)callback_state;
     if (pstate->ftxt != NULL) {
-        //fprintf(pstate->ftxt, "%c\n", c);
+        fprintf(pstate->ftxt, "%c", c);
     }
 }
 
index e285ebd1d2da007a59fd4526da777b7a6d68619f..9d2bbc223fb12c94c144e002374b0070d4f2ca4a 100644 (file)
@@ -231,6 +231,8 @@ struct FSK * fsk_create_hbr(int Fs, int Rs,int P,int M, int tx_f1, int tx_fs)
     fsk->f4_est = 0;    
     fsk->ppm = 0;
 
+    fsk->stats = NULL;
+    
     return fsk;
 }
 
@@ -342,6 +344,8 @@ struct FSK * fsk_create(int Fs, int Rs,int M, int tx_f1, int tx_fs)
     fsk->f4_est = 0;    
     fsk->ppm = 0;
 
+    fsk->stats = NULL;
+    
     return fsk;
 }
 
@@ -355,6 +359,10 @@ void fsk_destroy(struct FSK *fsk){
     free(fsk);
 }
 
+void fsk_setup_modem_stats(struct FSK *fsk,struct MODEM_STATS *stats){
+    fsk->stats = stats;
+}
+
 
 /*
  * Internal function to estimate the frequencies of the two tones within a block of samples.
@@ -477,7 +485,6 @@ void fsk_demod_freq_est(struct FSK *fsk, float fsk_in[],float *freqs,int M){
        for(i=0; i<M; i++){
                freqs[i] = (float)(freqi[i])*((float)Fs/(float)Ndft);
        }
-    
     #ifndef DEMOD_ALLOC_STACK
     free(fftin);
     free(fftout);
@@ -495,7 +502,7 @@ void fsk2_demod(struct FSK *fsk, uint8_t rx_bits[], float fsk_in[]){
     int Nmem = fsk->Nmem;
     int M = fsk->mode;
     int i,j,dc_i,cbuf_i;
-    float ft1,ft2;
+    float ft1;
     int nstash = fsk->nstash;
     COMP *f1_int, *f2_int;
     COMP t1,t2;
@@ -509,7 +516,7 @@ void fsk2_demod(struct FSK *fsk, uint8_t rx_bits[], float fsk_in[]){
     int using_old_samps;
     float *sample_src;
     COMP *f1_intbuf,*f2_intbuf;
-    float f_est[M];
+    float f_est[M],fc_avg,fc_tx;
     float meanebno,stdebno;
     
     
@@ -711,12 +718,12 @@ void fsk2_demod(struct FSK *fsk, uint8_t rx_bits[], float fsk_in[]){
         /* Accumulate resampled int magnitude for EbNodB estimation */
         /* Standard deviation is calculated by algorithm devised by crafty soviets */
         #ifdef EST_EBNO
+        /* Accumulate the square of the sampled value */
+        ft1 = tmax[ (tmax[1]>tmax[0]) ];
+        stdebno += ft1;
         
-        ft1 = sqrtf(t1.real*t1.real + t1.imag*t1.imag);
-        ft2 = sqrtf(t2.real*t2.real + t2.imag*t2.imag);
-        ft1 = fabsf(ft1-ft2);
-        meanebno += ft1;
-        
+        /* Figure the abs value of the max tone */
+        meanebno += sqrtf(ft1);
         #endif
         /* Soft output goes here */
     }
@@ -724,25 +731,12 @@ void fsk2_demod(struct FSK *fsk, uint8_t rx_bits[], float fsk_in[]){
     #ifdef EST_EBNO
     /* Calculate mean for EbNodB estimation */
     meanebno = meanebno/(float)nsym;
-    stdebno = 0;
-    /* Go back through the data and figure the std dev */
-    for(i=0; i<nsym; i++){
-        int st = (i+1)*P;
-        t1 =         fcmult(1-fract,f1_int[st+ low_sample]);
-        t1 = cadd(t1,fcmult(  fract,f1_int[st+high_sample]));
-        t2 =         fcmult(1-fract,f2_int[st+ low_sample]);
-        t2 = cadd(t2,fcmult(  fract,f2_int[st+high_sample]));
-        
-        /* Accumulate resampled int magnitude for EbNodB estimation */
-        ft1 = sqrtf(t1.real*t1.real + t1.imag*t1.imag);
-        ft2 = sqrtf(t2.real*t2.real + t2.imag*t2.imag);
-        ft1 = fabsf(ft1-ft2);
-        ft2 = abs(meanebno-ft1);
-        stdebno += ft2*ft2;
-    }
-    /* Finish figuring std. dev. */
-    stdebno = sqrtf(stdebno/(float)(nsym-1));
-    fsk->EbNodB = 20*log10f((1e-6+meanebno)/(1e-6+stdebno));
+    
+    /* Calculate the std. dev for EbNodB estimate */
+    stdebno = (stdebno/(float)nsym) - (meanebno*meanebno);
+    stdebno = sqrt(stdebno);
+    
+    fsk->EbNodB = -6+(20*log10f((1e-6+meanebno)/(1e-6+stdebno)));
     #else
     fsk->EbNodB = 1;
     #endif
@@ -754,6 +748,26 @@ void fsk2_demod(struct FSK *fsk, uint8_t rx_bits[], float fsk_in[]){
     free(f2_intbuf);
     #endif
     
+    /* Write some statistics out to the stats struct, if present */
+    if( fsk->stats != NULL ){
+        /* Save clock offset in ppm */
+        fsk->stats->clock_offset = fsk->ppm;
+        
+        /* Calculate and save SNR from EbNodB estimate */
+        fsk->stats->snr_est = fsk->EbNodB + 10*log10f(((float)Rs)/((float)Rs*M));
+        
+        /* Save rx timing */
+        fsk->stats->rx_timing = (float)rx_timing;
+        
+        /* Estimate and save frequency offset */
+        fc_avg = (f_est[0]+f_est[1])/2;
+        fc_tx = (fsk->f1_tx+fsk->f1_tx+fsk->fs_tx)/2;
+        fsk->stats->foff = fc_tx-fc_avg;
+    
+        fsk->stats->nr = 0;
+        fsk->stats->Nc = 0;
+    }
+    
     /* Dump some internal samples */
     modem_probe_samp_f("t_EbNodB",&(fsk->EbNodB),1);
     modem_probe_samp_f("t_ppm",&(fsk->ppm),1);
@@ -775,7 +789,7 @@ void fsk4_demod(struct FSK *fsk, uint8_t rx_bits[], float fsk_in[]){
     int Nmem = fsk->Nmem;
     int M = fsk->mode;
     int i,j,dc_i,cbuf_i;
-    float ft1,ft2;
+    float ft1;
     int nstash = fsk->nstash;
     COMP *f1_int, *f2_int, *f3_int, *f4_int;
     COMP t1,t2,t3,t4;
@@ -791,7 +805,7 @@ void fsk4_demod(struct FSK *fsk, uint8_t rx_bits[], float fsk_in[]){
     int using_old_samps;
     float *sample_src;
     COMP *f1_intbuf,*f2_intbuf,*f3_intbuf,*f4_intbuf;
-    float f_est[M];
+    float f_est[M],fc_avg,fc_tx;
     float meanebno,stdebno;
     
     /* Estimate tone frequencies */
@@ -1071,40 +1085,27 @@ void fsk4_demod(struct FSK *fsk, uint8_t rx_bits[], float fsk_in[]){
         /* Accumulate resampled int magnitude for EbNodB estimation */
         /* Standard deviation is calculated by algorithm devised by crafty soviets */
         #ifdef EST_EBNO
+        /* Accumulate the square of the sampled value */
+        ft1 = max;
+        stdebno += ft1;
         
-        ft1 = sqrtf(t1.real*t1.real + t1.imag*t1.imag);
-        ft2 = sqrtf(t2.real*t2.real + t2.imag*t2.imag);
-        ft1 = fabsf(ft1-ft2);
-        meanebno += ft1;
-        
+        /* Figure the abs value of the max tone */
+        meanebno += sqrtf(ft1);
         #endif
         /* Soft output goes here */
     }
     
-    #ifdef EST_EBNO
+     #ifdef EST_EBNO
     /* Calculate mean for EbNodB estimation */
     meanebno = meanebno/(float)nsym;
-    stdebno = 0;
-    /* Go back through the data and figure the std dev */
-    for(i=0; i<nsym; i++){
-        int st = (i+1)*P;
-        t1 =         fcmult(1-fract,f1_int[st+ low_sample]);
-        t1 = cadd(t1,fcmult(  fract,f1_int[st+high_sample]));
-        t2 =         fcmult(1-fract,f2_int[st+ low_sample]);
-        t2 = cadd(t2,fcmult(  fract,f2_int[st+high_sample]));
-        
-        /* Accumulate resampled int magnitude for EbNodB estimation */
-        ft1 = sqrtf(t1.real*t1.real + t1.imag*t1.imag);
-        ft2 = sqrtf(t2.real*t2.real + t2.imag*t2.imag);
-        ft1 = fabsf(ft1-ft2);
-        ft2 = abs(meanebno-ft1);
-        stdebno += ft2*ft2;
-    }
-    /* Finish figuring std. dev. */
-    stdebno = sqrtf(stdebno/(float)(nsym-1));
-    fsk->EbNodB = 20*log10f((1e-6+meanebno)/(1e-6+stdebno));
+    
+    /* Calculate the std. dev for EbNodB estimate */
+    stdebno = (stdebno/(float)nsym) - (meanebno*meanebno);
+    stdebno = sqrt(stdebno);
+    
+    fsk->EbNodB = -6+(20*log10f((1e-6+meanebno)/(1e-6+stdebno)));
     #else
-    fsk->EbNodB = 0;
+    fsk->EbNodB = 1;
     #endif
     
     #ifndef DEMOD_ALLOC_STACK
@@ -1118,6 +1119,26 @@ void fsk4_demod(struct FSK *fsk, uint8_t rx_bits[], float fsk_in[]){
     free(f4_intbuf);
     #endif
     
+    /* Write some statistics out to the stats struct, if present */
+    if( fsk->stats != NULL ){
+        /* Save clock offset in ppm */
+        fsk->stats->clock_offset = fsk->ppm;
+        
+        /* Calculate and save SNR from EbNodB estimate */
+        fsk->stats->snr_est = fsk->EbNodB + 10*log10f(((float)Rs*2)/((float)Rs*M));
+        
+        /* Save rx timing */
+        fsk->stats->rx_timing = (float)rx_timing;
+        
+        /* Estimate and save frequency offset */
+        fc_avg = (f_est[0]+f_est[1]+f_est[2]+f_est[3])/4;
+        fc_tx = (fsk->f1_tx+fsk->f1_tx+(fsk->fs_tx*3))/2;
+        fsk->stats->foff = fc_tx-fc_avg;
+    
+        fsk->stats->nr = 0;
+        fsk->stats->Nc = 0;
+    }
+    
     /* Dump some internal samples */
     modem_probe_samp_f("t_EbNodB",&(fsk->EbNodB),1);
     modem_probe_samp_f("t_ppm",&(fsk->ppm),1);
index 07fbccdde7da5db06c31e0745daac94fdf57f2fb..6e7a7dd5e7978f788dd41f500b7d6ecfb429e44b 100644 (file)
@@ -31,6 +31,7 @@
 #include <stdint.h>
 #include "comp.h"
 #include "kiss_fftr.h"
+#include "modem_stats.h"
 
 #define MODE_2FSK 2
 #define MODE_4FSK 4
@@ -82,6 +83,8 @@ struct FSK {
     /*  Parameters used by mod/demod and driving code */
     int nin;                /* Number of samples to feed the next demod cycle */
     
+    /*  Pointer to modem statistic struct */
+    struct MODEM_STATS *stats;
 };
 
 /*
@@ -104,6 +107,11 @@ struct FSK * fsk_create(int Fs, int Rs, int M, int tx_f1, int tx_fs);
  */
 struct FSK * fsk_create_hbr(int Fs, int Rs, int P, int M, int tx_f1, int tx_fs);
 
+/*
+ * Set a MODEM_STATS struct in which to deposit demod statistics
+ */
+void fsk_setup_modem_stats(struct FSK *fsk,struct MODEM_STATS *stats);
+
 /*
  * Destroy an FSK state struct and free it's memory
  *