Bike-X  0.8
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
OVR_SensorFilter.h
Go to the documentation of this file.
1 /************************************************************************************
2 
3 PublicHeader: OVR.h
4 Filename : OVR_SensorFilter.h
5 Content : Basic filtering of sensor data
6 Created : March 7, 2013
7 Authors : Steve LaValle, Anna Yershova, Max Katsev
8 
9 Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
10 
11 Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
12 you may not use the Oculus VR Rift SDK except in compliance with the License,
13 which is provided at the time of installation or download, or which
14 otherwise accompanies this software in either electronic or hard copy form.
15 
16 You may obtain a copy of the License at
17 
18 http://www.oculusvr.com/licenses/LICENSE-3.1
19 
20 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
21 distributed under the License is distributed on an "AS IS" BASIS,
22 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 See the License for the specific language governing permissions and
24 limitations under the License.
25 
26 *************************************************************************************/
27 
28 #ifndef OVR_SensorFilter_h
29 #define OVR_SensorFilter_h
30 
31 #include "Kernel/OVR_Math.h"
32 #include "Kernel/OVR_Deque.h"
33 #include "Kernel/OVR_Alg.h"
34 
35 namespace OVR {
36 
37 // A base class for filters that maintains a buffer of sensor data taken over time and implements
38 // various simple filters, most of which are linear functions of the data history.
39 // Maintains the running sum of its elements for better performance on large capacity values
40 template <typename T>
42 {
43 protected:
44  T RunningTotal; // Cached sum of the elements
45 
46 public:
48  : CircularBuffer<T>(capacity), RunningTotal()
49  {
50  this->Clear();
51  };
52 
53  // The following methods are augmented to update the cached running sum value
54  void PushBack(const T &e)
55  {
57  RunningTotal += e;
58  if (this->End == 0)
59  {
60  // update the cached total to avoid error accumulation
61  RunningTotal = T();
62  for (int i = 0; i < this->ElemCount; i++)
63  RunningTotal += this->Data[i];
64  }
65  }
66 
67  void PushFront(const T &e)
68  {
70  RunningTotal += e;
71  if (this->Beginning == 0)
72  {
73  // update the cached total to avoid error accumulation
74  RunningTotal = T();
75  for (int i = 0; i < this->ElemCount; i++)
76  RunningTotal += this->Data[i];
77  }
78  }
79 
80  T PopBack()
81  {
83  RunningTotal -= e;
84  return e;
85  }
86 
87  T PopFront()
88  {
90  RunningTotal -= e;
91  return e;
92  }
93 
94  void Clear()
95  {
97  RunningTotal = T();
98  }
99 
100  // Simple statistics
101  T Total() const
102  {
103  return RunningTotal;
104  }
105 
106  T Mean() const
107  {
108  return this->IsEmpty() ? T() : (Total() / (float) this->ElemCount);
109  }
110 
111  T MeanN(int n) const
112  {
113  OVR_ASSERT(n > 0);
114  OVR_ASSERT(this->Capacity >= n);
115  T total = T();
116  for (int i = 0; i < n; i++)
117  {
118  total += this->PeekBack(i);
119  }
120  return total / n;
121  }
122 
123  // A popular family of smoothing filters and smoothed derivatives
124 
126  {
127  OVR_ASSERT(this->Capacity >= 4);
128  return this->PeekBack(0)*0.7f +
129  this->PeekBack(1)*0.4f +
130  this->PeekBack(2)*0.1f -
131  this->PeekBack(3)*0.2f;
132  }
133 
135  {
136  OVR_ASSERT(this->Capacity >= 8);
137  return this->PeekBack(0)*0.41667f +
138  this->PeekBack(1)*0.33333f +
139  this->PeekBack(2)*0.25f +
140  this->PeekBack(3)*0.16667f +
141  this->PeekBack(4)*0.08333f -
142  this->PeekBack(6)*0.08333f -
143  this->PeekBack(7)*0.16667f;
144  }
145 
147  {
148  OVR_ASSERT(this->Capacity >= 4);
149  return this->PeekBack(0)*0.3f +
150  this->PeekBack(1)*0.1f -
151  this->PeekBack(2)*0.1f -
152  this->PeekBack(3)*0.3f;
153  }
154 
156  {
157  OVR_ASSERT(this->Capacity >= 5);
158  return this->PeekBack(0)*0.2f +
159  this->PeekBack(1)*0.1f -
160  this->PeekBack(3)*0.1f -
161  this->PeekBack(4)*0.2f;
162  }
163 
165  {
166  OVR_ASSERT(this->Capacity >= 12);
167  return this->PeekBack(0)*0.03846f +
168  this->PeekBack(1)*0.03147f +
169  this->PeekBack(2)*0.02448f +
170  this->PeekBack(3)*0.01748f +
171  this->PeekBack(4)*0.01049f +
172  this->PeekBack(5)*0.0035f -
173  this->PeekBack(6)*0.0035f -
174  this->PeekBack(7)*0.01049f -
175  this->PeekBack(8)*0.01748f -
176  this->PeekBack(9)*0.02448f -
177  this->PeekBack(10)*0.03147f -
178  this->PeekBack(11)*0.03846f;
179  }
180 
182  {
183  OVR_ASSERT(this->capacity >= n);
184  int m = (n-1)/2;
185  T result = T();
186  for (int k = 1; k <= m; k++)
187  {
188  int ind1 = m - k;
189  int ind2 = n - m + k - 1;
190  result += (this->PeekBack(ind1) - this->PeekBack(ind2)) * (float) k;
191  }
192  float coef = 3.0f/(m*(m+1.0f)*(2.0f*m+1.0f));
193  result = result*coef;
194  return result;
195  }
196 
197  T Median() const
198  {
199  T* copy = (T*) OVR_ALLOC(this->ElemCount * sizeof(T));
200  T result = Alg::Median(ArrayAdaptor(copy));
201  OVR_FREE(copy);
202  return result;
203  }
204 };
205 
206 // This class maintains a buffer of sensor data taken over time and implements
207 // various simple filters, most of which are linear functions of the data history.
208 template <typename T>
209 class SensorFilter : public SensorFilterBase<Vector3<T> >
210 {
211 public:
213 
214  // Simple statistics
215  Vector3<T> Median() const;
216  Vector3<T> Variance() const; // The diagonal of covariance matrix
217  Matrix3<T> Covariance() const;
219 };
220 
223 
224 // This filter operates on the values that are measured in the body frame and rotate with the device
225 class SensorFilterBodyFrame : public SensorFilterBase<Vector3d>
226 {
227 private:
228  // low pass filter gain
229  double gain;
230  // sum of squared norms of the values
232  // cumulative rotation quaternion
234  // current low pass filter output
236 
237  // make private so it isn't used by accident
238  // in addition to the normal SensorFilterBase::PushBack, keeps track of running sum of LengthSq
239  // for the purpose of variance computations
240  void PushBack(const Vector3d &e)
241  {
242  runningTotalLengthSq += this->IsFull() ? (e.LengthSq() - this->PeekFront().LengthSq()) : e.LengthSq();
244  if (this->End == 0)
245  {
246  // update the cached total to avoid error accumulation
248  for (int i = 0; i < this->ElemCount; i++)
249  runningTotalLengthSq += this->Data[i].LengthSq();
250  }
251  }
252 
253 public:
255  : SensorFilterBase<Vector3d>(capacity), gain(2.5),
256  runningTotalLengthSq(0), Q(), output() { };
257 
258  // return the scalar variance of the filter values (rotated to be in the same frame)
259  double Variance() const
260  {
261  return this->IsEmpty() ? 0 : (runningTotalLengthSq / this->ElemCount - this->Mean().LengthSq());
262  }
263 
264  // return the scalar standard deviation of the filter values (rotated to be in the same frame)
265  double StdDev() const
266  {
267  return sqrt(Variance());
268  }
269 
270  // confidence value based on the stddev of the data (between 0.0 and 1.0, more is better)
271  double Confidence() const
272  {
273  return Alg::Clamp(0.48 - 0.1 * log(StdDev()), 0.0, 1.0) * this->ElemCount / this->Capacity;
274  }
275 
276  // add a new element to the filter
277  // takes rotation increment since the last update
278  // in order to rotate the previous value to the current body frame
279  void Update(Vector3d value, double deltaT, Quatd deltaQ = Quatd())
280  {
281  if (this->IsEmpty())
282  {
283  output = value;
284  }
285  else
286  {
287  // rotate by deltaQ
288  output = deltaQ.Inverted().Rotate(output);
289  // apply low-pass filter
290  output += (value - output) * gain * deltaT;
291  }
292 
293  // put the value into the fixed frame for the stddev computation
294  Q = Q * deltaQ;
296  }
297 
298  // returns the filter average in the current body frame
300  {
301  return Q.Inverted().Rotate(this->Mean());
302  }
303 };
304 
305 } //namespace OVR
306 
307 #endif // OVR_SensorFilter_h
const int Capacity
Definition: OVR_Deque.h:59
Vector3d GetFilteredValue() const
Quat Inverted() const
Definition: OVR_Math.h:957
void PushFront(const T &e)
virtual bool IsFull() const
Definition: OVR_Deque.h:271
int ElemCount
Definition: OVR_Deque.h:65
int Beginning
Definition: OVR_Deque.h:60
void PushBack(const Vector3d &e)
virtual Elem PopBack(void)
Definition: OVR_Deque.h:183
Vector3< T > Rotate(const Vector3< T > &v) const
Definition: OVR_Math.h:951
void Update(Vector3d value, double deltaT, Quatd deltaQ=Quatd())
virtual void PushBack(const Elem &Item)
Definition: OVR_Deque.h:279
Vector3< T > Median() const
Quat< double > Quatd
Definition: OVR_Math.h:1086
T SavitzkyGolayDerivative12() const
SensorFilter(int capacity=SensorFilterBase< Vector3< T > >::DefaultCapacity)
#define OVR_ASSERT(p)
Matrix3< T > Covariance() const
OVR_FORCE_INLINE const T Clamp(const T v, const T minVal, const T maxVal)
Definition: OVR_Alg.h:52
SensorFilter< double > SensorFilterd
Elem * Data
Definition: OVR_Deque.h:58
Vector3< T > PearsonCoefficient() const
virtual Elem & PeekFront(int count=0)
Definition: OVR_Deque.h:229
T SavitzkyGolayDerivative5() const
Vector3< T > Variance() const
virtual Elem PopFront(void)
Definition: OVR_Deque.h:163
SensorFilterBodyFrame(int capacity=SensorFilterBase< Vector3d >::DefaultCapacity)
Array::ValueType & Median(Array &arr)
Definition: OVR_Alg.h:443
T SavitzkyGolayDerivative4() const
T LengthSq() const
Definition: OVR_Math.h:506
virtual void Clear(void)
Definition: OVR_Deque.h:119
virtual Elem & PeekBack(int count=0)
Definition: OVR_Deque.h:241
SensorFilter< float > SensorFilterf
#define OVR_ALLOC(s)
void PushBack(const T &e)
SensorFilterBase(int capacity=CircularBuffer< T >::DefaultCapacity)
#define OVR_FREE(p)
virtual void PushFront(const Elem &Item)
Definition: OVR_Deque.h:287
T SavitzkyGolayDerivativeN(int n) const