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