From: baobrien Date: Sun, 21 Feb 2016 04:38:01 +0000 (+0000) Subject: Fixed FSK EbNodB estimation; started hooking up FSK statistic generation X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=7eb36e057c5ffb86d9f62ff05c404bc2a54e09e0;p=freetel-svn-tracking.git Fixed FSK EbNodB estimation; started hooking up FSK statistic generation git-svn-id: https://svn.code.sf.net/p/freetel/code@2706 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2-dev/octave/tfsk.m b/codec2-dev/octave/tfsk.m index a84b60ba..69379f22 100644 --- a/codec2-dev/octave/tfsk.m +++ b/codec2-dev/octave/tfsk.m @@ -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 diff --git a/codec2-dev/src/fmfsk.c b/codec2-dev/src/fmfsk.c index 8e6b8ca3..93f377c0 100644 --- a/codec2-dev/src/fmfsk.c +++ b/codec2-dev/src/fmfsk.c @@ -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; diff --git a/codec2-dev/src/fmfsk.h b/codec2-dev/src/fmfsk.h index d3491524..1573f248 100644 --- a/codec2-dev/src/fmfsk.h +++ b/codec2-dev/src/fmfsk.h @@ -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 */ + + }; /* diff --git a/codec2-dev/src/freedv_api.c b/codec2-dev/src/freedv_api.c index f3362350..0c20ba32 100644 --- a/codec2-dev/src/freedv_api.c +++ b/codec2-dev/src/freedv_api.c @@ -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;in_speech_samples;i++){ diff --git a/codec2-dev/src/freedv_rx.c b/codec2-dev/src/freedv_rx.c index da3e7d68..3e4b514e 100644 --- a/codec2-dev/src/freedv_rx.c +++ b/codec2-dev/src/freedv_rx.c @@ -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); } } diff --git a/codec2-dev/src/fsk.c b/codec2-dev/src/fsk.c index e285ebd1..9d2bbc22 100644 --- a/codec2-dev/src/fsk.c +++ b/codec2-dev/src/fsk.c @@ -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; iNmem; 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; iEbNodB = 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; iEbNodB = 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); diff --git a/codec2-dev/src/fsk.h b/codec2-dev/src/fsk.h index 07fbccdd..6e7a7dd5 100644 --- a/codec2-dev/src/fsk.h +++ b/codec2-dev/src/fsk.h @@ -31,6 +31,7 @@ #include #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 *