From: drowe67 Date: Tue, 8 May 2018 10:46:02 +0000 (+0000) Subject: better freq offset estimation and sync, but still has some false sync states, ofdm_mo... X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=39588e0dc5da7dcb60521e01dbf9df59b740fdea;p=freetel-svn-tracking.git better freq offset estimation and sync, but still has some false sync states, ofdm_mod working with test frames, verbose option for freedv_rx git-svn-id: https://svn.code.sf.net/p/freetel/code@3585 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2-dev/src/freedv_api.c b/codec2-dev/src/freedv_api.c index 74c8d7d3..b8f4dc2c 100644 --- a/codec2-dev/src/freedv_api.c +++ b/codec2-dev/src/freedv_api.c @@ -108,6 +108,7 @@ struct freedv *freedv_open_advanced(int mode, struct freedv_advanced *adv) { return NULL; f->mode = mode; + f->verbose = 0; f->test_frames = f->smooth_symbols = 0; f->freedv_put_error_pattern = NULL; f->error_pattern_callback_state = NULL; @@ -1810,12 +1811,12 @@ static int freedv_comprx_700d(struct freedv *f, COMP demod_in_8kHz[], int *valid //fprintf(stderr, "nin: %d\n", ofdm_get_nin(ofdm)); ofdm_sync_state_machine(ofdm, rx_uw); - /* - fprintf(stderr, "%3d st: %-6s euw: %2d %1d f: %5.1f ist: %-6s %2d eraw: %3d ecdd: %3d iter: %3d pcc: %3d vld: %d, nout: %4d\n", - 0, ofdm->last_sync_state, ofdm->uw_errors, ofdm->sync_counter, ofdm->foff_est_hz, - ofdm->last_sync_state_interleaver, ofdm->frame_count_interleaver, - Nerrs_raw, Nerrs_coded, iter, parityCheckCount, *valid, nout); - */ + if (f->verbose) { + fprintf(stderr, "%3d st: %-6s euw: %2d %1d f: %5.1f ist: %-6s %2d eraw: %3d ecdd: %3d iter: %3d pcc: %3d vld: %d, nout: %4d\n", + 0, ofdm->last_sync_state, ofdm->uw_errors, ofdm->sync_counter, ofdm->foff_est_hz, + ofdm->last_sync_state_interleaver, ofdm->frame_count_interleaver, + Nerrs_raw, Nerrs_coded, iter, parityCheckCount, *valid, nout); + } /* no valid FreeDV signal - squelch output */ @@ -2112,6 +2113,13 @@ void freedv_set_total_bits_coded (struct freedv *f, int val) {f->total_ void freedv_set_clip (struct freedv *f, int val) {f->clip = val;} void freedv_set_varicode_code_num (struct freedv *f, int val) {varicode_set_code_num(&f->varicode_dec_states, val);} +void freedv_set_verbose(struct freedv *f, int verbosity) { + f->verbose = verbosity; + if (f->mode == FREEDV_MODE_700D) { + ofdm_set_verbose(f->ofdm, f->verbose); + } +} + // Set floats void freedv_set_snr_squelch_thresh (struct freedv *f, float val) {f->snr_squelch_thresh = val;} diff --git a/codec2-dev/src/freedv_api.h b/codec2-dev/src/freedv_api.h index 179d2053..7809fe7f 100644 --- a/codec2-dev/src/freedv_api.h +++ b/codec2-dev/src/freedv_api.h @@ -129,6 +129,7 @@ void freedv_set_data_header (struct freedv *freedv, unsigned char *h int freedv_set_alt_modem_samp_rate (struct freedv *freedv, int samp_rate); void freedv_set_carrier_ampl (struct freedv *freedv, int c, float ampl); void freedv_set_sync (struct freedv *freedv, int sync_cmd); +void freedv_set_verbose (struct freedv *freedv, int verbosity); // Get parameters ------------------------------------------------------------------------- diff --git a/codec2-dev/src/freedv_api_internal.h b/codec2-dev/src/freedv_api_internal.h index 9d2a0e86..f7686e1b 100644 --- a/codec2-dev/src/freedv_api_internal.h +++ b/codec2-dev/src/freedv_api_internal.h @@ -125,7 +125,8 @@ struct freedv { float snr_squelch_thresh; int squelch_en; int nin; - + int verbose; + /* Varicode txt channel states ----------------------------------------------------------------------*/ struct VARICODE_DEC varicode_dec_states; diff --git a/codec2-dev/src/freedv_rx.c b/codec2-dev/src/freedv_rx.c index 2c73dfa2..5d47d941 100644 --- a/codec2-dev/src/freedv_rx.c +++ b/codec2-dev/src/freedv_rx.c @@ -93,14 +93,14 @@ int main(int argc, char *argv[]) { int sync; float snr_est; float clock_offset; - int use_codecrx, use_testframes, interleave_frames; + int use_codecrx, use_testframes, interleave_frames, verbose; struct CODEC2 *c2 = NULL; int i; if (argc < 4) { printf("usage: %s 1600|700|700B|700C|700D|2400A|2400B|800XA InputModemSpeechFile OutputSpeechRawFile\n" - " [--testframes] [--interleaver depth] [--codecrx]\n", argv[0]); + " [--testframes] [--interleaver depth] [--codecrx] [-v]\n", argv[0]); printf("e.g %s 1600 hts1a_fdmdv.raw hts1a_out.raw txtLogFile\n", argv[0]); exit(1); } @@ -138,7 +138,7 @@ int main(int argc, char *argv[]) { exit(1); } - use_codecrx = 0; use_testframes = 0; interleave_frames = 1; + use_codecrx = 0; use_testframes = 0; interleave_frames = 1; verbose = 0; if (argc > 4) { for (i = 4; i < argc; i++) { @@ -164,6 +164,9 @@ int main(int argc, char *argv[]) { if (strcmp(argv[i], "--interleave") == 0) { interleave_frames = atoi(argv[i+1]); } + if (strcmp(argv[i], "-v") == 0) { + verbose = 1; + } } } @@ -178,6 +181,7 @@ int main(int argc, char *argv[]) { assert(freedv != NULL); freedv_set_test_frames(freedv, use_testframes); + freedv_set_verbose(freedv, verbose); freedv_set_snr_squelch_thresh(freedv, -100.0); freedv_set_squelch_en(freedv, 0); diff --git a/codec2-dev/src/interldpc.c b/codec2-dev/src/interldpc.c index e3da534c..71845281 100644 --- a/codec2-dev/src/interldpc.c +++ b/codec2-dev/src/interldpc.c @@ -128,7 +128,7 @@ void interleaver_sync_state_machine(struct OFDM *ofdm, // fprintf(stderr,"%d ", out_char[i]); //fprintf(stderr,"\n"); //fprintf(stderr, " iter: %d pcc: %d Nerrs: %d\n", iter[0], parityCheckCount[0], Nerrs_coded[0]); - if ((Nerrs_coded[0] == 0) && (iter[0] <= 5)) { + if ((Nerrs_coded[0] < 10) || (interleave_frames == 1)) { /* sucessful decode! */ strcpy(next_sync_state_interleaver, "synced"); ofdm->frame_count_interleaver = interleave_frames; diff --git a/codec2-dev/src/ofdm.c b/codec2-dev/src/ofdm.c index 75d8db8c..562991b3 100644 --- a/codec2-dev/src/ofdm.c +++ b/codec2-dev/src/ofdm.c @@ -51,7 +51,6 @@ const struct OFDM_CONFIG * OFDM_CONFIG_700D = &OFDM_CONFIG_700D_C; static void dft(struct OFDM *, complex float *, complex float *); static void idft(struct OFDM *, complex float *, complex float *); static complex float vector_sum(complex float *, int); -static int coarse_sync(struct OFDM *, complex float *, int, float *); /* Defines */ @@ -169,6 +168,7 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) { ofdm->timing_mx = 0.0f; ofdm->nin = OFDM_SAMPLESPERFRAME; ofdm->mean_amp = 0.0f; + ofdm->foff_metric = 0.0f + 0.0f * I; /* sync state machine */ @@ -196,13 +196,15 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) { idft(ofdm, temp, ofdm->pilots); /* - * pilot_samples is 160 samples, as we copy the last 16 to the front + * pilot_samples is 160 samples, but timing and freq offset est + * were found by experiment to work better without a cyclic + * prefix, so we uses zeroes instead. */ - /* first copy the last Cyclic Prefix (CP) values */ + /* zero out Cyclic Prefix (CP) values */ for (i = 0, j = (OFDM_M - OFDM_NCP); i < OFDM_NCP; i++, j++) { - ofdm->pilot_samples[i] = temp[j]; + ofdm->pilot_samples[i] = 0.0f + 0.0f * I;; } // From Octave: states.timing_norm = Npsam*(rate_fs_pilot_samples*rate_fs_pilot_samples'); @@ -218,8 +220,8 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) { float acc = 0.0f; for (i = 0; i < (OFDM_M + OFDM_NCP); i++) { - acc += (crealf(ofdm->pilot_samples[i]) * crealf(ofdm->pilot_samples[i]) + - cimagf(ofdm->pilot_samples[i]) * cimagf(ofdm->pilot_samples[i])); + acc += crealf(ofdm->pilot_samples[i]) * crealf(ofdm->pilot_samples[i]) + + cimagf(ofdm->pilot_samples[i]) * cimagf(ofdm->pilot_samples[i]); } ofdm->timing_norm = (OFDM_M + OFDM_NCP) * acc; @@ -298,19 +300,17 @@ static complex float vector_sum(complex float *a, int num_elements) { * samples to determine the most likely timing offset. Combines two * frames pilots so we need at least Nsamperframe+M+Ncp samples in rx. * - * Also estimates coarse frequency offset based on sampling the pilots - * phase at half symbol intervales. - * + * Can be used for acquisition (coarse timing), and fine timing. + * * Unlike Octave version use states to return a few values. */ -static int coarse_sync(struct OFDM *ofdm, complex float *rx, int length, float *foff_est) { - complex float csam, csam1, csam2; +static int est_timing(struct OFDM *ofdm, complex float *rx, int length) { + complex float csam; int Ncorr = length - (OFDM_SAMPLESPERFRAME + (OFDM_M + OFDM_NCP)); - int Fs = OFDM_FS; int SFrame = OFDM_SAMPLESPERFRAME; float corr[Ncorr]; - int i, j, k; + int i, j; float acc = 0.0f; @@ -349,11 +349,36 @@ static int coarse_sync(struct OFDM *ofdm, complex float *rx, int length, float * ofdm->timing_valid = timing_mx > OFDM_TIMING_MX_THRESH; if (ofdm->verbose > 1) { - fprintf(stderr, " max: %f timing_est: %d timing_valid: %d\n", ofdm->timing_mx, timing_est, ofdm->timing_valid); + fprintf(stderr, " av_level: %f max: %f timing_est: %d timing_valid: %d\n", av_level, ofdm->timing_mx, timing_est, ofdm->timing_valid); } - /* Coarse frequency estimation - note this isn't always used, some CPU could be saved - buy putting this in another function */ + return timing_est; +} + + +/* + * Determines frequency offset at current timing estimate, used for + * coarse freq offset estimation during acquisition. + * + * Freq offset is based on an averaged statistic that was found to be + * necessary to generate good quality estimates. + * + * Keep calling it when in trial or actual sync to keep statistic + * updated, in case we lose sync. + */ + + static float est_freq_offset(struct OFDM *ofdm, complex float *rx, int length, int timing_est) { + complex float csam1, csam2; + int Fs = OFDM_FS; + int SFrame = OFDM_SAMPLESPERFRAME; + int j, k; + float foff_est; + + /* + Freq offset can be considered as change in phase over two halves + of pilot symbols. We average this statistic over this and next + frames pilots. + */ complex float p1, p2, p3, p4; p1 = p2 = p3 = p4 = 0.0f + 0.0f * I; @@ -385,11 +410,17 @@ static int coarse_sync(struct OFDM *ofdm, complex float *rx, int length, float * improve estimate. Small real 1E-12 term to prevent instability with 0 inputs. */ - *foff_est = Fs1 * cargf(conjf(p1) * p2 + conjf(p3) * p4 + 1E-12f) / TAU; + ofdm->foff_metric = 0.9*ofdm->foff_metric + 0.1*(conjf(p1) * p2 + conjf(p3) * p4); + foff_est = Fs1 * cargf( ofdm->foff_metric + 1E-12f) / TAU; - return timing_est; + if (ofdm->verbose > 1) { + fprintf(stderr, " foff_metric: %f %f foff_est: %f\n", crealf(ofdm->foff_metric), cimagf(ofdm->foff_metric), foff_est); + } + + return foff_est; } + /* * ---------------------------------------------- * ofdm_txframe - modulates one frame of symbols @@ -562,8 +593,9 @@ int ofdm_sync_search(struct OFDM *ofdm, COMP *rxbuf_in) int st = OFDM_M + OFDM_NCP + OFDM_SAMPLESPERFRAME; int en = st + 2*OFDM_SAMPLESPERFRAME; - int ct_est = coarse_sync(ofdm, &ofdm->rxbuf[st], (en - st), &ofdm->coarse_foff_est_hz); - + int ct_est = est_timing(ofdm, &ofdm->rxbuf[st], (en - st)); + ofdm->coarse_foff_est_hz = est_freq_offset(ofdm, &ofdm->rxbuf[st], (en - st), ct_est); + if (ofdm->verbose) { fprintf(stderr, " ct_est: %4d foff_est: %3.1f timing_valid: %d timing_mx: %f\n", ct_est, ofdm->coarse_foff_est_hz, ofdm->timing_valid, ofdm->timing_mx); @@ -641,9 +673,16 @@ void ofdm_demod(struct OFDM *ofdm, int *rx_bits, COMP *rxbuf_in) { /* note coarse sync just used for timing est, we dont use coarse_foff_est in this call */ - ft_est = coarse_sync(ofdm, work, (en - st), &ofdm->coarse_foff_est_hz); + ft_est = est_timing(ofdm, work, (en - st)); ofdm->timing_est += (ft_est - ceilf(OFDM_FTWINDOWWIDTH / 2)); + /* keep the freq est statistic updated in case we lose sync, + note we supply it with uncorrected rxbuf, note + ofdm->coarse_fest_off_hz is unused in normal operation, + but stored for use in tofdm.c */ + + ofdm->coarse_foff_est_hz = est_freq_offset(ofdm, &ofdm->rxbuf[st], (en-st), ft_est); + if (ofdm->verbose > 1) { fprintf(stderr, " ft_est: %2d timing_est: %2d sample_point: %2d\n", ft_est, ofdm->timing_est, ofdm->sample_point); } @@ -1020,34 +1059,13 @@ void ofdm_demod(struct OFDM *ofdm, int *rx_bits, COMP *rxbuf_in) { void ofdm_sync_state_machine(struct OFDM *ofdm, int *rx_uw) { char next_state[OFDM_STATE_STR]; - int i, j; + int i; strcpy(next_state, ofdm->sync_state); ofdm->sync_start = ofdm->sync_end = 0; if (strcmp(ofdm->sync_state,"search") == 0) { if (ofdm->timing_valid) { - - /* freq offset est has some bias, but this refinement step fixes bias */ - - int st = OFDM_M + OFDM_NCP + OFDM_SAMPLESPERFRAME; - int en = st + 2 * OFDM_SAMPLESPERFRAME; - float woff_est = TAU * ofdm->foff_est_hz / OFDM_FS; - - complex float work[(en - st)]; - - for (i = st, j = 0; i < en; i++, j++) { - work[j] = ofdm->rxbuf[i] * cexpf(-I * woff_est * i); - } - - float foff_est; - coarse_sync(ofdm, work, (en - st), &foff_est); - - if (ofdm->verbose) { - fprintf(stderr, " coarse_foff: %4.1f refine: %4.1f combined: %4.1f\n", ofdm->foff_est_hz, foff_est, ofdm->foff_est_hz+foff_est); - } - - ofdm->foff_est_hz += foff_est; ofdm->frame_count = 0; ofdm->sync_counter = 0; ofdm->sync_start = 1; @@ -1100,7 +1118,7 @@ void ofdm_sync_state_machine(struct OFDM *ofdm, int *rx_uw) { ofdm->sync_counter = 0; } - if ((ofdm->sync_mode == OFDM_SYNC_AUTO) && (ofdm->sync_counter == 6)) { + if ((ofdm->sync_mode == OFDM_SYNC_AUTO) && (ofdm->sync_counter == 12)) { /* run of consective bad frames ... drop sync */ strcpy(next_state, "search"); strcpy(ofdm->sync_state_interleaver, "search"); diff --git a/codec2-dev/src/ofdm_demod.c b/codec2-dev/src/ofdm_demod.c index c5e26889..0ee5f0d4 100644 --- a/codec2-dev/src/ofdm_demod.c +++ b/codec2-dev/src/ofdm_demod.c @@ -169,6 +169,9 @@ int main(int argc, char *argv[]) if ((arg = opt_exists(argv, argc, "-v")) != 0) { ofdm_set_verbose(ofdm, 1); } + if ((arg = opt_exists(argv, argc, "-vv")) != 0) { + ofdm_set_verbose(ofdm, 2); + } int Nbitsperframe = ofdm_get_bits_per_frame(ofdm); int Nmaxsamperframe = ofdm_get_max_samples_per_frame(); @@ -206,7 +209,7 @@ int main(int argc, char *argv[]) if (strcmp(ofdm->sync_state,"search") == 0) { ofdm_sync_search(ofdm, rxbuf_in); } - + if ((strcmp(ofdm->sync_state,"synced") == 0) || (strcmp(ofdm->sync_state,"trial") == 0) ) { ofdm_demod(ofdm, rx_bits, rxbuf_in); diff --git a/codec2-dev/src/ofdm_internal.h b/codec2-dev/src/ofdm_internal.h index a52d8c33..119dd513 100644 --- a/codec2-dev/src/ofdm_internal.h +++ b/codec2-dev/src/ofdm_internal.h @@ -78,7 +78,7 @@ extern "C" { #define OFDM_MAX_SAMPLESPERFRAME (OFDM_SAMPLESPERFRAME + (OFDM_M + OFDM_NCP)/4) #define OFDM_RXBUF (3 * OFDM_SAMPLESPERFRAME + 3 * (OFDM_M + OFDM_NCP)) -#define OFDM_TIMING_MX_THRESH 0.3 +#define OFDM_TIMING_MX_THRESH 0.25 /* reserve 4 bits/frame for auxillary text information */ @@ -128,6 +128,7 @@ struct OFDM { float sig_var; float noise_var; float mean_amp; + complex float foff_metric; /* modem sync state machine */ diff --git a/codec2-dev/src/ofdm_mod.c b/codec2-dev/src/ofdm_mod.c index adc265e1..2c398390 100644 --- a/codec2-dev/src/ofdm_mod.c +++ b/codec2-dev/src/ofdm_mod.c @@ -70,7 +70,7 @@ int main(int argc, char *argv[]) if (argc < 3) { fprintf(stderr, "\n"); fprintf(stderr, "usage: %s InputOneCharPerBitFile OutputModemRawFile [--lpdc] [--interleaver depth]\n\n", argv[0]); - fprintf(stderr, " --testframe Nsecs Transmit test frames (adjusts test frames for raw and LDPC modes)\n"); + fprintf(stderr, " --testframes Nsecs Transmit test frames (adjusts test frames for raw and LDPC modes)\n"); fprintf(stderr, " --ldpc Run (%d,%d) LDPC decoder. This forces 112, one char/bit output values\n" " per frame. In testframe mode (-t) raw and coded errors will be counted\n", coded_bits_per_frame, data_bits_per_frame); @@ -126,7 +126,7 @@ int main(int argc, char *argv[]) testframes = 0; int Nframes = 0; - if ((arg = (opt_exists(argv, argc, "-t")))) { + if ((arg = (opt_exists(argv, argc, "--testframes")))) { testframes = 1; int Nsec, Nrows; Nsec = atoi(argv[arg+1]);