GestureRecognitionToolkit  Version: 0.1.0
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 GRT_BEGIN_NAMESPACE
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!" << std::endl;
97 
98  return false;
99 }
100 
101 bool FFT::saveModelToFile( std::fstream &file ) const{
102 
103  if( !file.is_open() ){
104  errorLog << "saveModelToFile(fstream &file) - The file is not open!" << std::endl;
105  return false;
106  }
107 
108  //Write the file header
109  file << "GRT_FFT_FILE_V1.0" << std::endl;
110 
111  //Save the base settings to the file
113  errorLog << "saveFeatureExtractionSettingsToFile(fstream &file) - Failed to save base feature extraction settings to file!" << std::endl;
114  return false;
115  }
116 
117  //Write the FFT settings
118  file << "HopSize: " << hopSize << std::endl;
119  file << "FftWindowSize: " << fftWindowSize << std::endl;
120  file << "FftWindowFunction: " << fftWindowFunction << std::endl;
121  file << "ComputeMagnitude: " << computeMagnitude << std::endl;
122  file << "ComputePhase: " << computePhase << std::endl;
123 
124  return true;
125 }
126 
127 bool FFT::loadModelFromFile( std::fstream &file ){
128 
129  if( !file.is_open() ){
130  errorLog << "loadModelFromFile(fstream &file) - The file is not open!" << std::endl;
131  return false;
132  }
133 
134  std::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!" << std::endl;
141  return false;
142  }
143 
145  errorLog << "loadFeatureExtractionSettingsFromFile(fstream &file) - Failed to load base feature extraction settings from file!" << std::endl;
146  return false;
147  }
148 
149  file >> word;
150  if( word != "HopSize:" ){
151  errorLog << "loadModelFromFile(fstream &file) - Failed to read HopSize header!" << std::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!" << std::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!" << std::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!" << std::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!" << std::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,DataType inputType,DataType outputType){
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!" << std::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!" << std::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  this->inputType = inputType;
210  this->outputType = outputType;
211  hopCounter = 0;
212  featureDataReady = false;
213  numInputDimensions = numDimensions;
214 
215  //Set the output size, the fftWindowSize is divided by 2 because the FFT is symmetrical so only half the actual FFT is returned
216  numOutputDimensions = 0;
217  if( computePhase ) numOutputDimensions += fftWindowSize/2 * numInputDimensions;
218  if( computeMagnitude ) numOutputDimensions += fftWindowSize/2 * numInputDimensions;
219 
220  //Resize the output feature vector
221  featureVector.resize( numOutputDimensions, 0);
222 
225 
226  for(UINT i=0; i<dataBufferSize; i++){
227  dataBuffer[i].resize( numInputDimensions, 0 );
228  }
229 
230  for(UINT i=0; i<dataBufferSize; i++){
231  dataBuffer[i].resize( numInputDimensions, 0 );
232  }
233 
234  //Setup the fft for each dimension
235  fft.resize(numInputDimensions);
236  for(unsigned int i=0; i<numInputDimensions; i++){
237  if( !fft[i].init(fftWindowSize,fftWindowFunction,computeMagnitude,computePhase) ){
238  errorLog << "init(UINT fftWindowSize,UINT hopSize,UINT numDimensions,UINT fftWindowFunction,bool computeMagnitude,bool computePhase) - Failed to initialize fft!" << std::endl;
239  clear();
240  return false;
241  }
242  }
243 
244  initialized = true;
245 
246  return true;
247 }
248 
249 bool FFT::computeFeatures(const VectorFloat &inputVector){
250  return update( inputVector );
251 }
252 
253 bool FFT::computeFeatures(const MatrixFloat &inputMatrix){
254  return update( inputMatrix );
255 }
256 
257 bool FFT::update(const Float x){
258 
259  if( !initialized ){
260  errorLog << "update(const Float x) - Not initialized!" << std::endl;
261  return false;
262  }
263 
264  if( numInputDimensions != 1 ){
265  errorLog << "update(const Float x) - The size of the input (1) does not match that of the FeatureExtraction (" << numInputDimensions << ")!" << std::endl;
266  return false;
267  }
268 
269  return update(VectorFloat(1,x));
270 }
271 
272 bool FFT::update(const VectorFloat &x){
273 
274  if( !initialized ){
275  errorLog << "update(const VectorFloat &x) - Not initialized!" << std::endl;
276  return false;
277  }
278 
279  if( x.size() != numInputDimensions ){
280  errorLog << "update(const VectorFloat &x) - The size of the input (" << x.size() << ") does not match that of the FeatureExtraction (" << numInputDimensions << ")!" << std::endl;
281  return false;
282  }
283 
284  //Add the current input to the data buffers
285  dataBuffer.push_back( x );
286 
287  featureDataReady = false;
288 
289  if( ++hopCounter == hopSize ){
290  hopCounter = 0;
291  //Compute the FFT for each dimension
292  for(UINT j=0; j<numInputDimensions; j++){
293 
294  //Copy the input data for this dimension into the temp buffer
295  for(UINT i=0; i<dataBufferSize; i++){
296  tempBuffer[i] = dataBuffer[i][j];
297  }
298 
299  //Compute the FFT
300  if( !fft[j].computeFFT( tempBuffer ) ){
301  errorLog << "update(const VectorFloat &x) - Failed to compute FFT!" << std::endl;
302  return false;
303  }
304  }
305 
306  //Flag that the fft was computed during this update
307  featureDataReady = true;
308 
309  //Copy the FFT data to the feature vector
310  UINT index = 0;
311  for(UINT j=0; j<numInputDimensions; j++){
312  if( computeMagnitude ){
313  Float *mag = fft[j].getMagnitudeDataPtr();
314  for(UINT i=0; i<fft[j].getFFTSize()/2; i++){
315  featureVector[index++] = *mag++;
316  }
317  }
318  if( computePhase ){
319  Float *phase = fft[j].getPhaseDataPtr();
320  for(UINT i=0; i<fft[j].getFFTSize()/2; i++){
321  featureVector[index++] = *phase++;
322  }
323  }
324  }
325  }
326 
327  return true;
328 }
329 
330 bool FFT::update(const MatrixFloat &x){
331 
332  if( !initialized ){
333  errorLog << "update(const MatrixFloat &x) - Not initialized!" << std::endl;
334  return false;
335  }
336 
337  if( x.getNumCols() != numInputDimensions ){
338  errorLog << "update(const MatrixFloat &x) - The number of columns in the inputMatrix (" << x.getNumCols() << ") does not match that of the FeatureExtraction (" << numInputDimensions << ")!" << std::endl;
339  return false;
340  }
341 
342  featureDataReady = false;
343 
344  for(UINT k=0; k<x.getNumRows(); k++){
345 
346  //Add the current input to the data buffers
347  dataBuffer.push_back( x.getRow(k) );
348 
349  if( ++hopCounter == hopSize ){
350  hopCounter = 0;
351  //Compute the FFT for each dimension
352  for(UINT j=0; j<numInputDimensions; j++){
353 
354  //Copy the input data for this dimension into the temp buffer
355  for(UINT i=0; i<dataBufferSize; i++){
356  tempBuffer[i] = dataBuffer[i][j];
357  }
358 
359  //Compute the FFT
360  if( !fft[j].computeFFT( tempBuffer ) ){
361  errorLog << "update(const VectorFloat &x) - Failed to compute FFT!" << std::endl;
362  return false;
363  }
364  }
365 
366  //Flag that the fft was computed during this update
367  featureDataReady = true;
368 
369  //Copy the FFT data to the feature vector
370  UINT index = 0;
371  for(UINT j=0; j<numInputDimensions; j++){
372  if( computeMagnitude ){
373  Float *mag = fft[j].getMagnitudeDataPtr();
374  for(UINT i=0; i<fft[j].getFFTSize()/2; i++){
375  featureVector[index++] = *mag++;
376  }
377  }
378  if( computePhase ){
379  Float *phase = fft[j].getPhaseDataPtr();
380  for(UINT i=0; i<fft[j].getFFTSize()/2; i++){
381  featureVector[index++] = *phase++;
382  }
383  }
384  }
385  }
386  }
387 
388  return true;
389 }
390 
391 bool FFT::clear(){
392 
393  //Clear the base class
395 
396  //Clear the buffers
397  tempBuffer.clear();
398  dataBuffer.clear();
399  fft.clear();
400 
401  return true;
402 }
403 
404 bool FFT::reset(){
405  if( initialized ) return init(fftWindowSize,hopSize,numInputDimensions,fftWindowFunction,computeMagnitude,computePhase,inputType,outputType);
406  return false;
407 }
408 
410  if(initialized){ return hopSize; }
411  return 0;
412 }
413 
415  if(initialized){ return dataBufferSize; }
416  return 0;
417 }
418 
420 
421  if( !initialized ) return 0;
422  return fftWindowSize;
423 }
424 
426  if(initialized){ return fftWindowFunction; }
427  return 0;
428 }
429 
431  if(initialized){ return hopCounter; }
432  return 0;
433 }
434 
435 VectorFloat FFT::getFrequencyBins(const unsigned int sampleRate){
436  if( !initialized ){ return VectorFloat(); }
437 
438  VectorFloat freqBins( fftWindowSize );
439  for(unsigned int i=0; i<fftWindowSize; i++){
440  freqBins[i] = (i*sampleRate) / fftWindowSize;
441  }
442  return freqBins;
443 }
444 
445 bool FFT::setHopSize(UINT hopSize){
446  if( hopSize > 0 ){
447  this->hopSize = hopSize;
448  hopCounter = 0;
449  return true;
450  }
451  errorLog << "setHopSize(UINT hopSize) - The hopSize value must be greater than zero!" << std::endl;
452  return false;
453 }
454 
455 bool FFT::setFFTWindowSize(UINT fftWindowSize){
456  if( isPowerOfTwo(fftWindowSize) ){
457  if( initialized ) return init(fftWindowSize, hopSize, numInputDimensions, fftWindowFunction, computeMagnitude, computePhase);
458  this->fftWindowSize = fftWindowSize;
459  return true;
460  }
461  errorLog << "setFFTWindowSize(UINT fftWindowSize) - fftWindowSize must be a power of two!" << std::endl;
462  return false;
463 
464 }
465 
466 bool FFT::setFFTWindowFunction(UINT fftWindowFunction){
467  if( validateFFTWindowFunction( fftWindowFunction ) ){
468  this->fftWindowFunction = fftWindowFunction;
469  return true;
470  }
471  return false;
472 }
473 
474 bool FFT::setComputeMagnitude(bool computeMagnitude){
475  if( initialized ) return init(fftWindowSize, hopSize, numInputDimensions, fftWindowFunction, computeMagnitude, computePhase);
476  this->computeMagnitude = computeMagnitude;
477  return true;
478 }
479 
480 bool FFT::setComputePhase(bool computePhase){
481  if( initialized ) return init(fftWindowSize, hopSize, numInputDimensions, fftWindowFunction, computeMagnitude, computePhase);
482  this->computePhase = computePhase;
483  return true;
484 
485 }
486 
487 bool FFT::isPowerOfTwo(unsigned int x){
488  if (x < 2) return false;
489  if (x & (x - 1)) return false;
490  return true;
491 }
492 
493 bool FFT::validateFFTWindowFunction(UINT fftWindowFunction){
494  if( fftWindowFunction != RECTANGULAR_WINDOW && fftWindowFunction != BARTLETT_WINDOW &&
495  fftWindowFunction != HAMMING_WINDOW && fftWindowFunction != HANNING_WINDOW ){
496  return false;
497  }
498  return true;
499 }
500 
501 GRT_END_NAMESPACE
bool push_back(const T &value)
UINT dataBufferSize
Stores how much previous input data is stored in the dataBuffer.
Definition: FFT.h:327
Vector< FastFourierTransform > fft
A buffer used to store the FFT results.
Definition: FFT.h:335
CircularBuffer< VectorFloat > dataBuffer
A circular buffer used to store the previous M inputs.
Definition: FFT.h:334
UINT fftWindowFunction
The current windowFunction used for the FFT.
Definition: FFT.h:329
bool setHopSize(UINT hopSize)
Definition: FFT.cpp:445
bool saveFeatureExtractionSettingsToFile(std::fstream &file) const
bool computePhase
Tracks if the phase of the FFT needs to be computed.
Definition: FFT.h:332
UINT hopSize
The current hopSize, this sets how often the fft should be computed.
Definition: FFT.h:326
virtual bool resize(const unsigned int size)
Definition: Vector.h:133
UINT hopCounter
Keeps track of how many input samples the FFT has seen.
Definition: FFT.h:330
VectorFloat tempBuffer
A temporary buffer used to store the input data for the FFT.
Definition: FFT.h:333
UINT getFFTWindowSize()
Definition: FFT.cpp:419
bool setComputeMagnitude(bool computeMagnitude)
Definition: FFT.cpp:474
virtual ~FFT(void)
Definition: FFT.cpp:56
Definition: FFT.h:56
std::string getFeatureExtractionType() const
std::map< unsigned int, unsigned int > windowSizeMap
A map to relate the FFTWindowSize enumerations to actual values.
Definition: FFT.h:336
UINT getDataBufferSize()
Definition: FFT.cpp:414
virtual bool clear()
Definition: FFT.cpp:391
UINT getFFTWindowFunction()
Definition: FFT.cpp:425
virtual bool loadModelFromFile(std::fstream &file)
Definition: FFT.cpp:127
UINT fftWindowSize
Stores the size of the fft (and also the dataBuffer)
Definition: FFT.h:328
FFT(UINT fftWindowSize=512, UINT hopSize=1, UINT numDimensions=1, UINT fftWindowFunction=RECTANGULAR_WINDOW, bool computeMagnitude=true, bool computePhase=true)
Definition: FFT.cpp:28
UINT getHopCounter()
Definition: FFT.cpp:430
unsigned int getNumRows() const
Definition: Matrix.h:542
unsigned int getNumCols() const
Definition: Matrix.h:549
The FFT class computes the Fourier transform of an N dimensional signal using a Fast Fourier Transfor...
virtual bool deepCopyFrom(const FeatureExtraction *featureExtraction)
Definition: FFT.cpp:84
bool setFFTWindowFunction(UINT fftWindowFunction)
Definition: FFT.cpp:466
VectorFloat getRow(const unsigned int r) const
Definition: MatrixFloat.h:100
bool loadFeatureExtractionSettingsFromFile(std::fstream &file)
bool setFFTWindowSize(UINT fftWindowSize)
Definition: FFT.cpp:455
bool setComputePhase(bool computePhase)
Definition: FFT.cpp:480
virtual bool computeFeatures(const VectorFloat &inputVector)
Definition: FFT.cpp:249
bool computeMagnitude
Tracks if the magnitude (and power) of the FFT need to be computed.
Definition: FFT.h:331
virtual bool saveModelToFile(std::fstream &file) const
Definition: FFT.cpp:101
bool copyBaseVariables(const FeatureExtraction *featureExtractionModule)
FFT & operator=(const FFT &rhs)
Definition: FFT.cpp:59
UINT getHopSize()
Definition: FFT.cpp:409
bool isPowerOfTwo(UINT x)
A helper function to compute if the input is a power of two.
Definition: FFT.cpp:487
virtual bool reset()
Definition: FFT.cpp:404
bool update(const Float x)
Definition: FFT.cpp:257
bool resize(const unsigned int newBufferSize)