From 6337d026ceb545fe19ea4767e688cd71dc17e6c7 Mon Sep 17 00:00:00 2001 From: drowe67 Date: Mon, 9 Apr 2018 05:45:30 +0000 Subject: [PATCH] ported ofdm sync state machine from Octave, still need to test and debug git-svn-id: https://svn.code.sf.net/p/freetel/code@3459 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/README_ofdm.txt | 22 ++++++++ codec2-dev/src/ofdm.c | 94 ++++++++++++++++++++++++++++++++-- codec2-dev/src/ofdm_internal.h | 26 ++++++++-- 3 files changed, 136 insertions(+), 6 deletions(-) diff --git a/codec2-dev/README_ofdm.txt b/codec2-dev/README_ofdm.txt index 33176225..c5a13a65 100644 --- a/codec2-dev/README_ofdm.txt +++ b/codec2-dev/README_ofdm.txt @@ -66,6 +66,28 @@ Built as part of codec2-dev, see README for build instructions. build_linux/src$ ./ofdm_demod ../../octave/ofdm_test.raw - | ./ofdm_put_test_bits - +Acceptance Tests +---------------- + +The rate 1/2 LPDC code can correct up to about 10% raw BER, so a good +test is to run the modem at Eb/No operating points that produce just +less that BER=0.1 + +The BER2 measure truncates the effect of any start up transients, +e.g. as the frequency offset is tracked out. + +1/ HF Multipath: + + octave:580> ofdm_tx("ofdm_test.raw",60,4,'hf',20,-0.1) + octave:581> ofdm_rx("ofdm_test.raw") + BER2.: 0.0997 Tbits: 93752 Terrs: 9344 + +2/ AWGN: + + octave:582> ofdm_tx("ofdm_test.raw",60,0,'awgn') + octave:583> ofdm_rx("ofdm_test.raw") + BER2.: 0.0827 Tbits: 96846 Terrs: 8008 + C Code ------ diff --git a/codec2-dev/src/ofdm.c b/codec2-dev/src/ofdm.c index e47b18ed..f1e55757 100644 --- a/codec2-dev/src/ofdm.c +++ b/codec2-dev/src/ofdm.c @@ -4,12 +4,13 @@ AUTHORS.....: David Rowe & Steve Sampson DATE CREATED: June 2017 - A Library of functions that implement a BPSK/QPSK OFDM modem + A Library of functions that implement a QPSK OFDM modem, C port of + the Octave functions in ofdm_lib.m \*---------------------------------------------------------------------------*/ /* - Copyright (C) 2017 David Rowe + Copyright (C) 2017/2018 David Rowe All rights reserved. @@ -378,6 +379,16 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) { ofdm->timing_mx = 0.0f; ofdm->nin = OFDM_SAMPLESPERFRAME; + /* sync state machine */ + + strcpy(ofdm->sync_state,"searching"); + strcpy(ofdm->last_sync_state,"searching"); + ofdm->uw_errors = 0; + ofdm->sync_counter = 0; + ofdm->frame_count = 0; + ofdm->sync_start = 0; + ofdm->sync_end = 0; + /* create the OFDM waveform */ complex float temp[OFDM_M]; @@ -613,7 +624,7 @@ void ofdm_demod(struct OFDM *ofdm, int *rx_bits, COMP *rxbuf_in) { ofdm->timing_est += (ft_est - ceilf(OFDM_FTWINDOWWIDTH / 2)); if (ofdm->verbose > 1) { - fprintf(stdout, " ft_est: %2d timing_est: %2d sample_point: %2d\n", ft_est, ofdm->timing_est, ofdm->sample_point); + fprintf(stderr, " ft_est: %2d timing_est: %2d sample_point: %2d\n", ft_est, ofdm->timing_est, ofdm->sample_point); } /* Black magic to keep sample_point inside cyclic prefix. Or something like that. */ @@ -935,3 +946,80 @@ void ofdm_demod(struct OFDM *ofdm, int *rx_bits, COMP *rxbuf_in) { } } + +/* iterate state machine ------------------------------------*/ + +void ofdm_sync_state_machine(struct OFDM *ofdm, int *rx_uw) { + char next_state[OFDM_STATE_STR]; + int i, j, sync_counter_thresh; + + strcpy(next_state, ofdm->sync_state); + ofdm->sync_start = ofdm->sync_end = 0; + + if (strcmp(ofdm->sync_state,"searching") == 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; + strcpy(next_state, "trial_sync"); + } + } + + if ((strcmp(ofdm->sync_state,"synced") == 0) || (strcmp(ofdm->sync_state, "trial_sync") == 0)) { + + ofdm->frame_count++; + + /* during trial sync we don't tolerate errors so much, once we have synced up + we are willing to wait out a fade */ + + if (ofdm->frame_count == 3) { + strcpy(next_state, "synced"); + } + + if (strcmp(ofdm->sync_state, "synced") == 0) { + sync_counter_thresh = 6; + } else { + sync_counter_thresh = 3; + } + + /* freq offset est may be too far out, and has aliases every 1/Ts, so + we use a Unique Word to get a really solid indication of sync. */ + + ofdm->uw_errors = 0; + for (i=0; iuw_errors += rx_uw[i]; + } + if (ofdm->uw_errors > 2) { + ofdm->sync_counter++; + } + if (ofdm->sync_counter == sync_counter_thresh) { + strcpy(next_state, "searching"); + } else { + ofdm->sync_counter = 0; + } + } + + strcpy(ofdm->last_sync_state, ofdm->sync_state); + strcpy(ofdm->sync_state, next_state); +} + diff --git a/codec2-dev/src/ofdm_internal.h b/codec2-dev/src/ofdm_internal.h index 5d37a322..d0de273a 100644 --- a/codec2-dev/src/ofdm_internal.h +++ b/codec2-dev/src/ofdm_internal.h @@ -43,7 +43,7 @@ extern "C" { #define TAU (2.0f * M_PI) /* mathematical constant */ -#define OFDM_NC 16 /* N Carriers */ +#define OFDM_NC 17 /* N Carriers */ #define OFDM_TS 0.018f /* Symbol time */ #define OFDM_RS (1.0f / OFDM_TS) /* Symbol rate */ #define OFDM_FS 8000.0f /* Sample rate */ @@ -64,7 +64,7 @@ extern "C" { #define OFDM_NCP ((int)(OFDM_TCP * OFDM_FS)) #endif -/* ? */ +/* number of symbols we estimate fine timing over */ #define OFDM_FTWINDOWWIDTH 11 /* Bits per frame (duh) */ #define OFDM_BITSPERFRAME ((OFDM_NS - 1) * (OFDM_NC * OFDM_BPS)) @@ -76,7 +76,17 @@ 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.3 + +/* reserve 4 bits/frame for auxillary text information */ + +#define OFDM_TXT_LEN 4 + +/* Unique word, used for positive indication of lock */ + +#define OFDM_UW_LEN ((OFDM_NS-1)*OFDM_BPS - OFDM_TXT_LEN) + +#define OFDM_STATE_STR 16 /* Dummy struct for now, will contain constant configuration for OFDM modem */ struct OFDM_CONFIG{ @@ -113,6 +123,16 @@ struct OFDM { complex float rx_np[OFDM_ROWSPERFRAME * OFDM_NC]; float rx_amp[OFDM_ROWSPERFRAME * OFDM_NC]; float aphase_est_pilot_log[OFDM_ROWSPERFRAME * OFDM_NC]; + + /* sync state machine */ + + char sync_state[OFDM_STATE_STR]; + char last_sync_state[OFDM_STATE_STR]; + int uw_errors; + int sync_counter; + int frame_count; + int sync_start; + int sync_end; }; #ifdef __cplusplus -- 2.25.1