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.
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 namespace GRT{
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 double sampleRate,const double cutoffFrequency,const double 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!" << endl;
106 
107  return false;
108 }
109 
110 bool FIRFilter::process(const VectorDouble &inputVector){
111 
112  if( !initialized ){
113  errorLog << "process(const VectorDouble &inputVector) - Not initialized!" << endl;
114  return false;
115  }
116 
117  if( inputVector.size() != numInputDimensions ){
118  errorLog << "process(const VectorDouble &inputVector) - The size of the inputVector (" << inputVector.size() << ") does not match that of the filter (" << numInputDimensions << ")!" << 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(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(fstream &file) const{
175 
176  if( !file.is_open() ){
177  errorLog << "saveSettingsToFile(fstream &file) - The file is not open!" << endl;
178  return false;
179  }
180 
181  //Save the file header
182  file << "GRT_FIR_FILTER_FILE_V1.0" << endl;
183 
184  //Save the preprocessing base variables
185  if( !savePreProcessingSettingsToFile( file ) ){
186  errorLog << "saveSettingsToFile(fstream &file) - Failed to save base settings to file!" << endl;
187  return false;
188  }
189 
190  //Save the filter settings
191  file << "FilterType: " << filterType << endl;
192  file << "NumTaps: " << numTaps << endl;
193  file << "SampleRate: " << sampleRate << endl;
194  file << "CutoffFrequency: " << cutoffFrequency << endl;
195  file << "CutoffFrequencyLower: " << cutoffFrequencyLower << endl;
196  file << "CutoffFrequencyUpper: " << cutoffFrequencyUpper << endl;
197  file << "Gain: " << gain << 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 << endl;
207  }
208 
209  return true;
210 }
211 
212 bool FIRFilter::loadModelFromFile(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(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!" << endl;
235  return false;
236  }
237 
238  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!" << 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!" << 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!" << 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!" << 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!" << 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!" << 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!" << 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!" << 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!" << 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, VectorDouble(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!" << 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!" << 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, VectorDouble(numInputDimensions,0) );
357  z.resize( numTaps, 0 );
358 
359  //Design the filter coeffients (z)
360  double alpha = 0;
361  double lambda = 0;
362  double phi = 0;
363  const double 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!" << endl;
396  return false;
397  break;
398  }
399 
400  //Init the preprocessing base class
402 
403  return true;
404 }
405 
406 double FIRFilter::filter(const double 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 double x) - The filter has not been initialized!" << endl;
411  return 0;
412  }
413 
414  //Run the main filter function
415  VectorDouble result = filter( VectorDouble(1,x) );
416 
417  if( result.size() == 0 ){
418  errorLog << "filter(const double x) - Something went wrong, the size of the filtered vector is zero" << endl;
419  return 0;
420  }
421 
422  //Return the filtered value
423  return result[0];
424 }
425 
426 VectorDouble FIRFilter::filter(const VectorDouble &x){
427 
428  if( !initialized ){
429  errorLog << "filter(const VectorDouble &x) - Not Initialized!" << endl;
430  return VectorDouble();
431  }
432 
433  if( x.size() != numInputDimensions ){
434  errorLog << "filter(const VectorDouble &x) - The Number Of Input Dimensions (" << numInputDimensions << ") does not match the size of the input vector (" << x.size() << ")!" << endl;
435  return VectorDouble();
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 double FIRFilter::getGain() const{
480  return gain;
481 }
482 
483 vector< VectorDouble > FIRFilter::getInputBuffer() const{
484  if( initialized ){
485  y.getDataAsVector();
486  }
487  return vector< VectorDouble >();
488 }
489 
490 VectorDouble FIRFilter::getFilterCoefficents() const{
491  if( initialized ){
492  return z;
493  }
494  return VectorDouble();
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!" << 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!" << endl;
519 
520  return false;
521 }
522 
523 bool FIRFilter::setSampleRate(const double sampleRate){
524 
525  if( sampleRate > 0 ){
526  this->sampleRate = sampleRate;
527  initialized = false;
528  return true;
529  }
530 
531  errorLog << "setSampleRate(const double sampleRate) - The sample rate should be a positive number greater than zero!" << endl;
532 
533  return false;
534 }
535 
536 bool FIRFilter::setCutoffFrequency(const double cutoffFrequency){
537 
538  if( filterType == BPF ){
539  warningLog << "setCutoffFrequency(const double cutoffFrequency) - Setting the cutoff frequency has no effect if you are using a BPF. You should set the lower and upper cutoff frequencies instead!" << endl;
540  }
541 
542  if( cutoffFrequency > 0 ){
543  this->cutoffFrequency = cutoffFrequency;
544  initialized = false;
545  return true;
546  }
547 
548  errorLog << "setCutoffFrequency(const double cutoffFrequency) - The cutoffFrequency should be a positive number greater than zero!" << endl;
549 
550  return false;
551 }
552 
553 bool FIRFilter::setCutoffFrequency(const double cutoffFrequencyLower,const double cutoffFrequencyUpper){
554 
555  if( filterType == LPF ){
556  warningLog << "setCutoffFrequency(const double cutoffFrequencyLower,const double cutoffFrequencyUpper) - Setting the lower and upper cutoff frequency has no effect if you are using a LPF. You should set the cutoff frequency instead!" << endl;
557  }
558 
559  if( filterType == HPF ){
560  warningLog << "setCutoffFrequency(const double cutoffFrequencyLower,const double cutoffFrequencyUpper) - Setting the lower and upper cutoff frequency has no effect if you are using a HPF. You should set the cutoff frequency instead!" << 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 double cutoffFrequencyLower,const double cutoffFrequencyUpper) - The cutoffFrequency should be a positive number greater than zero!" << endl;
571 
572  return false;
573 }
574 
575 bool FIRFilter::setGain(const double gain){
576 
577  if( gain > 0 ){
578  this->gain = gain;
579  return true;
580  }
581 
582  errorLog << "setGain(const double gain) - The gain should be a positive number greater than zero!" << endl;
583 
584  return false;
585 }
586 
587 
588 }//End of namespace GRT
virtual bool deepCopyFrom(const PreProcessing *preProcessing)
Definition: FIRFilter.cpp:93
FIRFilter & operator=(const FIRFilter &rhs)
Definition: FIRFilter.cpp:76
virtual bool clear()
virtual bool loadModelFromFile(string filename)
Definition: FIRFilter.cpp:212
double getCutoffFrequencyLower() const
Definition: FIRFilter.cpp:471
virtual bool clear()
Definition: FIRFilter.cpp:148
Definition: AdaBoost.cpp:25
bool setNumTaps(const UINT numTaps)
Definition: FIRFilter.cpp:510
VectorDouble getFilterCoefficents() const
Definition: FIRFilter.cpp:490
bool savePreProcessingSettingsToFile(fstream &file) const
UINT getNumTaps() const
Definition: FIRFilter.cpp:459
virtual bool process(const VectorDouble &inputVector)
Definition: FIRFilter.cpp:110
bool setCutoffFrequency(const double cutoffFrequency)
Definition: FIRFilter.cpp:536
string getPreProcessingType() const
bool setGain(const double gain)
Definition: FIRFilter.cpp:575
bool buildFilter()
Definition: FIRFilter.cpp:340
FIRFilter(const UINT filterType=LPF, const UINT numTaps=50, const double sampleRate=100, const double cutoffFrequency=10, const double gain=1, const UINT numDimensions=1)
Definition: FIRFilter.cpp:28
bool push_back(const T &value)
double getCutoffFrequency() const
Definition: FIRFilter.cpp:467
double getSampleRate() const
Definition: FIRFilter.cpp:463
vector< VectorDouble > getInputBuffer() const
Definition: FIRFilter.cpp:483
virtual bool saveModelToFile(string filename) const
Definition: FIRFilter.cpp:159
bool resize(const unsigned int newBufferSize)
virtual bool reset()
double getGain() const
Definition: FIRFilter.cpp:479
bool copyBaseVariables(const PreProcessing *preProcessingModule)
bool setFilterType(const UINT filterType)
Definition: FIRFilter.cpp:497
bool loadPreProcessingSettingsFromFile(fstream &file)
virtual bool reset()
Definition: FIRFilter.cpp:131
virtual ~FIRFilter()
Definition: FIRFilter.cpp:72
vector< T > getDataAsVector() const
This class implements a Finite Impulse Response (FIR) Filter.
double getCutoffFrequencyUpper() const
Definition: FIRFilter.cpp:475
UINT getFilterType() const
Definition: FIRFilter.cpp:455
double filter(const double x)
Definition: FIRFilter.cpp:406
bool setSampleRate(const double sampleRate)
Definition: FIRFilter.cpp:523