1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5pub enum FilterError {
6 NonFiniteInput,
8 InvalidCovariance,
10 SingularInnovation,
12 MeasurementGated,
14 NumericalInstability,
16 InvalidParameter,
18 CapacityExceeded,
20}
21
22impl core::fmt::Display for FilterError {
23 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
24 match self {
25 Self::NonFiniteInput => write!(
26 f,
27 "Input contains non-finite floating point values (NaN or Inf)"
28 ),
29 Self::InvalidCovariance => write!(f, "Covariance is non-positive or ill-conditioned"),
30 Self::SingularInnovation => {
31 write!(f, "Innovation covariance is singular or ill-conditioned")
32 }
33 Self::MeasurementGated => write!(
34 f,
35 "Measurement was gated out as an outlier or adversarial spike"
36 ),
37 Self::NumericalInstability => write!(
38 f,
39 "Numerical instability occurred during matrix factorization or square root"
40 ),
41 Self::InvalidParameter => write!(f, "Invalid parameter value provided to filter"),
42 Self::CapacityExceeded => write!(f, "Maximum registered sensor capacity exceeded"),
43 }
44 }
45}
46
47#[cfg(feature = "std")]
48impl std::error::Error for FilterError {}
49
50pub trait FloatOps {
52 fn is_valid_float(&self) -> bool;
53 fn abs_val(self) -> f64;
54 fn sqrt_val(self) -> f64;
55}
56
57impl FloatOps for f64 {
58 #[inline(always)]
59 fn is_valid_float(&self) -> bool {
60 self.is_finite()
61 }
62
63 #[inline(always)]
64 fn abs_val(self) -> f64 {
65 f64::from_bits(self.to_bits() & !(1u64 << 63))
66 }
67
68 #[inline]
69 fn sqrt_val(self) -> f64 {
70 #[cfg(feature = "std")]
71 {
72 self.sqrt()
73 }
74 #[cfg(not(feature = "std"))]
75 {
76 if self <= 0.0 {
77 return 0.0;
78 }
79 if !self.is_finite() {
80 return self;
81 }
82 let mut curr = self;
83 for _ in 0..24 {
84 let prev = curr;
85 curr = 0.5 * (curr + self / curr);
86 if (curr - prev).abs_val() <= 1e-15 * curr {
87 break;
88 }
89 }
90 curr
91 }
92 }
93}