first pass at fdmdv_get_rx_spectrum(), wrote octave tfft_log.m to test it
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Tue, 12 Jun 2012 05:07:40 +0000 (05:07 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Tue, 12 Jun 2012 05:07:40 +0000 (05:07 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@543 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/octave/tfft_log.m [new file with mode: 0644]
codec2-dev/src/fdmdv.c
codec2-dev/src/fdmdv.h
codec2-dev/src/fdmdv_demod.c
codec2-dev/src/fdmdv_internal.h
codec2-dev/win32/codec2.dll
codec2-dev/win32/codec2.lib

diff --git a/codec2-dev/octave/tfft_log.m b/codec2-dev/octave/tfft_log.m
new file mode 100644 (file)
index 0000000..8936496
--- /dev/null
@@ -0,0 +1,49 @@
+% tfft_log.m
+%
+% Used in conjunction swith src/fdmdv_demod to test the
+% fdmdv_get_rx_spectrum() function.
+%
+% codec2-dev/src$ ./fdmdv_demod fdmdv_mod.raw tmp.c2 dump.txt
+% octave:3> tfft_log("../src/dump.txt")
+%
+% Copyright David Rowe 2012
+% This program is distributed under the terms of the GNU General Public License 
+% Version 2
+%
+
+function tfft_log(dumpfilename)
+
+  load(dumpfilename);
+
+  [rows cols] = size(rx_spec_log_c);
+  Fs = 8000; low_freq = 0; high_freq = 2500;
+  res = (Fs/2)/cols;
+  st_bin = low_freq/res + 1;
+  en_bin = high_freq/res;
+  xaxis = (st_bin:en_bin)*res;
+
+  f_start = 2; f_end = 100;
+  beta = 0.1;
+
+  av = zeros(f_end, en_bin-st_bin+1);
+  for r=f_start:f_end
+      x = (1-beta)*av(r-1,:) + beta*rx_spec_log_c(r,st_bin:en_bin);
+      av(r,:) = x;
+  end
+
+  % spectrogram (waterfall)
+
+  figure(1)
+  clf;
+  imagesc(av,[-40 0]);
+
+  % animated spectrum display
+
+  figure(2)
+  clf;
+  for r=f_start:f_end
+      plot(xaxis, av(r,:))
+      axis([ low_freq high_freq -40 0])
+      sleep(0.1)
+  end
+endfunction
index c626e9d4c611e9257c92445cf7b6c1a3d8f2b118..2e88d1d4a4cbb79292b871378e418a91d85b03ab 100644 (file)
@@ -224,9 +224,9 @@ struct FDMDV * CODEC2_WIN32SUPPORT fdmdv_create(void)
        f->noise_est[c] = 0.0;
     }
 
-    for(i=0; i<2*FDMDV_NFFT; i++)
+    for(i=0; i<2*FDMDV_NSPEC; i++)
        f->fft_buf[i] = 0.0;
-    f->fft_cfg = kiss_fft_alloc (2*FDMDV_NFFT, 0, NULL, NULL);
+    f->fft_cfg = kiss_fft_alloc (2*FDMDV_NSPEC, 0, NULL, NULL);
     assert(f->fft_cfg != NULL);
 
 
@@ -1362,55 +1362,63 @@ void CODEC2_WIN32SUPPORT fdmdv_48_to_8(float out8k[], float in48k[], int n)
 
 /*---------------------------------------------------------------------------*\
                                                        
-  FUNCTION....: fdmdv_get_fft()             
+  FUNCTION....: fdmdv_get_rx_spectrum()             
   AUTHOR......: David Rowe                           
   DATE CREATED: 9 June 2012
 
-  Performs a FFT on the received modem signal at the input of the
-  demod, returns the FDMDV_NFFT point magnitiude spectrum in dB.  0dB
-  is a signal with amplitude +/- 2^15.
+  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.
 
-  The output can be used to plot a spectrum of the demod input.
-  Sucessive calls can be used to build up a waterfall or spectrogram
+  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 FFT can be adjusted by varying
-  FDMDV_NFFT.  Note that a 2*FDMDV_NFFT size FFT is reqd to get
-  FDMDV_NFFT output points.
+  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/tfft_log.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 CODEC2_WIN32SUPPORT fdmdv_get_fft(struct FDMDV *f, float mag_dB[], float rx_fdm[], int nin) 
+void CODEC2_WIN32SUPPORT fdmdv_get_rx_spectrum(struct FDMDV *f, float mag_spec_dB[], 
+                                              float rx_fdm[], int nin) 
 {
     int   i,j;
-    COMP  fft_in[2*FDMDV_NFFT];
-    COMP  fft_out[2*FDMDV_NFFT];
-    float fullscale_dB;
+    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_NFFT-nin; i++)
+    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];
-    assert(i == 2*FDMDV_NFFT);
+    assert(i == 2*FDMDV_NSPEC);
 
     /* window and FFT */
 
-    for(i=0; i<2*FDMDV_NFFT; i++) {
-       fft_in[i].real = f->fft_buf[i] * (0.5 - 0.5*cos((float)i*2.0*PI/(2*FDMDV_NFFT)));
+    for(i=0; i<2*FDMDV_NSPEC; i++) {
+       fft_in[i].real = f->fft_buf[i] * (0.5 - 0.5*cos((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);
 
-    /* scale and convert to dB */
+    /* FFT scales up a signal of level 1 FDMDV_NSPEC */
 
-    fullscale_dB = 20.0*log10(FDMDV_NFFT*32767.0);
+    full_scale_dB = 20*log10(FDMDV_NSPEC);
+
+    /* scale and convert to dB */
 
-    for(i=0; i<FDMDV_NFFT; i++) {
-       mag_dB[i]  = 10.0*log10(fft_out[i].real*fft_out[i].real + fft_out[i].imag*fft_out[i].imag);
-       mag_dB[i] -= fullscale_dB;
+    for(i=0; i<FDMDV_NSPEC; i++) {
+       mag_spec_dB[i]  = 10.0*log10(fft_out[i].real*fft_out[i].real + fft_out[i].imag*fft_out[i].imag);
+       mag_spec_dB[i] -= full_scale_dB;
     }
 }
 
index 6feb73e9d3adcdd96462e8daae3d5aa0c45bd576..809be97ecc87448fc69dd551d65536cff02590c5 100644 (file)
@@ -68,7 +68,7 @@ extern "C" {
 
 /* FFT points */
 
-#define FDMDV_NFFT             256
+#define FDMDV_NSPEC            512
 
 /* FDMDV states and stats structures */
 
@@ -93,7 +93,7 @@ void           CODEC2_WIN32SUPPORT fdmdv_get_test_bits(struct FDMDV *fdmdv_state
 void           CODEC2_WIN32SUPPORT fdmdv_put_test_bits(struct FDMDV *f, int *sync, int *bit_errors, int *ntest_bits, int rx_bits[]);
     
 void           CODEC2_WIN32SUPPORT fdmdv_get_demod_stats(struct FDMDV *fdmdv_state, struct FDMDV_STATS *fdmdv_stats);
-void           CODEC2_WIN32SUPPORT fdmdv_get_fft(struct FDMDV *fdmdv_state, float mag_dB[], float rx_fdm[], int nin);
+void           CODEC2_WIN32SUPPORT fdmdv_get_rx_spectrum(struct FDMDV *fdmdv_state, float mag_dB[], float rx_fdm[], int nin);
 
 void           CODEC2_WIN32SUPPORT fdmdv_8_to_48(float out48k[], float in8k[], int n);
 void           CODEC2_WIN32SUPPORT fdmdv_48_to_8(float out8k[], float in48k[], int n);
index 6f78c1776b46665df2103dc1d7f4312a33d7a643..e69253aa1974374c74100804add0871e9cb5c381 100644 (file)
@@ -76,8 +76,9 @@ int main(int argc, char *argv[])
     int           sync_bit_log[MAX_FRAMES];
     int           rx_bits_log[FDMDV_BITS_PER_FRAME*MAX_FRAMES];
     float         snr_est_log[MAX_FRAMES];
-    float        *fft_log;
+    float        *rx_spec_log;
+    int           max_frames_reached;
+
     if (argc < 3) {
        printf("usage: %s InputModemRawFile OutputBitFile [OctaveDumpFile]\n", argv[0]);
        printf("e.g    %s hts1a_fdmdv.raw hts1a.c2\n", argv[0]);
@@ -102,14 +103,15 @@ int main(int argc, char *argv[])
 
     rx_fdm_log = (float*)malloc(sizeof(float)*FDMDV_MAX_SAMPLES_PER_FRAME*MAX_FRAMES);
     assert(rx_fdm_log != NULL);
-    fft_log = (float*)malloc(sizeof(float)*FDMDV_NFFT*MAX_FRAMES);
-    assert(fft_log != NULL);
+    rx_spec_log = (float*)malloc(sizeof(float)*FDMDV_NSPEC*MAX_FRAMES);
+    assert(rx_spec_log != NULL);
 
     fdmdv = fdmdv_create();
     f = 0;
     state = 0;
     nin = FDMDV_NOM_SAMPLES_PER_FRAME;
     rx_fdm_log_col_index = 0;
+    max_frames_reached = 0;
 
     while(fread(rx_fdm_scaled, sizeof(short), nin, fin) == nin)
     {
@@ -137,12 +139,15 @@ int main(int argc, char *argv[])
            memcpy(&rx_bits_log[FDMDV_BITS_PER_FRAME*f], rx_bits, sizeof(int)*FDMDV_BITS_PER_FRAME);
            snr_est_log[f] = stats.snr_est;
 
-           fdmdv_get_fft(fdmdv, &fft_log[f*FDMDV_NFFT], rx_fdm, nin_prev);
+           fdmdv_get_rx_spectrum(fdmdv, &rx_spec_log[f*FDMDV_NSPEC], rx_fdm, nin_prev);
 
            f++;
        }
-       else
+       
+       if ((f == MAX_FRAMES) && !max_frames_reached) {
            fprintf(stderr,"MAX_FRAMES exceed in Octave log, log truncated\n");
+           max_frames_reached = 1;
+       }
 
        /* state machine to output codec bits only if we have a 0,1
           sync bit sequence */
@@ -209,7 +214,7 @@ int main(int argc, char *argv[])
            octave_save_int(foct, "rx_bits_log_c", rx_bits_log, 1, FDMDV_BITS_PER_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, "fft_log_c", fft_log, f, FDMDV_NFFT, FDMDV_NFFT);  
+           octave_save_float(foct, "rx_spec_log_c", rx_spec_log, f, FDMDV_NSPEC, FDMDV_NSPEC);  
            fclose(foct);
        }
     }
@@ -217,7 +222,7 @@ int main(int argc, char *argv[])
     fclose(fin);
     fclose(fout);
     free(rx_fdm_log);
-    free(fft_log);
+    free(rx_spec_log);
     fdmdv_destroy(fdmdv);
 
     return 0;
index 1c878b137f033dffda62200b72d1d45af7e2cc18..8c5ead6039d7cd2e611a84a0db46ef5b6e46617b 100644 (file)
@@ -137,7 +137,7 @@ struct FDMDV {
 
     /* Buf for FFT/waterfall */
 
-    float fft_buf[2*FDMDV_NFFT];
+    float fft_buf[2*FDMDV_NSPEC];
     kiss_fft_cfg fft_cfg;             
  };
 
index 67837fa796a9206eea1bde4a755c2e475e7ff5ab..36030c4bca25b73888bb4126541f021fcf564bc2 100755 (executable)
Binary files a/codec2-dev/win32/codec2.dll and b/codec2-dev/win32/codec2.dll differ
index 38a7b5db4dc7ad23a8069347d9575ed44d9e0f17..caa82a8fbc79657f6e48d67017dc0a3518a80c46 100644 (file)
Binary files a/codec2-dev/win32/codec2.lib and b/codec2-dev/win32/codec2.lib differ