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.
FIRFilter.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 "FIRFilter.h"
22 
23 GRT_BEGIN_NAMESPACE
24 
25 //Register the FIRFilter module with the PreProcessing base class
26 RegisterPreProcessingModule< FIRFilter > FIRFilter::registerModule("FIRFilter");
27 
28 FIRFilter::FIRFilter(const UINT filterType,const UINT numTaps,const Float sampleRate,const Float cutoffFrequency,const Float gain,const UINT numDimensions){
29  classType = "FIRFilter";
30  preProcessingType = classType;
31  debugLog.setProceedingText("[DEBUG FIRFilter]");
32  errorLog.setProceedingText("[ERROR FIRFilter]");
33  warningLog.setProceedingText("[WARNING FIRFilter]");
34 
35  initialized = false;
36  this->numInputDimensions = numDimensions;
37 
38  setFilterType( filterType );
39  setNumTaps( numTaps );
40  setSampleRate( sampleRate );
41  setGain(gain);
42 
43  //Set the cutoff freq and design the filter
44  switch( filterType ){
45  case LPF:
46  case HPF:
47  setCutoffFrequency( cutoffFrequency );
48  this->cutoffFrequencyLower = 0;
49  this->cutoffFrequencyUpper = 0;
50  //Build the filter
51  buildFilter();
52  break;
53  case BPF:
54  this->cutoffFrequency = 0;
55  setCutoffFrequency(cutoffFrequency, cutoffFrequency);
56  //Build the filter
57  buildFilter();
58  break;
59  }
60 }
61 
63  classType = "FIRFilter";
64  preProcessingType = classType;
65  debugLog.setProceedingText("[DEBUG FIRFilter]");
66  errorLog.setProceedingText("[ERROR FIRFilter]");
67  warningLog.setProceedingText("[WARNING FIRFilter]");
68 
69  *this = rhs;
70 }
71 
73 
74 }
75 
77  if(this!=&rhs){
78  this->filterType = rhs.filterType;
79  this->numTaps = rhs.numTaps;
80  this->sampleRate = rhs.sampleRate;
81  this->cutoffFrequency = rhs.cutoffFrequency;
82  this->cutoffFrequencyLower = rhs.cutoffFrequencyLower;
83  this->cutoffFrequencyUpper = rhs.cutoffFrequencyUpper;
84  this->gain = rhs.gain;
85  this->y = rhs.y;
86  this->z = rhs.z;
87 
89  }
90  return *this;
91 }
92 
93 bool FIRFilter::deepCopyFrom(const PreProcessing *preProcessing){
94 
95  if( preProcessing == NULL ) return false;
96 
97  if( this->getPreProcessingType() == preProcessing->getPreProcessingType() ){
98 
99  //Call the equals operator
100  *this = *(FIRFilter*)preProcessing;
101 
102  return true;
103  }
104 
105  errorLog << "deepCopyFrom(const PreProcessing *preProcessing) - PreProcessing Types Do Not Match!" << std::endl;
106 
107  return false;
108 }
109 
110 bool FIRFilter::process(const VectorFloat &inputVector){
111 
112  if( !initialized ){
113  errorLog << "process(const VectorFloat &inputVector) - Not initialized!" << std::endl;
114  return false;
115  }
116 
117  if( inputVector.size() != numInputDimensions ){
118  errorLog << "process(const VectorFloat &inputVector) - The size of the inputVector (" << inputVector.size() << ") does not match that of the filter (" << numInputDimensions << ")!" << std::endl;
119  return false;
120  }
121 
122  //Run the filter
123  filter( inputVector );
124 
125  //Check to ensure the size of the filter results match the number of dimensions
126  if( processedData.size() == numOutputDimensions ) return true;
127 
128  return false;
129 }
130 
132 
133  //Reset the base class
135 
136  if( initialized ){
137  //Set the data history buffer to zero
138  for(UINT n=0; n<numInputDimensions; n++){
139  for(UINT i=0; i<numTaps; i++){
140  y[n][i] = 0;
141  }
142  }
143  }
144 
145  return true;
146 }
147 
149 
150  //Clear the base class
152 
153  y.clear();
154  z.clear();
155 
156  return true;
157 }
158 
159 bool FIRFilter::saveModelToFile( std::string filename ) const{
160 
161  std::fstream file;
162  file.open(filename.c_str(), std::ios::out);
163 
164  if( !saveModelToFile( file ) ){
165  file.close();
166  return false;
167  }
168 
169  file.close();
170 
171  return true;
172 }
173 
174 bool FIRFilter::saveModelToFile( std::fstream &file ) const{
175 
176  if( !file.is_open() ){
177  errorLog << "saveSettingsToFile(fstream &file) - The file is not open!" << std::endl;
178  return false;
179  }
180 
181  //Save the file header
182  file << "GRT_FIR_FILTER_FILE_V1.0" << std::endl;
183 
184  //Save the preprocessing base variables
185  if( !savePreProcessingSettingsToFile( file ) ){
186  errorLog << "saveSettingsToFile(fstream &file) - Failed to save base settings to file!" << std::endl;
187  return false;
188  }
189 
190  //Save the filter settings
191  file << "FilterType: " << filterType << std::endl;
192  file << "NumTaps: " << numTaps << std::endl;
193  file << "SampleRate: " << sampleRate << std::endl;
194  file << "CutoffFrequency: " << cutoffFrequency << std::endl;
195  file << "CutoffFrequencyLower: " << cutoffFrequencyLower << std::endl;
196  file << "CutoffFrequencyUpper: " << cutoffFrequencyUpper << std::endl;
197  file << "Gain: " << gain << std::endl;
198 
199  if( initialized ){
200 
201  //Store z, we do not need to store y
202  file << "FilterCoeff: ";
203  for(UINT i=0; i<numTaps; i++){
204  file << z[i] << " ";
205  }
206  file << std::endl;
207  }
208 
209  return true;
210 }
211 
212 bool FIRFilter::loadModelFromFile( std::string filename ){
213 
214  std::fstream file;
215  file.open(filename.c_str(), std::ios::in);
216 
217  if( !loadModelFromFile( file ) ){
218  file.close();
219  initialized = false;
220  return false;
221  }
222 
223  file.close();
224 
225  return true;
226 }
227 
228 bool FIRFilter::loadModelFromFile( std::fstream &file ){
229 
230  //Clear the filter
231  clear();
232 
233  if( !file.is_open() ){
234  errorLog << "loadModelFromFile(fstream &file) - The file is not open!" << std::endl;
235  return false;
236  }
237 
238  std::string word;
239 
240  //Load the header
241  file >> word;
242 
243  if( word != "GRT_FIR_FILTER_FILE_V1.0" ){
244  errorLog << "loadModelFromFile(fstream &file) - Invalid file format!" << std::endl;
245  clear();
246  return false;
247  }
248 
249  if( !loadPreProcessingSettingsFromFile( file ) ){
250  errorLog << "loadModelFromFile(fstream &file) - Failed to load preprocessing base settings from file!" << std::endl;
251  clear();
252  return false;
253  }
254 
255  //Load if the filter type
256  file >> word;
257  if( word != "FilterType:" ){
258  errorLog << "loadModelFromFile(fstream &file) - Failed to read FilterType header!" << std::endl;
259  clear();
260  return false;
261  }
262  file >> filterType;
263 
264  //Load if the number of taps
265  file >> word;
266  if( word != "NumTaps:" ){
267  errorLog << "loadModelFromFile(fstream &file) - Failed to read NumTaps header!" << std::endl;
268  clear();
269  return false;
270  }
271  file >> numTaps;
272 
273  //Load if the sample rate
274  file >> word;
275  if( word != "SampleRate:" ){
276  errorLog << "loadModelFromFile(fstream &file) - Failed to read SampleRate header!" << std::endl;
277  clear();
278  return false;
279  }
280  file >> sampleRate;
281 
282  //Load if the cutoffFrequency
283  file >> word;
284  if( word != "CutoffFrequency:" ){
285  errorLog << "loadModelFromFile(fstream &file) - Failed to read CutoffFrequency header!" << std::endl;
286  clear();
287  return false;
288  }
289  file >> cutoffFrequency;
290 
291  //Load if the CutoffFrequencyLower
292  file >> word;
293  if( word != "CutoffFrequencyLower:" ){
294  errorLog << "loadModelFromFile(fstream &file) - Failed to read CutoffFrequencyLower header!" << std::endl;
295  clear();
296  return false;
297  }
298  file >> cutoffFrequencyLower;
299 
300  //Load if the CutoffFrequencyUpper
301  file >> word;
302  if( word != "CutoffFrequencyUpper:" ){
303  errorLog << "loadModelFromFile(fstream &file) - Failed to read CutoffFrequencyUpper header!" << std::endl;
304  clear();
305  return false;
306  }
307  file >> cutoffFrequencyUpper;
308 
309  //Load if the Gain
310  file >> word;
311  if( word != "Gain:" ){
312  errorLog << "loadModelFromFile(fstream &file) - Failed to read Gain header!" << std::endl;
313  clear();
314  return false;
315  }
316  file >> gain;
317 
318  if( initialized ){
319 
320  //Setup the memory and then load z
321  y.resize( numTaps, VectorFloat(numInputDimensions,0) );
322  z.resize( numTaps );
323 
324  //Load z
325  file >> word;
326  if( word != "FilterCoeff:" ){
327  errorLog << "loadModelFromFile(fstream &file) - Failed to read FilterCoeff header!" << std::endl;
328  clear();
329  return false;
330  }
331 
332  for(UINT i=0; i<numTaps; i++){
333  file >> z[i];
334  }
335  }
336 
337  return true;
338 }
339 
341 
342  if( numInputDimensions == 0 ){
343  errorLog << "buildFilter() - Failed to design filter, the number of inputs has not been set!" << std::endl;
344  return false;
345  }
346 
347  //Flag that the filter has not been built yet
348  initialized = false;
349 
350  //Set the number of outputs to the number of inputs
351  numOutputDimensions = numInputDimensions;
352 
353  //Reset the memory
354  y.clear();
355  z.clear();
356  y.resize( numTaps, VectorFloat(numInputDimensions,0) );
357  z.resize( numTaps, 0 );
358 
359  //Design the filter coeffients (z)
360  Float alpha = 0;
361  Float lambda = 0;
362  Float phi = 0;
363  const Float nyquist = sampleRate / 2.0;
364 
365  switch( filterType ){
366  case LPF:
367  //Design the low pass filter
368  lambda = PI * cutoffFrequency / nyquist;
369  for(UINT i=0; i<numTaps; i++){
370  alpha = i - (numTaps - 1.0) / 2.0;
371  if( alpha == 0.0 ) z[i] = lambda / PI;
372  else z[i] = sin( alpha * lambda ) / (alpha * PI);
373  }
374  break;
375  case HPF:
376  //Design the high pass filter
377  lambda = PI * cutoffFrequency / nyquist;
378  for(UINT i=0; i<numTaps; i++){
379  alpha = i - (numTaps - 1.0) / 2.0;
380  if( alpha == 0.0 ) z[i] = 1.0 - lambda / PI;
381  else z[i] = -sin( alpha * lambda ) / (alpha * PI);
382  }
383  break;
384  case BPF:
385  //Design the band pass filter
386  lambda = PI * cutoffFrequencyLower / nyquist;
387  phi = PI * cutoffFrequencyUpper / nyquist;
388  for(UINT i=0; i<numTaps; i++){
389  alpha = i - (numTaps - 1.0) / 2.0;
390  if( alpha == 0.0 ) z[i] = (phi - lambda) / PI;
391  else z[i] = (sin( alpha * phi ) - sin( alpha * lambda )) / (alpha * PI);
392  }
393  break;
394  default:
395  errorLog << "designFilter() - Failed to design filter. Unknown filter type!" << std::endl;
396  return false;
397  break;
398  }
399 
400  //Init the preprocessing base class
402 
403  return true;
404 }
405 
406 Float FIRFilter::filter(const Float x){
407 
408  //If the filter has not been initialised then return 0, otherwise filter x and return y
409  if( !initialized ){
410  errorLog << "filter(const Float x) - The filter has not been initialized!" << std::endl;
411  return 0;
412  }
413 
414  //Run the main filter function
415  VectorFloat result = filter( VectorFloat(1,x) );
416 
417  if( result.size() == 0 ){
418  errorLog << "filter(const Float x) - Something went wrong, the size of the filtered vector is zero" << std::endl;
419  return 0;
420  }
421 
422  //Return the filtered value
423  return result[0];
424 }
425 
427 
428  if( !initialized ){
429  errorLog << "filter(const VectorFloat &x) - Not Initialized!" << std::endl;
430  return VectorFloat();
431  }
432 
433  if( x.size() != numInputDimensions ){
434  errorLog << "filter(const VectorFloat &x) - The Number Of Input Dimensions (" << numInputDimensions << ") does not match the size of the input vector (" << x.size() << ")!" << std::endl;
435  return VectorFloat();
436  }
437 
438  //Add the new sample to the buffer
439  y.push_back( x );
440 
441  const UINT K = numTaps-1;
442 
443  //Run the filter for each input dimension
444  for(UINT n=0; n<numInputDimensions; n++){
445  processedData[n] = 0;
446  for(UINT i=0; i<numTaps; i++){
447  processedData[n] += y[K-i][n] * z[i];
448  }
449  processedData[n] *= gain;
450  }
451 
452  return processedData;
453 }
454 
456  return filterType;
457 }
458 
460  return numTaps;
461 }
462 
464  return sampleRate;
465 }
466 
468  return cutoffFrequency;
469 }
470 
472  return cutoffFrequencyLower;
473 }
474 
476  return cutoffFrequencyUpper;
477 }
478 
479 Float FIRFilter::getGain() const{
480  return gain;
481 }
482 
484  if( initialized ){
485  return y.getData();
486  }
487  return Vector< VectorFloat >();
488 }
489 
491  if( initialized ){
492  return z;
493  }
494  return VectorFloat();
495 }
496 
497 bool FIRFilter::setFilterType(const UINT filterType){
498 
499  if( filterType == LPF || filterType == HPF || filterType == BPF ){
500  this->filterType = filterType;
501  initialized = false;
502  return true;
503  }
504 
505  errorLog << "setFilterType(const UINT filterType) - Failed to set filter type, unknown filter type!" << std::endl;
506 
507  return false;
508 }
509 
510 bool FIRFilter::setNumTaps(const UINT numTaps){
511 
512  if( numTaps > 0 ){
513  this->numTaps = numTaps;
514  initialized = false;
515  return true;
516  }
517 
518  errorLog << "setNumTaps(const UINT numTaps) - The number of taps must be greater than zero!" << std::endl;
519 
520  return false;
521 }
522 
523 bool FIRFilter::setSampleRate(const Float sampleRate){
524 
525  if( sampleRate > 0 ){
526  this->sampleRate = sampleRate;
527  initialized = false;
528  return true;
529  }
530 
531  errorLog << "setSampleRate(const Float sampleRate) - The sample rate should be a positive number greater than zero!" << std::endl;
532 
533  return false;
534 }
535 
536 bool FIRFilter::setCutoffFrequency(const Float cutoffFrequency){
537 
538  if( filterType == BPF ){
539  warningLog << "setCutoffFrequency(const Float cutoffFrequency) - Setting the cutoff frequency has no effect if you are using a BPF. You should set the lower and upper cutoff frequencies instead!" << std::endl;
540  }
541 
542  if( cutoffFrequency > 0 ){
543  this->cutoffFrequency = cutoffFrequency;
544  initialized = false;
545  return true;
546  }
547 
548  errorLog << "setCutoffFrequency(const Float cutoffFrequency) - The cutoffFrequency should be a positive number greater than zero!" << std::endl;
549 
550  return false;
551 }
552 
553 bool FIRFilter::setCutoffFrequency(const Float cutoffFrequencyLower,const Float cutoffFrequencyUpper){
554 
555  if( filterType == LPF ){
556  warningLog << "setCutoffFrequency(const Float cutoffFrequencyLower,const Float cutoffFrequencyUpper) - Setting the lower and upper cutoff frequency has no effect if you are using a LPF. You should set the cutoff frequency instead!" << std::endl;
557  }
558 
559  if( filterType == HPF ){
560  warningLog << "setCutoffFrequency(const Float cutoffFrequencyLower,const Float cutoffFrequencyUpper) - Setting the lower and upper cutoff frequency has no effect if you are using a HPF. You should set the cutoff frequency instead!" << std::endl;
561  }
562 
563  if( cutoffFrequencyLower > 0 && cutoffFrequencyUpper > 0 ){
564  this->cutoffFrequencyLower = cutoffFrequencyLower;
565  this->cutoffFrequencyUpper = cutoffFrequencyUpper;
566  initialized = false;
567  return true;
568  }
569 
570  errorLog << "setCutoffFrequency(const Float cutoffFrequencyLower,const Float cutoffFrequencyUpper) - The cutoffFrequency should be a positive number greater than zero!" << std::endl;
571 
572  return false;
573 }
574 
575 bool FIRFilter::setGain(const Float gain){
576 
577  if( gain > 0 ){
578  this->gain = gain;
579  return true;
580  }
581 
582  errorLog << "setGain(const Float gain) - The gain should be a positive number greater than zero!" << std::endl;
583 
584  return false;
585 }
586 
587 GRT_END_NAMESPACE
588 
bool push_back(const T &value)
Vector< VectorFloat > getInputBuffer() const
Definition: FIRFilter.cpp:483
virtual bool clear()
Definition: FIRFilter.cpp:148
UINT getNumTaps() const
Definition: FIRFilter.cpp:459
virtual bool loadModelFromFile(std::string filename)
Definition: FIRFilter.cpp:212
bool setNumTaps(const UINT numTaps)
Definition: FIRFilter.cpp:510
bool savePreProcessingSettingsToFile(std::fstream &file) const
bool loadPreProcessingSettingsFromFile(std::fstream &file)
virtual bool reset()
Definition: FIRFilter.cpp:131
bool setFilterType(const UINT filterType)
Definition: FIRFilter.cpp:497
Float getCutoffFrequency() const
Definition: FIRFilter.cpp:467
Float getGain() const
Definition: FIRFilter.cpp:479
virtual bool resize(const unsigned int size)
Definition: Vector.h:133
FIRFilter(const UINT filterType=LPF, const UINT numTaps=50, const Float sampleRate=100, const Float cutoffFrequency=10, const Float gain=1, const UINT numDimensions=1)
Definition: FIRFilter.cpp:28
Float filter(const Float x)
Definition: FIRFilter.cpp:406
Float getCutoffFrequencyUpper() const
Definition: FIRFilter.cpp:475
Float getSampleRate() const
Definition: FIRFilter.cpp:463
bool setCutoffFrequency(const Float cutoffFrequency)
Definition: FIRFilter.cpp:536
virtual bool process(const VectorFloat &inputVector)
Definition: FIRFilter.cpp:110
virtual bool reset()
virtual ~FIRFilter()
Definition: FIRFilter.cpp:72
std::string getPreProcessingType() const
bool setSampleRate(const Float sampleRate)
Definition: FIRFilter.cpp:523
VectorFloat getFilterCoefficents() const
Definition: FIRFilter.cpp:490
virtual bool saveModelToFile(std::string filename) const
Definition: FIRFilter.cpp:159
virtual bool deepCopyFrom(const PreProcessing *preProcessing)
Definition: FIRFilter.cpp:93
This class implements a Finite Impulse Response (FIR) Filter.
FIRFilter & operator=(const FIRFilter &rhs)
Definition: FIRFilter.cpp:76
bool copyBaseVariables(const PreProcessing *preProcessingModule)
virtual bool clear()
UINT getFilterType() const
Definition: FIRFilter.cpp:455
Float getCutoffFrequencyLower() const
Definition: FIRFilter.cpp:471
Vector< T > getData(const bool rawBuffer=false) const
bool buildFilter()
Definition: FIRFilter.cpp:340
bool setGain(const Float gain)
Definition: FIRFilter.cpp:575
bool resize(const unsigned int newBufferSize)