EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
Emrys::PosteriorCramerRaoBound< Space_, Scalar_ > Class Template Reference

The posterior Cramér-Rao bound along true trajectories: the Fisher information \( J_k \) of the state, whose inverse bounds the mean squared error of any estimator of \( x_k \). More...

#include <EmrysFilter/Models/CramerRao.h>

Public Types

using Scalar = Scalar_
 the scalar type
using SpaceType = Space_
 the state space
using VectorType = typename Moments<Space_, Scalar_>::VectorType
 a state value
using MatrixType = typename Moments<Space_, Scalar_>::MatrixType
 \( J \), over differences

Public Member Functions

template<MatrixExpression Info>
 PosteriorCramerRaoBound (Space_ space, Info &&info)
 The bound in space with the information matrix information, symmetric and positive semidefinite over the space's differences: zero for a state that nothing is known about.
Space_ const & space () const
MatrixType const & info () const
std::expected< MatrixType, GaussianError > covariance () const
template<ProcessModel Model, typename Truths, typename... Inputs>
requires (!ExecutionPolicy<Model>)
std::expected< void, GaussianError > predict (Model const &model, Eigen::MatrixBase< Truths > const &truths, TimeStep< Scalar_ > auto const &dt, Inputs const &... inputs)
 Moves the bound forward by dt, any TimeStep (see Time steps), through the process model model with the true inputs inputs, from the true states truths, a column each: \( J \leftarrow Q^{-1} - Q^{-1} \bar F (J + D^{11})^{-1} \bar F^T Q^{-1} \), with model's Jacobian \( F \) at each column.
template<ExecutionPolicy P, ProcessModel Model, typename Truths, typename... Inputs>
std::expected< void, GaussianError > predict (P &&policy, Model const &model, Eigen::MatrixBase< Truths > const &truths, TimeStep< Scalar_ > auto const &dt, Inputs const &... inputs)
 predict(model, truths, dt, inputs...) under policy: the Jacobians at the columns are taken as a reduction (see Execution policies), so the result depends on the count of truths but not on how the work was scheduled, and with fewer than internal::chunkSize truths it is Sequential's.
template<typename Model, typename Truths, typename... Inputs>
requires ( !ExecutionPolicy<Model> && (isFixedStep<Model> || isUnboundStep<Model>) && requires(Model const & m) { m.model(); } )
std::expected< void, GaussianError > predict (Model const &model, Eigen::MatrixBase< Truths > const &truths, Inputs const &... inputs)
 predict() over the step of the fixed-step model model, or of fixedStep()'s result, with its process noise.
template<ExecutionPolicy P, typename Model, typename Truths, typename... Inputs>
requires ((isFixedStep<Model> || isUnboundStep<Model>) && requires(Model const & m) { m.model(); })
std::expected< void, GaussianError > predict (P &&policy, Model const &model, Eigen::MatrixBase< Truths > const &truths, Inputs const &... inputs)
 predict(model, truths, inputs...) over a fixed-step model's step under policy.
template<typename Truths, MeasurementModel M, typename... Args>
std::expected< void, GaussianError > update (Eigen::MatrixBase< Truths > const &truths, M const &model, Args const &... args)
 Adds the information that a measurement at the true states truths, a column each, carries: \( J \leftarrow J + \mathrm{E}[H^T R^{-1} H] \), with \( H \) the Jacobian of the measurement model model's function at each column, and the call's args the sure inputs the model reads, as simulate() takes them.
template<ExecutionPolicy P, typename Truths, MeasurementModel M, typename... Args>
std::expected< void, GaussianError > update (P &&policy, Eigen::MatrixBase< Truths > const &truths, M const &model, Args const &... args)
 update(truths, model, args...) under policy: a reduction over the columns, as in predict().

Static Public Member Functions

static std::expected< PosteriorCramerRaoBound, GaussianError > create (GaussianParams< Space_, Scalar_ > const &prior)

Detailed Description

template<Space Space_, RealScalar Scalar_ = double>
class Emrys::PosteriorCramerRaoBound< Space_, Scalar_ >

The posterior Cramér-Rao bound along true trajectories: the Fisher information \( J_k \) of the state, whose inverse bounds the mean squared error of any estimator of \( x_k \).

This is the posterior, or Van Trees, form of the Cramér-Rao bound: for any filter, \( \mathrm{E}[(\hat x_k \boxminus x_k)(\hat x_k \boxminus x_k)^T] \ge J_k^{-1} \), the expectation taken over the true trajectories and their measurements. Compare a filter's mean squared error over Monte Carlo runs with covariance(), and its own covariance with NEES (see NeesMonitor): the bound says how far the error is from the best possible, NEES whether the filter knows its error.

It starts from the prior, \( J_0 = P_0^{-1} \) (create()), or from an information matrix, zero for a state that nothing is known about. Each step is given the true states at its time as the columns of a matrix, a SampleSet: one column for one trajectory, or one per Monte Carlo run, each drawn by simulate() from its own start, so that the bound takes the expectations over them. predict() and update() are the recursion of Tichavský, Muravchik, andNehorai (1998), Proposition 1, eq. (21), with the matrices of eqs. (34) to (36) for additive Gaussian noise, split in two since \( D^{22} \) is a sum:

\[ J \leftarrow Q^{-1} - Q^{-1} \bar F (J + D^{11})^{-1} \bar F^T Q^{-1}, \qquad J \leftarrow J + \mathrm{E}[H^T R^{-1} H], \]

with \( \bar F = \mathrm{E}[F] \) and \( D^{11} = \mathrm{E}[F^T Q^{-1} F] \), each expectation the mean over the columns. With one true state and no expectation the prediction is \( (Q + F J^{-1} F^T)^{-1} \), an extended Kalman filter's covariance recursion with every Jacobian taken at the truth, and for an affine model the Kalman filter's covariance itself.

The Jacobians are the Linearized method's at each true state, whatever method a model asks for, so a function that returns its Jacobian (withJacobian()) is called once per state. On a space with its own plus() and minus() they are in its tangent space, and the bound is that of Chahbazian et al. (2024), Proposition 2 and eqs. (68) to (72), for noise that enters as \( f(x) \boxplus w \), as simulate() draws it. The paper takes \( F \) at the pair of true states, as the derivative of \( x_{k+1} \boxminus f(x_k \boxplus \epsilon) \); this takes it at \( f(x_k) \), which is the same on Linear and agrees to first order in the noise elsewhere, the order of the paper's own truncation.

The process noise \( Q \) must be positive definite: a noiseless block, such as a Constant one, makes the transition density singular, which is Section IV of the paper and not supported yet. A model's inputs are the true ones, as simulate() takes them. The measurements are a measurement model's (see measurementModel()), with no observation, since the bound averages over the measurements the model would draw. Its noise must be additive and Gaussian (AdditiveNoise of a Gaussian), with \( R \) positive definite.

auto bound = PosteriorCramerRaoBound<State>::create(initial); // J = P0^-1
// truths: a column per Monte Carlo run, advanced by simulate() between the steps
bound->predict(model, truths, dt);
bound->update(truths, rangeSensor);
auto const floor = bound->covariance(); // compare with the filters' mean squared error
static std::expected< PosteriorCramerRaoBound, GaussianError > create(GaussianParams< Space_, Scalar_ > const &prior)
Definition CramerRao.h:146
Template Parameters
Space_the state space (see Spaces)
Scalar_scalar type, double by default
See also
simulate(), NeesMonitor

Member Function Documentation

◆ covariance()

template<Space Space_, RealScalar Scalar_ = double>
std::expected< MatrixType, GaussianError > Emrys::PosteriorCramerRaoBound< Space_, Scalar_ >::covariance ( ) const
inlinenodiscard
Returns
the bound itself, \( J^{-1} \), the least covariance of any estimator's error, or GaussianError::Singular while the information leaves a direction unknown

◆ create()

template<Space Space_, RealScalar Scalar_ = double>
std::expected< PosteriorCramerRaoBound, GaussianError > Emrys::PosteriorCramerRaoBound< Space_, Scalar_ >::create ( GaussianParams< Space_, Scalar_ > const & prior)
inlinestaticnodiscard
Returns
the bound whose information is the inverse of the covariance of prior, \( J_0 = P_0^{-1} \), or GaussianError::NotPositiveDefinite where the covariance has no inverse

◆ info()

template<Space Space_, RealScalar Scalar_ = double>
MatrixType const & Emrys::PosteriorCramerRaoBound< Space_, Scalar_ >::info ( ) const
inlinenodiscard
Returns
the Fisher information \( J \), over the space's differences

◆ predict()

template<Space Space_, RealScalar Scalar_ = double>
template<ProcessModel Model, typename Truths, typename... Inputs>
requires (!ExecutionPolicy<Model>)
std::expected< void, GaussianError > Emrys::PosteriorCramerRaoBound< Space_, Scalar_ >::predict ( Model const & model,
Eigen::MatrixBase< Truths > const & truths,
TimeStep< Scalar_ > auto const & dt,
Inputs const &... inputs )
inlinenodiscard

Moves the bound forward by dt, any TimeStep (see Time steps), through the process model model with the true inputs inputs, from the true states truths, a column each: \( J \leftarrow Q^{-1} - Q^{-1} \bar F (J + D^{11})^{-1} \bar F^T Q^{-1} \), with model's Jacobian \( F \) at each column.

A model that gives its transition matrix is not differentiated, and its truths are not read.

Returns
nothing, or GaussianError::NotPositiveDefinite where \( Q \) is not positive definite, and GaussianError::Singular where \( J + D^{11} \) has no inverse; the bound is then unchanged

◆ space()

template<Space Space_, RealScalar Scalar_ = double>
Space_ const & Emrys::PosteriorCramerRaoBound< Space_, Scalar_ >::space ( ) const
inlinenodiscard
Returns
the state space

◆ update()

template<Space Space_, RealScalar Scalar_ = double>
template<typename Truths, MeasurementModel M, typename... Args>
std::expected< void, GaussianError > Emrys::PosteriorCramerRaoBound< Space_, Scalar_ >::update ( Eigen::MatrixBase< Truths > const & truths,
M const & model,
Args const &... args )
inlinenodiscard

Adds the information that a measurement at the true states truths, a column each, carries: \( J \leftarrow J + \mathrm{E}[H^T R^{-1} H] \), with \( H \) the Jacobian of the measurement model model's function at each column, and the call's args the sure inputs the model reads, as simulate() takes them.

The model's noise must be additive and Gaussian (additiveNoise() of a GaussianParams), with \( R \) positive definite. Several measurements at one time are several updates.

Returns
nothing, or GaussianError::NotPositiveDefinite where \( R \) is not positive definite; the bound is then unchanged

The documentation for this class was generated from the following file: