From ff4cc06b4f213e540575f5be02c34912a1b3b620 Mon Sep 17 00:00:00 2001 From: drowe67 Date: Sun, 15 Jan 2017 00:12:20 +0000 Subject: [PATCH] refactored stats handling for fsk and fmfsk to be consistent with other modems, freedv_api, and FreeDV GUI. Tested freedv_tx/rx with 2400A/2400B/800XA. Still need to test GUI output, e.g. for fsk_demod on wenet type applications git-svn-id: https://svn.code.sf.net/p/freetel/code@2974 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/src/fmfsk.c | 98 ++++++++++++++++++------------ codec2-dev/src/fmfsk.h | 20 +++--- codec2-dev/src/fmfsk_demod.c | 2 +- codec2-dev/src/freedv_api.c | 19 +++--- codec2-dev/src/fsk.c | 114 ++++++++++++++++++++++------------- codec2-dev/src/fsk.h | 18 +++--- codec2-dev/src/fsk_demod.c | 2 +- 7 files changed, 162 insertions(+), 111 deletions(-) diff --git a/codec2-dev/src/fmfsk.c b/codec2-dev/src/fmfsk.c index 1c89179c..ab56945f 100644 --- a/codec2-dev/src/fmfsk.c +++ b/codec2-dev/src/fmfsk.c @@ -82,7 +82,13 @@ struct FMFSK * fmfsk_create(int Fs,int Rb){ } fmfsk->oldsamps = oldsamps; - fmfsk->stats = NULL; + + fmfsk->stats = (struct MODEM_STATS*)malloc(sizeof(struct MODEM_STATS)); + if (fmfsk->stats == NULL) { + free(oldsamps); + free(fmfsk); + return NULL; + } return fmfsk; } @@ -103,8 +109,26 @@ uint32_t fmfsk_nin(struct FMFSK *fmfsk){ return (uint32_t)fmfsk->nin; } -void fmfsk_setup_modem_stats(struct FMFSK *fmfsk,struct MODEM_STATS *stats){ - fmfsk->stats = stats; +void fmfsk_get_demod_stats(struct FMFSK *fmfsk,struct MODEM_STATS *stats){ + /* copy from internal stats, note we can't overwrite stats completely + as it has other states rqd by caller, also we want a consistent + interface across modem types for the freedv_api. + */ + + stats->clock_offset = fmfsk->stats->clock_offset; + stats->snr_est = fmfsk->stats->snr_est; // TODO: make this SNR not Eb/No + stats->rx_timing = fmfsk->stats->rx_timing; + stats->foff = fmfsk->stats->foff; + + stats->neyesamp = fmfsk->stats->neyesamp; + stats->neyetr = fmfsk->stats->neyetr; + memcpy(stats->rx_eye, fmfsk->stats->rx_eye, sizeof(stats->rx_eye)); + + /* these fields not used for FSK so set to something sensible */ + + stats->sync = 0; + stats->nr = fmfsk->stats->nr; + stats->Nc = fmfsk->stats->Nc; } /* @@ -306,48 +330,46 @@ void fmfsk_demod(struct FMFSK *fmfsk, uint8_t rx_bits[],float fmfsk_in[]){ fmfsk->lodd = lastv; /* Save demod statistics */ - if(fmfsk->stats != NULL){ - fmfsk->stats->Nc = 0; - fmfsk->stats->nr = 0; + fmfsk->stats->Nc = 0; + fmfsk->stats->nr = 0; - /* Clock offset and RX timing are all we know here */ - fmfsk->stats->clock_offset = fmfsk->ppm; - fmfsk->stats->rx_timing = (float)rx_timing; + /* Clock offset and RX timing are all we know here */ + fmfsk->stats->clock_offset = fmfsk->ppm; + fmfsk->stats->rx_timing = (float)rx_timing; - /* Zero out all of the other things */ - fmfsk->stats->foff = 0; + /* Zero out all of the other things */ + fmfsk->stats->foff = 0; - #ifdef EST_EBNO - amp_bit = fabsf(amp_bit - amp_noise); - fmfsk->snr_mean *= .9; - fmfsk->snr_mean += (amp_bit+1e-6)/(amp_noise+1e-6); - fmfsk->stats->snr_est = 20+20*log10f(fmfsk->snr_mean); - #else - fmfsk->stats->snr_est = 0; - #endif +#ifdef EST_EBNO + amp_bit = fabsf(amp_bit - amp_noise); + fmfsk->snr_mean *= .9; + fmfsk->snr_mean += (amp_bit+1e-6)/(amp_noise+1e-6); + fmfsk->stats->snr_est = 20+20*log10f(fmfsk->snr_mean); +#else + fmfsk->stats->snr_est = 0; +#endif - /* Collect an eye diagram */ - /* Take a sample for the eye diagrams */ - neyesamp = fmfsk->stats->neyesamp = Ts*4; - neyeoffset = sample_offset+(Ts*2*28); + /* Collect an eye diagram */ + /* Take a sample for the eye diagrams */ + neyesamp = fmfsk->stats->neyesamp = Ts*4; + neyeoffset = sample_offset+(Ts*2*28); - fmfsk->stats->neyetr = 8; - for(k=0; kstats->neyetr; k++) - for(j=0; jstats->rx_eye[k][j] = rx_filt[k*neyesamp+neyeoffset+j]; - //fmfsk->stats->rx_eye[k][j] = fmfsk_in[k*neyesamp+neyeoffset+j]; - eye_max = 0; + fmfsk->stats->neyetr = 8; + for(k=0; kstats->neyetr; k++) + for(j=0; jstats->rx_eye[k][j] = rx_filt[k*neyesamp+neyeoffset+j]; + //fmfsk->stats->rx_eye[k][j] = fmfsk_in[k*neyesamp+neyeoffset+j]; + eye_max = 0; - /* Normalize eye to +/- 1 */ - for(i=0; istats->neyetr; i++) - for(j=0; jstats->rx_eye[i][j])>eye_max) - eye_max = fabsf(fmfsk->stats->rx_eye[i][j]); + /* Normalize eye to +/- 1 */ + for(i=0; istats->neyetr; i++) + for(j=0; jstats->rx_eye[i][j])>eye_max) + eye_max = fabsf(fmfsk->stats->rx_eye[i][j]); - for(i=0; istats->neyetr; i++) - for(j=0; jstats->rx_eye[i][j] = (fmfsk->stats->rx_eye[i][j]/(2*eye_max))+.5; - } + for(i=0; istats->neyetr; i++) + for(j=0; jstats->rx_eye[i][j] = (fmfsk->stats->rx_eye[i][j]/(2*eye_max))+.5; modem_probe_samp_f("t_norm_rx_timing",&norm_rx_timing,1); modem_probe_samp_f("t_rx_filt",rx_filt,(nsym+1)*Ts); diff --git a/codec2-dev/src/fmfsk.h b/codec2-dev/src/fmfsk.h index dd04ccd7..9ec6418b 100644 --- a/codec2-dev/src/fmfsk.h +++ b/codec2-dev/src/fmfsk.h @@ -29,14 +29,14 @@ #ifndef __C2FMFSK_H #define __C2FMFSK_H #include -#include "comp.h" -#include "modem_stats.h" - -#define FMFSK_SCALE 16383 - -/* - * fm-me-2fsk state - */ +#include "comp.h" +#include "modem_stats.h" + +#define FMFSK_SCALE 16383 + +/* + * fm-me-2fsk state + */ struct FMFSK{ /* Static fmfsk parameters */ int Rb; /* Manchester-encoded bitrate */ @@ -77,9 +77,9 @@ struct FMFSK * fmfsk_create(int Fs,int Rb); void fmfsk_destroy(struct FMFSK *fmfsk); /* - * Set a MODEM_STATS struct in which to deposit demod statistics + * Deposit demod statistics into a MODEM_STATS struct */ -void fmfsk_setup_modem_stats(struct FMFSK *fmfsk,struct MODEM_STATS *stats); +void fmfsk_get_demod_stats(struct FMFSK *fmfsk,struct MODEM_STATS *stats); /* * Returns the number of samples that must be fed to fmfsk_demod the next diff --git a/codec2-dev/src/fmfsk_demod.c b/codec2-dev/src/fmfsk_demod.c index 63785143..1421c875 100644 --- a/codec2-dev/src/fmfsk_demod.c +++ b/codec2-dev/src/fmfsk_demod.c @@ -76,7 +76,6 @@ int main(int argc,char *argv[]){ if(argc>5){ if(strcmp(argv[5],"S")==0){ enable_stats = 1; - fmfsk_setup_modem_stats(fmfsk,&stats); loop_time = ((float)fmfsk_nin(fmfsk))/((float)Fs); stats_loop = (int)(.125/loop_time); stats_ctr = 0; @@ -110,6 +109,7 @@ int main(int argc,char *argv[]){ fwrite(bitbuf,sizeof(uint8_t),fmfsk->nbit,fout); if(enable_stats && stats_ctr <= 0){ + fmfsk_get_demod_stats(fmfsk,&stats); fprintf(stderr,"{\"EbNodB\": %2.2f,\t\"ppm\": %d,",stats.snr_est,(int)stats.clock_offset); fprintf(stderr,"\t\"f1_est\":%.1f,\t\"f2_est\":%.1f",0.0,0.0); fprintf(stderr,",\t\"eye_diagram\":["); diff --git a/codec2-dev/src/freedv_api.c b/codec2-dev/src/freedv_api.c index b81827b2..071e5bc3 100644 --- a/codec2-dev/src/freedv_api.c +++ b/codec2-dev/src/freedv_api.c @@ -183,9 +183,6 @@ 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) { @@ -210,9 +207,6 @@ 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 */ - fmfsk_setup_modem_stats(f->fmfsk,&(f->stats)); } if (mode == FREEDV_MODE_800XA) { @@ -242,9 +236,6 @@ struct freedv *freedv_open(int mode) { f->n_protocol_bits = 0; codec2_mode = CODEC2_MODE_700C; - - /* Set up the stats */ - fsk_setup_modem_stats(f->fsk,&(f->stats)); } @@ -1578,8 +1569,14 @@ void freedv_get_modem_extended_stats(struct freedv *f, struct MODEM_STATS *stats { if (f->mode == FREEDV_MODE_1600) fdmdv_get_demod_stats(f->fdmdv, stats); - if ((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA)) - memcpy(stats,&(f->stats),sizeof(struct MODEM_STATS)); + + if ((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_800XA)) { + fsk_get_demod_stats(f->fsk, stats); + } + + if (f->mode == FREEDV_MODE_2400B) { + fmfsk_get_demod_stats(f->fmfsk, stats); + } #ifndef CORTEX_M4 if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) diff --git a/codec2-dev/src/fsk.c b/codec2-dev/src/fsk.c index 9a805d2f..3b510b85 100644 --- a/codec2-dev/src/fsk.c +++ b/codec2-dev/src/fsk.c @@ -238,8 +238,15 @@ struct FSK * fsk_create_hbr(int Fs, int Rs,int P,int M, int tx_f1, int tx_fs) fsk->ppm = 0; - fsk->stats = NULL; - + fsk->stats = (struct MODEM_STATS*)malloc(sizeof(struct MODEM_STATS)); + if(fsk->stats == NULL){ + free(fsk->fft_est); + free(fsk->samp_old); + free(fsk->fft_cfg); + free(fsk); + return NULL; + } + return fsk; } @@ -364,9 +371,16 @@ struct FSK * fsk_create(int Fs, int Rs,int M, int tx_f1, int tx_fs) fsk->f_est[i] = 0; fsk->ppm = 0; - - fsk->stats = NULL; + fsk->stats = (struct MODEM_STATS*)malloc(sizeof(struct MODEM_STATS)); + if(fsk->stats == NULL){ + free(fsk->fft_est); + free(fsk->samp_old); + free(fsk->fft_cfg); + free(fsk); + return NULL; + } + return fsk; } @@ -419,11 +433,30 @@ uint32_t fsk_nin(struct FSK *fsk){ void fsk_destroy(struct FSK *fsk){ free(fsk->fft_cfg); free(fsk->samp_old); + free(fsk->stats); free(fsk); } -void fsk_setup_modem_stats(struct FSK *fsk,struct MODEM_STATS *stats){ - fsk->stats = stats; +void fsk_get_demod_stats(struct FSK *fsk, struct MODEM_STATS *stats){ + /* copy from internal stats, note we can't overwrite stats completely + as it has other states rqd by caller, also we want a consistent + interface across modem types for the freedv_api. + */ + + stats->clock_offset = fsk->stats->clock_offset; + stats->snr_est = fsk->stats->snr_est; // TODO: make this SNR not Eb/No + stats->rx_timing = fsk->stats->rx_timing; + stats->foff = fsk->stats->foff; + + stats->neyesamp = fsk->stats->neyesamp; + stats->neyetr = fsk->stats->neyetr; + memcpy(stats->rx_eye, fsk->stats->rx_eye, sizeof(stats->rx_eye)); + + /* these fields not used for FSK so set to something sensible */ + + stats->sync = 0; + stats->nr = fsk->stats->nr; + stats->Nc = fsk->stats->Nc; } /* @@ -893,50 +926,49 @@ void fsk2_demod(struct FSK *fsk, uint8_t rx_bits[], float rx_sd[], COMP fsk_in[] fsk->EbNodB = 1; #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; + /* Write some statistics to the stats struct */ + + /* Save clock offset in ppm */ + fsk->stats->clock_offset = fsk->ppm; - /* Calculate and save SNR from EbNodB estimate */ - fsk->stats->snr_est = .5*fsk->stats->snr_est + .5*fsk->EbNodB;//+ 10*log10f(((float)Rs)/((float)Rs*M)); + /* Calculate and save SNR from EbNodB estimate */ + fsk->stats->snr_est = .5*fsk->stats->snr_est + .5*fsk->EbNodB;//+ 10*log10f(((float)Rs)/((float)Rs*M)); - /* Save rx timing */ - fsk->stats->rx_timing = (float)rx_timing; + /* 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; - - /* Take a sample for the eye diagrams */ - neyesamp = fsk->stats->neyesamp = P*2; - neyeoffset = high_sample+1+(P*28); + /* 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; + + /* Take a sample for the eye diagrams */ + neyesamp = fsk->stats->neyesamp = P*2; + neyeoffset = high_sample+1+(P*28); - int eye_traces = MODEM_STATS_ET_MAX/M; + int eye_traces = MODEM_STATS_ET_MAX/M; - fsk->stats->neyetr = fsk->mode*eye_traces; - for( i=0; istats->rx_eye[i*M+m][j] = cabsolute(f_int[m][neyesamp*i+neyeoffset+j]); - } + fsk->stats->neyetr = fsk->mode*eye_traces; + for( i=0; istats->rx_eye[i*M+m][j] = cabsolute(f_int[m][neyesamp*i+neyeoffset+j]); } + } - eye_max = 0; - /* Normalize eye to +/- 1 */ - for(i=0; istats->rx_eye[i][j])>eye_max) - eye_max = fabsf(fsk->stats->rx_eye[i][j]); + eye_max = 0; + /* Normalize eye to +/- 1 */ + for(i=0; istats->rx_eye[i][j])>eye_max) + eye_max = fabsf(fsk->stats->rx_eye[i][j]); - for(i=0; istats->rx_eye[i][j] = fsk->stats->rx_eye[i][j]/eye_max; + for(i=0; istats->rx_eye[i][j] = fsk->stats->rx_eye[i][j]/eye_max; - fsk->stats->nr = 0; - fsk->stats->Nc = 0; - } + fsk->stats->nr = 0; + fsk->stats->Nc = 0; /* Dump some internal samples */ modem_probe_samp_f("t_EbNodB",&(fsk->EbNodB),1); diff --git a/codec2-dev/src/fsk.h b/codec2-dev/src/fsk.h index b84d802b..470121b1 100644 --- a/codec2-dev/src/fsk.h +++ b/codec2-dev/src/fsk.h @@ -33,14 +33,14 @@ #include "kiss_fftr.h" #include "modem_stats.h" -#define MODE_2FSK 2 -#define MODE_4FSK 4 +#define MODE_2FSK 2 +#define MODE_4FSK 4 #define MODE_M_MAX 4 - -#define FSK_SCALE 16383 - -struct FSK { + +#define FSK_SCALE 16383 + +struct FSK { /* Static parameters set up by fsk_init */ int Ndft; /* buffer size for freq offset est fft */ int Fs; /* sample freq */ @@ -83,7 +83,7 @@ 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 */ + /* modem statistic struct */ struct MODEM_STATS *stats; }; @@ -123,9 +123,9 @@ void fsk_set_est_limits(struct FSK *fsk,int fmin, int fmax); void fsk_clear_estimators(struct FSK *fsk); /* - * Set a MODEM_STATS struct in which to deposit demod statistics + * Fills MODEM_STATS struct with demod statistics */ -void fsk_setup_modem_stats(struct FSK *fsk,struct MODEM_STATS *stats); +void fsk_get_demod_stats(struct FSK *fsk, struct MODEM_STATS *stats); /* * Destroy an FSK state struct and free it's memory diff --git a/codec2-dev/src/fsk_demod.c b/codec2-dev/src/fsk_demod.c index a89249f1..06bad874 100644 --- a/codec2-dev/src/fsk_demod.c +++ b/codec2-dev/src/fsk_demod.c @@ -181,7 +181,6 @@ int main(int argc,char *argv[]){ } if(enable_stats){ - fsk_setup_modem_stats(fsk,&stats); loop_time = ((float)fsk_nin(fsk))/((float)Fs); stats_loop = (int)(1/(stats_rate*loop_time)); stats_ctr = 0; @@ -232,6 +231,7 @@ int main(int argc,char *argv[]){ } if(enable_stats && stats_ctr <= 0){ + fsk_get_demod_stats(fsk,&stats); /* Print standard 2FSK stats */ fprintf(stderr,"{\"EbNodB\": %2.2f,\t\"ppm\": %d,",stats.snr_est,(int)fsk->ppm); fprintf(stderr,"\t\"f1_est\":%.1f,\t\"f2_est\":%.1f",fsk->f_est[0],fsk->f_est[1]); -- 2.25.1