20#include <Eigen/Cholesky>
41template <
typename Space,
typename OutputSpace,
typename Scalar =
double>
131[[nodiscard]]
constexpr Joseph
144 std::is_same_v<T, updates::Standard> || std::is_same_v<T, updates::Symmetric> || std::is_same_v<T, updates::Joseph>;
155template <
typename InputSpace,
typename OutputSpace,
typename Scalar =
double>
189template <
typename Jacobian,
typename Noise>
200template <
typename Root,
typename Whitened,
typename Noise>
201struct JosephRootTerms
211template <
typename Matrix,
typename Gain,
typename Cross,
typename OutputCov,
typename Linearize>
222 return Matrix{cov - multiply(gain, cross.transpose())};
229template <
typename Matrix,
typename Gain,
typename Cross,
typename OutputCov,
typename Linearize>
236 OutputCov
const & outputCov,
240 using Scalar =
typename Matrix::Scalar;
241 OutputCov
const symmetric = outputCov.template selfadjointView<Eigen::Lower>();
242 Matrix result = cov - multiply(multiply(gain, symmetric), gain.transpose());
243 return Matrix{Scalar(0.5) * (result + result.transpose())};
253template <
typename Matrix,
typename Gain,
typename Cross,
typename OutputCov,
typename Linearize>
261 Linearize
const & linearize
264 using Scalar =
typename Matrix::Scalar;
265 auto const terms = linearize();
266 Matrix result = multiply(multiply(gain, terms.noise), gain.transpose());
267 if constexpr (
requires { terms.root; })
269 Matrix
const factor = terms.root - multiply(gain, terms.whitened.transpose());
270 result.noalias() += multiply(factor, factor.transpose());
274 Matrix
const factor = Matrix::Identity(cov.rows(), cov.cols()) - multiply(gain, terms.jacobian);
275 result.noalias() += multiply(multiply(factor, cov), factor.transpose());
277 return Matrix{Scalar(0.5) * (result + result.transpose())};
284template <std::
size_t K>
285using ConsideredRows = std::array<BlockRows, K>;
288using NoConsidered = ConsideredRows<0>;
293template <
typename Gain, std::
size_t K>
295zeroConsideredRows(Gain & gain, ConsideredRows<K>
const & considered)
297 for (BlockRows
const rows : considered)
299 gain.middleRows(rows.start, rows.size).setZero();
306template <
typename Matrix, std::
size_t K>
308keepConsideredCovariance(Matrix & cov, Matrix
const & prior, ConsideredRows<K>
const & considered)
310 for (BlockRows
const a : considered)
312 for (BlockRows
const b : considered)
314 cov.block(a.start, b.start, a.size, b.size) = prior.block(a.start, b.start, a.size, b.size);
320template <
typename Space,
typename Scalar>
321struct KalmanConditioned
323 GaussianParams<Space, Scalar> posterior;
324 std::optional<InnovationStatistics<Scalar>> statistics;
330template <
typename Scalar>
331struct ConditionedInPlace
333 std::optional<InnovationStatistics<Scalar>> statistics;
334 bool accepted =
true;
375 typename OutputMatrix,
380 typename Accept = AcceptEvery>
381[[nodiscard]] std::expected<ConditionedInPlace<Scalar>,
GaussianError>
382kalmanConditionInPlace(
383 GaussianParams<Space, Scalar> & state,
384 Eigen::MatrixBase<Residual>
const & residual,
385 OutputMatrix & outputCov,
388 Linearize
const & linearize,
389 [[maybe_unused]] ConsideredRows<K>
const & considered,
390 Accept
const & accept = {}
394 [[maybe_unused]] Eigen::Index
const nd = state.differenceDimension();
395 [[maybe_unused]] Eigen::Index
const md = outputCov.rows();
396 EMRYS_FILTER_ASSERT(cross.rows() == nd && cross.cols() == md &&
"the prediction was not made from this prior");
397 EMRYS_FILTER_ASSERT(
residual.size() == md);
399 auto const factored = innovationCholesky<Repair>(outputCov);
402 return std::unexpected{factored.error()};
404 auto const & llt = *factored;
405 auto result = ConditionedInPlace<Scalar>{};
406 if constexpr (Statistics || acceptsByNis<Accept>)
408 result.statistics = innovationStatistics(llt, residual);
410 if constexpr (acceptsByNis<Accept>)
412 if (!accept(result.statistics->nis, md))
414 result.accepted =
false;
422 auto gain = transposedSolve<typename Cross::PlainObject>(llt, cross.transpose());
423 auto & moments = GaussianAccess::moments(state);
424 Matrix & cov = moments.covarianceLower();
427 auto const symmetric = symmetricFromLower<Matrix>(cov);
428 if constexpr (std::is_same_v<Form, updates::Joseph>)
430 zeroConsideredRows(gain, considered);
431 cov = posteriorCov(form, symmetric, gain, cross, outputCov, linearize);
435 cov = posteriorCov(form, symmetric, gain, cross, outputCov, linearize);
436 zeroConsideredRows(gain, considered);
438 keepConsideredCovariance(cov, symmetric, considered);
440 else if constexpr (std::is_same_v<Form, updates::Standard>)
442 cov.template triangularView<Eigen::StrictlyUpper>() = cov.transpose();
443 cov.noalias() -= multiply(gain, cross.transpose());
447 auto const symmetric = symmetricFromLower<Matrix>(cov);
448 cov = posteriorCov(form, symmetric, gain, cross, outputCov, linearize);
452 moments.mean() =
Emrys::plus(state.space(), moments.mean(), multiply(gain, residual));
458 Vector
const start = moments.mean();
459 auto step = Difference{};
461 step.noalias() = multiply(gain, residual);
462 moments.mean() =
Emrys::plus(state.space(), start, step);
463 resetCovarianceAt(state.space(), start, step, moments.mean(), cov);
483 typename OutputMatrix,
488[[nodiscard]] std::expected<KalmanConditioned<typename Prior::SpaceType, typename Prior::Scalar>,
GaussianError>
491 Eigen::MatrixBase<Residual>
const & residual,
492 OutputMatrix & outputCov,
495 Linearize
const & linearize,
496 ConsideredRows<K>
const & considered
499 using Posterior = GaussianParams<typename Prior::SpaceType, typename Prior::Scalar>;
500 auto result = KalmanConditioned<typename Prior::SpaceType, typename Prior::Scalar>{
503 typename Posterior::VectorType{prior.mean()},
504 typename Posterior::MatrixType{covarianceLowerOf(prior)}
508 auto conditioned = kalmanConditionInPlace<Statistics, Repair>(
519 return std::unexpected{conditioned.error()};
521 result.statistics = conditioned->statistics;
530 typename OutputSpace,
531 typename LinearizationForm,
535[[nodiscard]] std::expected<Conditioned<typename Prior::SpaceType, OutputSpace, typename Prior::Scalar>,
GaussianError>
538 OutputWithCross<typename Prior::SpaceType, OutputSpace, LinearizationForm, typename Prior::Scalar>
const &
540 Eigen::MatrixBase<Derived>
const & observed,
542 Linearize
const & linearize
545 using Output = GaussianParams<OutputSpace, typename Prior::Scalar>;
546 Output
const & output = predicted.output();
547 EMRYS_FILTER_ASSERT(observed.size() == output.valueDimension());
548 typename Output::DifferenceVectorType
residual =
Emrys::minus(output.space(), observed, output.mean());
549 auto const & cross = predicted.crossCovariance();
550 auto conditioned = kalmanCondition<false, NoRepair>(
553 output.covarianceLower(),
561 return std::unexpected{conditioned.error()};
563 return Conditioned<typename Prior::SpaceType, OutputSpace, typename Prior::Scalar>{
564 std::move(conditioned->posterior),
565 {std::move(residual), output.covarianceLower()}
575template <
typename Form,
typename InputSpace,
typename OutputSpace,
typename LinearizationForm,
typename Scalar>
577linearizeFor(OutputWithCross<InputSpace, OutputSpace, LinearizationForm, Scalar>
const & predicted)
579 if constexpr (std::is_same_v<Form, updates::Joseph>)
581 using Linearization = StatisticalLinearization<InputSpace, OutputSpace, Scalar>;
582 using Predicted = OutputWithCross<InputSpace, OutputSpace, LinearizationForm, Scalar>;
583 typename Linearization::ErrorMatrix noise = predicted.inputsCovariance() + predicted.unexplainedCovariance();
584 if constexpr (std::is_same_v<LinearizationForm, RootForm>)
586 using Terms = JosephRootTerms<
587 typename Predicted::RootMatrix
const &,
588 typename Predicted::CrossMatrix
const &,
589 typename Linearization::ErrorMatrix>;
590 return Terms{predicted.root(), predicted.whitenedCross(), std::move(noise)};
594 return JosephTerms<typename Linearization::JacobianMatrix const &, typename Linearization::ErrorMatrix>{
595 predicted.jacobian(),
602 return std::tuple<>{};
633template <
typename InputSpace,
typename OutputSpace,
typename Form,
typename Scalar>
639 return Result{
typename Result::JacobianMatrix{predicted.
jacobian()}, std::move(errorCov)};
670 UncertainInput Prior,
671 typename OutputSpace,
672 typename LinearizationForm,
674 CovarianceUpdate Form = updates::Standard>
680 Eigen::MatrixBase<Derived>
const & observed,
681 Form
const & form = {}
684 return internal::kalmanUpdate(prior, predicted, observed, form, [&] {
685 return internal::linearizeFor<Form>(predicted);
The Gaussian: its parameters GaussianParams, the Gaussian that evaluates the density,...
What a transform returns and what a measurement update reads from it (decisions.md [linearization-for...
The macros every header includes first.
Products of fixed-size matrices by Eigen's fixed-size product at every size: multiply() is by Eigen'...
The covariance reset (decisions.md [covariance-reset]): hasIdentityReset<>, resetJacobian(),...
Solving by a factorization of a small matrix: transposedSolve() gives , the shape of a Kalman gain an...
The Space concept and what every continuous space shares (decisions.md [sizes-and-dimensions]): the t...
Tag paths and the index utilities (decisions.md [tag-addressing], [index-names]): TagPath and TagPath...
A Gaussian distribution: a mean and covariance in a space.
Definition Gaussian.h:259
typename MomentsType::MatrixType MatrixType
a matrix over differences
Definition Gaussian.h:267
typename MomentsType::VectorType VectorType
a value, such as the mean
Definition Gaussian.h:265
typename MomentsType::DifferenceVectorType DifferenceVectorType
a difference, such as a residual
Definition Gaussian.h:266
The innovation of an update: the residual of the observation from the predicted output,...
Definition Linearization.h:536
Scalar logLikelihood() const
Definition Linearization.h:615
The result of transform() with an input marked by withCross(): the output's Gaussian and its lineariz...
Definition Linearization.h:237
JacobianMatrix const & jacobian() const
Definition Linearization.h:377
OutputMatrix const & unexplainedCovariance() const
Definition Linearization.h:350
OutputMatrix const & inputsCovariance() const
Definition Linearization.h:339
One of the covariance updates: updates::Standard, updates::Symmetric, or updates::Joseph.
Definition Condition.h:143
NumericError GaussianError
Reasons a Gaussian, in any of its forms (decisions.md [gaussian-forms]), can fail to give a density,...
Definition NumericError.h:45
constexpr auto symmetric(Fallbacks... fallbacks)
Definition Roots.h:1204
constexpr Residual< Inner > residual(Inner inner={})
Definition Resampling.h:544
auto plus(S const &space, Eigen::MatrixBase< XDerived > const &x, Eigen::MatrixBase< DDerived > const &d)
Definition Space.h:675
auto minus(S const &space, Eigen::MatrixBase< ADerived > const &a, Eigen::MatrixBase< BDerived > const &b)
Definition Space.h:715
constexpr bool hasIdentityReset
Whether the reset Jacobian of S is the identity, so that a covariance needs no change when its mean m...
Definition Reset.h:100
constexpr int valueDimensionAtCompileTime
The value dimension of Space at compile time, or Eigen::Dynamic if it is resizable.
Definition Space.h:251
constexpr int maxValueDimensionAtCompileTime
The largest valid value dimension of Space, or Eigen::Dynamic if it is unbounded.
Definition Space.h:258
The covariance update forms, each made by its factory (decisions.md [policy-factories],...
Definition Condition.h:61
The result of condition(): the posterior, and the innovation, from which the log-likelihood of the ob...
Definition Condition.h:43
Scalar logLikelihood() const
Definition Condition.h:49
GaussianParams< Space, Scalar > posterior
the input conditioned on the observation
Definition Condition.h:44
Innovation< OutputSpace, Scalar > innovation
the observation's residual and its covariance
Definition Condition.h:45
The statistical linearization of an output in an input, from statisticalLinearization(): the affine f...
Definition Condition.h:157
JacobianMatrix jacobian
Definition Condition.h:177
internal::MatrixOf< Scalar, valueDimensionAtCompileTime< DifferenceSpace< OutputSpace > >, valueDimensionAtCompileTime< DifferenceSpace< InputSpace > >, maxValueDimensionAtCompileTime< DifferenceSpace< OutputSpace > >, maxValueDimensionAtCompileTime< DifferenceSpace< InputSpace > > > JacobianMatrix
The Jacobian's type: output differences by input differences.
Definition Condition.h:159
internal::MatrixOf< Scalar, valueDimensionAtCompileTime< DifferenceSpace< OutputSpace > >, valueDimensionAtCompileTime< DifferenceSpace< OutputSpace > >, maxValueDimensionAtCompileTime< DifferenceSpace< OutputSpace > >, maxValueDimensionAtCompileTime< DifferenceSpace< OutputSpace > > > ErrorMatrix
The error covariance's type: over the output's differences.
Definition Condition.h:167
ErrorMatrix errorCov
Definition Condition.h:182
The Joseph covariance update: , with and from the statistical linearization of the output in the in...
Definition Condition.h:126
The standard covariance update of condition(): , which is written without .
Definition Condition.h:75
The symmetric covariance update: , equal to the standard form when is the optimal gain,...
Definition Condition.h:94