EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
Emrys::NisMonitor< Window, MaxWindow, Scalar, Allocator > Class Template Reference

A chi-squared consistency check over a window of updates. More...

#include <EmrysFilter/Models/Consistency.h>

Inheritance diagram for Emrys::NisMonitor< Window, MaxWindow, Scalar, Allocator >:

Public Member Functions

 NisMonitor ()=default
 A monitor over the most recent Window updates, or over every update for Cumulative.
 NisMonitor (Eigen::Index window, Allocator const &allocator={})
 A monitor over the most recent window updates, whose window, if it has no bound, comes from allocator.
 NisMonitor (NisMonitor const &other, Allocator const &allocator)
 Copies other into a window from allocator.
template<typename Update>
requires requires(Update const & update) { update.branches.front().nis(); update.innovationSize(); }
void add (Update const &update)
 Adds an update with a single branch, as from Gaussian noise: a MeasurementUpdate, or the FilterUpdate a filter returns, accepted or not (see the class comment).

Detailed Description

template<int Window = Eigen::Dynamic, int MaxWindow = Window, typename Scalar = double, typename Allocator = DefaultAllocator>
class Emrys::NisMonitor< Window, MaxWindow, Scalar, Allocator >

A chi-squared consistency check over a window of updates.

For a consistent filter, each update's normalized innovation squared (NIS, see UpdateBranch) is chi-squared with the innovation's dimension as its degrees of freedom, and the sum over the window is chi-squared with the total. verdict() tests that sum against two-sided bounds: above them the filter is overconfident, such as with noise set too small, an error; below them it is underconfident, a loss of precision but no error (see Consistency).

The monitor is fed by the caller, so a filter that doesn't use one pays nothing:

auto monitor = NisMonitor<50>{};
if (auto const updated = filter.update(fix)) { monitor.add(*updated); }
if (monitor.verdict(0.99) == Consistency::Overconfident) { ... }
NisMonitor()=default
A monitor over the most recent Window updates, or over every update for Cumulative.
@ Overconfident
the sum lies above the upper bound: the covariance understates the errors
Definition Consistency.h:58

A std::expected compares equal to a value only when it holds one, so the comparison is false while the window is empty.

The window is sized as an Eigen vector is. Window is its length, a ring inline; with Eigen::Dynamic the length is given at construction, as in NisMonitor{50}, inline up to MaxWindow where that is a bound and from Allocator where it is Eigen::Dynamic too. With Cumulative there is no window: the test runs over every update since construction or reset(), the time-average test over a whole run, and keeps only a sum. Its bounds narrow as the run grows, so a long run fails on a small mistuning that a moving window, which a monitor on a running system wants, passes; and a NaN, once added, stays until reset().

add(update) counts an update whether or not its policy accepted it (decisions.md [update-outcomes]). The test asks whether the filter predicts the measurements it is given, and a gate rejects the ones it predicts worst: leaving them out would hide a filter that has diverged behind its gate, and biases the sum low even for a consistent filter, whose accepted updates under a 0.99 gate on two coordinates average 0.953 rather than 1. A caller who wants the accepted updates alone tests accepted and passes those. With mixture noise there are several branches, each with its own NIS, so pass the one to test, such as the inlier component's, with add(nis, dimension). The filters of several components, modes, or points are tested the same way, on the NIS of the dominant branch: the most probable branch of the most probable component or mode. That NIS is chi-squared only while the dominant branch carries nearly all of the probability, since the predictive distribution of the measurement is a mixture, so the test reads a filter that is often split between branches as inconsistent when it may not be.

The NIS needs nothing but the filter and the data, so it runs on a real system. It can pass while the state's error is far larger than the covariance says, in a direction the measurements don't see; in a simulation, where the true state is known, NeesMonitor tests the state itself.

The time-average normalized innovation squared test of Bar-Shalom, Li, and Kirubarajan (2001), over a moving window or a whole run. The NIS and its chi-squared law are as given in Chen et al. (2023), §III-A, equation (8); the test over one run's window is this library's form of their test across runs, §III-B.

See also
NeesMonitor

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