Strapdown inertial navigation and GNSS-degradation simulation in Rust.
strapdown-rs is a library and command-line toolkit for research on inertial navigation
systems (INS), particularly when GNSS is unavailable or untrustworthy. It provides:
- local-level strapdown mechanization (Groves, Principles of GNSS, Inertial, and Multisensor Integrated Navigation Systems, 2nd ed., §5.4);
- four loosely coupled navigation filters behind one trait;
- a simulator that replays recorded or synthetic IMU/GNSS data while removing, thinning or corrupting the GNSS stream according to a seeded scenario file.
📖 User guide ·
📚 API documentation ·
Navigation algorithms are commonly prototyped in MATLAB or Python. There they are fast only once rewritten in vectorized form, which is especially awkward for particle filters. Real GNSS-denied data is expensive, regulated and impossible to repeat exactly.
strapdown-rs addresses both problems:
- Filters are written plainly and compiled, so the same code serves research scripts, experiments and applications.
- Any trajectory can be run under controlled, reproducible GNSS outages and faults, so algorithms are compared under identical conditions.
It is aimed at graduate students, researchers and engineers working on INS/GNSS integration and alternative positioning, navigation and timing (PNT).
- Filters. All four implement the
NavigationFiltertrait:- error-state Kalman filter (ESKF, the default): 15 error states, plus a barometric bias
state unless
--no-estimate-baro-bias; - extended Kalman filter (EKF);
- unscented Kalman filter (UKF);
- Rao-Blackwellized particle filter after Canciani & Raquet (2017).
- error-state Kalman filter (ESKF, the default): 15 error states, plus a barometric bias
state unless
- Aiding. GNSS position and velocity, barometric altitude with bias estimation, magnetometer heading (World Magnetic Model declination), and ZUPT/ZARU. Chi-squared innovation gating with recovery.
- Initialization. Coarse alignment, IMU calibration and lever-arm compensation via the
InsEnginebuilder. - GNSS degradation.
- Schedulers: pass-through, fixed interval, duty-cycle outages.
- Faults: correlated AR(1) noise, slow bias drift, position hijacking, combinations.
- Configured from TOML, YAML or JSON files, or from CLI flags.
- Synthetic trajectories with IMU error models by sensor grade (
strapdown-sim syn). - Metrics. RMSE, CEP, NEES and NIS.
- Output. The CLI writes CSV. The library also writes HDF5, NetCDF and MCAP.
- Experimental: gravity and magnetic anomaly map aiding (
strapdown-geonav).
It is loosely coupled only. There are no pseudorange or carrier-phase models, and no raw-signal processing.
The repository is a two-language monorepo. The Rust crates form a Cargo workspace. The
Python package is a uv workspace declared by the root
pyproject.toml. Neither is a member of the other.
| Path | Language | What it is |
|---|---|---|
core/ |
Rust | strapdown-core: mechanization, filters, measurement models, scenario engine |
sim/ |
Rust | strapdown-sim: the command-line simulator |
geonav/ |
Rust | strapdown-geonav: experimental gravity and magnetic anomaly aiding |
analysis/ |
Python | the analyze CLI: preprocessing, measurement statistics, result comparison |
examples/ |
— | scenario configuration files |
conf/ |
— | the experiment recipes behind the published results |
rust-toolchain.toml fetches the pinned Rust toolchain (1.91) on the first cargo command.
What else you need depends on what you build.
Library only. strapdown-core with default features needs nothing beyond Rust:
cargo add strapdown-core --git https://github.com/jbrodovsky/strapdown-rsThe library crate is imported as strapdown:
use strapdown::StrapdownState;Simulator.
cargo install --git https://github.com/jbrodovsky/strapdown-rs strapdown-simIts default plotting feature, and the HDF5 and NetCDF features, compile C libraries from
vendored sources. Those builds need a C/C++ compiler and cmake 3.26 or newer, and
HDF5_DIR must be unset. See the installation guide.
The crates are also published to crates.io. Version 1.0.0 is released there together with the JOSS paper; until then, install from git as above.
Developing. From a clone:
cargo build --workspace --releaseuv syncjust setup runs both. The analyze map-drawing subcommands also need the GMT C library;
every other subcommand runs without it.
# A 10-minute synthetic trajectory: noisy IMU, GNSS and barometer records (add --no-noise for the truth)
strapdown-sim syn -o synthetic.csv --duration-s 600 --seed 42
# Closed loop (ESKF) with a duty-cycled outage: 50 s denied, then 100 s available, repeating
strapdown-sim cl -i synthetic.csv -o eskf.csv --seed 42 --sched duty --on-s 100 --off-s 50
# Dead reckoning: no aiding at all
strapdown-sim dr -i synthetic.csv -o dr.csvUse --filter ukf or --filter ekf to select another filter. strapdown-sim pf runs the
particle filter. strapdown-sim <command> --help lists every option. Logging is controlled
with --log-level and --log-file; see the
logging guide.
Geophysical aiding is experimental and behind a feature:
cargo install --git https://github.com/jbrodovsky/strapdown-rs strapdown-sim --features geonavstrapdown-sim cl -i data.csv -o out.csv --geo --gravity-resolution one-minuteTwo worked examples live in core/examples/. Both generate their own
trajectory, so there is no dataset to fetch first.
# Minimal InsEngine usage: propagate IMU, fuse GNSS, read the solution.
cargo run -p strapdown-core --example basic_ins# Coasting through a GNSS outage, and recovery when the signal returns.
cargo run -p strapdown-core --example gnss_outageRead basic_ins first. It is the propagate/update/read loop that every application is
built around, on a trajectory simple enough to check by hand. It also spells out the
specific-force sign convention, the most common way to get a first integration wrong: an
accelerometer at rest reads −9.81 m/s² on the down axis in NED, because it senses the
ground pushing up.
Then gnss_outage. It shows the error staying flat while aided, growing while coasting,
and collapsing on recovery. It then explains why the coasting error is several times
smaller than double-integrating the accelerometer bias would predict: the filter absorbed
most of the bias into a fraction of a degree of pitch, which position and velocity aiding
cannot tell apart from bias.
# Every Rust test, all features (as CI runs it)
cargo test --workspace --all-features# The minimal-feature configuration CI also tests
cargo test-min# The Python analysis package
uv run pytest -qThe accuracy regression suite (core/tests/perf_baseline.rs) runs every filter over
recorded and synthetic scenarios. It fails if a gated metric moves beyond tolerance. Its
results are published as the
performance baselines
page. CI runs on Linux, macOS and Windows.
- Bugs and feature requests: open an issue.
- Questions about using the toolkit: open an issue with the question template.
- Contributions: see CONTRIBUTING.md for the setup, the lint gate and the pull-request checklist.
This project follows the Contributor Covenant.
If you use strapdown-rs in research, please cite it using CITATION.cff
(GitHub's "Cite this repository" button). The JOSS paper is under review; its DOI will be
added on acceptance.
MIT. See LICENSE.