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