5#include <Eigen/Cholesky>
6#include <boost/numeric/odeint.hpp>
7#include <smooth/compat/odeint.hpp>
8#include <smooth/concepts/lie_group.hpp>
9#include <smooth/diff.hpp>
11namespace smooth::feedback {
29 diff::Type DiffType = diff::Type::Default,
30 template<
typename...>
typename Stpr = boost::numeric::odeint::euler>
37 using CovT = Eigen::Matrix<Scalar<G>, Dof<G>, Dof<G>>;
79 template<
typename F,
typename QDer>
80 void predict(F && f,
const Eigen::MatrixBase<QDer> & Q, Scalar<G> tau, std::optional<Scalar<G>> dt = {})
82 const auto state_ode = [&f](
const G & g, Tangent<G> & dg, Scalar<G> t) { dg = f(t, g); };
84 const auto cov_ode = [
this, &f, &Q](
const CovT & cov, CovT & dcov, Scalar<G> t) {
85 const auto f_x = [&f, &t]<
typename _T>(
const CastT<_T, G> & x) -> Tangent<CastT<_T, G>> {
return f(t, x); };
86 const auto [fv, dr] = diff::dr<1, DiffType>(f_x, wrt(g_hat_));
87 const CovT A = -ad<G>(fv) + dr;
88 dcov = (A * cov + cov * A.transpose() + Q).
template selfadjointView<Eigen::Upper>();
92 const Scalar<G> dt_v = dt.value_or(2 * tau);
93 while (t + dt_v < tau) {
95 cst_.do_step(cov_ode, P_, t, dt_v);
96 sst_.do_step(state_ode, g_hat_, t, dt_v);
101 cst_.do_step(cov_ode, P_, t, tau - t);
102 sst_.do_step(state_ode, g_hat_, t, tau - t);
116 template<
typename F,
typename RDev, Manifold Y = std::invoke_result_t<F, G>>
117 void update(F && h,
const Y & y,
const Eigen::MatrixBase<RDev> & R)
119 const auto [hval, H] = diff::dr<1, DiffType>(h, wrt(g_hat_));
121 using Result = std::decay_t<
decltype(hval)>;
123 static_assert(Manifold<Result>,
"h(x) is not a Manifold");
125 static constexpr Eigen::Index Ny = Dof<Result>;
127 static_assert(Ny > 0,
"h(x) must be statically sized");
129 const Eigen::Matrix<Scalar<G>, Ny, Ny> S =
130 (H * P_.template selfadjointView<Eigen::Upper>() * H.transpose() + R).
template triangularView<Eigen::Upper>();
133 const Eigen::Matrix<Scalar<G>, Dof<G>, Ny> K =
134 S.template selfadjointView<Eigen::Upper>().ldlt().solve(H * P_).transpose();
137 g_hat_ += K * (y - hval);
138 P_ = ((CovT::Identity() - K * H) * P_).template selfadjointView<Eigen::Upper>();
143 G g_hat_ = Default<G>();
144 CovT P_ = CovT::Identity();
147 Stpr<G, Scalar<G>, Tangent<G>, Scalar<G>, boost::numeric::odeint::vector_space_algebra> sst_{};
148 Stpr<CovT, Scalar<G>, CovT, Scalar<G>, boost::numeric::odeint::vector_space_algebra> cst_{};
Extended Kalman filter on Lie groups.
Eigen::Matrix< Scalar< G >, Dof< G >, Dof< G > > CovT
void predict(F &&f, const Eigen::MatrixBase< QDer > &Q, Scalar< G > tau, std::optional< Scalar< G > > dt={})
Propagate EKF through dynamics with covariance over a time interval .
void reset(const G &g, const CovT &P)
Reset the state of the EKF.
void update(F &&h, const Y &y, const Eigen::MatrixBase< RDev > &R)
Update EKF with a measurement where .
G estimate() const
Access filter state estimate.
CovT covariance() const
Access filter covariance.