ported ofdm sync state machine from Octave, still need to test and debug
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Mon, 9 Apr 2018 05:45:30 +0000 (05:45 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Mon, 9 Apr 2018 05:45:30 +0000 (05:45 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@3459 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/README_ofdm.txt
codec2-dev/src/ofdm.c
codec2-dev/src/ofdm_internal.h

index 33176225c60474f0754fc4d736e8f3b3d8ffab0c..c5a13a65803b1e1523c143c297bf6ba4f8b15159 100644 (file)
@@ -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
 ------
 
index e47b18ed2b7e5896cc462e402e42a486b3bd6472..f1e557570ba799e5b32fc9d341369e143d8005ea 100644 (file)
@@ -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; i<OFDM_UW_LEN; i++) {
+            ofdm->uw_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);
+}
+
index 5d37a322ec1003e5abc78442964d4de80873de2b..d0de273a5f7fd02c2e7b9dc141ed7fb1fc0a071f 100644 (file)
@@ -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