OSVR-Core
EigenFilters.h
Go to the documentation of this file.
1 
11 // Copyright 2015 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 #ifndef INCLUDED_EigenFilters_h_GUID_ECD959BF_587B_4ABB_30B3_E881B4520AC8
26 #define INCLUDED_EigenFilters_h_GUID_ECD959BF_587B_4ABB_30B3_E881B4520AC8
27 
28 // Internal Includes
30 #include <osvr/Util/EigenExtras.h>
32 
33 // Library/third-party includes
34 // - none
35 
36 // Standard includes
37 #include <cmath>
38 
39 namespace osvr {
40 namespace util {
41 
43  namespace filters {
45  namespace low_pass {
46  template <typename Derived>
47  inline Derived computeStep(Eigen::MatrixBase<Derived> const &hatx,
49  typename Derived::Scalar alpha) {
50  Derived ret = alpha * x + (1 - alpha) * hatx;
51  return ret;
52  }
53 
54  template <typename Derived>
55  inline Derived
56  computeStep(Eigen::QuaternionBase<Derived> const &hatx,
58  typename Derived::Scalar alpha) {
59  Derived ret = hatx.slerp(alpha, x).normalized();
60  return ret;
61  }
62 
68  template <typename T> class LowPassFilter {
69  public:
70  using value_type = T;
71  using scalar = typename T::Scalar;
72  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
73 
76  value_type const &filter(value_type const &x, scalar alpha) {
77  if (m_firstTime) {
78  m_firstTime = false;
79  m_hatx = x;
80  return m_hatx;
81  }
82  if (std::isfinite(alpha)) {
83  m_hatx = computeStep(hatx(), x, alpha);
84  }
85  return m_hatx;
86  }
87 
88  value_type const &hatx() const { return m_hatx; }
89 
90  private:
91  value_type m_hatx;
92  bool m_firstTime = true;
93  };
94 
95  } // namespace low_pass
96 
99  namespace one_euro {
100 
101  namespace detail {
104  template <typename T> inline T computeAlpha(T dt, T cutoff) {
105  auto tau = T(1) / (T(2) * M_PI * cutoff);
106  return T(1) / (T(1) + tau / dt);
107  }
108 
109  } // namespace detail
110 
121  struct Params {
122  Params() : minCutoff(1), beta(0), derivativeCutoff(1) {}
123  Params(double minCut, double b = 0.5, double dCut = 1)
124  : minCutoff(minCut), beta(b), derivativeCutoff(dCut) {}
125 
127  double minCutoff;
129  double beta;
134  };
135 
138  template <typename T> struct DerivativeTraits {
139  using DerivativeType = T;
140  static void setIdentity(DerivativeType &dx) {
141  dx = DerivativeType::Zero();
142  }
143  static DerivativeType compute(T const &prev, T const &curr,
144  double dt) {
145  return (curr - prev) / dt;
146  }
147  static double computeMagnitude(DerivativeType const &dx) {
148  return dx.norm();
149  }
150  };
151 
154  template <> struct DerivativeTraits<Eigen::Quaterniond> {
155  using DerivativeType = Eigen::Vector3d;
156  static void setIdentity(DerivativeType &dx) {
157  dx = DerivativeType::Zero();
158  }
159  static DerivativeType compute(Eigen::Quaterniond const &prev,
160  Eigen::Quaterniond const &curr,
161  double dt) {
162  return util::quat_ln(curr * prev.conjugate()) / dt;
163  }
164  static double computeMagnitude(DerivativeType const &dx) {
165  return dx.norm();
166  }
167  };
168 
170 
180  template <typename T> class OneEuroFilter {
181  public:
182  using value_type = T;
183  using scalar = typename T::Scalar;
184  using deriv = DerivativeTraits<T>;
185  using deriv_type = typename deriv::DerivativeType;
186  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
187 
188  explicit OneEuroFilter(Params const &p) : m_params(p) {}
189 
190  value_type const &filter(scalar dt, value_type const &x) {
191  auto dx = deriv_type{};
192  if (m_firstTime) {
193  m_firstTime = false;
194  deriv::setIdentity(dx);
195  } else {
196  dx = deriv::compute(m_xFilter.hatx(), x, dt);
197  }
198  // Low-pass-filter the derivative.
199  m_dxFilter.filter(dx, detail::computeAlpha<scalar>(
200  dt, m_params.derivativeCutoff));
201  // Get the magnitude of the (filtered) derivative
202  auto dxMag = deriv::computeMagnitude(m_dxFilter.hatx());
203  // Compute the cutoff to use for the x filter
204  auto cutoff = m_params.minCutoff + m_params.beta * dxMag;
205 
206  // Filter the x and return the results.
207  return m_xFilter.filter(
208  x, detail::computeAlpha<scalar>(dt, cutoff));
209  }
210 
211  value_type const &getState() const { return m_xFilter.hatx(); }
212  scalar getDerivativeMagnitude() const {
213  return deriv::computeMagnitude(m_dxFilter.hatx());
214  }
215 
216  private:
217  bool m_firstTime = true;
218  const Params m_params;
219  low_pass::LowPassFilter<T> m_xFilter;
221  };
222 
226  template <typename Scalar> class PoseOneEuroFilter {
227  public:
228  using scalar = Scalar;
232  using Isometry = Isometry3<scalar>;
233 
234  PoseOneEuroFilter(Params const &positionFilterParams = Params{},
235  Params const &oriFilterParams = Params{})
236  : m_positionFilter(positionFilterParams),
237  m_orientationFilter(oriFilterParams){};
238 
239  void filter(scalar dt, Vec3 const &position,
240  Quat const &orientation) {
241  if (dt <= scalar(0)) {
243  dt = scalar(1);
244  }
245  m_positionFilter.filter(dt, position);
246  m_orientationFilter.filter(dt, orientation);
247  }
248 
249  Vec3 const &getPosition() const {
250  return m_positionFilter.getState();
251  }
252 
253  scalar getLinearVelocityMagnitude() const {
254  return m_positionFilter.getDerivativeMagnitude();
255  }
256 
257  Quat const &getOrientation() const {
258  return m_orientationFilter.getState();
259  }
260 
261  scalar getAngularVelocityMagnitude() const {
262  return m_orientationFilter.getDerivativeMagnitude();
263  }
264 
265  Isometry getIsometry() const {
266  return makeIsometry(getPosition(), getOrientation());
267  }
268 
269  private:
270  OneEuroFilter<Vec3> m_positionFilter;
271  OneEuroFilter<Quat> m_orientationFilter;
272  };
273 
274  } // namespace one_euro
275 
278 
280  } // namespace filters
281 
282 } // namespace util
283 } // namespace osvr
284 #endif // INCLUDED_EigenFilters_h_GUID_ECD959BF_587B_4ABB_30B3_E881B4520AC8
Definition: RunLoopManager.h:42
Low pass filter (designed for use within the One Euro filter) that works with Eigen types...
Definition: EigenFilters.h:68
Parameters needed for the one-euro filter.
Definition: EigenFilters.h:121
The main namespace for all C++ elements of the framework, internal and external.
Definition: namespace_osvr.dox:3
iterative scaling algorithm to equilibrate rows and column norms in matrices
Definition: TestIMU_Common.h:87
double minCutoff
Minimum cutoff frequency (in Hz) at "0" speed.
Definition: EigenFilters.h:127
Header wrapping include of <Eigen/Core> and <Eigen/Geometry> for warning quieting.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW value_type const & filter(value_type const &x, scalar alpha)
Feeds in new data with the specified alpha.
Definition: EigenFilters.h:76
Definition: ForwardDeclarations.h:236
double derivativeCutoff
Cutoff frequency used for the low-pass filter applied to the derivative, in Hz.
Definition: EigenFilters.h:133
Default derivative traits: assumes derivative is same datatype as main data, identity is zeros...
Definition: EigenFilters.h:138
Definition: newuoa.h:1888
Filters for use with Eigen datatypes.
Definition: EigenFilters.h:43
double beta
Slope of cutoff frequency with respect to speed.
Definition: EigenFilters.h:129
Quaternion conjugate(void) const
Definition: Quaternion.h:395
Definition: ForwardDeclarations.h:233
Definition: Quaternion.h:47
Isometry3< typename Derived1::Scalar > makeIsometry(Eigen::MatrixBase< Derived1 > const &translation, Eigen::RotationBase< Derived2, 3 > const &rotation)
A simpler, functional-style alternative to .fromPositionOrientationScale when no scaling is performed...
Definition: EigenExtras.h:93
T computeAlpha(T dt, T cutoff)
Computing the alpha value for a step in the one euro filter for any scalar type.
Definition: EigenFilters.h:104
void filter(scalar dt, Vec3 const &position, Quat const &orientation)
Definition: EigenFilters.h:239
Combines a one-euro filter for position and a one-euro filter for orientation for the common use case...
Definition: EigenFilters.h:226
Quaternion< double > Quaterniond
double precision quaternion type
Definition: Quaternion.h:211
A simple filter designed for human input sources: high accuracy at low velocity, low latency at high ...
Definition: EigenFilters.h:180
The matrix class, also used for vectors and row-vectors.
Definition: Matrix.h:127
Base class for all dense matrices, vectors, and expressions.
Definition: MatrixBase.h:48
Definition: Transform.h:43
double Scalar
Common scalar type.
Definition: FlexibleKalmanBase.h:48