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