GestureRecognitionToolkit  Version: 1.0 Revision: 04-03-15
The Gesture Recognition Toolkit (GRT) is a cross-platform, open-source, c++ machine learning library for real-time gesture recognition.
FFT.cpp
1 /*
2  GRT MIT License
3  Copyright (c) <2012> <Nicholas Gillian, Media Lab, MIT>
4 
5  Permission is hereby granted, free of charge, to any person obtaining a copy of this software
6  and associated documentation files (the "Software"), to deal in the Software without restriction,
7  including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
9  subject to the following conditions:
10 
11  The above copyright notice and this permission notice shall be included in all copies or substantial
12  portions of the Software.
13 
14  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include "FFT.h"
22 
23 namespace GRT{
24 
25 //Register the FFT module with the FeatureExtraction base class
26 RegisterFeatureExtractionModule< FFT > FFT::registerModule("FFT");
27 
28 FFT::FFT(UINT fftWindowSize,UINT hopSize,UINT numDimensions,UINT fftWindowFunction,bool computeMagnitude,bool computePhase){
29 
30  classType = "FFT";
31  featureExtractionType = classType;
32 
33  initialized = false;
34  featureDataReady = false;
35  numInputDimensions = 0;
36  numOutputDimensions = 0;
37 
38  infoLog.setProceedingText("[FFT]");
39  warningLog.setProceedingText("[WARNING FFT]");
40  errorLog.setProceedingText("[ERROR FFT]");
41 
42  if( isPowerOfTwo(fftWindowSize) && hopSize > 0 && numDimensions > 0 ){
43  init(fftWindowSize,hopSize,numDimensions,fftWindowFunction,computeMagnitude,computePhase);
44  }
45 }
46 
47 FFT::FFT(const FFT &rhs){
48  infoLog.setProceedingText("[FFT]");
49  warningLog.setProceedingText("[WARNING FFT]");
50  errorLog.setProceedingText("[ERROR FFT]");
51 
52  //Invoke the equals operator to copy the data from the rhs instance to this instance
53  *this = rhs;
54 }
55 
56 FFT::~FFT(void){
57 }
58 
59 FFT& FFT::operator=(const FFT &rhs){
60 
61  if( this != &rhs ){
62  this->hopSize = rhs.hopSize;
63  this->dataBufferSize = rhs.dataBufferSize;
64  this->fftWindowSize = rhs.fftWindowSize;
66  this->hopCounter = rhs.hopCounter;
68  this->computePhase = rhs.computePhase;
69  this->dataBuffer = rhs.dataBuffer;
70  this->tempBuffer = rhs.tempBuffer;
71  this->fft = rhs.fft;
72  this->windowSizeMap = rhs.windowSizeMap;
73 
75 
76  for(UINT i=0; i<dataBufferSize; i++){
77  dataBuffer[i].resize( numInputDimensions, 0 );
78  }
79  }
80  return *this;
81 }
82 
83 //Clone method
84 bool FFT::deepCopyFrom(const FeatureExtraction *featureExtraction){
85 
86  if( featureExtraction == NULL ) return false;
87 
88  if( this->getFeatureExtractionType() == featureExtraction->getFeatureExtractionType() ){
89 
90  //Invoke the equals operator to copy the data from the rhs instance to this instance
91  *this = *(FFT*)featureExtraction;
92 
93  return true;
94  }
95 
96  errorLog << "clone(FeatureExtraction *featureExtraction) - FeatureExtraction Types Do Not Match!" << endl;
97 
98  return false;
99 }
100 
101 bool FFT::saveModelToFile(fstream &file) const{
102 
103  if( !file.is_open() ){
104  errorLog << "saveModelToFile(fstream &file) - The file is not open!" << endl;
105  return false;
106  }
107 
108  //Write the file header
109  file << "GRT_FFT_FILE_V1.0" << endl;
110 
111  //Save the base settings to the file
113  errorLog << "saveFeatureExtractionSettingsToFile(fstream &file) - Failed to save base feature extraction settings to file!" << endl;
114  return false;
115  }
116 
117  //Write the FFT settings
118  file << "HopSize: " << hopSize << endl;
119  file << "FftWindowSize: " << fftWindowSize << endl;
120  file << "FftWindowFunction: " << fftWindowFunction << endl;
121  file << "ComputeMagnitude: " << computeMagnitude << endl;
122  file << "ComputePhase: " << computePhase << endl;
123 
124  return true;
125 }
126 
127 bool FFT::loadModelFromFile(fstream &file){
128 
129  if( !file.is_open() ){
130  errorLog << "loadModelFromFile(fstream &file) - The file is not open!" << endl;
131  return false;
132  }
133 
134  string word;
135 
136  //Load the header
137  file >> word;
138 
139  if( word != "GRT_FFT_FILE_V1.0" ){
140  errorLog << "loadModelFromFile(fstream &file) - Invalid file format!" << endl;
141  return false;
142  }
143 
145  errorLog << "loadFeatureExtractionSettingsFromFile(fstream &file) - Failed to load base feature extraction settings from file!" << endl;
146  return false;
147  }
148 
149  file >> word;
150  if( word != "HopSize:" ){
151  errorLog << "loadModelFromFile(fstream &file) - Failed to read HopSize header!" << endl;
152  return false;
153  }
154  file >> hopSize;
155 
156  file >> word;
157  if( word != "FftWindowSize:" ){
158  errorLog << "loadModelFromFile(fstream &file) - Failed to read FftWindowSize header!" << endl;
159  return false;
160  }
161  file >> fftWindowSize;
162 
163  file >> word;
164  if( word != "FftWindowFunction:" ){
165  errorLog << "loadModelFromFile(fstream &file) - Failed to read FftWindowFunction header!" << endl;
166  return false;
167  }
168  file >> fftWindowFunction;
169 
170  file >> word;
171  if( word != "ComputeMagnitude:" ){
172  errorLog << "loadModelFromFile(fstream &file) - Failed to read ComputeMagnitude header!" << endl;
173  return false;
174  }
175  file >> computeMagnitude;
176 
177  file >> word;
178  if( word != "ComputePhase:" ){
179  errorLog << "loadModelFromFile(fstream &file) - Failed to read ComputePhase header!" << endl;
180  return false;
181  }
182  file >> computePhase;
183 
184  //Init the FFT module to ensure everything is initialized correctly
185  return init(fftWindowSize,hopSize,numInputDimensions,fftWindowFunction,computeMagnitude,computePhase);
186 }
187 
188 bool FFT::init(UINT fftWindowSize,UINT hopSize,UINT numDimensions,UINT fftWindowFunction,bool computeMagnitude,bool computePhase){
189 
190  //Clear any previous setup
191  clear();
192 
193  if( !isPowerOfTwo(fftWindowSize) ){
194  errorLog << "init(UINT fftWindowSize,UINT hopSize,UINT numDimensions,UINT fftWindowFunction,bool computeMagnitude,bool computePhase) - fftWindowSize is not a power of two!" << endl;
195  return false;
196  }
197 
198  if( !validateFFTWindowFunction( fftWindowFunction ) ){
199  errorLog << "init(UINT fftWindowSize,UINT hopSize,UINT numDimensions,UINT fftWindowFunction,bool computeMagnitude,bool computePhase) - Unkown Window Function!" << endl;
200  return false;
201  }
202 
204  this->fftWindowSize = fftWindowSize;
205  this->hopSize = hopSize;
206  this->fftWindowFunction = fftWindowFunction;
207  this->computeMagnitude = computeMagnitude;
208  this->computePhase = computePhase;
209  hopCounter = 0;
210  featureDataReady = false;
211  numInputDimensions = numDimensions;
212 
213  //Set the output size, the fftWindowSize is divided by 2 because the FFT is symmetrical so only half the actual FFT is returned
214  numOutputDimensions = 0;
215  if( computePhase ) numOutputDimensions += fftWindowSize/2 * numInputDimensions;
216  if( computeMagnitude ) numOutputDimensions += fftWindowSize/2 * numInputDimensions;
217 
218  //Resize the output feature vector
219  featureVector.resize( numOutputDimensions, 0);
220 
222  tempBuffer.resize( dataBufferSize );
223 
224  for(UINT i=0; i<dataBufferSize; i++){
225  dataBuffer[i].resize( numInputDimensions, 0 );
226  }
227 
228  for(UINT i=0; i<dataBufferSize; i++){
229  dataBuffer[i].resize( numInputDimensions, 0 );
230  }
231 
232  //Setup the fft for each dimension
233  fft.resize(numInputDimensions);
234  for(unsigned int i=0; i<numInputDimensions; i++){
235  if( !fft[i].init(fftWindowSize,fftWindowFunction,computeMagnitude,computePhase) ){
236  errorLog << "init(UINT fftWindowSize,UINT hopSize,UINT numDimensions,UINT fftWindowFunction,bool computeMagnitude,bool computePhase) - Failed to initialize fft!" << endl;
237  clear();
238  return false;
239  }
240  }
241 
242  initialized = true;
243 
244  return true;
245 }
246 
247 bool FFT::computeFeatures(const VectorDouble &inputVector){
248 
249  if( !initialized ){
250  errorLog << "computeFeatures(const VectorDouble &inputVector) - Not initialized!" << endl;
251  return false;
252  }
253 
254  if( inputVector.size() != numInputDimensions ){
255  errorLog << "computeFeatures(const VectorDouble &inputVector) - The size of the inputVector (" << inputVector.size() << ") does not match that of the FeatureExtraction (" << numInputDimensions << ")!" << endl;
256  return false;
257  }
258 
259  return update(inputVector);
260 }
261 
262 bool FFT::update(const double x){
263 
264  if( !initialized ){
265  errorLog << "update(const double x) - Not initialized!" << endl;
266  return false;
267  }
268 
269  if( numInputDimensions != 1 ){
270  errorLog << "update(const double x) - The size of the input (1) does not match that of the FeatureExtraction (" << numInputDimensions << ")!" << endl;
271  return false;
272  }
273 
274  return update(VectorDouble(1,x));
275 }
276 
277 bool FFT::update(const VectorDouble &x){
278 
279  if( !initialized ){
280  errorLog << "update(const VectorDouble &x) - Not initialized!" << endl;
281  return false;
282  }
283 
284  if( x.size() != numInputDimensions ){
285  errorLog << "update(const VectorDouble &x) - The size of the input (" << x.size() << ") does not match that of the FeatureExtraction (" << numInputDimensions << ")!" << endl;
286  return false;
287  }
288 
289  //Add the current input to the data buffers
291 
292  featureDataReady = false;
293 
294  if( ++hopCounter == hopSize ){
295  hopCounter = 0;
296  //Compute the FFT for each dimension
297  for(UINT j=0; j<numInputDimensions; j++){
298 
299  //Copy the input data for this dimension into the temp buffer
300  for(UINT i=0; i<dataBufferSize; i++){
301  tempBuffer[i] = dataBuffer[i][j];
302  }
303 
304  //Compute the FFT
305  if( !fft[j].computeFFT( tempBuffer ) ){
306  errorLog << "update(const VectorDouble &x) - Failed to compute FFT!" << endl;
307  return false;
308  }
309  }
310 
311  //Flag that the fft was computed during this update
312  featureDataReady = true;
313 
314  //Copy the FFT data to the feature vector
315  UINT index = 0;
316  for(UINT j=0; j<numInputDimensions; j++){
317  if( computeMagnitude ){
318  double *mag = fft[j].getMagnitudeDataPtr();
319  for(UINT i=0; i<fft[j].getFFTSize()/2; i++){
320  featureVector[index++] = *mag++;
321  }
322  }
323  if( computePhase ){
324  double *phase = fft[j].getPhaseDataPtr();
325  for(UINT i=0; i<fft[j].getFFTSize()/2; i++){
326  featureVector[index++] = *phase++;
327  }
328  }
329  }
330  }
331 
332  return true;
333 }
334 
335 bool FFT::clear(){
336 
337  //Clear the base class
339 
340  //Clear the buffers
341  tempBuffer.clear();
342  dataBuffer.clear();
343  fft.clear();
344 
345  return true;
346 }
347 
348 bool FFT::reset(){
349  if( initialized ) return init(fftWindowSize,hopSize,numInputDimensions,fftWindowFunction,computeMagnitude,computePhase);
350  return false;
351 }
352 
354  if(initialized){ return hopSize; }
355  return 0;
356 }
357 
359  if(initialized){ return dataBufferSize; }
360  return 0;
361 }
362 
364 
365  if( !initialized ) return 0;
366  return fftWindowSize;
367 }
368 
370  if(initialized){ return fftWindowFunction; }
371  return 0;
372 }
373 
375  if(initialized){ return hopCounter; }
376  return 0;
377 }
378 
379 VectorDouble FFT::getFrequencyBins(const unsigned int sampleRate){
380  if( !initialized ){ return VectorDouble(); }
381 
382  VectorDouble freqBins( fftWindowSize );
383  for(unsigned int i=0; i<fftWindowSize; i++){
384  freqBins[i] = (i*sampleRate) / fftWindowSize;
385  }
386  return freqBins;
387 }
388 
389 bool FFT::setHopSize(UINT hopSize){
390  if( hopSize > 0 ){
391  this->hopSize = hopSize;
392  hopCounter = 0;
393  return true;
394  }
395  errorLog << "setHopSize(UINT hopSize) - The hopSize value must be greater than zero!" << endl;
396  return false;
397 }
398 
399 bool FFT::setFFTWindowSize(UINT fftWindowSize){
400  if( isPowerOfTwo(fftWindowSize) ){
401  if( initialized ) return init(fftWindowSize, hopSize, numInputDimensions, fftWindowFunction, computeMagnitude, computePhase);
402  this->fftWindowSize = fftWindowSize;
403  return true;
404  }
405  errorLog << "setFFTWindowSize(UINT fftWindowSize) - fftWindowSize must be a power of two!" << endl;
406  return false;
407 
408 }
409 
410 bool FFT::setFFTWindowFunction(UINT fftWindowFunction){
411  if( validateFFTWindowFunction( fftWindowFunction ) ){
412  this->fftWindowFunction = fftWindowFunction;
413  return true;
414  }
415  return false;
416 }
417 
418 bool FFT::setComputeMagnitude(bool computeMagnitude){
419  if( initialized ) return init(fftWindowSize, hopSize, numInputDimensions, fftWindowFunction, computeMagnitude, computePhase);
420  this->computeMagnitude = computeMagnitude;
421  return true;
422 }
423 
424 bool FFT::setComputePhase(bool computePhase){
425  if( initialized ) return init(fftWindowSize, hopSize, numInputDimensions, fftWindowFunction, computeMagnitude, computePhase);
426  this->computePhase = computePhase;
427  return true;
428 
429 }
430 
431 bool FFT::isPowerOfTwo(unsigned int x){
432  if (x < 2) return false;
433  if (x & (x - 1)) return false;
434  return true;
435 }
436 
437 bool FFT::validateFFTWindowFunction(UINT fftWindowFunction){
438  if( fftWindowFunction != RECTANGULAR_WINDOW && fftWindowFunction != BARTLETT_WINDOW &&
439  fftWindowFunction != HAMMING_WINDOW && fftWindowFunction != HANNING_WINDOW ){
440  return false;
441  }
442  return true;
443 }
444 
445 
446 }//End of namespace GRT
GRT::VectorDouble tempBuffer
A temporary buffer used to store the input data for the FFT.
Definition: FFT.h:311
bool setFFTWindowFunction(UINT fftWindowFunction)
Definition: FFT.cpp:410
virtual bool saveModelToFile(fstream &file) const
Definition: FFT.cpp:101
virtual bool reset()
Definition: FFT.cpp:348
UINT hopSize
The current hopSize, this sets how often the fft should be computed.
Definition: FFT.h:304
Definition: AdaBoost.cpp:25
FFT(UINT fftWindowSize=512, UINT hopSize=1, UINT numDimensions=1, UINT fftWindowFunction=RECTANGULAR_WINDOW, bool computeMagnitude=true, bool computePhase=true)
Definition: FFT.cpp:28
virtual ~FFT(void)
Definition: FFT.cpp:56
UINT getHopCounter()
Definition: FFT.cpp:374
UINT dataBufferSize
Stores how much previous input data is stored in the dataBuffer.
Definition: FFT.h:305
string getFeatureExtractionType() const
virtual bool computeFeatures(const VectorDouble &inputVector)
Definition: FFT.cpp:247
UINT getFFTWindowSize()
Definition: FFT.cpp:363
virtual bool deepCopyFrom(const FeatureExtraction *featureExtraction)
Definition: FFT.cpp:84
virtual bool clear()
Definition: FFT.cpp:335
bool computePhase
Tracks if the phase of the FFT needs to be computed.
Definition: FFT.h:310
bool setComputeMagnitude(bool computeMagnitude)
Definition: FFT.cpp:418
bool push_back(const T &value)
FFT & operator=(const FFT &rhs)
Definition: FFT.cpp:59
UINT fftWindowSize
Stores the size of the fft (and also the dataBuffer)
Definition: FFT.h:306
bool computeMagnitude
Tracks if the magnitude (and power) of the FFT need to be computed.
Definition: FFT.h:309
bool setFFTWindowSize(UINT fftWindowSize)
Definition: FFT.cpp:399
vector< FastFourierTransform > fft
A buffer used to store the FFT results.
Definition: FFT.h:313
bool resize(const unsigned int newBufferSize)
CircularBuffer< VectorDouble > dataBuffer
A circular buffer used to store the previous M inputs.
Definition: FFT.h:312
bool update(const double x)
Definition: FFT.cpp:262
bool loadFeatureExtractionSettingsFromFile(fstream &file)
UINT getHopSize()
Definition: FFT.cpp:353
UINT getFFTWindowFunction()
Definition: FFT.cpp:369
bool isPowerOfTwo(UINT x)
A helper function to compute if the input is a power of two.
Definition: FFT.cpp:431
std::map< unsigned int, unsigned int > windowSizeMap
A map to relate the FFTWindowSize enumerations to actual values.
Definition: FFT.h:314
The FFT class computes the Fourier transform of an N dimensional signal using a Fast Fourier Transfor...
bool setHopSize(UINT hopSize)
Definition: FFT.cpp:389
bool setComputePhase(bool computePhase)
Definition: FFT.cpp:424
UINT fftWindowFunction
The current windowFunction used for the FFT.
Definition: FFT.h:307
bool saveFeatureExtractionSettingsToFile(fstream &file) const
UINT getDataBufferSize()
Definition: FFT.cpp:358
virtual bool loadModelFromFile(fstream &file)
Definition: FFT.cpp:127
bool copyBaseVariables(const FeatureExtraction *featureExtractionModule)
Definition: FFT.h:56
UINT hopCounter
Keeps track of how many input samples the FFT has seen.
Definition: FFT.h:308