GestureRecognitionToolkit  Version: 0.2.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 #define GRT_DLL_EXPORTS
22 #include "FFT.h"
23 
24 GRT_BEGIN_NAMESPACE
25 
26 //Register the FFT module with the FeatureExtraction base class
27 RegisterFeatureExtractionModule< FFT > FFT::registerModule("FFT");
28 
29 FFT::FFT(UINT fftWindowSize,UINT hopSize,UINT numDimensions,UINT fftWindowFunction,bool computeMagnitude,bool computePhase){
30 
31  classType = "FFT";
32  featureExtractionType = classType;
33 
34  initialized = false;
35  featureDataReady = false;
36  numInputDimensions = 0;
37  numOutputDimensions = 0;
38 
39  infoLog.setProceedingText("[FFT]");
40  warningLog.setProceedingText("[WARNING FFT]");
41  errorLog.setProceedingText("[ERROR FFT]");
42 
43  if( isPowerOfTwo(fftWindowSize) && hopSize > 0 && numDimensions > 0 ){
44  init(fftWindowSize,hopSize,numDimensions,fftWindowFunction,computeMagnitude,computePhase);
45  }
46 }
47 
48 FFT::FFT(const FFT &rhs){
49  infoLog.setProceedingText("[FFT]");
50  warningLog.setProceedingText("[WARNING FFT]");
51  errorLog.setProceedingText("[ERROR FFT]");
52 
53  //Invoke the equals operator to copy the data from the rhs instance to this instance
54  *this = rhs;
55 }
56 
57 FFT::~FFT(void){
58 }
59 
60 FFT& FFT::operator=(const FFT &rhs){
61 
62  if( this != &rhs ){
63  this->hopSize = rhs.hopSize;
64  this->dataBufferSize = rhs.dataBufferSize;
65  this->fftWindowSize = rhs.fftWindowSize;
67  this->hopCounter = rhs.hopCounter;
69  this->computePhase = rhs.computePhase;
70  this->dataBuffer = rhs.dataBuffer;
71  this->tempBuffer = rhs.tempBuffer;
72  this->fft = rhs.fft;
73  this->windowSizeMap = rhs.windowSizeMap;
74 
76 
77  for(UINT i=0; i<dataBufferSize; i++){
78  dataBuffer[i].resize( numInputDimensions, 0 );
79  }
80  }
81  return *this;
82 }
83 
84 //Clone method
85 bool FFT::deepCopyFrom(const FeatureExtraction *featureExtraction){
86 
87  if( featureExtraction == NULL ) return false;
88 
89  if( this->getFeatureExtractionType() == featureExtraction->getFeatureExtractionType() ){
90 
91  //Invoke the equals operator to copy the data from the rhs instance to this instance
92  *this = *(FFT*)featureExtraction;
93 
94  return true;
95  }
96 
97  errorLog << "clone(FeatureExtraction *featureExtraction) - FeatureExtraction Types Do Not Match!" << std::endl;
98 
99  return false;
100 }
101 
102 bool FFT::saveModelToFile( std::fstream &file ) const{
103 
104  if( !file.is_open() ){
105  errorLog << "saveModelToFile(fstream &file) - The file is not open!" << std::endl;
106  return false;
107  }
108 
109  //Write the file header
110  file << "GRT_FFT_FILE_V1.0" << std::endl;
111 
112  //Save the base settings to the file
114  errorLog << "saveFeatureExtractionSettingsToFile(fstream &file) - Failed to save base feature extraction settings to file!" << std::endl;
115  return false;
116  }
117 
118  //Write the FFT settings
119  file << "HopSize: " << hopSize << std::endl;
120  file << "FftWindowSize: " << fftWindowSize << std::endl;
121  file << "FftWindowFunction: " << fftWindowFunction << std::endl;
122  file << "ComputeMagnitude: " << computeMagnitude << std::endl;
123  file << "ComputePhase: " << computePhase << std::endl;
124 
125  return true;
126 }
127 
128 bool FFT::loadModelFromFile( std::fstream &file ){
129 
130  if( !file.is_open() ){
131  errorLog << "loadModelFromFile(fstream &file) - The file is not open!" << std::endl;
132  return false;
133  }
134 
135  std::string word;
136 
137  //Load the header
138  file >> word;
139 
140  if( word != "GRT_FFT_FILE_V1.0" ){
141  errorLog << "loadModelFromFile(fstream &file) - Invalid file format!" << std::endl;
142  return false;
143  }
144 
146  errorLog << "loadFeatureExtractionSettingsFromFile(fstream &file) - Failed to load base feature extraction settings from file!" << std::endl;
147  return false;
148  }
149 
150  file >> word;
151  if( word != "HopSize:" ){
152  errorLog << "loadModelFromFile(fstream &file) - Failed to read HopSize header!" << std::endl;
153  return false;
154  }
155  file >> hopSize;
156 
157  file >> word;
158  if( word != "FftWindowSize:" ){
159  errorLog << "loadModelFromFile(fstream &file) - Failed to read FftWindowSize header!" << std::endl;
160  return false;
161  }
162  file >> fftWindowSize;
163 
164  file >> word;
165  if( word != "FftWindowFunction:" ){
166  errorLog << "loadModelFromFile(fstream &file) - Failed to read FftWindowFunction header!" << std::endl;
167  return false;
168  }
169  file >> fftWindowFunction;
170 
171  file >> word;
172  if( word != "ComputeMagnitude:" ){
173  errorLog << "loadModelFromFile(fstream &file) - Failed to read ComputeMagnitude header!" << std::endl;
174  return false;
175  }
176  file >> computeMagnitude;
177 
178  file >> word;
179  if( word != "ComputePhase:" ){
180  errorLog << "loadModelFromFile(fstream &file) - Failed to read ComputePhase header!" << std::endl;
181  return false;
182  }
183  file >> computePhase;
184 
185  //Init the FFT module to ensure everything is initialized correctly
186  return init(fftWindowSize,hopSize,numInputDimensions,fftWindowFunction,computeMagnitude,computePhase);
187 }
188 
189 bool FFT::init(UINT fftWindowSize,UINT hopSize,UINT numDimensions,UINT fftWindowFunction,bool computeMagnitude,bool computePhase,DataType inputType,DataType outputType){
190 
191  //Clear any previous setup
192  clear();
193 
194  if( !isPowerOfTwo(fftWindowSize) ){
195  errorLog << "init(UINT fftWindowSize,UINT hopSize,UINT numDimensions,UINT fftWindowFunction,bool computeMagnitude,bool computePhase) - fftWindowSize is not a power of two!" << std::endl;
196  return false;
197  }
198 
199  if( !validateFFTWindowFunction( fftWindowFunction ) ){
200  errorLog << "init(UINT fftWindowSize,UINT hopSize,UINT numDimensions,UINT fftWindowFunction,bool computeMagnitude,bool computePhase) - Unkown Window Function!" << std::endl;
201  return false;
202  }
203 
205  this->fftWindowSize = fftWindowSize;
206  this->hopSize = hopSize;
207  this->fftWindowFunction = fftWindowFunction;
208  this->computeMagnitude = computeMagnitude;
209  this->computePhase = computePhase;
210  this->inputType = inputType;
211  this->outputType = outputType;
212  hopCounter = 0;
213  featureDataReady = false;
214  numInputDimensions = numDimensions;
215 
216  //Set the output size, the fftWindowSize is divided by 2 because the FFT is symmetrical so only half the actual FFT is returned
217  numOutputDimensions = 0;
218  if( computePhase ) numOutputDimensions += fftWindowSize/2 * numInputDimensions;
219  if( computeMagnitude ) numOutputDimensions += fftWindowSize/2 * numInputDimensions;
220 
221  //Resize the output feature vector
222  featureVector.resize( numOutputDimensions, 0);
223 
226 
227  for(UINT i=0; i<dataBufferSize; i++){
228  dataBuffer[i].resize( numInputDimensions, 0 );
229  }
230 
231  for(UINT i=0; i<dataBufferSize; i++){
232  dataBuffer[i].resize( numInputDimensions, 0 );
233  }
234 
235  //Setup the fft for each dimension
236  fft.resize(numInputDimensions);
237  for(unsigned int i=0; i<numInputDimensions; i++){
238  if( !fft[i].init(fftWindowSize,fftWindowFunction,computeMagnitude,computePhase) ){
239  errorLog << "init(UINT fftWindowSize,UINT hopSize,UINT numDimensions,UINT fftWindowFunction,bool computeMagnitude,bool computePhase) - Failed to initialize fft!" << std::endl;
240  clear();
241  return false;
242  }
243  }
244 
245  initialized = true;
246 
247  return true;
248 }
249 
250 bool FFT::computeFeatures(const VectorFloat &inputVector){
251  return update( inputVector );
252 }
253 
254 bool FFT::computeFeatures(const MatrixFloat &inputMatrix){
255  return update( inputMatrix );
256 }
257 
258 bool FFT::update(const Float x){
259 
260  if( !initialized ){
261  errorLog << "update(const Float x) - Not initialized!" << std::endl;
262  return false;
263  }
264 
265  if( numInputDimensions != 1 ){
266  errorLog << "update(const Float x) - The size of the input (1) does not match that of the FeatureExtraction (" << numInputDimensions << ")!" << std::endl;
267  return false;
268  }
269 
270  return update(VectorFloat(1,x));
271 }
272 
273 bool FFT::update(const VectorFloat &x){
274 
275  if( !initialized ){
276  errorLog << "update(const VectorFloat &x) - Not initialized!" << std::endl;
277  return false;
278  }
279 
280  if( x.size() != numInputDimensions ){
281  errorLog << "update(const VectorFloat &x) - The size of the input (" << x.size() << ") does not match that of the FeatureExtraction (" << numInputDimensions << ")!" << std::endl;
282  return false;
283  }
284 
285  //Add the current input to the data buffers
286  dataBuffer.push_back( x );
287 
288  featureDataReady = false;
289 
290  if( ++hopCounter == hopSize ){
291  hopCounter = 0;
292  //Compute the FFT for each dimension
293  for(UINT j=0; j<numInputDimensions; j++){
294 
295  //Copy the input data for this dimension into the temp buffer
296  for(UINT i=0; i<dataBufferSize; i++){
297  tempBuffer[i] = dataBuffer[i][j];
298  }
299 
300  //Compute the FFT
301  if( !fft[j].computeFFT( tempBuffer ) ){
302  errorLog << "update(const VectorFloat &x) - Failed to compute FFT!" << std::endl;
303  return false;
304  }
305  }
306 
307  //Flag that the fft was computed during this update
308  featureDataReady = true;
309 
310  //Copy the FFT data to the feature vector
311  UINT index = 0;
312  for(UINT j=0; j<numInputDimensions; j++){
313  if( computeMagnitude ){
314  Float *mag = fft[j].getMagnitudeDataPtr();
315  for(UINT i=0; i<fft[j].getFFTSize()/2; i++){
316  featureVector[index++] = *mag++;
317  }
318  }
319  if( computePhase ){
320  Float *phase = fft[j].getPhaseDataPtr();
321  for(UINT i=0; i<fft[j].getFFTSize()/2; i++){
322  featureVector[index++] = *phase++;
323  }
324  }
325  }
326  }
327 
328  return true;
329 }
330 
331 bool FFT::update(const MatrixFloat &x){
332 
333  if( !initialized ){
334  errorLog << "update(const MatrixFloat &x) - Not initialized!" << std::endl;
335  return false;
336  }
337 
338  if( x.getNumCols() != numInputDimensions ){
339  errorLog << "update(const MatrixFloat &x) - The number of columns in the inputMatrix (" << x.getNumCols() << ") does not match that of the FeatureExtraction (" << numInputDimensions << ")!" << std::endl;
340  return false;
341  }
342 
343  featureDataReady = false;
344 
345  for(UINT k=0; k<x.getNumRows(); k++){
346 
347  //Add the current input to the data buffers
348  dataBuffer.push_back( x.getRow(k) );
349 
350  if( ++hopCounter == hopSize ){
351  hopCounter = 0;
352  //Compute the FFT for each dimension
353  for(UINT j=0; j<numInputDimensions; j++){
354 
355  //Copy the input data for this dimension into the temp buffer
356  for(UINT i=0; i<dataBufferSize; i++){
357  tempBuffer[i] = dataBuffer[i][j];
358  }
359 
360  //Compute the FFT
361  if( !fft[j].computeFFT( tempBuffer ) ){
362  errorLog << "update(const VectorFloat &x) - Failed to compute FFT!" << std::endl;
363  return false;
364  }
365  }
366 
367  //Flag that the fft was computed during this update
368  featureDataReady = true;
369 
370  //Copy the FFT data to the feature vector
371  UINT index = 0;
372  for(UINT j=0; j<numInputDimensions; j++){
373  if( computeMagnitude ){
374  Float *mag = fft[j].getMagnitudeDataPtr();
375  for(UINT i=0; i<fft[j].getFFTSize()/2; i++){
376  featureVector[index++] = *mag++;
377  }
378  }
379  if( computePhase ){
380  Float *phase = fft[j].getPhaseDataPtr();
381  for(UINT i=0; i<fft[j].getFFTSize()/2; i++){
382  featureVector[index++] = *phase++;
383  }
384  }
385  }
386  }
387  }
388 
389  return true;
390 }
391 
392 bool FFT::clear(){
393 
394  //Clear the base class
396 
397  //Clear the buffers
398  tempBuffer.clear();
399  dataBuffer.clear();
400  fft.clear();
401 
402  return true;
403 }
404 
405 bool FFT::reset(){
406  if( initialized ) return init(fftWindowSize,hopSize,numInputDimensions,fftWindowFunction,computeMagnitude,computePhase,inputType,outputType);
407  return false;
408 }
409 
411  if(initialized){ return hopSize; }
412  return 0;
413 }
414 
416  if(initialized){ return dataBufferSize; }
417  return 0;
418 }
419 
421 
422  if( !initialized ) return 0;
423  return fftWindowSize;
424 }
425 
427  if(initialized){ return fftWindowFunction; }
428  return 0;
429 }
430 
432  if(initialized){ return hopCounter; }
433  return 0;
434 }
435 
436 VectorFloat FFT::getFrequencyBins(const unsigned int sampleRate){
437  if( !initialized ){ return VectorFloat(); }
438 
439  VectorFloat freqBins( fftWindowSize );
440  for(unsigned int i=0; i<fftWindowSize; i++){
441  freqBins[i] = (i*sampleRate) / fftWindowSize;
442  }
443  return freqBins;
444 }
445 
446 bool FFT::setHopSize(UINT hopSize){
447  if( hopSize > 0 ){
448  this->hopSize = hopSize;
449  hopCounter = 0;
450  return true;
451  }
452  errorLog << "setHopSize(UINT hopSize) - The hopSize value must be greater than zero!" << std::endl;
453  return false;
454 }
455 
456 bool FFT::setFFTWindowSize(UINT fftWindowSize){
457  if( isPowerOfTwo(fftWindowSize) ){
458  if( initialized ) return init(fftWindowSize, hopSize, numInputDimensions, fftWindowFunction, computeMagnitude, computePhase);
459  this->fftWindowSize = fftWindowSize;
460  return true;
461  }
462  errorLog << "setFFTWindowSize(UINT fftWindowSize) - fftWindowSize must be a power of two!" << std::endl;
463  return false;
464 
465 }
466 
467 bool FFT::setFFTWindowFunction(UINT fftWindowFunction){
468  if( validateFFTWindowFunction( fftWindowFunction ) ){
469  this->fftWindowFunction = fftWindowFunction;
470  return true;
471  }
472  return false;
473 }
474 
475 bool FFT::setComputeMagnitude(bool computeMagnitude){
476  if( initialized ) return init(fftWindowSize, hopSize, numInputDimensions, fftWindowFunction, computeMagnitude, computePhase);
477  this->computeMagnitude = computeMagnitude;
478  return true;
479 }
480 
481 bool FFT::setComputePhase(bool computePhase){
482  if( initialized ) return init(fftWindowSize, hopSize, numInputDimensions, fftWindowFunction, computeMagnitude, computePhase);
483  this->computePhase = computePhase;
484  return true;
485 
486 }
487 
488 bool FFT::isPowerOfTwo(unsigned int x){
489  if (x < 2) return false;
490  if (x & (x - 1)) return false;
491  return true;
492 }
493 
494 bool FFT::validateFFTWindowFunction(UINT fftWindowFunction){
495  if( fftWindowFunction != RECTANGULAR_WINDOW && fftWindowFunction != BARTLETT_WINDOW &&
496  fftWindowFunction != HAMMING_WINDOW && fftWindowFunction != HANNING_WINDOW ){
497  return false;
498  }
499  return true;
500 }
501 
502 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:446
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:420
bool setComputeMagnitude(bool computeMagnitude)
Definition: FFT.cpp:475
virtual ~FFT(void)
Definition: FFT.cpp:57
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:415
virtual bool clear()
Definition: FFT.cpp:392
UINT getFFTWindowFunction()
Definition: FFT.cpp:426
virtual bool loadModelFromFile(std::fstream &file)
Definition: FFT.cpp:128
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:29
UINT getHopCounter()
Definition: FFT.cpp:431
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:85
bool setFFTWindowFunction(UINT fftWindowFunction)
Definition: FFT.cpp:467
VectorFloat getRow(const unsigned int r) const
Definition: MatrixFloat.h:100
bool loadFeatureExtractionSettingsFromFile(std::fstream &file)
bool setFFTWindowSize(UINT fftWindowSize)
Definition: FFT.cpp:456
bool setComputePhase(bool computePhase)
Definition: FFT.cpp:481
virtual bool computeFeatures(const VectorFloat &inputVector)
Definition: FFT.cpp:250
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:102
bool copyBaseVariables(const FeatureExtraction *featureExtractionModule)
FFT & operator=(const FFT &rhs)
Definition: FFT.cpp:60
UINT getHopSize()
Definition: FFT.cpp:410
bool isPowerOfTwo(UINT x)
A helper function to compute if the input is a power of two.
Definition: FFT.cpp:488
virtual bool reset()
Definition: FFT.cpp:405
bool update(const Float x)
Definition: FFT.cpp:258
bool resize(const unsigned int newBufferSize)