pub struct Gates {
pub gnss_position: Gate<2>,
pub gnss_height: Gate<1>,
pub gnss_velocity: Gate<3>,
pub baro_altitude: Gate<1>,
pub mag_heading: Gate<1>,
pub gnss_heading: Gate<1>,
pub course: Gate<1>,
pub stationary: Gate<3>,
pub position_hold: Gate<2>,
}Expand description
Innovation gate thresholds γ, one per observation, from equation (37).
The filter reports r = ε / γ, so these set what r = 1 means. Built from a percentile,
then adjusted per source where a caller has a reason:
use fusion_nav::{Gate, Gates, Percentile};
let mut gates = Gates::at(Percentile::P99);
gates.baro_altitude = Gate::<1>::at(Percentile::P999); // a barometer that sees prop washA threshold of the wrong dimension does not compile:
let mut gates = Gates::default();
gates.baro_altitude = Gate::<3>::at(Percentile::P99); // expected `Gate<1>`, found `Gate<3>`Every threshold is compared against the joint ε = yᵀ S⁻¹ y over all of the
observation’s components, not one component at a time. Both production estimators test
per component against the diagonal of S only: PX4 each axis at 5σ
(src/modules/ekf2/EKF/ekf.h:1142 at c4e4ef98e9), which fits its fusing the axes one by
one (EKF/position_fusion.cpp:62-68); ArduPilot the horizontal pair as one sum against the
summed variances and the vertical alone
(libraries/AP_NavEKF3/AP_NavEKF3_PosVelFusion.cpp:904-906 and :1023 at 368dc0c428).
The joint test is what makes a Percentile mean what it names: only ε is chi-square
with dim(z) degrees of freedom, so only it rejects exactly 1 − p of good measurements,
where a per-component test’s rate depends on correlations nothing states. And it keeps
those correlations — a yaw error couples north and east, so the region S describes is an
ellipsoid rather than a box aligned with the navigation axes.
A GNSS position fix is the exception, split into a horizontal Gate<2> and a vertical Gate<1>
as ArduPilot splits it, because the joint test’s cost is all or nothing: a height the estimate
disagrees with rejects a good horizontal fix, 3945 of 4616 on a vehicle whose barometer and
receiver drift apart (evidence). The split keeps the joint test within each half, so north and
east are still tested as the ellipse S describes; what it gives up is the north–down and
east–down correlation, which a position fix barely carries. See
GnssFusion.
Fields§
§gnss_position: Gate<2>GNSS position, horizontal: north and east.
gnss_height: Gate<1>GNSS position, vertical: the height half of the same fix.
gnss_velocity: Gate<3>GNSS velocity.
baro_altitude: Gate<1>Barometric altitude.
mag_heading: Gate<1>Magnetic heading.
gnss_heading: Gate<1>Dual-antenna GNSS heading.
course: Gate<1>Course constraint.
stationary: Gate<3>A caller’s claim that the vehicle is still: zero velocity, all three axes.
position_hold: Gate<2>The position hold an unaided filter fuses: north and east.
Implementations§
Trait Implementations§
impl Copy for Gates
Source§impl Default for Gates
impl Default for Gates
Source§fn default() -> Self
fn default() -> Self
The 99.9th percentile: the tightest gate that costs nothing measurable on good data.
Replayed at 95 %, 99 %, 99.9 % and 5σ, the corpus could not tell them apart and the
simulator prices the tight end: on mission 95 % turns away one good fix in thirty for
worse accuracy, and 99.9 % and 5σ give what 99 % does (evidence). 99.9 % is still tighter
than both production estimators, which test each axis at 5σ (PX4
src/modules/ekf2/EKF/common.h:348-374 at c4e4ef98e9; ArduPilot *_I_GATE_DEFAULT 500,
in hundredths of σ, libraries/AP_NavEKF3/AP_NavEKF3.cpp:34-36 at 368dc0c428): a one-axis
outlier fails γ = 16.27 at 4.0σ.
impl StructuralPartialEq for Gates
Auto Trait Implementations§
impl Freeze for Gates
impl RefUnwindSafe for Gates
impl Send for Gates
impl Sync for Gates
impl Unpin for Gates
impl UnsafeUnpin for Gates
impl UnwindSafe for Gates
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> Scalar for T
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.