Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

GrFFTAvgSink.h

Go to the documentation of this file.
00001 /* -*- Mode: c++ -*- */
00002 /*
00003  * Copyright 2001,2002,2003 Free Software Foundation, Inc.
00004  * 
00005  * This file is part of GNU Radio
00006  * 
00007  * GNU Radio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2, or (at your option)
00010  * any later version.
00011  * 
00012  * GNU Radio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with GNU Radio; see the file COPYING.  If not, write to
00019  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020  * Boston, MA 02111-1307, USA.
00021  */
00022 
00023 #ifndef _GRFFTAVGSINK_H_
00024 #define _GRFFTAVGSINK_H_
00025 
00026 #include <VrSink.h>
00027 #include <gr_fft.h>
00028 #include "VrGUI.h"
00029 #include <algorithm>
00030 #include <stdexcept>
00031 
00032 extern "C" {
00033 #include <dlfcn.h>
00034 #include <float.h>
00035 #include <math.h>
00036            }
00037 
00038 #define PRINT_PEAK      0
00039 
00040 
00041 #define FFT_XAXIS_NAME                  "Frequency (Hz)"
00042 #define FFT_YAXIS_NAME                  "Avg Mag Squared (dB)"
00043 
00044 
00045 template<class iType> 
00046 class GrFFTAvgSink : public VrSink<iType> {
00047 
00048  public:
00049   GrFFTAvgSink (VrGUILayout *layout,
00050                 double ymin, double ymax,
00051                 int nPoints = DEFAULT_nPoints,
00052                 const char *label = FFT_YAXIS_NAME);
00053   
00054   ~GrFFTAvgSink();
00055 
00056   virtual const char *name() { return "GrFFTAvgSink"; }
00057 
00058   virtual void initialize();
00059 
00060   virtual int work3 (VrSampleRange output, 
00061                      VrSampleRange inputs[], void *i[]);
00062 
00063 
00064   static const int DEFAULT_nPoints = 512;       // number of points to plot
00065   static const int DIVISIONS = 10;              // number of x-axis divisions
00066   static const int DEFAULT_display_freq = 20;   // Hz
00067   static const int DEFAULT_ffts_per_display = 5;  // # of ffts per display update
00068   static const double ALPHA = 1.0 / (4 * DEFAULT_ffts_per_display);
00069 
00070  private:
00071   gr_fft_complex *d_fft;
00072   double         *d_xValues;
00073   double         *d_dbValues;           // FFT magnitude in dB
00074   double         *d_avgdbValues;        // average FFT magnitude in dB
00075   float          *d_window;
00076   int             d_nPoints;            // max number of points to plot
00077   float           d_axis_offset;
00078   VrGUIPlot      *d_display;
00079   double          d_ymin, d_ymax;       // possible range of sample values
00080   int             d_nextPoint;          // index of next point to generate for graph
00081   int             d_one_or_two;
00082   VrGUILayout    *d_layout;
00083   int             d_increment;
00084   int             d_skip_count;
00085   const char     *d_label;
00086   int             d_display_freq;       // how many display updates / sec
00087   int             d_ffts_per_display;   // how may FFTs computed / display
00088   int             d_fft_count;
00089 
00090   void collectData (iType *i, long count);
00091 
00092   void set_skip_count (){
00093     d_skip_count = std::max (0, d_increment - d_nPoints);
00094   }
00095 };
00096 
00097 /*****************************************************************************
00098  * Implementation of template (C++ requires it to be in .h file).
00099  ****************************************************************************/
00100 
00101 
00102 /*
00103  * Creates a new GrFFTAvgSink.
00104  */
00105 template<class iType>
00106 GrFFTAvgSink<iType>::GrFFTAvgSink (VrGUILayout *layout,
00107                                    double ymin, double ymax, int nPoints,
00108                                    const char *label) : d_label (label)
00109 {
00110   d_layout = layout;
00111   d_nPoints = nPoints;
00112 
00113   d_fft = new gr_fft_complex (d_nPoints);
00114   d_dbValues = new double[d_nPoints];
00115   d_avgdbValues = new double[d_nPoints];
00116   memset (d_avgdbValues, 0, d_nPoints * sizeof (double));
00117   d_xValues = new double[d_nPoints];
00118   d_window = new float[d_nPoints];
00119 
00120   for (int i = 0; i < d_nPoints; i++)
00121     d_window[i] = 0.54 - 0.46 * cos (2*M_PI/d_nPoints*i); // hamming d_window
00122 
00123   d_ymin = ymin;
00124   d_ymax = ymax;
00125   d_nextPoint = 0;
00126   d_axis_offset = 0.0;
00127 
00128   d_display_freq = DEFAULT_display_freq;
00129   d_ffts_per_display = DEFAULT_ffts_per_display;
00130   d_fft_count = 0;
00131 }
00132 
00133 template<class iType> void
00134 GrFFTAvgSink<iType>::initialize()
00135 {
00136   iType test_for_complex=0;
00137   double    samplingFrequency = getInputSamplingFrequencyN(0);  // Hz
00138 
00139   if (is_complex(test_for_complex)) {
00140     // this used to display the second half as "negative frequencies", but
00141     // it was screwed.  This just leaves them as is.  0 is the DC component.
00142 
00143     d_display = new VrGUIPlot (d_layout, FFT_XAXIS_NAME, d_label, true,
00144                                0, samplingFrequency,
00145                                d_ymin, d_ymax, d_nPoints, DIVISIONS);
00146     d_one_or_two = 1;
00147     for (int i = 0; i < d_nPoints; i++)
00148       d_xValues[i] = 
00149         ((double)i / (double) d_nPoints * samplingFrequency) - d_axis_offset;
00150   }
00151   else {
00152     d_display = new VrGUIPlot (d_layout, FFT_XAXIS_NAME, d_label, true,
00153                                0, samplingFrequency/2,
00154                                d_ymin, d_ymax, d_nPoints/2, DIVISIONS);
00155     d_one_or_two = 2;
00156     for (int i = 0; i <= d_nPoints/2 ; i++)
00157       d_xValues[i] =
00158         ((double)i / (double) d_nPoints * samplingFrequency) - d_axis_offset;
00159   }
00160 
00161   double fft_freq = d_display_freq * d_ffts_per_display;        // FFT's / second
00162   d_increment = (int) (samplingFrequency / fft_freq);
00163   if (d_increment < 1)
00164     d_increment = 1;
00165 
00166   set_skip_count ();
00167 
00168   std::cerr << "GrFFTAvgSink:\n"
00169             << "  sampling_freq      = " << samplingFrequency << std::endl
00170             << "  d_display_freq     = " << d_display_freq << std::endl
00171             << "  d_ffts_per_display = " << d_ffts_per_display << std::endl
00172             << "  fft_freq           = " << fft_freq << std::endl
00173             << "  d_increment        = " << d_increment << std::endl
00174             << "  d_skip_count       = " << d_skip_count << std::endl;
00175 }
00176 
00177 template<class iType> int
00178 GrFFTAvgSink<iType>::work3(VrSampleRange output, 
00179                         VrSampleRange inputs[], void *ai[])
00180 {
00181   sync (output.index);
00182 
00183   collectData (((iType **) ai)[0], output.size);
00184 
00185   return output.size;
00186 }
00187 
00188 /*
00189  * Acquires the next point to plot on the graph.  Displays the graph when
00190  * all points are acquired.
00191  */
00192 template<class iType> void
00193 GrFFTAvgSink<iType>::collectData(iType *in, long samples_available)
00194 {
00195   VrComplex     *fft_input = d_fft->get_inbuf ();
00196   VrComplex     *fft_output = d_fft->get_outbuf ();
00197   
00198   while (samples_available > 0){
00199     
00200     if (d_skip_count > 0){
00201       int       n = std::min ((long) d_skip_count, samples_available);
00202       d_skip_count -= n;
00203 
00204       in += n;
00205       samples_available -= n;
00206       continue;
00207     }
00208 
00209     if (d_nextPoint < d_nPoints)  {
00210       iType             sampleValue;
00211 
00212       sampleValue = *in++;
00213       samples_available--;
00214 
00215       fft_input[d_nextPoint] = sampleValue * d_window[d_nextPoint];
00216 
00217       d_nextPoint++;
00218     }
00219 
00220     if (d_nextPoint >= d_nPoints)  {
00221       d_nextPoint = 0;
00222       set_skip_count ();
00223     
00224       d_fft->execute ();        // do the work
00225 
00226       // compute log magnitude
00227       //
00228       // this could be computed as 20 * log10 (abs (d_fft_output[i])), but
00229       // then you'd be wasting cycles computing the sqrt hidden in abs (z)
00230     
00231       for (int i = 0; i < d_nPoints ; i++){
00232         d_dbValues[i] =
00233           10 * log10 (real(fft_output[i]) * real(fft_output[i])
00234                       + imag(fft_output[i]) * imag(fft_output[i]));
00235 
00236         d_avgdbValues[i] = (d_dbValues[i] * ALPHA
00237                             + d_avgdbValues[i] * (1.0 - ALPHA));
00238       }
00239 
00240       if (++d_fft_count >= d_ffts_per_display){
00241         d_display->data (d_xValues, d_dbValues, d_nPoints / d_one_or_two);
00242         d_fft_count = 0;
00243       }
00244     }
00245   }
00246 }
00247 
00248 template<class iType> 
00249 GrFFTAvgSink<iType>::~GrFFTAvgSink()
00250 {
00251   delete d_fft;
00252   delete[] d_xValues;
00253   delete[] d_dbValues;
00254   delete[] d_avgdbValues;
00255   delete[] d_window;
00256 }
00257 #endif

Generated on Tue Mar 15 23:46:36 2005 for GNU Radio by  doxygen 1.4.0