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