OpenKalman
Unscented.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2017-2021 Christopher Lee Ogden <ogden@gatech.edu>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
9  */
10 
16 #ifndef OPENKALMAN_UNSCENTED_HPP
17 #define OPENKALMAN_UNSCENTED_HPP
18 
19 namespace OpenKalman
20 {
21  namespace oin = OpenKalman::internal;
22 
23 
24  template<typename Parameters>
25  struct Unscented;
26 
27 
30  {
32  static constexpr double alpha = 0.001;
34  static constexpr double beta = 2.0;
37  template<std::size_t dim>
38  static constexpr double kappa = 0.0;
39  };
40 
41 
44  {
46  static constexpr double alpha = 0.001;
48  static constexpr double beta = 2.0;
51  template<std::size_t dim>
52  static constexpr double kappa = 3. - double(dim);
53  };
54 
55 
57 
59 
62 
63 
71 #if __cpp_nontype_template_args >= 201911L
72  template<typename Parameters = UnscentedParametersStateEstimation> // \@todo add as floating-point parameters: alpha, beta, kappa
73 #else
74  template<typename Parameters = UnscentedParametersStateEstimation>
75 #endif
76  struct Unscented : oin::ScaledSigmaPointsBase<Unscented<Parameters>>
77  {
78 
84  template<std::size_t dim>
85  static constexpr std::size_t sigma_point_count = dim * 2 + 1;
86 
87 
92  static constexpr auto alpha = Parameters::alpha;
93 
94 
99  static constexpr auto beta = Parameters::beta;
100 
101 
107  template<std::size_t dim>
108  static constexpr auto unscaled_W0()
109  {
110  return Parameters::template kappa<dim> / (dim + Parameters::template kappa<dim>);
111  }
112 
113 
119  template<std::size_t dim>
120  static constexpr auto unscaled_W()
121  {
122  return 0.5 / (dim + Parameters::template kappa<dim>);
123  }
124 
125  private:
126 
128  Unscented() {};
129 
130 
131  /*
132  * Scale and translate normalized sample points based on mean and (square root) covariance.
133  * This algorithm decreases the complexity from O(n^3) to O(n^2).
134  * This steps recursively through a tuple of input and noise distributions.
135  */
136  template<
137  std::size_t dim, //< The total number of dimensions for which sigma points are assigned.
138  std::size_t pos = 0, //< The writing position during this recursive step.
139  typename D, //< First input or noise distribution.
140  typename...Ds> //< Other input or noise distributions.
141  static auto
142  sigma_points_impl(const D& d, const Ds&...ds)
143  {
144  using Scalar = typename DistributionTraits<D>::Scalar;
145  using Coeffs = typename DistributionTraits<D>::StaticDescriptor;
146  using M = typename DistributionTraits<D>::Mean;
147  constexpr auto points_count = sigma_point_count<dim>;
148  constexpr auto dim_i = index_dimension_of_v<D, 0>;
149  constexpr auto frame_size = dim_i * 2;
150  constexpr Scalar gamma_L = alpha * alpha * (Parameters::template kappa<dim> + dim);
151  const auto delta = make_vector_space_adapter(to_dense_object(square_root(gamma_L * covariance_of(d))), Coeffs{}, Dimensions<dim_i>{});
152 
153  if constexpr(1 + frame_size == points_count)
154  {
155  // | 0 | delta | -delta |
156  static_assert(sizeof...(ds) == 0);
158  const auto m0 = make_zero<M0>(Dimensions<dim_i>{}, Dimensions<1>{});
159  auto ret {make_self_contained(concatenate_horizontal(std::move(m0), delta, -delta))};
160  static_assert(index_dimension_of_v<decltype(ret), 1> == points_count);
161  return std::tuple {std::move(ret)};
162  }
163  else if constexpr (pos == 0)
164  {
165  // | 0 | delta | -delta | 0 ... |
167  const auto m0 = make_zero<M0>(Dimensions<dim_i>{}, Dimensions<1>{});
168  constexpr auto width = points_count - (1 + frame_size);
170  const auto mright = make_zero<Mright>(Dimensions<dim_i>{}, Dimensions<width>{});
171  auto ret {make_self_contained(concatenate_horizontal(std::move(m0), delta, -delta, std::move(mright)))};
172  static_assert(index_dimension_of_v<decltype(ret), 1> == points_count);
173  return std::tuple_cat(std::tuple {std::move(ret)}, sigma_points_impl<dim, 1 + frame_size>(ds...));
174  }
175  else if constexpr (pos + frame_size < points_count)
176  {
177  // | 0 | 0 ... | delta | -delta | 0 ... |
179  const auto mleft = make_zero<Mleft>(Dimensions<dim_i>{}, Dimensions<pos>{});
180  constexpr auto width = points_count - (pos + frame_size);
182  const auto mright = make_zero<Mright>(Dimensions<dim_i>{}, Dimensions<width>{});
183  auto ret {make_self_contained(concatenate_horizontal(std::move(mleft), delta, -delta, std::move(mright)))};
184  static_assert(index_dimension_of_v<decltype(ret), 1> == points_count);
185  return std::tuple_cat(std::tuple {std::move(ret)}, sigma_points_impl<dim, pos + frame_size>(ds...));
186  }
187  else
188  {
189  // | 0 | 0 ... | delta | -delta |
190  static_assert(sizeof...(ds) == 0);
192  const auto mleft = make_zero<Mleft>(Dimensions<dim_i>{}, Dimensions<pos>{});
193  auto ret {make_self_contained(concatenate_horizontal(std::move(mleft), delta, -delta))};
194  static_assert(index_dimension_of_v<decltype(ret), 1> == points_count);
195  return std::tuple {std::move(ret)};
196  }
197  }
198 
199  public:
200 
208 #ifdef __cpp_concepts
209  template<gaussian_distribution ... Dist> requires (sizeof...(Dist) > 0)
210 #else
211  template<typename...Dist, std::enable_if_t<
212  (gaussian_distribution<Dist> and ...) and (sizeof...(Dist) > 0), int> = 0>
213 #endif
214  static auto
215  sample_points(const Dist& ...ds)
216  {
217  constexpr auto dim = (index_dimension_of_v<Dist, 0> + ...);
218  return sigma_points_impl<dim>(ds...);
219  }
220  };
221 
222 
223 }
224 
225 #endif //OPENKALMAN_UNSCENTED_HPP
Definition: ScaledSigmaPointsBase.hpp:37
static constexpr double alpha
Scaling factor (typically 0.001 but may be from 0.0001 to 1).
Definition: Unscented.hpp:32
auto make_vector_space_adapter(Arg &&arg, Descriptors &&descriptors)
If necessary, wrap an object in a wrapper that adds vector space descriptors for each index...
Definition: make_vector_space_adapter.hpp:37
static constexpr double kappa
Secondary scaling parameter.
Definition: Unscented.hpp:38
Unscented parameters for use in parameter estimation.
Definition: Unscented.hpp:43
decltype(auto) constexpr concatenate_horizontal(V &&v, Vs &&... vs)
Concatenate one or more matrix objects vertically.
Definition: typed-matrix-overloads.hpp:308
decltype(auto) constexpr to_dense_object(Arg &&arg)
Convert the argument to a dense, writable matrix of a particular scalar type.
Definition: to_dense_object.hpp:37
Unscented parameters for use in state estimation (the default).
Definition: Unscented.hpp:29
The root namespace for OpenKalman.
Definition: basics.hpp:34
Scaled symmetric sigma points.
Definition: Unscented.hpp:25
static auto sample_points(const Dist &...ds)
Calculate the scaled and translated sigma points, given a prior distribution and noise terms...
Definition: Unscented.hpp:215
std::decay_t< decltype(make_dense_object< T, layout, S >(std::declval< D >()))> dense_writable_matrix_t
An alias for a dense, writable matrix, patterned on parameter T.
Definition: dense_writable_matrix_t.hpp:38
constexpr bool gaussian_distribution
T is a Gaussian distribution.
Definition: object-types.hpp:182
static constexpr auto unscaled_W()
The unscaled W parameter.
Definition: Unscented.hpp:120
Mean(V &&) -> Mean< Dimensions< index_dimension_of_v< V, 0 >>, passable_t< V >>
Deduce template parameters from a typed_matrix_nestable, assuming untyped coordinates::pattern.
static constexpr double beta
Factor to compensate for the distribution (beta==2 is optimal for Gaussian distributions).
Definition: Unscented.hpp:34
static constexpr auto unscaled_W0()
The unscaled W0 parameter.
Definition: Unscented.hpp:108
Definition: basics.hpp:48