00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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;
00065 static const int DIVISIONS = 10;
00066 static const int DEFAULT_display_freq = 20;
00067 static const int DEFAULT_ffts_per_display = 5;
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;
00074 double *d_avgdbValues;
00075 float *d_window;
00076 int d_nPoints;
00077 float d_axis_offset;
00078 VrGUIPlot *d_display;
00079 double d_ymin, d_ymax;
00080 int d_nextPoint;
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;
00087 int d_ffts_per_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
00099
00100
00101
00102
00103
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);
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);
00138
00139 if (is_complex(test_for_complex)) {
00140
00141
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;
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
00190
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 ();
00225
00226
00227
00228
00229
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