Main Page | Namespace List | Class Hierarchy | Class List | 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 Wed Aug 4 02:22:04 2004 for GNU Radio by doxygen 1.3.8