added support for measuring bit errors before diversity combination, part of 700C...
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Thu, 23 Feb 2017 03:35:46 +0000 (03:35 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Thu, 23 Feb 2017 03:35:46 +0000 (03:35 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@3047 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/src/codec2_cohpsk.h
codec2-dev/src/cohpsk.c
codec2-dev/src/cohpsk_demod.c
codec2-dev/src/cohpsk_internal.h
codec2-dev/src/cohpsk_put_test_bits.c
codec2-dev/src/freedv_api.c
codec2-dev/src/freedv_api.h
codec2-dev/src/freedv_api_internal.h

index b64cde84e6a9240afca2cec0cb4a8656a8fe2266..5520ec793642a6abfe563cba18288bbf1c863862 100644 (file)
@@ -53,9 +53,15 @@ void cohpsk_get_demod_stats(struct COHPSK *cohpsk, struct MODEM_STATS *stats);
 void cohpsk_set_verbose(struct COHPSK *coh, int verbose);
 void cohpsk_get_test_bits(struct COHPSK *coh, int rx_bits[]);
 void cohpsk_put_test_bits(struct COHPSK *coh, int *state, short error_pattern[],
-                          int *bit_errors, char rx_bits[]);
+                          int *bit_errors, char rx_bits[], int channel);
 int cohpsk_error_pattern_size(void);
 void cohpsk_set_frame(struct COHPSK *coh, int frame);
 void fdmdv_freq_shift_coh(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, float Fs,
                           COMP *foff_phase_rect, int nin);
+
+/* used for accessing upper and lower bits before diversity combination */
+
+float *cohpsk_get_rx_bits_lower(struct COHPSK *coh);
+float *cohpsk_get_rx_bits_upper(struct COHPSK *coh);
+
 #endif
index 83f155c5ac2e5afcb0a1a32e5cdbd0d3fa432403..58d13b29ca294c54208590e96101b1fd337b75e0 100644 (file)
@@ -181,7 +181,7 @@ struct COHPSK *cohpsk_create(void)
 
     /* test frames */
 
-    coh->ptest_bits_coh_tx = coh->ptest_bits_coh_rx = (int*)test_bits_coh;
+    coh->ptest_bits_coh_tx = coh->ptest_bits_coh_rx[0] = coh->ptest_bits_coh_rx[1] = (int*)test_bits_coh;
     coh->ptest_bits_coh_end = (int*)test_bits_coh + sizeof(test_bits_coh)/sizeof(int);
 
     return coh;
@@ -362,6 +362,18 @@ void qpsk_symbols_to_bits(struct COHPSK *coh, float rx_bits[], COMP ct_symb_buf[
             i = c*NSYMROW + r;
             rx_bits[2*i+1] = rot.real;
             rx_bits[2*i]   = rot.imag;
+
+            /* demodulate bits from upper and lower carriers separately for test purposes */
+
+            assert(ND == 2);
+
+            i = c*NSYMROW + r;
+            rot = cmult(coh->rx_symb[r][c], pi_on_4);
+            coh->rx_bits_lower[2*i+1] = rot.real;
+            coh->rx_bits_lower[2*i]   = rot.imag;
+            rot = cmult(coh->rx_symb[r][c + COHPSK_NC], pi_on_4);
+            coh->rx_bits_upper[2*i+1] = rot.real;
+            coh->rx_bits_upper[2*i]   = rot.imag;
         }
     }
 
@@ -1195,23 +1207,29 @@ void cohpsk_get_test_bits(struct COHPSK *coh, int rx_bits[])
   Accepts bits from demod and attempts to sync with the known
   test_bits sequence.  When synced measures bit errors.
 
+  Has states to track two separate received test sequences based on
+  channel 0 or 1.
+
 \*---------------------------------------------------------------------------*/
 
 void cohpsk_put_test_bits(struct COHPSK *coh, int *state, short error_pattern[],
-                        int *bit_errors, char rx_bits_char[])
+                          int *bit_errors, char rx_bits_char[], int channel)
 {
     int i, next_state, anerror;
     int rx_bits[COHPSK_BITS_PER_FRAME];
 
+    assert((channel == 0) || (channel == 1));
+    int *ptest_bits_coh_rx = coh->ptest_bits_coh_rx[channel];
+
     for(i=0; i<COHPSK_BITS_PER_FRAME; i++) {
         rx_bits[i] = rx_bits_char[i];
     }
 
     *bit_errors = 0;
     for(i=0; i<COHPSK_BITS_PER_FRAME; i++) {
-        anerror = (rx_bits[i] & 0x1) ^ coh->ptest_bits_coh_rx[i];
+        anerror = (rx_bits[i] & 0x1) ^ ptest_bits_coh_rx[i];
         if ((anerror < 0) || (anerror > 1)) {
-            fprintf(stderr, "i: %d rx_bits: %d ptest_bits_coh_rx: %d\n", i, rx_bits[i], coh->ptest_bits_coh_rx[i]);
+            fprintf(stderr, "i: %d rx_bits: %d ptest_bits_coh_rx: %d\n", i, rx_bits[i], ptest_bits_coh_rx[i]);
         }
         *bit_errors += anerror;
         error_pattern[i] = anerror;
@@ -1224,9 +1242,9 @@ void cohpsk_put_test_bits(struct COHPSK *coh, int *state, short error_pattern[],
     if (*state == 0) {
         if (*bit_errors < 4) {
             next_state = 1;
-            coh->ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME;
-            if (coh->ptest_bits_coh_rx >= coh->ptest_bits_coh_end) {
-                coh->ptest_bits_coh_rx = (int*)test_bits_coh;
+            ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME;
+            if (ptest_bits_coh_rx >= coh->ptest_bits_coh_end) {
+                ptest_bits_coh_rx = (int*)test_bits_coh;
             }
         }
     }
@@ -1245,19 +1263,30 @@ void cohpsk_put_test_bits(struct COHPSK *coh, int *state, short error_pattern[],
     }
 
     if (*state > 0) {
-        coh->ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME;
-        if (coh->ptest_bits_coh_rx >= coh->ptest_bits_coh_end) {
-            coh->ptest_bits_coh_rx = (int*)test_bits_coh;
+        ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME;
+        if (ptest_bits_coh_rx >= coh->ptest_bits_coh_end) {
+            ptest_bits_coh_rx = (int*)test_bits_coh;
         }
     }
 
     //fprintf(stderr, "state: %d next_state: %d bit_errors: %d\n", *state, next_state, *bit_errors);
 
     *state = next_state;
+    coh->ptest_bits_coh_rx[channel] = ptest_bits_coh_rx;
 }
 
+
 int cohpsk_error_pattern_size(void) {
     return COHPSK_BITS_PER_FRAME;
 }
 
 
+float *cohpsk_get_rx_bits_lower(struct COHPSK *coh) {
+    return coh->rx_bits_lower;
+}
+
+
+float *cohpsk_get_rx_bits_upper(struct COHPSK *coh) {
+    return coh->rx_bits_upper;
+}
+
index 875cc7e87be6487925c7bf73819ad3d679c45988..e05e7c84e2e901c80ad5fd27d1d6ca5c8504bcc7 100644 (file)
@@ -88,7 +88,7 @@ int main(int argc, char *argv[])
     }
 
     cohpsk = cohpsk_create();
-    cohpsk_set_verbose(cohpsk, 1);
+    cohpsk_set_verbose(cohpsk, 0);
 
     if (oct) {
         logframes = LOG_FRAMES;
index b77aff0ba80f1baa694497ac82384dd57ac1df8e..e8ce554128af71ac4cf2263b9c9efccf8cac98b2 100644 (file)
@@ -46,9 +46,9 @@
 struct COHPSK {
     COMP         ch_fdm_frame_buf[NSW*NSYMROWPILOT*COHPSK_M];  /* buffer of several frames of symbols from channel      */
     float        pilot2[2*NPILOTSFRAME][COHPSK_NC];
-    float        phi_[NSYMROW][COHPSK_NC*ND];           /* phase estimates for this frame of rx data symbols     */
+    float        phi_[NSYMROWPILOT][COHPSK_NC*ND];      /* phase estimates for this frame of rx data symbols     */
     float        amp_[NSYMROW][COHPSK_NC*ND];           /* amplitude estimates for this frame of rx data symbols */
-    COMP         rx_symb[NSYMROW][COHPSK_NC*ND];        /* demodulated symbols                                   */
+    COMP         rx_symb[NSYMROWPILOT][COHPSK_NC*ND];   /* demodulated symbols                                   */
     float        f_est;
     COMP         rx_filter_memory[COHPSK_NC*ND][COHPSK_NFILTER];
     COMP         ct_symb_buf[NCT_SYMB_BUF][COHPSK_NC*ND];
@@ -73,9 +73,14 @@ struct COHPSK {
     int           verbose;
 
     int          *ptest_bits_coh_tx;
-    int          *ptest_bits_coh_rx;
+    int          *ptest_bits_coh_rx[2];
     int          *ptest_bits_coh_end;
 
+    /* counting bit errors using pilots */
+
+    int           npilotbits;
+    int           npilotbiterrors;
+
     /* optional log variables used for testing Octave to C port */
 
     COMP          *rx_baseband_log;
@@ -92,6 +97,11 @@ struct COHPSK {
 
     float         *rx_timing_log;
     int            rx_timing_log_index;
+
+    /* demodulated bits before diversity combination for test/instrumentation purposes */
+
+    float          rx_bits_lower[COHPSK_BITS_PER_FRAME];
+    float          rx_bits_upper[COHPSK_BITS_PER_FRAME];
 };
 
 void bits_to_qpsk_symbols(COMP tx_symb[][COHPSK_NC*COHPSK_ND], int tx_bits[], int nbits);
index aa2c4e804a75582646bc0bf6f5ec5ff503740ea2..d2f6d198c5d12f2d2d050b1ca9b35a5449c5c294 100644 (file)
@@ -82,7 +82,7 @@ int main(int argc, char *argv[])
     state = 0; nbits = 0; nerrors = 0;
     while (fread(rx_bits, sizeof(char), COHPSK_BITS_PER_FRAME, fin) ==  COHPSK_BITS_PER_FRAME) {
 
-        cohpsk_put_test_bits(coh, &state, error_pattern, &bit_errors, rx_bits);
+        cohpsk_put_test_bits(coh, &state, error_pattern, &bit_errors, rx_bits, 0);
         if (state == 1) {
             for(i=0; i<COHPSK_BITS_PER_FRAME; i++)
                 error_positions_hist[i] += error_pattern[i];
index f8930445cb81ac41af565056b924e04612853aec..9a64c658ef86218c4365a92ecdd99b8abca04719 100644 (file)
@@ -156,7 +156,7 @@ struct freedv *freedv_open(int mode) {
         f->sz_error_pattern = cohpsk_error_pattern_size();
     }
 #endif  
-    if ((mode == FREEDV_MODE_2400A) || (mode == FREEDV_MODE_2400B)){
+    if ((mode == FREEDV_MODE_2400A) || (mode == FREEDV_MODE_2400B)) {
       
         /* Set up the C2 mode */
         codec2_mode = CODEC2_MODE_1300;
@@ -246,7 +246,9 @@ struct freedv *freedv_open(int mode) {
     }
     
 
+    f->test_frames_diversity = 1;
     f->test_frame_sync_state = 0;
+    f->test_frame_sync_state_upper = 0;
     f->total_bits = 0;
     f->total_bit_errors = 0;
 
@@ -1229,21 +1231,63 @@ static int freedv_comprx_fdmdv_700(struct freedv *f, COMP demod_in_8kHz[], int *
             nout = f->n_speech_samples;
         }
         else {
-            short error_pattern[COHPSK_BITS_PER_FRAME];
-            int   bit_errors;
-
-            /* test data, lets see if we can sync to the test data sequence */
-
-            char rx_bits_char[COHPSK_BITS_PER_FRAME];
-            for(i=0; i<COHPSK_BITS_PER_FRAME; i++)
-                rx_bits_char[i] = rx_bits[i] < 0.0;
-            cohpsk_put_test_bits(f->cohpsk, &f->test_frame_sync_state, error_pattern, &bit_errors, rx_bits_char);
-            if (f->test_frame_sync_state) {
-                f->total_bit_errors += bit_errors;
-                f->total_bits       += COHPSK_BITS_PER_FRAME;
-                if (f->freedv_put_error_pattern != NULL) {
-                    (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, COHPSK_BITS_PER_FRAME);
+            //fprintf(stderr, " freedv_api:  f->test_frames_diversity: %d\n", f->test_frames_diversity);
+
+            if (f->test_frames_diversity) {
+                /* normal operation - error pattern on frame after diveristy combination */
+                short error_pattern[COHPSK_BITS_PER_FRAME];
+                int   bit_errors;
+
+                /* test data, lets see if we can sync to the test data sequence */
+
+                char rx_bits_char[COHPSK_BITS_PER_FRAME];
+                for(i=0; i<COHPSK_BITS_PER_FRAME; i++)
+                    rx_bits_char[i] = rx_bits[i] < 0.0;
+                cohpsk_put_test_bits(f->cohpsk, &f->test_frame_sync_state, error_pattern, &bit_errors, rx_bits_char, 0);
+                if (f->test_frame_sync_state) {
+                    f->total_bit_errors += bit_errors;
+                    f->total_bits       += COHPSK_BITS_PER_FRAME;
+                    if (f->freedv_put_error_pattern != NULL) {
+                        (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, COHPSK_BITS_PER_FRAME);
+                    }
+                }
+            } 
+            else {
+                /* calculate error pattern on uncombined carriers - test mode to spot any carrier specific issues like
+                   tx passband filtering */
+
+                short error_pattern[2*COHPSK_BITS_PER_FRAME];
+                char  rx_bits_char[COHPSK_BITS_PER_FRAME];
+                int   bit_errors_lower, bit_errors_upper;
+
+                /* lower group of carriers */
+
+                float *rx_bits_lower = cohpsk_get_rx_bits_lower(f->cohpsk);
+                for(i=0; i<COHPSK_BITS_PER_FRAME; i++) {
+                    rx_bits_char[i] = rx_bits_lower[i] < 0.0;
+                }
+                cohpsk_put_test_bits(f->cohpsk, &f->test_frame_sync_state, error_pattern, &bit_errors_lower, rx_bits_char, 0);
+
+                /* upper group of carriers */
+
+                float *rx_bits_upper = cohpsk_get_rx_bits_upper(f->cohpsk);
+                for(i=0; i<COHPSK_BITS_PER_FRAME; i++) {
+                    rx_bits_char[i] = rx_bits_upper[i] < 0.0;
+                }
+                cohpsk_put_test_bits(f->cohpsk, &f->test_frame_sync_state_upper, &error_pattern[COHPSK_BITS_PER_FRAME], &bit_errors_upper, rx_bits_char, 1);
+                //                fprintf(stderr, " freedv_api:  f->test_frame_sync_state: %d f->test_frame_sync_state_upper: %d\n", 
+                //        f->test_frame_sync_state, f->test_frame_sync_state_upper);
+
+                /* combine total errors and call callback */
+
+                if (f->test_frame_sync_state && f->test_frame_sync_state_upper) {
+                    f->total_bit_errors += bit_errors_lower + bit_errors_upper;
+                    f->total_bits       += 2*COHPSK_BITS_PER_FRAME;
+                    if (f->freedv_put_error_pattern != NULL) {
+                        (*f->freedv_put_error_pattern)(f->error_pattern_callback_state, error_pattern, 2*COHPSK_BITS_PER_FRAME);
+                    }
                 }
+
             }
             
            *valid = 0;
@@ -1503,10 +1547,11 @@ void freedv_get_modem_stats(struct freedv *f, int *sync, float *snr_est)
 
 // Set integers
 void freedv_set_test_frames               (struct freedv *f, int val) {f->test_frames = val;}
+void freedv_set_test_frames_diversity    (struct freedv *f, int val) {f->test_frames_diversity = val;}
 void freedv_set_squelch_en                (struct freedv *f, int val) {f->squelch_en = val;}
 void freedv_set_total_bit_errors          (struct freedv *f, int val) {f->total_bit_errors = val;}
 void freedv_set_total_bits                (struct freedv *f, int val) {f->total_bits = val;}
-void freedv_set_clip                       (struct freedv *f, int val) {f->clip = val;}
+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);}
 
 // Set floats
@@ -1587,8 +1632,19 @@ int freedv_get_n_max_modem_samples        (struct freedv *f) {return f->n_max_mo
 int freedv_get_n_nom_modem_samples        (struct freedv *f) {return f->n_nom_modem_samples;}
 int freedv_get_total_bits                 (struct freedv *f) {return f->total_bits;}
 int freedv_get_total_bit_errors           (struct freedv *f) {return f->total_bit_errors;}
-int freedv_get_sync                       (struct freedv *f) {return  f->stats.sync;}
-int freedv_get_sz_error_pattern           (struct freedv *f) {return  f->sz_error_pattern;}
+int freedv_get_sync                       (struct freedv *f) {return f->stats.sync;}
+
+int freedv_get_sz_error_pattern(struct freedv *f) 
+{
+    if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) {
+        /* if diversity disabled callback sends error pattern for upper and lower carriers */
+        return f->sz_error_pattern * (2 - f->test_frames_diversity);
+    }
+    else {
+        return f->sz_error_pattern;
+    }
+}
+
 // Get floats
 
 struct CODEC2 *freedv_get_codec2       (struct freedv *f){return  f->codec2;}
index 7691bab3daa6c7dab44feda7b86131d6e69a2ddc..9d05d44015cdfcacf447d2559cedff2ccf63c52a 100644 (file)
@@ -89,6 +89,7 @@ void freedv_set_callback_txt            (struct freedv *freedv, freedv_callback_
 void freedv_set_callback_protocol       (struct freedv *freedv, freedv_callback_protorx rx, freedv_callback_prototx tx, void *callback_state);
 void freedv_set_callback_data         (struct freedv *freedv, freedv_callback_datarx datarx, freedv_callback_datatx datatx, void *callback_state);
 void freedv_set_test_frames                        (struct freedv *freedv, int test_frames);
+void freedv_set_test_frames_diversity  (struct freedv *freedv, int test_frames_diversity);
 void freedv_set_smooth_symbols             (struct freedv *freedv, int smooth_symbols);
 void freedv_set_squelch_en                         (struct freedv *freedv, int squelch_en);
 void freedv_set_snr_squelch_thresh         (struct freedv *freedv, float snr_squelch_thresh);
index b25e581134e66e823a2216883dd92c9780caa266..7ef000cff7b6e41dee84cfb5046babb9da83c934 100644 (file)
@@ -95,7 +95,9 @@ struct freedv {
     int                 *ptest_bits_coh_end;
 
     int                  test_frames;            // set this baby for 1 to tx/rx test frames to look at bit error stats
+    int                  test_frames_diversity;  // 1 -> used combined carriers for error counting on 700 waveforms
     int                  test_frame_sync_state;
+    int                  test_frame_sync_state_upper;  // when test_frames_diveristy==0 we need extra states for upper carriers
     int                  test_frame_count;
     int                  total_bits;
     int                  total_bit_errors;