moved around the spectrum plotting functions a few times
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Mon, 15 Jun 2015 05:07:50 +0000 (05:07 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Mon, 15 Jun 2015 05:07:50 +0000 (05:07 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@2189 01035d8c-6547-0410-b346-abe4f91aad63

13 files changed:
codec2-dev/src/CMakeLists.txt
codec2-dev/src/codec2_cohpsk.h
codec2-dev/src/codec2_fdmdv.h
codec2-dev/src/cohpsk.c
codec2-dev/src/fdmdv.c
codec2-dev/src/fdmdv_demod.c
codec2-dev/src/fdmdv_internal.h
codec2-dev/src/freedv_api.c
codec2-dev/src/freedv_api.h
codec2-dev/src/freedv_rx.c
codec2-dev/src/modem_stats.c [new file with mode: 0644]
codec2-dev/src/modem_stats.h [new file with mode: 0644]
codec2-dev/unittest/fdmdv_mem.c

index 981c4116a74aa496593385af4562793a1ec70bd7..18a4ce71c53911d80d6b3ba93b7d6ff4409a2af8 100644 (file)
@@ -204,6 +204,7 @@ set(CODEC2_SRCS
     golay23.c
     freedv_api.c
     varicode.c
+    modem_stats.c
 )
 
 set(CODEC2_PUBLIC_HEADERS
@@ -245,7 +246,7 @@ target_link_libraries(fdmdv_get_test_bits ${CMAKE_REQUIRED_LIBRARIES})
 add_executable(fdmdv_mod fdmdv_mod.c fdmdv.c kiss_fft.c)
 target_link_libraries(fdmdv_mod ${CMAKE_REQUIRED_LIBRARIES})
 
-add_executable(fdmdv_demod fdmdv_demod.c fdmdv.c kiss_fft.c octave.c)
+add_executable(fdmdv_demod fdmdv_demod.c fdmdv.c kiss_fft.c octave.c modem_stats.c)
 target_link_libraries(fdmdv_demod ${CMAKE_REQUIRED_LIBRARIES})
 
 add_executable(fdmdv_put_test_bits fdmdv_put_test_bits.c fdmdv.c kiss_fft.c)
index 273a2c912bbbea987ab486c7b4b522b7420f1371..8e242750ce892b8e840ca99a86507c779add20e8 100644 (file)
@@ -38,6 +38,7 @@
                                                          oversampling rate */
 
 #include "comp.h"
+#include "modem_stats.h"
 
 struct COHPSK;
 
@@ -46,5 +47,6 @@ void cohpsk_destroy(struct COHPSK *coh);
 void cohpsk_mod(struct COHPSK *cohpsk, COMP tx_fdm[], int tx_bits[]);
 void cohpsk_clip(COMP tx_fdm[]);
 void cohpsk_demod(struct COHPSK *cohpsk, float rx_bits[], int *reliable_sync_bit, COMP rx_fdm[], int *nin_frame);
+void cohpsk_get_demod_stats(struct COHPSK *cohpsk, struct MODEM_STATS *stats);
 
 #endif
index df1d3725ae219d403d1290c6694b3f14ae5774db..e440c1df44f257cd5e10754ba40f11e97c697cb8 100644 (file)
@@ -56,6 +56,7 @@ extern "C" {
 #endif
 
 #include "comp.h"
+#include "modem_stats.h"
 
 #define FDMDV_NC                      14  /* default number of data carriers                                */                               
 #define FDMDV_NC_MAX                  20  /* maximum number of data carriers                                */                               
@@ -72,25 +73,10 @@ extern "C" {
 #define FDMDV_OS_TAPS_16K       48                            /* number of OS filter taps at 16kHz   */
 #define FDMDV_OS_TAPS_8K        (FDMDV_OS_TAPS_16K/FDMDV_OS)  /* number of OS filter taps at 8kHz    */
 
-/* FFT points */
-
-#define FDMDV_NSPEC             512
-#define FDMDV_MAX_F_HZ          4000
-
 /* FDMDV states and stats structures */
 
 struct FDMDV;
     
-struct FDMDV_STATS {
-    int    Nc;
-    float  snr_est;                    /* estimated SNR of rx signal in dB (3 kHz noise BW)  */
-    COMP   rx_symbols[FDMDV_NC_MAX+1]; /* latest received symbols, for scatter plot          */ 
-    int    sync;                       /* demod sync state                                   */ 
-    float  foff;                       /* estimated freq offset in Hz                        */       
-    float  rx_timing;                  /* estimated optimum timing offset in samples         */
-    float  clock_offset;               /* Estimated tx/rx sample clock offset in ppm         */
-};
-
 struct FDMDV * fdmdv_create(int Nc);
 void           fdmdv_destroy(struct FDMDV *fdmdv_state);
 void           fdmdv_use_old_qpsk_mapping(struct FDMDV *fdmdv_state);
@@ -105,8 +91,7 @@ void           fdmdv_get_test_bits(struct FDMDV *fdmdv_state, int tx_bits[]);
 int            fdmdv_error_pattern_size(struct FDMDV *fdmdv_state);
 void           fdmdv_put_test_bits(struct FDMDV *f, int *sync, short error_pattern[], int *bit_errors, int *ntest_bits, int rx_bits[]);
     
-void           fdmdv_get_demod_stats(struct FDMDV *fdmdv_state, struct FDMDV_STATS *fdmdv_stats);
-void           fdmdv_get_rx_spectrum(struct FDMDV *fdmdv_state, float mag_dB[], COMP rx_fdm[], int nin);
+void           fdmdv_get_demod_stats(struct FDMDV *fdmdv_state, struct MODEM_STATS *stats);
 
 void           fdmdv_8_to_16(float out16k[], float in8k[], int n);
 void           fdmdv_8_to_16_short(short out16k[], short in8k[], int n);
index 677d4f7293f9d7d5085df64f85f588908ad5cd1d..0c15013af6f407b98aa6258a187e92fcf36e3b8c 100644 (file)
@@ -324,7 +324,7 @@ void qpsk_symbols_to_bits(struct COHPSK *coh, float rx_bits[], COMP ct_symb_buf[
         }
     }
     
-    /* and finally optional diversity combination, note output is soft decm a "1" is < 0 */
+    /* and finally optional diversity combination, note output is soft decn a "1" is < 0 */
 
     for(c=0; c<COHPSK_NC; c++) {
         for(r=0; r<NSYMROW; r++) {
@@ -1075,3 +1075,34 @@ int cohpsk_fs_offset(COMP out[], COMP in[], int n, float sample_rate_ppm)
     return tout;
 }
 
+
+/*---------------------------------------------------------------------------*\
+                                                       
+  FUNCTION....: cohpsk_get_demod_stats()            
+  AUTHOR......: David Rowe                           
+  DATE CREATED: 14 June 2015
+
+  Fills stats structure with a bunch of demod information.
+
+\*---------------------------------------------------------------------------*/
+
+void cohpsk_get_demod_stats(struct COHPSK *coh, struct MODEM_STATS *stats)
+{
+    int   c,r;
+
+    stats->Nc = COHPSK_NC*ND;
+    assert(stats->Nc <= MODEM_STATS_NC_MAX);
+    stats->snr_est = 20*log10(coh->sig_rms/coh->noise_rms);
+    stats->sync = coh->sync;
+    stats->foff = coh->f_est;
+    stats->rx_timing = coh->rx_timing;
+    stats->clock_offset = 0.0; /* TODO - implement clock offset estimation */
+
+    assert(stats->nr <= MODEM_STATS_NR_MAX);
+    stats->nr = NSYMROW;
+    for(c=0; c<COHPSK_NC*ND; c++) {
+        for (r=0; r<NSYMROW; r++) {
+            stats->rx_symbols[r][c] = coh->rx_symb[r][c];
+        }
+    }
+}
index fa22dbf328a257a076c74f9d576f44854a4ba243..9feb6b77b736fe882de27b13663bc9490f3616d2 100644 (file)
@@ -182,11 +182,6 @@ struct FDMDV * fdmdv_create(int Nc)
        f->noise_est[c] = 0.0;
     }
 
-    for(i=0; i<2*FDMDV_NSPEC; i++)
-       f->fft_buf[i] = 0.0;
-    f->fft_cfg = kiss_fft_alloc (2*FDMDV_NSPEC, 0, NULL, NULL);
-    assert(f->fft_cfg != NULL);
-    
     f->sig_pwr_av = 0.0;
 
     return f;
@@ -206,7 +201,6 @@ void fdmdv_destroy(struct FDMDV *fdmdv)
 {
     assert(fdmdv != NULL);
     KISS_FFT_FREE(fdmdv->fft_pilot_cfg);
-    KISS_FFT_FREE(fdmdv->fft_cfg);
     free(fdmdv->rx_test_bits_mem);
     free(fdmdv);
 }
@@ -1611,19 +1605,22 @@ float calc_snr(int Nc, float sig_est[], float noise_est[])
 
 \*---------------------------------------------------------------------------*/
 
-void fdmdv_get_demod_stats(struct FDMDV *fdmdv, struct FDMDV_STATS *fdmdv_stats)
+void fdmdv_get_demod_stats(struct FDMDV *fdmdv, struct MODEM_STATS *stats)
 {
     int   c;
 
-    fdmdv_stats->Nc = fdmdv->Nc;
-    fdmdv_stats->snr_est = calc_snr(fdmdv->Nc, fdmdv->sig_est, fdmdv->noise_est);
-    fdmdv_stats->sync = fdmdv->sync;
-    fdmdv_stats->foff = fdmdv->foff;
-    fdmdv_stats->rx_timing = fdmdv->rx_timing;
-    fdmdv_stats->clock_offset = 0.0; /* TODO - implement clock offset estimation */
+    assert(fdmdv->Nc <= MODEM_STATS_NC_MAX);
+
+    stats->Nc = fdmdv->Nc;
+    stats->snr_est = calc_snr(fdmdv->Nc, fdmdv->sig_est, fdmdv->noise_est);
+    stats->sync = fdmdv->sync;
+    stats->foff = fdmdv->foff;
+    stats->rx_timing = fdmdv->rx_timing;
+    stats->clock_offset = 0.0; /* TODO - implement clock offset estimation */
 
+    stats->nr = 1;
     for(c=0; c<fdmdv->Nc+1; c++) {
-       fdmdv_stats->rx_symbols[c] = fdmdv->phase_difference[c];
+       stats->rx_symbols[0][c] = fdmdv->phase_difference[c];
     }
 }
 
@@ -1757,71 +1754,6 @@ void fdmdv_16_to_8_short(short out8k[], short in16k[], int n)
        in16k[i] = in16k[i + n*FDMDV_OS];
 }
 
-/*---------------------------------------------------------------------------*\
-                                                       
-  FUNCTION....: fdmdv_get_rx_spectrum()             
-  AUTHOR......: David Rowe                           
-  DATE CREATED: 9 June 2012
-
-  Returns the FDMDV_NSPEC point magnitude spectrum of the rx signal in
-  dB. The spectral samples are scaled so that 0dB is the peak, a good
-  range for plotting is 0 to -40dB.
-
-  Note only the real part of the complex input signal is used at
-  present.  A complex variable is used for input for compatability
-  with the other rx signal procesing.
-
-  Successive calls can be used to build up a waterfall or spectrogram
-  plot, by mapping the received levels to colours.
-
-  The time-frequency resolution of the spectrum can be adjusted by varying
-  FDMDV_NSPEC.  Note that a 2*FDMDV_NSPEC size FFT is reqd to get
-  FDMDV_NSPEC output points. FDMDV_NSPEC must be a power of 2.
-
-  See octave/tget_spec.m for a demo real time spectral display using
-  Octave. This demo averages the output over time to get a smoother
-  display:
-
-     av = 0.9*av + 0.1*mag_dB
-
-\*---------------------------------------------------------------------------*/
-
-void fdmdv_get_rx_spectrum(struct FDMDV *f, float mag_spec_dB[], 
-                                              COMP rx_fdm[], int nin) 
-{
-    int   i,j;
-    COMP  fft_in[2*FDMDV_NSPEC];
-    COMP  fft_out[2*FDMDV_NSPEC];
-    float full_scale_dB;
-
-    /* update buffer of input samples */
-
-    for(i=0; i<2*FDMDV_NSPEC-nin; i++)
-       f->fft_buf[i] = f->fft_buf[i+nin];
-    for(j=0; j<nin; j++,i++)
-       f->fft_buf[i] = rx_fdm[j].real;
-    assert(i == 2*FDMDV_NSPEC);
-
-    /* window and FFT */
-
-    for(i=0; i<2*FDMDV_NSPEC; i++) {
-       fft_in[i].real = f->fft_buf[i] * (0.5 - 0.5*cosf((float)i*2.0*PI/(2*FDMDV_NSPEC)));
-       fft_in[i].imag = 0.0;
-    }
-
-    kiss_fft(f->fft_cfg, (kiss_fft_cpx *)fft_in, (kiss_fft_cpx *)fft_out);
-
-    /* FFT scales up a signal of level 1 FDMDV_NSPEC */
-
-    full_scale_dB = 20*log10(FDMDV_NSPEC);
-
-    /* scale and convert to dB */
-
-    for(i=0; i<FDMDV_NSPEC; i++) {
-       mag_spec_dB[i]  = 10.0*log10f(fft_out[i].real*fft_out[i].real + fft_out[i].imag*fft_out[i].imag + 1E-12);
-       mag_spec_dB[i] -= full_scale_dB;
-    }
-}
 
 /*---------------------------------------------------------------------------*\
                                                        
index 6c0ece11227c676e61dcb5d67bf4040ccb41641b..98762ee015bf8a435dc7bed8f34882d9020cda8e 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "codec2_fdmdv.h"
 #include "octave.h"
+#include "freedv_api.h"
 
 /* lof of information we want to dump to Octave */
 
@@ -62,7 +63,7 @@ int main(int argc, char *argv[])
     int           sync = 0;
     int           f;
     FILE         *foct = NULL;
-    struct FDMDV_STATS stats;
+    struct MODEM_STATS stats;
     COMP         *rx_fdm_log;
     int           rx_fdm_log_col_index;
     COMP         *rx_symbols_log;
@@ -111,6 +112,7 @@ int main(int argc, char *argv[])
         Nc = FDMDV_NC;
     
     fdmdv = fdmdv_create(Nc);
+    modem_stats_open(&stats);
 
     bits_per_fdmdv_frame = fdmdv_bits_per_frame(fdmdv);
     bits_per_codec_frame = 2*fdmdv_bits_per_frame(fdmdv);
@@ -126,7 +128,7 @@ int main(int argc, char *argv[])
 
     rx_fdm_log = (COMP*)malloc(sizeof(COMP)*FDMDV_MAX_SAMPLES_PER_FRAME*MAX_FRAMES);
     assert(rx_fdm_log != NULL);
-    rx_spec_log = (float*)malloc(sizeof(float)*FDMDV_NSPEC*MAX_FRAMES);
+    rx_spec_log = (float*)malloc(sizeof(float)*MODEM_STATS_NSPEC*MAX_FRAMES);
     assert(rx_spec_log != NULL);
     rx_symbols_log = (COMP*)malloc(sizeof(COMP)*(Nc+1)*MAX_FRAMES);
     assert(rx_fdm_log != NULL);
@@ -156,7 +158,7 @@ int main(int argc, char *argv[])
            rx_fdm_log_col_index += nin_prev;
 
            for(c=0; c<Nc+1; c++)
-               rx_symbols_log[f*(Nc+1)+c] = stats.rx_symbols[c];
+               rx_symbols_log[f*(Nc+1)+c] = stats.rx_symbols[0][c];
            foff_log[f] = stats.foff;
            rx_timing_log[f] = stats.rx_timing;
            sync_log[f] = stats.sync;
@@ -164,7 +166,7 @@ int main(int argc, char *argv[])
            memcpy(&rx_bits_log[bits_per_fdmdv_frame*f], rx_bits, sizeof(int)*bits_per_fdmdv_frame);
            snr_est_log[f] = stats.snr_est;
 
-           fdmdv_get_rx_spectrum(fdmdv, &rx_spec_log[f*FDMDV_NSPEC], rx_fdm, nin_prev);
+           modem_stats_get_rx_spectrum(&stats, &rx_spec_log[f*MODEM_STATS_NSPEC], rx_fdm, nin_prev);
 
            f++;
        }
@@ -227,7 +229,7 @@ int main(int argc, char *argv[])
        octave_save_int(foct, "rx_bits_log_c", rx_bits_log, 1, bits_per_fdmdv_frame*f);
        octave_save_int(foct, "sync_bit_log_c", sync_bit_log, 1, f);  
        octave_save_float(foct, "snr_est_log_c", snr_est_log, 1, f, MAX_FRAMES);  
-       octave_save_float(foct, "rx_spec_log_c", rx_spec_log, f, FDMDV_NSPEC, FDMDV_NSPEC);  
+       octave_save_float(foct, "rx_spec_log_c", rx_spec_log, f, MODEM_STATS_NSPEC, MODEM_STATS_NSPEC);  
        fclose(foct);
     }
 
index c4f2a32e475b79525fb55bc99b57e3ca9761192b..74911774ff270d6be19b8f5701a1b856319fcd2b 100644 (file)
@@ -148,11 +148,6 @@ struct FDMDV {
     float sig_est[NC+1];
     float noise_est[NC+1];
 
-    /* Buf for FFT/waterfall */
-
-    float fft_buf[2*FDMDV_NSPEC];
-    kiss_fft_cfg fft_cfg;  
-
     /* channel simulation */
 
     float sig_pwr_av;
index 53de89c67536d8bcf4a19c396bf3ca161a4ce7f6..d4fbc43885db868ed849118f1effacd2c9d9be99 100644 (file)
@@ -58,7 +58,7 @@
 
 struct freedv *freedv_open(int mode) {
     struct freedv *f;
-    int            Nc, codec2_mode, nbit, nbyte;
+    int            Nc, codec2_mode, nbit, nbyte, i;
     
     if ((mode != FREEDV_MODE_1600) && (mode != FREEDV_MODE_700))
         return NULL;
@@ -133,7 +133,7 @@ struct freedv *freedv_open(int mode) {
     f->freedv_put_next_rx_char = NULL;
 
     f->total_bit_errors = 0;
-
+    
     return f;
 }
 
@@ -453,9 +453,11 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) {
 
         nin_prev = f->nin;
         fdmdv_demod(f->fdmdv, f->fdmdv_bits, &reliable_sync_bit, demod_in, &f->nin);
-        fdmdv_get_demod_stats(f->fdmdv, &f->fdmdv_stats);
+        fdmdv_get_demod_stats(f->fdmdv, &f->stats);
+        f->reliable_sync_bit = reliable_sync_bit;
+        f->snr_est = f->stats.snr_est;
 
-        if (f->fdmdv_stats.sync) {
+        if (f->stats.sync) {
             if (reliable_sync_bit == 0) {
                 memcpy(f->rx_bits, f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int));
                 nout = 0;
@@ -526,7 +528,7 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) {
 
                 /* squelch if beneath SNR threshold */
 
-                if (f->fdmdv_stats.snr_est < f->snr_thresh) {
+                if (f->stats.snr_est < f->snr_thresh) {
                     for(i=0; i<f->n_speech_samples; i++)
                         speech_out[i] = 0;
                 }
@@ -550,6 +552,9 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) {
 
         nin_prev = f->nin;
        cohpsk_demod(f->cohpsk, rx_bits, &reliable_sync_bit, demod_in, &f->nin);
+        f->reliable_sync_bit = reliable_sync_bit;
+        f->snr_est = 2.0;
+        fprintf(stderr, "%d\n", reliable_sync_bit);
 
        if (reliable_sync_bit) {
 
@@ -587,11 +592,21 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) {
             nout = f->n_speech_samples;
         }
         else {
+            float t,a,b,s;
+            int   t1,t2;
+
             /* if not in sync pass through analog samples */
             /* this lets us "hear" whats going on, e.g. during tuning */
-            for(i=0; i<nin_prev; i++)
-                speech_out[i] = FDMDV_SCALE*demod_in[i].real;
-            nout = nin_prev;
+            /* need to linearly interp as Fs in and out slightly different */
+
+            for(i=0, t=0.0; i<f->n_speech_samples; i++, t+=f->modem_sample_rate/FS) {
+                t1 = floor(t); t2 = ceil(t);
+                a = t - t1;
+                b = t2 - t1;
+                s = b*demod_in[t1].real + a*demod_in[t2].real;
+                speech_out[i] = FDMDV_SCALE*s;
+            }
+            nout = f->n_speech_samples;
         }
      }
 
index 1382dcfc7e13db67cc79de30a0320dff00a98b41..bf4003b4eb205a631a26347168546bc832f5f42e 100644 (file)
@@ -46,14 +46,14 @@ struct freedv {
 
     struct CODEC2       *codec2;
     struct FDMDV        *fdmdv;
-    struct FDMDV_STATS   fdmdv_stats;
+    struct MODEM_STATS   stats;
     struct COHPSK       *cohpsk;
 
     int                  n_speech_samples;
     int                  n_nom_modem_samples;    // size of tx and most rx modenm sample buffers
     int                  n_max_modem_samples;    // make your rx modem sample buffers this big
 
-    int                  modem_sample_rate;      // caller is responsible for meeting this
+    int                  modem_sample_rate;      // ATM caller is responsible for meeting this (TBC)
     int                  clip;                   // non-zero for cohpsk modem output clipping for low PAPR
 
     unsigned char       *packed_codec_bits;
@@ -64,6 +64,8 @@ struct freedv {
     int                  tx_sync_bit;
     int                  total_bit_errors;
 
+    int                  reliable_sync_bit;
+    float                snr_est;
     float                snr_thresh;
     int                  nin;
 
index 740a33e8feaa3d7fea83b0e7b0ce47588e24a57a..eb1d8d916cadffa7f60c8730382dc7d8d2935469 100644 (file)
@@ -121,7 +121,7 @@ int main(int argc, char *argv[]) {
         frame++;
         if (ftxt != NULL) {
             fprintf(ftxt, "frame: %d  demod sync: %d  demod snr: %3.2f dB  bit errors: %d\n", frame, 
-                    freedv->fdmdv_stats.sync, freedv->fdmdv_stats.snr_est, freedv->total_bit_errors);
+                    freedv->stats.sync, freedv->stats.snr_est, freedv->total_bit_errors);
         }
 
        /* if this is in a pipeline, we probably don't want the usual
diff --git a/codec2-dev/src/modem_stats.c b/codec2-dev/src/modem_stats.c
new file mode 100644 (file)
index 0000000..d13b1a0
--- /dev/null
@@ -0,0 +1,111 @@
+/*---------------------------------------------------------------------------*\
+                                                                             
+  FILE........: modem_stats.c
+  AUTHOR......: David Rowe
+  DATE CREATED: June 2015
+                                                                             
+  Common functions for returning demod stats from fdmdv and cohpsk modems.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+  Copyright (C) 2015 David Rowe
+
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License version 2.1, as
+  published by the Free Software Foundation.  This program is
+  distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <math.h>
+#include "modem_stats.h"
+#include "codec2_fdmdv.h"
+
+void modem_stats_open(struct MODEM_STATS *f) 
+{
+    int i;
+
+    for(i=0; i<2*MODEM_STATS_NSPEC; i++)
+       f->fft_buf[i] = 0.0;
+    f->fft_cfg = kiss_fft_alloc (2*MODEM_STATS_NSPEC, 0, NULL, NULL);
+    assert(f->fft_cfg != NULL);
+}
+
+void modem_stats_close(struct MODEM_STATS *f) 
+{
+    KISS_FFT_FREE(f->fft_cfg);
+}
+
+/*---------------------------------------------------------------------------*\
+                                                       
+  FUNCTION....: modem_stats_get_rx_spectrum()       
+  AUTHOR......: David Rowe                           
+  DATE CREATED: 9 June 2012
+
+  Returns the MODEM_STATS_NSPEC point magnitude spectrum of the rx signal in
+  dB. The spectral samples are scaled so that 0dB is the peak, a good
+  range for plotting is 0 to -40dB.
+
+  Note only the real part of the complex input signal is used at
+  present.  A complex variable is used for input for compatability
+  with the other rx signal procesing.
+
+  Successive calls can be used to build up a waterfall or spectrogram
+  plot, by mapping the received levels to colours.
+
+  The time-frequency resolution of the spectrum can be adjusted by varying
+  MODEM_STATS_NSPEC.  Note that a 2* MODEM_STATS_NSPEC size FFT is reqd to get
+  MODEM_STATS_NSPEC output points.  MODEM_STATS_NSPEC must be a power of 2.
+
+  See octave/tget_spec.m for a demo real time spectral display using
+  Octave. This demo averages the output over time to get a smoother
+  display:
+
+     av = 0.9*av + 0.1*mag_dB
+
+\*---------------------------------------------------------------------------*/
+
+void modem_stats_get_rx_spectrum(struct MODEM_STATS *f, float mag_spec_dB[], COMP rx_fdm[], int nin) 
+{
+    int   i,j;
+    COMP  fft_in[2*MODEM_STATS_NSPEC];
+    COMP  fft_out[2*MODEM_STATS_NSPEC];
+    float full_scale_dB;
+
+    /* update buffer of input samples */
+
+    for(i=0; i<2*MODEM_STATS_NSPEC-nin; i++)
+       f->fft_buf[i] = f->fft_buf[i+nin];
+    for(j=0; j<nin; j++,i++)
+       f->fft_buf[i] = rx_fdm[j].real;
+    assert(i == 2*MODEM_STATS_NSPEC);
+
+    /* window and FFT */
+
+    for(i=0; i<2*MODEM_STATS_NSPEC; i++) {
+       fft_in[i].real = f->fft_buf[i] * (0.5 - 0.5*cosf((float)i*2.0*M_PI/(2*MODEM_STATS_NSPEC)));
+       fft_in[i].imag = 0.0;
+    }
+
+    kiss_fft(f->fft_cfg, (kiss_fft_cpx *)fft_in, (kiss_fft_cpx *)fft_out);
+
+    /* FFT scales up a signal of level 1 FDMDV_NSPEC */
+
+    full_scale_dB = 20*log10(MODEM_STATS_NSPEC*FDMDV_SCALE);
+
+    /* scale and convert to dB */
+
+    for(i=0; i<MODEM_STATS_NSPEC; i++) {
+       mag_spec_dB[i]  = 10.0*log10f(fft_out[i].real*fft_out[i].real + fft_out[i].imag*fft_out[i].imag + 1E-12);
+       mag_spec_dB[i] -= full_scale_dB;
+    }
+}
diff --git a/codec2-dev/src/modem_stats.h b/codec2-dev/src/modem_stats.h
new file mode 100644 (file)
index 0000000..99dc637
--- /dev/null
@@ -0,0 +1,68 @@
+/*---------------------------------------------------------------------------*\
+                                                                             
+  FILE........: modem_stats.h
+  AUTHOR......: David Rowe
+  DATE CREATED: June 2015
+                                                                             
+  Common structure for returning demod stats from fdmdv and cohpsk modems.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+  Copyright (C) 2015 David Rowe
+
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License version 2.1, as
+  published by the Free Software Foundation.  This program is
+  distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+#ifndef __MODEM_STATS__
+#define __MODEM_STATS__
+
+#include "comp.h"
+#include "kiss_fft.h"
+
+#define MODEM_STATS_NC_MAX 20
+#define MODEM_STATS_NR_MAX 6
+#define MODEM_STATS_NSPEC            512
+#define MODEM_STATS_MAX_F_HZ         4000
+
+struct MODEM_STATS {
+    int    Nc;
+    float  snr_est;                          /* estimated SNR of rx signal in dB (3 kHz noise BW)  */
+    COMP   rx_symbols[MODEM_STATS_NR_MAX][MODEM_STATS_NC_MAX+1]; 
+                                             /* latest received symbols, for scatter plot          */ 
+    int    nr;                               /* number of rows in rx_symbols                       */
+    int    sync;                             /* demod sync state                                   */ 
+    float  foff;                             /* estimated freq offset in Hz                        */       
+    float  rx_timing;                        /* estimated optimum timing offset in samples         */
+    float  clock_offset;                     /* Estimated tx/rx sample clock offset in ppm         */
+
+    /* Buf for FFT/waterfall */
+
+    float        fft_buf[2*MODEM_STATS_NSPEC];
+    kiss_fft_cfg fft_cfg;  
+};
+
+void modem_stats_open(struct MODEM_STATS *f);
+void modem_stats_close(struct MODEM_STATS *f); 
+void modem_stats_get_rx_spectrum(struct MODEM_STATS *f, float mag_spec_dB[], COMP rx_fdm[], int nin);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
index 06a0ca0fe5b6531e7694778abdbd85b111a51cb8..ad105e8345df6c75471a484f3da5e5dcb0fbf1d7 100644 (file)
@@ -40,25 +40,23 @@ int main(int argc, char *argv[])
 {
     struct FDMDV *fdmdv;
 
-    printf("struct FDMDV..........: %d\n", sizeof(struct FDMDV));
-    printf("prev_tx_symbols.......: %d\n", sizeof(fdmdv->prev_tx_symbols));
-    printf("tx_filter_memory......: %d\n", sizeof(fdmdv->tx_filter_memory));
-    printf("phase_tx..............: %d\n", sizeof(fdmdv->phase_tx));
-    printf("freq..................: %d\n", sizeof(fdmdv->freq));
-    printf("pilot_lut.............: %d\n", sizeof(fdmdv->pilot_lut));
-    printf("pilot_baseband1.......: %d\n", sizeof(fdmdv->pilot_baseband1));
-    printf("pilot_baseband2.......: %d\n", sizeof(fdmdv->pilot_baseband2));
-    printf("pilot_lpf1............: %d\n", sizeof(fdmdv->pilot_lpf1));
-    printf("pilot_lpf2............: %d\n", sizeof(fdmdv->pilot_lpf2));
-    printf("S1....................: %d\n", sizeof(fdmdv->S1));
-    printf("S2....................: %d\n", sizeof(fdmdv->S2));
-    printf("phase_rx..............: %d\n", sizeof(fdmdv->phase_rx));
-    printf("rx_fdm_mem............: %d\n", sizeof(fdmdv->rx_fdm_mem));
-    printf("rx_filter_mem_timing..: %d\n", sizeof(fdmdv->rx_filter_mem_timing));
-    printf("phase_difference......: %d\n", sizeof(fdmdv->phase_difference));
-    printf("prev_rx_symbols.......: %d\n", sizeof(fdmdv->prev_rx_symbols));
-    printf("fft_buf...............: %d\n", sizeof(fdmdv->fft_buf));
-    printf("kiss_fft_cfg..........: %d\n", sizeof(fdmdv->fft_cfg));
+    printf("struct FDMDV..........: %ld\n", sizeof(struct FDMDV));
+    printf("prev_tx_symbols.......: %ld\n", sizeof(fdmdv->prev_tx_symbols));
+    printf("tx_filter_memory......: %ld\n", sizeof(fdmdv->tx_filter_memory));
+    printf("phase_tx..............: %ld\n", sizeof(fdmdv->phase_tx));
+    printf("freq..................: %ld\n", sizeof(fdmdv->freq));
+    printf("pilot_lut.............: %ld\n", sizeof(fdmdv->pilot_lut));
+    printf("pilot_baseband1.......: %ld\n", sizeof(fdmdv->pilot_baseband1));
+    printf("pilot_baseband2.......: %ld\n", sizeof(fdmdv->pilot_baseband2));
+    printf("pilot_lpf1............: %ld\n", sizeof(fdmdv->pilot_lpf1));
+    printf("pilot_lpf2............: %ld\n", sizeof(fdmdv->pilot_lpf2));
+    printf("S1....................: %ld\n", sizeof(fdmdv->S1));
+    printf("S2....................: %ld\n", sizeof(fdmdv->S2));
+    printf("phase_rx..............: %ld\n", sizeof(fdmdv->phase_rx));
+    printf("rx_fdm_mem............: %ld\n", sizeof(fdmdv->rx_fdm_mem));
+    printf("rx_filter_mem_timing..: %ld\n", sizeof(fdmdv->rx_filter_mem_timing));
+    printf("phase_difference......: %ld\n", sizeof(fdmdv->phase_difference));
+    printf("prev_rx_symbols.......: %ld\n", sizeof(fdmdv->prev_rx_symbols));
 
     return 0;
 }