EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
Smoothers

The last layer (decisions.md [layered-headers]): estimates of past states from later data [smoothing]. More...

Classes

class  Emrys::CategoricalHistory< Space_, Scalar_, Allocator_ >
 The record of a HiddenMarkovFilter's forward pass that a smoother runs backward over: one CategoricalPredictedJoint per prediction, each with room for its smoothed distribution. More...
struct  Emrys::ValueSequence< Space, Scalar, Allocator >
 The most probable sequence of values over a CategoricalHistory, and its posterior probability, from mostProbableSequence(). More...
class  Emrys::GaussianHistory< Space_, Scalar_, Allocator_ >
 The record of a Kalman filter's forward pass that a smoother runs backward over: one PredictedJoint per prediction, each with room for its smoothed Gaussian. More...
class  Emrys::GaussianMixtureHistory< Space_, Scalar_, Allocator_ >
 The record of a Gaussian mixture filter's forward pass that its smoother runs backward over: one GaussianMixturePredictedJoint per prediction, each with room for its smoothed mixture. More...
class  Emrys::HybridGaussianHistory< Space_, ModeSpace_, Scalar_, Allocator_ >
 The record of an IMM filter's forward pass that its smoother runs backward over: one HybridPredictedJoint per prediction, each with room for its smoothed HybridGaussian. More...
struct  Emrys::Lag
 The number of steps a fixed-lag history keeps. More...
class  Emrys::ParticleHistory< Space_, Scalar_, Allocator_ >
 The record of a particle filter's forward pass that ancestor tracing runs backward over: the particles at each step, how each descends from the step before, and room for the step's smoothed particles. More...

Functions

template<typename Space, typename Scalar>
CategoricalParams< Space, Scalar > Emrys::smoothStep (CategoricalPredictedJoint< Space, Scalar > const &joint, CategoricalParams< Space, Scalar > const &smoothedNext)
template<typename Space, typename Scalar>
CategoricalPredictedJoint< Space, Scalar >::MatrixType Emrys::transitionPosterior (CategoricalPredictedJoint< Space, Scalar > const &joint, CategoricalParams< Space, Scalar > const &smoothedNext)
template<typename Space, typename Scalar, typename Allocator>
ValueSequence< Space, Scalar, Allocator > Emrys::mostProbableSequence (CategoricalHistory< Space, Scalar, Allocator > const &history, CategoricalParams< Space, Scalar > const &latest)
template<typename Space_, typename Scalar_>
GaussianParams< Space_, Scalar_ > Emrys::smoothStep (PredictedJoint< Space_, Scalar_ > const &joint, typename GaussianParams< Space_, Scalar_ >::MatrixType const &gain, GaussianParams< Space_, Scalar_ > const &smoothedNext)
template<typename Space_, typename Scalar_>
GaussianParams< Space_, Scalar_ > Emrys::smoothStep (PredictedJoint< Space_, Scalar_ > const &joint, GaussianParams< Space_, Scalar_ > const &smoothedNext)
 smoothStep() with the gain computed here, from joint alone (internal::rtsGain()): the form for one step; a history keeps the gain with the step and applies it at every smooth().

Detailed Description

The last layer (decisions.md [layered-headers]): estimates of past states from later data [smoothing].

A filter is unchanged by smoothing but for predictJoint(), which fills the joint of a step's start and end, and the record of the forward pass is the caller's: a history, which the caller keeps outside the filter and pushes each step to, and whose smooth() takes the filter's latest state and fills every step's smoothed estimate, from the newest step back, over the whole run or the newest steps of a Lag. GaussianHistory.h, with smoothStep(), the Rauch-Tung-Striebel step, is the shape the others follow: HybridGaussianHistory.h smooths an ImmFilter by its modes, GaussianMixtureHistory.h a MixtureFilter of Gaussians by its components' lineage, ParticleHistory.h a ParticleFilter by its particles' ancestors, and CategoricalHistory.h a HiddenMarkovFilter, with its most probable sequence.

Function Documentation

◆ mostProbableSequence()

template<typename Space, typename Scalar, typename Allocator>
ValueSequence< Space, Scalar, Allocator > Emrys::mostProbableSequence ( CategoricalHistory< Space, Scalar, Allocator > const & history,
CategoricalParams< Space, Scalar > const & latest )
nodiscard
Returns
the most probable sequence of values over history and latest, the filter's state after its newest step, with its posterior log-probability; its values come from the history's allocator

The Viterbi algorithm of Viterbi (1967), in the max-product form of Rabiner (1989), §III-B: a forward pass of \( \delta_{k+1}(j) = \max_i [\delta_k(i) + \log K_{ij}] + \log L_{k+1}(j) \) with back-pointers, then a backtrack from the best final value. The departure is where the likelihoods come from: the history keeps no measurements, so \( L_{k+1}(j) \) is the ratio of the filtered to the predicted probability, \( f_{k+1}(j) / \hat p_{k+1}(j) \), which is the product of every update's likelihood between the two predictions divided by their evidence. The evidence is the same for every sequence, so the argmax is unchanged, and since \( \delta \) starts from the oldest step's filtered distribution, the maximum is the posterior log-probability of the sequence rather than a joint density. Over a fixed-lag window the sequence is the most probable one of the window's values, the earlier ones summed out. It is a free function and not a filter member because it is the one place the library takes a maximum instead of a sum.

Ties go to the lowest value. It allocates the back-pointers, one index per value per step, and the result.

◆ smoothStep() [1/2]

template<typename Space, typename Scalar>
CategoricalParams< Space, Scalar > Emrys::smoothStep ( CategoricalPredictedJoint< Space, Scalar > const & joint,
CategoricalParams< Space, Scalar > const & smoothedNext )
nodiscard
Returns
the smoothed distribution at the start of joint's step, given smoothedNext, the smoothed distribution at its end: with \( f \) the filtered distribution, \( \hat p \) the prediction, \( s \) the smoothed one at the end, and \( K \) the step's transitions,

\[ s'_i = f_i \sum_j K_{ij} \, \frac{s_j}{\hat p_j}. \]

The Bayesian smoothing equation of Särkkä (2013), chapter 8, on a finite set, where its integral is a sum. On a hidden Markov model it gives the smoothed marginals \( \gamma \) of the forward-backward algorithm (Rabiner (1989), §III-A) in the form that needs only the filtered distributions and no likelihoods, as smoothStep() does for a Gaussian, rather than Rabiner's product of forward and backward variables. The two are the same, since \( s_j / \hat p_j \) is the backward variable, normalized. The ratio is taken in logs and scaled by its largest entry, so a value improbable beyond a double's range at either end still divides correctly. smoothedNext must have valid weights, and give no probability to a value the prediction rules out.

See also
CategoricalHistory, transitionPosterior()

◆ smoothStep() [2/2]

template<typename Space_, typename Scalar_>
GaussianParams< Space_, Scalar_ > Emrys::smoothStep ( PredictedJoint< Space_, Scalar_ > const & joint,
typename GaussianParams< Space_, Scalar_ >::MatrixType const & gain,
GaussianParams< Space_, Scalar_ > const & smoothedNext )
nodiscard
Returns
the smoothed Gaussian at the start of joint's step, given smoothedNext, the smoothed Gaussian at its end: the Rauch-Tung-Striebel backward step in the tangent space, with the gain \( G_k = C_k P_{k+1 \mid k}^{-1} \) from the joint's cross-covariance,

\[ \hat x_{k \mid N} = \hat x_{k \mid k} \boxplus G_k \,(\hat x_{k+1 \mid N} \boxminus \hat x_{k+1 \mid k}), \qquad P_{k \mid N} = P_{k \mid k} + G_k \,(P_{k+1 \mid N} - P_{k+1 \mid k})\, G_k^T. \]

The smoother of Rauch, Tung, and Striebel (1965), in the form of the Gaussian smoother of Särkkä (2013), chapter 10, which writes the gain in terms of the cross-covariance so that the same step serves the affine, linearized, and unscented predictions. The departure is the manifold: the residual is \( \boxminus \) and the step \( \boxplus \), so a unit quaternion's smoothed mean stays unit, and each covariance is moved to the tangent space it is combined in (decisions.md [covariance-reset]). \( P_{k+1 \mid N} \), about the smoothed mean, is carried back to the tangent space at the predicted mean by the inverse of the reset Jacobian at the predicted mean and the correction, and the smoothed covariance, formed at the filtered mean, is carried to the smoothed mean by resetCovariance(). On a space with an identity reset both are nothing. \( P_{k+1 \mid k} \) is factorized by LDLT, which tolerates a semidefinite prediction.

See also
GaussianHistory, PredictedJoint, Smoothers

◆ transitionPosterior()

template<typename Space, typename Scalar>
CategoricalPredictedJoint< Space, Scalar >::MatrixType Emrys::transitionPosterior ( CategoricalPredictedJoint< Space, Scalar > const & joint,
CategoricalParams< Space, Scalar > const & smoothedNext )
nodiscard
Returns
the posterior probability of each transition of joint's step given smoothedNext, the smoothed distribution at its end: \( \xi_{ij} = P(x_k = i, x_{k+1} = j \mid z_{1:N}) = f_i K_{ij} s_j / \hat p_j \), a matrix whose entries sum to one, whose row sums are smoothStep() and whose column sums are smoothedNext

The pairwise posteriors \( \xi \) of Rabiner (1989), §III-C, there in terms of the forward and backward variables, here of the filtered and smoothed distributions as smoothStep() takes them. Summed over a history they are the expected transition counts that the Baum-Welch re-estimation of a chain consumes; the re-estimation itself is model identification, outside the library (decisions.md [analysis-project]). smoothedNext must meet smoothStep()'s conditions.