When building telemetry filters for autonomous drones or robotics, the textbook recommendation is always the same: “Just slap a Kalman Filter on it.”
In theory, the linear Kalman filter is mathematically optimal under Gaussian white noise. In the real world, however, physical sensors do not live in textbook conditions:
- Adversarial GPS/Baro Spoofing: A rogue transmitter or RF jammer injects sudden, massive delta jumps (e.g., +150 meters in a single millisecond).
- Numerical Covariance Degeneracy: Floating-point round-off errors over millions of iterations cause the error covariance matrix $P$ to lose its positive-definiteness ($P \not\succ 0$), producing negative variances and exploding state estimates.
- Severe Non-Linearities: Radar range calculations ($r = \sqrt{x^2 + y^2}$) and orientation quaternions break linear assumptions; Extended Kalman Filters (EKF) require calculating brittle analytical Jacobian matrices that drift rapidly.
To solve these mission-critical vulnerabilities, we built and open-sourced aegis-filter under Exploidus—a cyber-resilient, #![no_std], hard real-time estimation engine written from scratch in pure Rust.
Here is the engineering breakdown of how it works and what the simulation numbers prove.
1. The Core Architecture
aegis-filter is engineered with three core defenses:
A. Joseph-Stabilized Covariance Update
Standard Kalman filters update covariance using $P_k = (I - K_k H_k) P_{k|k-1}$. In finite-precision IEEE 754 floating-point arithmetic, subtraction can yield asymmetric, non-positive-definite matrices.
aegis-filter enforces the Joseph Stabilized Form:
$$P_k = (I - K_k H_k) P_{k|k-1} (I - K_k H_k)^T + K_k R_k K_k^T$$
Because both terms are quadratic forms ($A P A^T + B R B^T$), positive-definiteness is mathematically guaranteed across infinite operational lifetimes.
B. Chi-Square / 3-Sigma Outlier Rejection Gating
Before any raw measurement is allowed to alter the state vector, the innovation $\tilde{y}k = z_k - H_k \hat{x}{k|k-1}$ is evaluated against the innovation covariance $S_k = H_k P_{k|k-1} H_k^T + R_k$:
$$\text{Reject if } |\tilde{y}_k| > \gamma \sqrt{S_k}$$
If an adversary transmits a spoofed altitude or an IMU glitches, the reading is gated at line-rate. The filter falls back safely to its physical state propagation without corrupting the state.
C. Unscented Kalman Filtering (UKF) & $H_\infty$ Robust Minimax
- UKF (Merwe Scaled Sigma Points): Replaces brittle Jacobian derivations by propagating $2n + 1$ deterministic sigma points through non-linear observation closures.
- $H_\infty$ Minimax: Optimizes state estimation against the worst-case disturbance rather than assuming well-behaved Gaussian noise.
2. Flight Telemetry & Spoofing Resilience Simulation
To prove real-world resilience, we simulated a quadcopter ascending at $1.5\text{ m/s}$ subjected to atmospheric turbulence, normal sensor noise, and deliberate adversarial spoofing:
- Step 12: Instantaneous $+150\text{m}$ GPS spoofing attack.
- Step 22: Severe $-80\text{m}$ sensor hardware dropout glitch.
Here is the telemetry log produced by running cargo run --example flight_telemetry:
===============================================================================
AEGIS-FILTER :: FLIGHT TELEMETRY & ADVERSARIAL RESILIENCE SIMULATION
Developed under Exploidus (https://github.com/Exploidus)
===============================================================================
Step | True Alt (m) | Sensor Raw (m) | Aegis Est (m) | Abs Error | Status
-------+--------------+----------------+----------------+--------------+-----------
1 | 1.50 | 1.79 | 1.75 | 0.254 | VALID
2 | 3.00 | 3.22 | 3.24 | 0.238 | VALID
3 | 4.50 | 3.46 | 4.31 | 0.187 | VALID
4 | 6.00 | 6.74 | 6.06 | 0.057 | VALID
5 | 7.50 | 7.67 | 7.58 | 0.081 | VALID
6 | 9.00 | 8.90 | 9.04 | 0.045 | VALID
7 | 10.50 | 9.68 | 10.39 | 0.113 | VALID
8 | 12.00 | 12.98 | 12.08 | 0.075 | VALID
9 | 13.50 | 13.41 | 13.55 | 0.047 | VALID
10 | 15.00 | 14.69 | 14.99 | 0.009 | VALID
11 | 16.50 | 16.04 | 16.42 | 0.080 | VALID
12 | 18.00 | 168.00 | 17.92 | 0.080 | SPOOF REJECT
13 | 19.50 | 19.08 | 19.36 | 0.138 | VALID
14 | 21.00 | 20.65 | 20.83 | 0.172 | VALID
15 | 22.50 | 22.43 | 22.34 | 0.156 | VALID
16 | 24.00 | 24.93 | 24.01 | 0.012 | VALID
17 | 25.50 | 24.79 | 25.40 | 0.099 | VALID
18 | 27.00 | 26.78 | 26.88 | 0.116 | VALID
19 | 28.50 | 28.76 | 28.44 | 0.060 | VALID
20 | 30.00 | 30.64 | 30.04 | 0.044 | VALID
21 | 31.50 | 30.61 | 31.41 | 0.095 | VALID
22 | 33.00 | -47.00 | 32.91 | 0.095 | SPOOF REJECT
23 | 34.50 | 34.96 | 34.50 | 0.003 | VALID
24 | 36.00 | 36.25 | 36.04 | 0.036 | VALID
25 | 37.50 | 36.60 | 37.39 | 0.110 | VALID
26 | 39.00 | 39.34 | 38.96 | 0.041 | VALID
27 | 40.50 | 40.99 | 40.54 | 0.039 | VALID
28 | 42.00 | 41.84 | 42.01 | 0.009 | VALID
29 | 43.50 | 42.78 | 43.40 | 0.100 | VALID
30 | 45.00 | 45.60 | 45.00 | 0.003 | VALID
-------------------------------------------------------------------------------
SIMULATION SUMMARY:
- Total Steps Processed : 30
- Valid Readings Fused : 28
- Adversarial Spikes Blocked : 2 (100% Gated)
- Final Variance Confidence : 0.1185
===============================================================================
Key Takeaways from the Data:
- Millimeter Tracking Precision: Under normal noisy conditions (Step 10, Step 30), estimation error dropped to 0.003–0.009 meters (3–9 mm).
- Flawless Spoof Rejection: When the raw altitude leaped to $168\text{m}$ at Step 12, the filter isolated the anomaly, kept the aircraft altitude at $17.92\text{m}$ (error: $0.080\text{m}$), and prevented a fatal motor cut.
3. Quick Start (Rust)
Add aegis-filter to your Cargo.toml:
[dependencies]
aegis-filter = "0.1.0"
For bare-metal Cortex-M/RISC-V embedded targets:
[dependencies]
aegis-filter = { version = "0.1.0", default-features = false }
1D Outlier-Gated Fusion Example:
use aegis_filter::{ScalarKalmanFilter, FilterError};
fn main() -> Result<(), FilterError> {
// Initial state: 0.0m, Initial variance: 5.0, Process noise: 0.02, Measurement noise: 0.8
let mut filter = ScalarKalmanFilter::new(0.0, 5.0, 0.02, 0.8)?;
let sensor_stream = [1.5, 3.1, 4.4, 168.0 /* Spoofed spike */, 6.0];
for &raw_reading in &sensor_stream {
filter.predict(1.5)?; // Predict forward by 1.5m climb
match filter.update(raw_reading, Some(3.0)) { // 3-sigma gate
Ok(estimated_alt) => println!("Estimated Altitude: {:.2}m", estimated_alt),
Err(FilterError::MeasurementGated) => {
println!("Spoofed sensor reading ({:.1}m) rejected! Holding state.", raw_reading);
}
Err(e) => return Err(e),
}
}
Ok(())
}
4. Open Source Links
The engine is open-source under dual MIT/Apache-2.0 licenses:
- Crates.io: crates.io/crates/aegis-filter
- GitHub Repository: Exploidus/aegis-filter
- Documentation: docs.rs/aegis-filter
Feedback, issues, and PRs from control engineers and systems developers are warmly welcome!
Top comments (0)