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.
PeakDetection.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 "PeakDetection.h"
23 
24 GRT_BEGIN_NAMESPACE
25 
26 PeakDetection::PeakDetection(const UINT lowPassFilterSize,const UINT searchWindowSize){
27 
28  this->lowPassFilterSize = lowPassFilterSize;
29  this->searchWindowSize = searchWindowSize;
30 
31  inputTimeoutCounter = 0;
32  maximaCounter = 0;
33  minimaCounter = 0;
34  inputTimeoutLimit = 10;
35  searchHistorySize = 10;
36  deadZoneThreshold = 0.01;
37  enableSearch = false;
38  peakDetected = false;
39 
40  setSearchWindowSize( searchWindowSize );
41 }
42 
43 PeakDetection::PeakDetection(const PeakDetection &rhs){
44 
45  this->lowPassFilterSize = rhs.lowPassFilterSize;
46  this->searchWindowSize = rhs.searchWindowSize;
47  this->lowPassFilter = rhs.lowPassFilter;
48 }
49 
50 PeakDetection::~PeakDetection(){
51 
52 }
53 
54 PeakDetection& PeakDetection::operator=(const PeakDetection &rhs){
55  if(this!=&rhs){
56  this->lowPassFilterSize = rhs.lowPassFilterSize;
57  this->searchWindowSize = rhs.searchWindowSize;
58  this->lowPassFilter = rhs.lowPassFilter;
59  }
60  return *this;
61 }
62 
63 bool PeakDetection::update( const Float x){
64 
65  //Update the input counter
66  if( ++inputTimeoutCounter >= inputTimeoutLimit ){
67  inputTimeoutCounter = inputTimeoutLimit;
68  enableSearch = true;
69  }else enableSearch = false;
70 
71  peakDetected = false;
72  peakInfo.clear();
73 
74  //Low pass filter the input data to remove some noise
75  Float filteredValue = lowPassFilter.filter(x);
76 
77  //Compute the first deriv
78  Float firstDeriv = filteredValue - filteredDataBuffer.getBack();
79 
80  //Compute the second deriv
81  Float secondDeriv = firstDeriv - firstDerivBuffer.getBack();
82 
83  //Filter the second deriv using the deadzone filter, this removes any jitter around the 0
84  secondDeriv = deadZoneFilter.filter( secondDeriv );
85 
86  //Store the values in the buffers
87  filteredDataBuffer.push_back( filteredValue );
88  firstDerivBuffer.push_back( firstDeriv );
89  secondDerivBuffer.push_back( secondDeriv );
90 
91  //Search for any maxima/minima within the window
92  unsigned int peakType = NO_PEAK_FOUND;
93 
94  //No matter what, set the global minima and maxima peak info to NO_PEAK_FOUND
95  globalMaximaPeakInfo.peakType = NO_PEAK_FOUND;
96  globalMinimaPeakInfo.peakType = NO_PEAK_FOUND;
97 
98  //Reset the global maxima value if it has exceeded the search history size
99  if( ++maximaCounter >= searchHistorySize ){
100  maximaCounter = 0;
101  globalMaximaPeakInfo.peakValue = DEFAULT_GLOBAL_MAXIMA_VALUE;
102  }
103 
104  //Reset the global minima value if it has exceeded the search history size
105  if( ++minimaCounter >= searchHistorySize ){
106  minimaCounter = 0;
107  globalMinimaPeakInfo.peakValue = DEFAULT_GLOBAL_MINIMA_VALUE;
108  }
109 
110  if( enableSearch ){
111  for(unsigned int i=1; i<searchWindowSize-1; i++){
112  peakType = NO_PEAK_FOUND;
113  if( (secondDerivBuffer[i-1] <= 0 && secondDerivBuffer[i] > 0) || (secondDerivBuffer[i-1] <= 0 && secondDerivBuffer[i+1] > 0) ){
114 
115  peakDetected = true;
116  peakType = LOCAL_MAXIMA_FOUND;
117 
118  //Check for a global maxima
119  if( filteredDataBuffer[i] > globalMaximaPeakInfo.peakValue ){
120  maximaCounter = 0;
121  globalMaximaPeakInfo.peakType = GLOBAL_MAXIMA_FOUND;
122  globalMaximaPeakInfo.peakIndex = i;
123  globalMaximaPeakInfo.peakValue = filteredDataBuffer[i];
124  }
125 
126  peakInfo.push_back( PeakInfo(peakType,i,filteredDataBuffer[i]) );
127  break;
128  }
129 
130 
131  if( (secondDerivBuffer[i-1] >= 0 && secondDerivBuffer[i] < 0) || (secondDerivBuffer[i-1] >= 0 && secondDerivBuffer[i+1] < 0) ){
132 
133  peakDetected = true;
134  peakType = LOCAL_MINIMA_FOUND;
135 
136  if( filteredDataBuffer[i] < globalMinimaPeakInfo.peakValue ){
137  minimaCounter = 0;
138  globalMinimaPeakInfo.peakType = GLOBAL_MINIMA_FOUND;
139  globalMinimaPeakInfo.peakIndex = i;
140  globalMinimaPeakInfo.peakValue = filteredDataBuffer[i];
141  }
142 
143  peakInfo.push_back( PeakInfo(peakType,i,filteredDataBuffer[i]) );
144  break;
145  }
146  }
147  }
148 
149  peakTypesBuffer.push_back( peakType );
150 
151  return peakDetected ? true : false;
152 }
153 
154 bool PeakDetection::reset(){
155  //Reset the low pass filter
156  lowPassFilter.init(lowPassFilterSize,1);
157 
158  //Reset the deadzone filter
159  deadZoneFilter.init(-deadZoneThreshold,deadZoneThreshold,1);
160 
161  //Setup the data buffers
162  filteredDataBuffer.clear();
163  firstDerivBuffer.clear();
164  secondDerivBuffer.clear();
165  peakTypesBuffer.clear();
166 
167  filteredDataBuffer.resize( searchWindowSize, 0 );
168  firstDerivBuffer.resize( searchWindowSize, 0 );
169  secondDerivBuffer.resize( searchWindowSize, 0 );
170  peakTypesBuffer.resize( searchWindowSize, NO_PEAK_FOUND );
171 
172  //Enable future searches
173  peakDetected = false;
174  inputTimeoutCounter = 0;
175  maximaCounter = 0;
176  minimaCounter = 0;
177 
178  globalMaximaPeakInfo.peakType = NO_PEAK_FOUND;
179  globalMaximaPeakInfo.peakIndex = 0;
180  globalMaximaPeakInfo.peakValue = DEFAULT_GLOBAL_MAXIMA_VALUE;
181  globalMinimaPeakInfo.peakType = NO_PEAK_FOUND;
182  globalMinimaPeakInfo.peakIndex = 0;
183  globalMinimaPeakInfo.peakValue = DEFAULT_GLOBAL_MINIMA_VALUE;
184 
185  return true;
186 }
187 
188 bool PeakDetection::setSearchWindowSize(const UINT searchWindowSize){
189  this->searchWindowSize = searchWindowSize;
190  reset();
191  return true;
192 }
193 
194 GRT_END_NAMESPACE
bool push_back(const T &value)
Float filter(const Float x)
Definition: DeadZone.cpp:198
T getBack() const
bool init(UINT filterSize, UINT numDimensions)
bool init(Float lowerLimit, Float upperLimit, UINT numDimensions)
Definition: DeadZone.cpp:173
bool resize(const unsigned int newBufferSize)