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

GrFFTSink.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 _GRFFTSINK_H_
00024 #define _GRFFTSINK_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                  "Magnitude Squared (dB)"
00043 
00044 
00045 template<class iType> 
00046 class GrFFTSink : public VrSink<iType> {
00047 
00048  public:
00049   GrFFTSink (VrGUILayout *layout,
00050                 double ymin, double ymax,
00051                 int nPoints = DEFAULT_nPoints,
00052                 const char *label = FFT_YAXIS_NAME);
00053   
00054   ~GrFFTSink();
00055 
00056   virtual const char *name() { return "GrFFTSink"; }
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 = 1024;      // number of points to plot
00065   static const int DIVISIONS = 10;              // number of x-axis divisions
00066 
00067  private:
00068   gr_fft_complex *d_fft;
00069   double         *d_xValues;
00070   double         *d_dbValues;           // FFT magnitude in dB
00071   float          *d_window;
00072   int             d_nPoints;            // max number of points to plot
00073   float           d_axis_offset;
00074   VrGUIPlot      *d_display;
00075   VrGUILayout    *d_layout;
00076   double          d_ymin, d_ymax;       // possible range of sample values
00077   int             d_nextPoint;  // index of next point to generate for graph
00078   int             d_one_or_two;
00079   int             d_increment;
00080   int             d_skip_count;
00081   int             d_kludge_count;
00082   const char     *d_label;
00083 
00084   void collectData (iType *i, long count);
00085 
00086   void set_skip_count (){
00087     d_skip_count = std::max (0, d_increment - d_nPoints);
00088   }
00089 };
00090 
00091 /*****************************************************************************
00092  * Implementation of template (C++ requires it to be in .h file).
00093  ****************************************************************************/
00094 
00095 
00096 /*
00097  * Creates a new GrFFTSink.
00098  */
00099 template<class iType>
00100 GrFFTSink<iType>::GrFFTSink (VrGUILayout *layout,
00101                                    double ymin, double ymax, int nPoints,
00102                                    const char *label) : d_label (label)
00103 {
00104   d_layout = layout;
00105   d_nPoints = nPoints;
00106 
00107   d_fft = new gr_fft_complex (d_nPoints);
00108 
00109   d_dbValues = new double[d_nPoints];
00110   d_xValues = new double[d_nPoints];
00111   d_window = new float[d_nPoints];
00112 
00113   for (int i = 0; i < d_nPoints; i++)
00114     d_window[i] = 0.54 - 0.46 * cos (2*M_PI/d_nPoints*i); // hamming d_window
00115 
00116   d_ymin = ymin;
00117   d_ymax = ymax;
00118   d_nextPoint = 0;
00119   d_axis_offset = 0.0;
00120   d_kludge_count = 0;
00121 }
00122 
00123 template<class iType> void
00124 GrFFTSink<iType>::initialize()
00125 {
00126   iType test_for_complex=0;
00127   double    samplingFrequency = getInputSamplingFrequencyN(0);  // Hz
00128 
00129   if (is_complex(test_for_complex)) {
00130     // this used to display the second half as "negative frequencies", but
00131     // it was screwed.  This just leaves them as is.  0 is the DC component.
00132 
00133     d_display = new VrGUIPlot (d_layout, FFT_XAXIS_NAME, d_label, true,
00134                                0, samplingFrequency,
00135                                d_ymin, d_ymax, d_nPoints, DIVISIONS);
00136     d_one_or_two = 1;
00137     for (int i = 0; i < d_nPoints; i++)
00138       d_xValues[i] = 
00139         ((double)i / (double) d_nPoints * samplingFrequency) - d_axis_offset;
00140   }
00141   else {
00142     d_display = new VrGUIPlot (d_layout, FFT_XAXIS_NAME, d_label, true,
00143                                0, samplingFrequency/2,
00144                                d_ymin, d_ymax, d_nPoints/2, DIVISIONS);
00145     d_one_or_two = 2;
00146     for (int i = 0; i <= d_nPoints/2 ; i++)
00147       d_xValues[i] =
00148         ((double)i / (double) d_nPoints * samplingFrequency) - d_axis_offset;
00149   }
00150 
00151   double updateFrequency = 30;  // update d_display 30 times / second
00152   d_increment = (int) (samplingFrequency / updateFrequency);
00153   if (d_increment < 1)
00154     d_increment = 1;
00155 
00156   set_skip_count ();
00157 }
00158 
00159 template<class iType> int
00160 GrFFTSink<iType>::work3(VrSampleRange output, 
00161                         VrSampleRange inputs[], void *ai[])
00162 {
00163   sync (output.index);
00164 
00165   collectData (((iType **) ai)[0], output.size);
00166 
00167   return output.size;
00168 }
00169 
00170 /*
00171  * Acquires the next point to plot on the graph.  Displays the graph when
00172  * all points are acquired.
00173  */
00174 template<class iType> void
00175 GrFFTSink<iType>::collectData(iType *in, long samples_available)
00176 {
00177   VrComplex     *fft_input = d_fft->get_inbuf ();
00178   VrComplex     *fft_output = d_fft->get_outbuf ();
00179   
00180   while (samples_available > 0){
00181     
00182     if (d_skip_count > 0){
00183       int       n = std::min ((long) d_skip_count, samples_available);
00184       d_skip_count -= n;
00185 
00186       in += n;
00187       samples_available -= n;
00188       continue;
00189     }
00190 
00191     if (d_nextPoint < d_nPoints)  {
00192       iType             sampleValue;
00193 
00194       sampleValue = *in++;
00195       samples_available--;
00196 
00197       fft_input[d_nextPoint] = sampleValue * d_window[d_nextPoint];
00198 
00199       d_nextPoint++;
00200     }
00201 
00202     if (d_nextPoint >= d_nPoints)  {
00203       d_nextPoint = 0;
00204       set_skip_count ();
00205     
00206       d_fft->execute ();        // do the work
00207 
00208       // compute log magnitude
00209       //
00210       // this could be computed as 20 * log10 (abs (d_fft_output[i])), but
00211       // then you'd be wasting cycles computing the sqrt hidden in abs (z)
00212     
00213       for (int i = 0; i < d_nPoints ; i++){
00214         d_dbValues[i] =
00215           10 * log10 (real(fft_output[i]) * real(fft_output[i])
00216                       + imag(fft_output[i]) * imag(fft_output[i]));
00217       }
00218 
00219       d_display->data (d_xValues, d_dbValues, d_nPoints / d_one_or_two);
00220 
00221       if (PRINT_PEAK && ++d_kludge_count == 250){
00222         double dbMax = d_dbValues[0];
00223         int    dbMaxIndex = 0;
00224 
00225         for (int i = 1; i < d_nPoints ; i++){
00226           if (d_dbValues[i] > dbMax){
00227             dbMax = d_dbValues[i];
00228             dbMaxIndex = i;
00229           }
00230         }
00231         printf ("dbMax = %f, dbMaxIndex = %d, freq = %g\n",
00232                 dbMax, dbMaxIndex,
00233                 dbMaxIndex * getSamplingFrequency() / d_nPoints);
00234         d_kludge_count = 0;
00235       }
00236       
00237     }
00238   }
00239 }
00240 
00241 template<class iType> 
00242 GrFFTSink<iType>::~GrFFTSink()
00243 {
00244   delete d_fft;
00245   delete[] d_xValues;
00246   delete[] d_dbValues;
00247   delete[] d_window;
00248 }
00249 #endif

Generated on Tue Mar 15 23:47:07 2005 for GNU Radio by  doxygen 1.4.0