Skip to content

Releases: ashfordeOU/kshana

v0.16.0

11 Jun 22:13

Choose a tag to compare

Added

  • Reference-grade precise orbit determination, cross-validated against real
    agency products.
    A new batch least-squares estimator (src/precise_od.rs)
    with a variational state-transition matrix and outlier editing, driven by a
    full force model (PreciseForceModel: EGM2008 geopotential, third bodies,
    solid + ocean + atmospheric tides, and empirical CPR/2-per-rev accelerations),
    fed by a real IERS finals2000A Earth-orientation parser. Validated against
    published reference orbits: Galileo MEO to 13 cm post-fit, ESA Swarm-A
    LEO
    , and LRO lunar (selenocentric, GRAIL gravity, IAU-2015 body frame —
    reduced-dynamic 6.6 m, honestly above the 5 m target on the open path; the
    DE-grade ANISE/DE440 path that reaches it is a workspace-excluded crate).
  • spoof-detect scenario — an integrated multi-layer spoofing detector
    combining per-epoch RAIM parity, AGC and signal-quality (SQM) monitors and a
    fused decision, validated against the published TEXBAT scenario parameters
    (Humphreys et al., ION GNSS 2012), including the carrier-aligned hard case.
  • ephemeris scenario — state, frames, ground track and Doppler. Propagate
    one satellite (TLE→SGP4 or an analytic orbit) and emit, per step, the inertial
    TEME and GCRS state (position and velocity), the Earth-fixed ITRF/ECEF
    position, the WGS-84 sub-satellite ground track (latitude / longitude /
    altitude), and the topocentric azimuth / elevation / range with range-rate and
    Doppler from a ground station. Reachable from the CLI, Python, WASM and the
    MCP server, and shipped as the "Ground track" preset in the web playground,
    where the track is drawn over a real world map (Natural Earth 1:110m
    coastlines, embedded — no network or external dependency).
  • CCSDS OEM export (--export-oem / export_oem = true) — the
    velocity-carrying Orbit Ephemeris Message consumed by GMAT / Orekit / STK, at
    parity with the existing SP3 and OMM exporters.
  • Solid, ocean (FES2004) and atmospheric (Ray 2001 S2) Earth tides on the
    geopotential (IERS Conventions Ch. 6), wired into the force model.
  • ARM64 wheels — the PyPI build now also produces Linux aarch64
    (manylinux_2_28), macOS arm64 and Windows arm64 wheels.
  • Extended technical report (preprint) linked from the README, and the JOSS
    paper made submittable (author ORCID, compiled to PDF in CI on every change).

Changed

  • Frames validated to the millimetre against published Vallado vectors. The
    TEME→PEF/ITRF reduction, the full CIO IAU 2006/2000A GCRS→ITRS chain and the
    ECEF→geodetic WGS-84 conversion are now pinned to the worked example in Vallado
    et al. (AIAA 2006-6753) with its IERS EOP, not just to internal self-consistency.
  • Independent time-scale cross-checks. ERA and the UTC/TAI/TT scales agree
    with hifitime to < 1 µs, and the DE440 planetary ephemeris agrees with JPL
    Horizons (Moon/Sun geocentric positions), both as always-on CI gates.
  • The web playground hides the figures-of-merit tab when a result carries no
    figure-of-merit rows, so chart-only packs (ephemeris, RAIM, spoof) open on
    their chart — for ephemeris, the ground track — instead of an empty table.
  • The playground's guided sliders and parameter sweep now work for the
    ephemeris / ground-track scenario
    : its knobs (station latitude / longitude,
    time step, duration, UT1−UTC) are tunable, and a sweep can plot pass geometry
    (max elevation, peak Doppler, altitude, speed) against any of them — e.g. max
    elevation vs station latitude. The Sweep tab is now shown only when a scenario
    is actually sweepable, so no pack offers a control that plots nothing.
  • Documented the SGP4 DUT1 ≈ 0 approximation at the GMST call site (a ≤ ~13″
    rotation error, well inside SGP4's own model error) and refreshed CAPABILITY.md.

Get this release

Download — attached below, prebuilt (no toolchain needed); each artifact carries
SLSA build-provenance (verify with gh attestation verify <file> --repo AshfordeOU/kshana):

  • kshana — the simulator CLI / engine (Linux x86-64)
  • kshana-mcp — the Model Context Protocol server (Linux x86-64)
  • kshana-sbom.cdx.json — CycloneDX SBOM
  • kshana-validation-summary.html — the per-release validation summary

On macOS or Windows, install from a registry below — the PyPI wheels, the npm/WASM
package, and the Docker image are all cross-platform.

Install from a package registry:

Channel Get it
crates.io cargo install kshana · cargo install kshana-mcp
PyPI pip install kshana
npm npm install kshana
ghcr.io docker run -i ghcr.io/ashfordeou/kshana-mcp:0.16.0
MCP registry io.github.ashfordeOU/kshana-mcp (auto-discovered by MCP clients)
JetBrains Marketplace search "Kshana" in your IDE → Plugins

No install: run it in your browser at kshana.dev · Cite: DOI 10.5281/zenodo.20528627


Full changelog: CHANGELOG.md · Docs: README

v0.15.1

09 Jun 15:02

Choose a tag to compare

Added

  • The Kshana — PNT simulator JetBrains plugin is now published and approved on the
    JetBrains Marketplace.
    README, kshana.dev, and the distribution docs link to it directly.

Fixed

  • MCP registry publish now succeeds: the server.json description was over the
    registry's 100-character limit (HTTP 422). Shortened it, and aligned the server name
    (and the image's ownership label) to the canonical namespace
    io.github.ashfordeOU/kshana-mcp.
  • JetBrains Marketplace publish now succeeds: the CI re-uploaded the same plugin
    version that was listed manually, which the Marketplace rejects. The plugin version is
    bumped to 0.1.1, and the idempotency guard now also treats an "already contains
    version" response as a no-op success.
  • kshana.dev cache-busting: the version-stamped style.css/app.js query strings
    track the release, so returning visitors always get the current build.

Get this release

Download — attached below, prebuilt (no toolchain needed); each artifact carries
SLSA build-provenance (verify with gh attestation verify <file> --repo AshfordeOU/kshana):

  • kshana — the simulator CLI / engine (Linux x86-64)
  • kshana-mcp — the Model Context Protocol server (Linux x86-64)
  • kshana-sbom.cdx.json — CycloneDX SBOM
  • kshana-validation-summary.html — the per-release validation summary

On macOS or Windows, install from a registry below — the PyPI wheels, the npm/WASM
package, and the Docker image are all cross-platform.

Install from a package registry:

Channel Get it
crates.io cargo install kshana · cargo install kshana-mcp
PyPI pip install kshana
npm npm install kshana
ghcr.io docker run -i ghcr.io/ashfordeou/kshana-mcp:0.15.1
MCP registry io.github.ashfordeOU/kshana-mcp (auto-discovered by MCP clients)
JetBrains Marketplace search "Kshana" in your IDE → Plugins

No install: run it in your browser at kshana.dev · Cite: DOI 10.5281/zenodo.20528627


Full changelog: CHANGELOG.md · Docs: README

v0.15.0

08 Jun 21:07

Choose a tag to compare

Added

  • kshana-mcp — Kshana as a Model Context Protocol (MCP) server (mcp/kshana-mcp/).
    A standalone, workspace-excluded crate (the rmcp SDK is edition 2024) that exposes the
    validated engine to AI agents and assistants — Cursor, JetBrains AI Assistant / Junie,
    and any MCP client — over stdio. Tools: run_scenario, list_scenario_kinds,
    validate_scenario, export_sp3, export_omm, each a thin wrapper over kshana::api.
  • JetBrains IDE plugin (ide/jetbrains/). Right-click a scenario .toml
    Run Kshana Scenario; figures of merit and result JSON stream into a Kshana tool
    window. Pure-platform Kotlin plugin, compatible with every JetBrains IDE 2024.3+.
  • Public distribution + per-release auto-publish for both:
    • kshana-mcp to crates.io (cargo install kshana-mcp) via publish.yml.
    • kshana-mcp as a multi-arch OCI image on ghcr.io
      (docker run ghcr.io/ashfordeou/kshana-mcp) via a new mcp-publish.yml.
    • kshana-mcp to the official MCP registry via GitHub OIDC (zero secrets); the
      registry entry (server.json) uses the OCI package type with a label-verified owner.
    • the IDE plugin to the JetBrains Marketplace via publishPlugin (token-gated,
      optional developer signing) on each release tag.

Get this release

Download — attached below, prebuilt (no toolchain needed); each artifact carries
SLSA build-provenance (verify with gh attestation verify <file> --repo AshfordeOU/kshana):

  • kshana — the simulator CLI / engine (Linux x86-64)
  • kshana-mcp — the Model Context Protocol server (Linux x86-64)
  • kshana-sbom.cdx.json — CycloneDX SBOM
  • kshana-validation-summary.html — the per-release validation summary

On macOS or Windows, install from a registry below — the PyPI wheels, the npm/WASM
package, and the Docker image are all cross-platform.

Install from a package registry:

Channel Get it
crates.io cargo install kshana · cargo install kshana-mcp
PyPI pip install kshana
npm npm install kshana
ghcr.io docker run -i ghcr.io/ashfordeou/kshana-mcp:0.15.0
MCP registry io.github.ashfordeOU/kshana-mcp (auto-discovered by MCP clients)
JetBrains Marketplace search "Kshana" in your IDE → Plugins

No install: run it in your browser at kshana.dev · Cite: DOI 10.5281/zenodo.20528627


Full changelog: CHANGELOG.md · Docs: README

v0.14.1

08 Jun 16:39

Choose a tag to compare

Added

  • Independent ANISE/SPICE reference-frame cross-validation (xval/anise-frames/).
    A standalone, workspace-excluded crate cross-checks kshana's IAU 2006/2000A CIO
    reduction (kshana::cio::gcrs_to_itrs_matrix, GCRS→ITRS) against ANISE (the
    pure-Rust NAIF/SPICE reimplementation) rotating GCRF→ITRF93 from JPL's
    earth_latest_high_prec.bpc, with the same IERS finals2000A Earth-orientation
    parameters fed to both sides
    , over eight quarterly epochs 2020–2023. The two
    independent frame realizations agree to a maximum relative rotation of 0.028″ —
    ≤ 0.86 m on the ground, ≤ 0.93 m at LEO, ≤ 3.6 m at GNSS orbit
    , meeting the
    long-standing ROADMAP "< 10 m" frame cross-check with large margin (it complements,
    and does not replace, the existing bit-for-bit SOFA/ERFA anchors). The crate is
    isolated because anise + hifitime are MPL-2.0 / edition-2024 and must never enter
    the published kshana dependency graph, its Cargo.lock, the cargo deny license
    gate, or the MSRV build; ANISE is pinned default-features = false. Includes a
    frame-xval binary (fetches the ~5 MB BPC, prints a table, writes report.{json,md}),
    a kernel/network-self-skipping test gate, and an optional workflow_dispatch-only CI
    job (never blocks main). Documented in docs/VALIDATION.md (CIO row) and ROADMAP.md.

Fixed

  • Mobile-friendly playground. Fixed horizontal overflow of the playground .panel
    on phones (a CSS-grid item defaulting to min-width: auto rendered ~100 px wider than
    the viewport) via min-width: 0 and width-guarded controls; verified clean at 360 /
    390 / 414 / 768 px. Aligned the "Pin to compare" / "Download report" action buttons
    (equal margin boxes in the flex row). Enlarged run buttons, sliders, selects and nav
    links to the ~44 px WCAG 2.5.5 / Apple-HIG touch-target minimum on phones and touch
    devices, with desktop sizing unchanged.

Full changelog: CHANGELOG.md · Docs: README

v0.14.0

08 Jun 13:28

Choose a tag to compare

Fixed

  • Robustness hardening from an adversarial battle-test pass. (1) sbas_protection_level now
    rejects non-finite elevation/azimuth/variance and negative or non-finite covariance diagonals
    (a near-singular geometry scaled up by small σ could previously slip the absolute-pivot gate and
    return a NaN VPL / absurd HPL as a valid Some — a silent integrity failure). (2) The
    numerical propagator (propagate/propagate_dopri) fails closed on a non-finite initial state
    instead of spinning the adaptive controller forever. (3) The DEM cell helper no longer panics on
    a single-sample (1×N) grid. (4) lunar_look_angle azimuth is held strictly in [0, 360).
    (5) SphericalHarmonicField::from_gfc rejects non-physical (NaN / non-positive) GM/radius.

Added

  • validation_report binary + release artifact: a dependency-free generator that emits a
    one-page, print-ready HTML validation summary indexing every CI-enforced validation (SGP4
    666/666, EGM2008, bit-for-bit frames, NIST Allan, IMU datasheets, ARAIM/SBAS, 3-OS
    reproducibility, coverage) to its test and external oracle. The release workflow generates
    kshana-validation-summary.html and attaches it (with SLSA provenance) to each tagged release.
  • numpy-interop pytest + wheel hardening: tests/python/test_numpy_interop.py (run in CI)
    plus a pinned manylinux container and an auditwheel show verification step in the wheel build.
  • Tutorials & education: docs/tutorials/ (three worked tutorials, per-domain annotated
    scenarios, Tier-1/2/3 exercises) with tests/tutorials.rs pinning every quoted number to live
    engine output.
  • External submission artifacts (paper/, notebooks/, submissions/): a JOSS paper
    draft, a quantum-vs-classical notebook, and ready-to-file kits for awesome-gnss / ESA Navipedia
    / NASA ASCL / ESA ESSR / ION/IAC, plus FUNDING.yml — staging the external steps for submission.
  • Terrain-referenced & combined alt-PNT navigation (altpnt module): a TERCOM/SITAN
    terrain-matching navigator over a DEM (.hgt loader + synthetic-fixture generator) and a
    combined gravity + magnetic (IGRF) + terrain GPS-denied navigator, exposed as terrain-nav and
    combined-altpnt scenario kinds. Validated by terrain-match convergence (a known injected
    offset recovered) and a bounded combined-filter error over a GPS-denied window.
  • LunaNet LANS geometry (lunar): named lunar surface sites (Apollo 11/15/16, Shackleton
    rim) with authoritative selenographic coordinates, surface look angles (az/el/range),
    visibility/coverage, and site DOP, validated against the Moon radius, the published site
    coordinates, and the radial-overhead 90° elevation identity.
  • Guided browser playground: guided-mode sliders, a tabbed output panel, a first-run tour
    overlay, parameter-sweep and multi-run-overlay modes, a dependency-free canvas/SVG 3D orbit
    view (the orbit pack now emits an additive eci_track), an embed/iframe mode, and
    download-as-HTML-report — each with node unit tests in CI.
  • Datasheet-validated IMU error model (tests/imu_allan_spec.rs): ADIS16465/16488/16460
    ARW/VRW/bias-instability recovered from the synthesised Allan deviation and checked against the
    manufacturer specs (NIST SP1065 / IEEE 952 identification).
  • NIST SP1065 Allan-estimator validation (tests/allan_nist_sp1065_1000point.rs): the four
    estimators reproduce the published 1000-point reference deviations and Table-32 confidence
    bounds.
  • SBAS / DO-229E protection levels, L1/L5 ionosphere-free, and a DO-316 compliance map
    (sbas module). sbas_protection_level forms the weighted geometry matrix from each
    satellite's elevation/azimuth and UDRE/GIVE/airborne/tropo error budget, inverts the normal
    matrix (shared orbit::invert4), and projects the variances into HPL/VPL via the DO-229E
    K-factors (PA 6.0/5.33, NPA 6.18). iono_free_l1l5 adds the GPS L1/L5 ionosphere-free
    pseudorange (IS-GPS-705, γ₁₅ = 1.79327), validated to cancel the engine's independent
    first-order ionospheric delay. do316_compliance_map traces DO-316/DO-229E requirements to
    the implementing functions. Validated against closed-form K-factor definitions, the numpy
    inv(GᵀG) reference geometry, and the two-route covariance identity; the published-PL
    RTKLIB/gLAB conformance cross-check is documented as founder-gated in docs/COMPLIANCE.md.
  • Full tesseral spherical-harmonic gravity — the EGM2008 field to degree/order 70.
    A new gravity_sh::SphericalHarmonicField evaluates the geopotential and its acceleration
    in the Earth-fixed frame from fully-normalized C̄_nm, S̄_nm coefficients, using the stable
    Holmes–Featherstone normalized Legendre recurrence (de-normalizing would overflow at this
    degree). The shipped coefficients are the NGA EGM2008 product (public domain, via ICGEM),
    bundled in egm2008_data.rs and reproduced bit-for-bit by tools/gen_egm2008.py from the
    committed tools/egm2008_to70.gfc; any ICGEM .gfc model loads via from_gfc. Validated
    against three independent oracles: point-mass collapse (C̄00-only = −μr/|r|³), a zonal-only
    field reproducing the existing forces::zonal_accel to ~1e-9, and the analytic acceleration
    matching the finite-difference gradient of the directly-summed potential to <1e-6.
  • General-relativistic Lense–Thirring (frame-dragging) acceleration
    (forces::lense_thirring_accel, IERS 2010 Eq. 10.12), the gravitomagnetic term beyond the
    existing Schwarzschild correction, wired into the numerical propagator via a new
    ForceModel::lense_thirring() flag. Validated as linear in the Earth's angular momentum and
    1–2 orders of magnitude below the Schwarzschild term, the regime of the LAGEOS / Gravity
    Probe B measurements.
  • A Propagator trait unifying the analytic and numerical orbit propagators. The
    numerical Cowell force-model propagator is now a first-class peer of SGP4: a new
    NumericalPropagator type (initial state + ForceModel + Tolerance + choice of
    step-doubling or Dormand–Prince Integrator) and Sgp4 both implement
    propagator::Propagator, whose state_at(t_seconds) -> StateVector returns the inertial
    TEME state in SI units (m, m/s) so the two are interchangeable behind a
    Box<dyn Propagator>. The SGP4 impl is the exact km/min→SI conversion of the inherent
    method (verified by an equality test); the numerical impl clears the same sub-metre
    exact-Kepler gate through the trait, the two adaptive drivers agree, and a PropagatorError
    surfaces the underlying SGP4 code.

Full changelog: CHANGELOG.md · Docs: README

v0.13.0

08 Jun 08:23

Choose a tag to compare

This release closes the largest correctness gap in the engine: Earth-orientation
and reference-frame reduction are now done to reference-implementation grade
(validated bit-for-bit against ERFA/SOFA), the integrity stack gains
dual-constellation ARAIM on real GPS+Galileo TLEs, and the propagation,
quantum-sensor, lunar/cislunar, and geomagnetic layers all deepen — alongside a
typed Python API, a richer browser playground, and a three-OS reproducibility
matrix. Highlights:

  • Reference frames, bit-for-bit. Full IAU 2000A and 2000B nutation, IAU 2006
    precession, the CIO-based (X, Y, s) IAU 2006/2000A GCRS↔ITRS reduction, IERS
    polar motion, and TEME→GCRS/ITRS output frames — each validated bit-for-bit
    against ERFA/SOFA reference routines.
  • Dual-constellation ARAIM (GPS + Galileo) on real TLEs, with HPL/VPL,
    Stanford-diagram output, and an open docs/ARAIM_REFERENCE.md.
  • Cislunar PNT: an Earth–Moon CR3BP propagator, MCI↔MCMF frames, selenographic
    coordinates, and a runnable LunaNet lunar-integrity scenario.
  • Quantum sensing: Coriolis and AC-Stark systematics for the cold-atom
    interferometer, a drift sweep, and validation against the Freier (2016) budget.
  • IGRF-14 geomagnetic main-field model, self-contained and validated.
  • Typed Python API (PyO3 RunOutput/ScenarioMeta, .data(), scenario_kinds,
    validate_toml, type stubs) with a CI wheel build, plus first-class GCRS/ITRS
    propagator output and CCSDS OMM export.
  • Credibility & reproducibility: a head-to-head SGP4 accuracy comparison against
    the independent sgp4 crate, a CI coverage gate (~97% line on src/), and a
    three-OS (ubuntu/macos/windows) reproducibility matrix.

Changed

  • Every playground chart now matches the site theme. All twelve SVG chart
    generators — the result/holdover chart (src/report.rs + src/chart.rs), the
    Allan-deviation chart (web/app.js), and every scenario chart (src/hybrid.rs,
    jamming.rs, timetransfer.rs, spoof.rs, raim.rs Stanford + availability,
    lunar.rs, ensemble.rs, sweep.rs, gnss_sim.rs, fusion/pack.rs,
    inertial/mod.rs) — used cool navy panels (#0e131b), cool-gray axes/text, and
    a clashing red/blue/purple series palette. They now use the warm graphite palette
    throughout: --bg panels, warm --line grid, --fg labels, with a consistent
    series assignment — quantum = honey-gold (--accent-bright), classical = warm
    amber (--partial), spec/limit = --crit. Safety-coded views keep their
    meaning: the RAIM Stanford diagram stays green (available) / amber (misleading) /
    red (hazardous) / muted steel (unavailable), and HPL/VPL read as gold/bronze.
  • Charts are now self-describing when saved/downloaded. Both charts bake their
    title into the SVG (the Allan chart's title + "lower is better" subtitle were
    previously only HTML around the image, so a saved image had no caption), and both
    carry a provenance footer — Kshana v<version> · <scenario-hash> · kshana.dev
    so a downloaded chart stands on its own and stays reproducible.
  • Every chart now carries the provenance footer. The footer —
    Kshana v<version> · scenario <hash> · kshana.dev — is stamped centrally for all
    scenario kinds in api::run_toml (it was previously only on the holdover and Allan
    charts), so any saved or downloaded image — from the playground, the CLI's
    .chart.svg export, or the HTML scorecard — identifies its version, scenario
    fingerprint, and source. The hash is labelled scenario for clarity and comes from
    the result's scenario_hash where present, with a source-hash fallback for the
    integrity/lunar reports. What the fingerprint is and why it's there is documented in
    the README "Output" section and docs/PROVENANCE.md.

Fixed

  • raim::chi2_quantile and the RAIM Stanford-noise sampler are now panic-free on
    out-of-range / non-finite inputs
    (a read_dir-order-dependent fuzz finding from
    the new ARAIM scenarios). chi2_quantile now guards p/k like normal_quantile
    (returning a boundary value instead of assert!-panicking), and the availability
    Stanford-noise Normal clamps to a strictly-positive σ — so the integrity/ARAIM
    stack never panics on mutated or mis-configured scenarios.

Added

  • Cross-platform reproducibility CI matrix. A new reproducibility-matrix
    job runs the reproducibility tests on ubuntu-latest, macos-latest, and
    windows-latest
    on every push. Because full result JSON is not byte-identical
    across OSes (last-ULP libm divergence), it asserts the platform-invariant
    projection exactly — the input fingerprint plus output shape, pinned per
    scenario as SHA-256 goldens in tests/golden/ by the new
    tests/cross_platform_golden.rs — alongside the numeric pins (golden.rs, to
    1e-6), the SGP4 states (sgp4_verification.rs, to 2e-5 km), and same-process
    determinism (determinism.rs). Together these prove cross-platform
    reproducibility on three OSes without the brittleness of exact full-output byte
    hashing. docs/REPRODUCIBILITY.md documents the split.
  • Code-coverage gate in CI. A new coverage job runs cargo-tarpaulin with
    the LLVM source-based engine, publishes an lcov report as a build artifact, and
    enforces a line-coverage floor on src/ (generated data tables, the CLI
    entrypoint, the tests, and web assets excluded). Measured line coverage is
    ~97% on src/ (SGP4 and the clock modules ≥95%); the gate is set at 85% — above
    the ≥80% target and clear of the measured value, so it catches regressions
    without flaking. A coverage badge is published in the README.
  • SGP4/SDP4 head-to-head against the independent sgp4 crate. A new test
    (tests/sgp4_crate_comparison.rs) cross-validates Kshana's propagator against
    the most widely used Rust SGP4 library (neuromorphicsystems/sgp4, added as a
    test-only dev-dependency) over the same 666 AIAA 2006-6753 vectors. With both
    driven on the WGS72 gravity model the vectors use, the two independent
    implementations agree to sub-micron on near-earth and resonant orbits and
    4.12 mm worst-case across all regimes, both reproducing the reference
    tcppver.out table. The committed comparison table
    (tests/fixtures/sgp4_comparison.md, regenerated via KSHANA_REGEN_FIXTURES=1)
    breaks the result out per regime (LEO/MEO, deep-space, ½-day and 1-day
    resonance) and notes the four deliberately-pathological cases the crate rejects
    at construction. The live assertions hold both within 2e-5 km of the reference
    and agree to within 4e-5 km — a regression guard, not a one-off. This is
    competitive pedigree: correctness against an independent codebase, not just a
    static table. (The crate's default from_elements uses WGS84 and so differs
    from the WGS72 reference by ~km — surfaced honestly in the table prose.)
  • CCSDS OMM export is now reachable end-to-end. The OMM writer
    (src/omm.rs) previously had no CLI/API path; an orbit scenario's mean
    elements can now be published as a CCSDS 502.0-B-2 OMM catalogue — one OMM KVN
    message per TLE-defined satellite — via kshana <orbit.toml> --export-omm out.omm, or export_omm = true in the scenario auto-writes <scenario>.omm
    (mirroring the existing --export-sp3). Each message carries the satellite's
    real NORAD catalogue number, COSPAR international designator (YYYY-NNNP),
    and epoch (CCSDS day-of-year form), parsed from the TLE line 1 by the new
    tle::parse_tle_identity; the name line becomes OBJECT_NAME (else OBJECT <id>). CREATION_DATE is the scenario epoch, not wall-clock, so the output is
    reproducible. New API: api::export_omm / api::auto_export_omm,
    OmmFile::from_tle_block, OrbitClockScenario::to_omm_string. A synthetic
    Walker or RINEX scenario (no TLE mean elements) errors rather than emitting an
    empty file. Validated against the bundled 30-satellite gps-ops snapshot
    (tests/sp3_export_roundtrip.rs).
  • Interactive hover read-outs on the playground charts. Moving the cursor over
    a chart snaps a crosshair to the nearest sample and shows a value tooltip
    (web/hover.mjs, wired in web/app.js). On the Allan chart it reads τ and each
    clock's σ_y(τ); on the time-series scenario charts (clock holdover, dead-reckoning,
    time-transfer, hybrid PNT, GNSS/INS) it reads the time and each suite's value in
    the chart's own units (ns / m / ps / utilization), parsed from the result so the
    read-out matches the curve. Specialised diagrams (RAIM, spoof, sweep) get no
    overlay. The charts stay self-describing blob <img>s — the overlay is a
    transparent crosshair + tooltip on top, so download/compare/export are untouched.
    Coordinate math (nearest-sample, cursor→plot-fraction, polyline parsing) is
    unit-tested (web/hover.test.mjs, run in CI).
  • A/B compare mode in the playground. Pin any run as a baseline A, run a
    second scenario, and the two are shown side by side with a figure-of-merit
    delta table (holdover, timing RMS/p95, availability) that colours the winner
    per metric (web/compare.mjs, wired in web/app.js; delta logic unit-tested
    in web/compare.test.mjs, run in CI). All values are inserted as text and all
    charts via blob <img>, so nothing from a scenario string is ever injected as
    markup.
  • Chart download buttons (SVG + PNG). Each playground chart now has a
    theme-matched "Download SVG / PNG" toolbar (web/chartdl.mjs, wired in
    web/app.js). SVG hands back the faithful, scalable original; PNG rasterises
    that same self-describing image at 2x for slides and documents. Files are named
    with their provenance — kshana-<chart>-v<version>-<scenario-hash>.<ext> — and
    the filename/size logic is unit-tested (web/chartdl.test.mjs, run in CI).
  • IGRF-14 geomagnetic main-field model (src/igrf.rs). The IAGA standard
    spherical-harmonic field (degree/order 13, 2025.0 epoch + 2025–2030 ...
Read more

v0.12.0

06 Jun 19:31

Choose a tag to compare

This release lands Kshana's first non-analytic orbit propagator — a Cowell
integrator with a hierarchical six-perturbation force model (two-body + J2–J6 zonal +
epoch-driven Sun/Moon third body + solar-radiation pressure with a conical
umbra/penumbra shadow + atmospheric drag + the post-Newtonian Schwarzschild relativistic
correction) driven by a choice of two adaptive integrators (RK4 step-doubling and the
Dormand–Prince RK5(4) embedded pair) — alongside a maneuver / trajectory-design layer
(impulsive and finite burns, an Izzo Lambert solver, and a porkchop sweep), a
gravity-map-matching alt-PNT layer that recovers a 60-minute GPS-denied track to under
500 m, a batch + sequential orbit-determination pipeline, and a full 17-state
tightly-coupled GNSS/INS UKF with quantum-CAI dead-reckoning. Every numerical capability
is pinned against analytic truth or a hand-derived closed form; the off-by-default
perturbations leave the released goldens untouched.

Added

  • Post-Newtonian (Schwarzschild) relativistic correction (forces::relativistic_accel +
    propagator::ForceModel::relativity).
    Adds the dominant general-relativistic perturbation on a
    near-Earth orbit — the leading driver of the relativistic perigee advance — in the IERS /
    Montenbruck–Gill β = γ = 1 form a = (μ/c²r³)·{[4μ/r − v²]·r + 4(r·v)·v}. Like atmospheric
    drag it is velocity-dependent, so it rides the (r, v) integrator RHS via
    [accel_rv], opt-in and off by default. Validated self-contained: on a circular orbit it
    collapses to the closed form 3μ²/(c²r³)·r̂ (purely radial and outward, off-axis components
    exactly zero); its ratio to two-body is the textbook ≈1.9·10⁻⁹ at LEO (the μ/(c²r)
    signature); a radial-velocity case matches the hand-simplified μ(4μ + 3v²r)/(c²r³); and in the
    propagator it perturbs the orbit without dissipating it — the semi-major axis is conserved to
    well under a metre/day, the structural opposite of drag's monotonic decay. Because it is off by
    default the two-body/J2/zonal goldens are untouched. PPN-parameter (β,γ) tuning and the
    Lense–Thirring frame-dragging term remain follow-ons.
  • Conical umbra+penumbra shadow model (forces::conical_shadow), now used by solar-radiation
    pressure.
    Upgrades the binary umbral-cylinder eclipse to a smooth ν ∈ [0,1] factor: the Sun
    and Earth are modelled as disks of apparent angular radii a = asin(R☉/d☉), b = asin(Rₑ/|r|)
    with apparent centre separation c, and ν is one minus the fraction of the Sun's disk occulted
    by the Earth's disk (the circle–circle lens-overlap area) — full sun for c ≥ a+b, total umbra
    for c ≤ b−a, annular for c ≤ a−b, and a continuous penumbra in between. srp_accel now uses
    it, so the SRP force tapers smoothly through eclipse instead of switching on/off. Adds the IAU
    nominal forces::SOLAR_RADIUS. Validated self-contained: ν = 1 in full sun and ν = 0 deep in
    the umbra (exact), a smooth monotonic penumbra (ν rises 0 → ~½ at c = b → 1 across the
    [b−a, b+a] band), and the conical penumbra extends beyond the umbral cylinder (a point the
    binary cylinder calls fully lit is 0 < ν < 1 for the cone). The simpler cylindrical_shadow
    remains available; solar limb darkening and the oblate-Earth shadow remain follow-ons.
  • Dormand–Prince RK5(4) embedded integrator (integrator::dopri54_step /
    integrator::integrate_dopri + propagator::propagate_dopri).
    Adds the standard
    Dormand–Prince (1980) embedded Butcher-tableau pair alongside the existing RK4 step-doubling
    driver: seven FSAL stages yield a 5th-order solution and a 4th-order error estimate from one set
    of evaluations (7 vs 11 function calls per step), a cheaper local-error estimate. The adaptive
    driver reuses the same RMS-error norm and 0.9·(1/err)^(1/5) step controller, so it is a drop-in
    alternative; propagator::propagate_dopri exposes it on the orbit force model. Validated
    self-contained: the embedded error estimate is O(h⁵) (halving the step cuts it ~32×); DP5(4)
    integrates y' = y to e and the harmonic oscillator over 50 periods conserving energy to
    <1e-6; it reaches the same endpoint at the same tolerance in fewer function evaluations than
    step doubling (without sacrificing accuracy); and propagate_dopri clears the same analytic-truth
    gate as the RK4 path — sub-metre against the exact universal-variable Kepler solution over a
    24 h LEO orbit
    — while the two drivers agree to <1 m on a J2..J6 orbit (no closed form). Higher
    embedded pairs (RKF7(8) / DOP853) remain a follow-on.
  • Atmospheric drag wired into the propagator as its first velocity-dependent force
    (forces::atmospheric_density + forces::drag_accel + propagator::ForceModel::drag).
    Adds
    the Vallado Table 8-4 piecewise-exponential atmosphere ρ = ρ0·exp(−(h−h0)/H) (28 bands from
    sea level past 1000 km, clamped below the surface) and the quadratic drag
    a = −½ · ρ(h) · (C_D·A/m) · |v_rel| · v_rel against the co-rotating atmosphere
    v_rel = v − ωₑ ẑ × r (forces::EARTH_ROTATION_RATE = 7.2921151467e-5). Because drag depends on
    velocity, ForceModel gains a new accel_rv(t, r, v) and the integrator RHS now passes velocity
    (f(t,[r;v]) = [v; a(t,r,v)]); the position-only accel_at is unchanged, so the conservative
    terms and goldens are untouched. Validated self-contained: the density anchors at the
    1.225 kg/m³ sea-level value
    , clamps below the surface, decreases monotonically through LEO,
    sits in the solar-mean ~1e-12 kg/m³ band at 400 km, and its recovered local scale height
    (≈ 58 km at 400 km)
    is physical; drag opposes the co-rotating relative velocity at the
    ~2e-6 m/s² LEO magnitude for C_D·A/m = 0.02 m²/kg; and — the key signature — drag is
    dissipative: a 300 km orbit loses specific energy monotonically and its semi-major axis
    decays a bounded ~km/day, where the vacuum baseline conserves energy to <1e-9. The
    NRLMSISE-00 thermospheric density (the < 5 % drag-density clause) remains a follow-on.
  • Solar-radiation pressure wired epoch-driven into the propagator force model
    (forces::srp_accel + propagator::ForceModel::solar_radiation).
    Adds the cannonball SRP
    model
    a = ν · P☉ · cᵣ · (A/m) · (AU/d)² · d̂ with a cylindrical-shadow eclipse factor
    (forces::cylindrical_shadow, ν ∈ {0,1}): the radiation pressure P☉ = Φ☉/c from the modern
    1361 W/m² total solar irradiance (≈ 4.5398·10⁻⁶ N/m²), the inverse-square (AU/d)² flux fall-off,
    and the radial push away from the Sun. It rides the same epoch-driven RHS as the third
    body, sampling the ephem Sun once at the advanced epoch epoch_jd_tt + t/86400 shared between
    the Sun third body and SRP. Composable:
    with_zonals_j2_j6().third_body(true, true, epoch).solar_radiation(1.5, 0.02). Validated
    self-contained against hand-derived signatures: the 1-AU radiation pressure pins to its textbook
    ≈ 4.5398·10⁻⁶ N/m²
    ; a fully-lit LEO sat's SRP is bit-identical to the cannonball formula,
    points away from the Sun, and sits in the ~1.36·10⁻⁷ m/s² band for cᵣ = 1.5, A/m = 0.02
    m²/kg; doubling the Sun distance quarters the magnitude (inverse-square); the cylindrical
    shadow eclipses only the umbral cylinder
    (anti-sunward and within one Earth radius of the
    Earth–Sun line) and yields exactly zero SRP in eclipse; and in the propagator SRP perturbs
    a LEO orbit by a small bounded amount that scales ~linearly with A/m
    — while a model with no
    perturbations stays bit-for-bit time-independent, leaving the two-body/J2/zonal goldens untouched.
    The conical umbra/penumbra (smooth ν ∈ [0,1]), atmospheric drag, and external GMAT/Orekit
    cross-validation remain follow-ons.
  • Epoch-driven Sun/Moon third body wired into the time-varying propagator RHS
    (propagator::ForceModel::third_body / accel_at).
    The third-body perturbation is no longer a
    standalone force term — it is now integrated by the Cowell propagator as a genuinely time-varying
    force: each RHS evaluation samples the ephem Sun/Moon positions at the advanced epoch
    epoch_jd_tt + t/86400
    (reusing precession::julian_centuries_tt for the day↔century
    conversion), so the perturbers move along their orbits during the integration rather than being
    frozen at the start. Composable with any gravity model
    (ForceModel::with_zonals_j2_j6().third_body(true, true, epoch)). Validated self-contained:
    the RHS Sun term is bit-identical to third_body_accel evaluated at the ephemeris position for
    that instant at both t = 0 and t = 1 day (proving the 86400 s ↔ 1 day ↔ 1/36525 century
    wiring exactly), the perturber advances ~2.6·10⁹ m/day between samples (not frozen), the
    instantaneous LEO tidal magnitudes hit the textbook ~5·10⁻⁷ m/s² (Sun) and ~1.1·10⁻⁶ m/s²
    (Moon, ≈ 2× the Sun) bands, each body measurably perturbs the day-long trajectory while staying
    bounded
    , and the same initial state propagated at epochs a quarter-year apart yields a
    different trajectory
    (the tidal axis rotates 90°) — while a model with neither body enabled is
    bit-for-bit time-independent, leaving the two-body/J2/zonal goldens untouched. DE-grade ephemeris
    accuracy and external GMAT/Orekit cross-validation remain follow-ons.
  • Low-precision Moon ephemeris (ephem::moon_position), completing the Sun/Moon third-body pair.
    Adds the Montenbruck & Gill low-precision lunar series (§3.3.2) alongside the Sun model, so the
    body-agnostic forces::third_body_accel can now be driven by either luminary with no external
    DE/SPK kernel
    . Validated self-contained against hand-derived lunar signatures: the geocentric
    distance stays inside the real perigee/apogee envelope (~356 500–406 700 km) over a month and its
    monthly mean recovers the ~384 400 km semi-major axis; the **ecliptic latitude never exce...
Read more

v0.11.0

05 Jun 15:01

Choose a tag to compare

Changed

  • Honest framing for the quantum positioning. The headline descriptor is now a
    "PNT-resilience simulator with quantum-sensor performance models" consistently
    across the README tagline, citation line, CITATION.cff (title + abstract), and
    the banner artwork — replacing the looser "hybrid quantum/classical PNT simulator"
    marketing phrasing. The README's What it is / is not section gains an explicit
    "It is not (yet)" scope statement (not a first-principles atom-interferometry
    physics engine, not a GNSS receiver/PVT solver, not a mission-design tool), and a
    new top-level ROADMAP.md makes the Quantum physics layer a P2
    item
    (Mach–Zehnder CAI phase, projection noise, vibration tensor) so readers know
    the first-principles physics is scoped-and-coming, not abandoned. No behaviour or
    API change.

Added

  • Constellation-design trade study: Walker design sweep with a Pareto front, revisit-time
    JSON, and a sub-kilometre Walker-formula validation.
    src/walker.rs gains
    walker_design_sweep, which runs a planes × sats_per_plane grid (e.g. a 3×3 trade) at a
    fixed inclination and tabulates, per design, the coverage fraction, worst-case PDOP, and the
    max/mean revisit gap; pareto_front flags the non-dominated designs (fewer satellites, more
    coverage, lower PDOP, shorter revisit), and WalkerDesignReport::to_json serialises the cells
    and Pareto front — revisit-time fields included — as JSON. New validation pins the generator to
    the Walker i:T/P/F formula: same-slot satellites in adjacent planes are shown to map onto one
    another by an exact R_z(2π/P) rotation to under 1 km over a full 24 h of SGP4 propagation
    (the J2 short-period breathing is common-mode and cancels), and the in-plane slots are confirmed
    spaced 2π/S in the mean. Builds on the committed real Celestrak gps-ops 2021-07-28 snapshot
    (scenarios/orbit-sgp4-gps.toml, exercised by the scenario-coverage and SP3 round-trip tests).
  • Advanced time-and-frequency transfer: TWSTFT, GNSS common-view, PPP, optical, IEEE-1139
    power-law fit, and a clock ensemble.
    New src/timetransfer_adv.rs builds the operational
    transfer methods on the shipped Sagnac/common-view closed forms and the Allan-stability tools.
    twstft_sagnac gives the Two-Way Satellite Time and Frequency Transfer Sagnac correction as the
    three-hop loop sum, equal to the BIPM closed form Δt = 2·A·ω_E/c² exactly (cross-checked by the
    independent twstft_sagnac_bipm); run_twstft emits a one-day T_A − T_B series and its TDEV.
    gnss_common_view_series single-differences two synthetic ground stations so the satellite clock
    cancels. iono_free_combination + ppp_receiver_clock are the PPP ionosphere-free combination and
    receiver-clock solve against an SP3-grade (synthetic) truth, cancelling the first-order ionosphere
    exactly. rytov_variance, fried_parameter, and the unit-mean lognormal_fading model a free-space
    optical link's turbulence-induced scintillation. fit_power_law_psd is a full IEEE-1139 five-coefficient
    h_α least-squares fit of the Allan-variance curve (all five canonical noise processes at once) with the
    dominant process reported per τ-decade. ensemble_timescale forms an inverse-variance-weighted paper
    timescale whose Allan deviation falls strictly below the best contributing clock. 31 unit tests;
    validation targets are closed forms and synthetic truth — a real BIPM Circular-T / IGS SP3 ingest remains.
  • IONEX ionosphere maps: file parser, time interpolation, and slant obliquity mapping. src/ionex.rs
    gains parse_ionex, which reads the IONEX file format (header grid definition + START/END OF TEC MAP
    blocks) into a sequence of IonexMaps — normalising the file's north-to-south latitude ordering into a
    positive-step TecGrid and scaling values by 10^EXPONENT. interpolate_tec_in_time blends two
    successive maps to a query epoch, and obliquity_factor / slant_tec map the vertical TEC onto a slant
    ray via the single-layer thin-shell factor M(z) = 1/cos z′ (sin z′ = (Rₑ/(Rₑ+H))·sin z). Together
    with the shipped grid model these turn a measured IGS global ionosphere map into a usable slant delay.
  • Constellation design: streets-of-coverage sizing + multi-constellation comparison. src/walker.rs
    gains min_satellites_streets_of_coverage, an idealised streets-of-coverage minimum-satellite solver —
    from the shipped coverage half-angle λ and street half-width c it sizes the near-polar constellation
    for continuous single global coverage as p = ⌈π/(2c)⌉ planes (e.g. a GPS-altitude 4-satellite plane
    needs 2 planes, 8 satellites), and reports None when the satellites are too sparse to form a continuous
    street. compare_constellations is the multi-constellation comparison tool: it scores each named Walker
    design on the same station/window via pdop_sweep and returns their coverage / PDOP / size side by side.
    Honest scope: the seam-exact Rider correction at the counter-rotating plane boundary and a 3-D coverage
    globe are follow-ons.
  • Multi-layer spoof detection: RAIM-consistency parity detector + layer fusion. src/spoof_monitors.rs
    gains the third and final detection layer and the fusion stage: parity_raim_test least-squares-fits
    the position/clock solution to a redundant pseudorange set and tests the leftover weighted residual
    sum-of-squares against its χ²(m−4) threshold — flagging a biased subset of satellites while
    correctly leaving a common-mode bias (absorbed by the receiver clock) RAIM-invisible, not papered
    over. fuse_spoof_layers combines the parity, AGC and SQM layers into one weighted decision that
    records which layers fired. A Monte-Carlo characterises the detector: empirical P_fa ≈ 0.068
    against a 0.05 design point, with missed-detection falling from 0.885 at a 2σ spoof bias to 0.16 at
    . Honest scope: cross-validation against specific published (Spirent / ION GNSS+) spoofing test
    vectors needs those external datasets and remains a follow-on.
  • Coupled-vs-decoupled Kalman validation ensemble. A 100-trial Monte-Carlo in
    src/fusion/coupled.rs quantifies the value of carrying the position↔clock cross-covariance: a
    faithful inline decoupled baseline (validated bit-for-bit against the shipped CoupledPntFilter)
    processes the same data with the cross blocks zeroed, and after near-degenerate pseudoranges plus a
    clock-only fix the coupled filter recovers position to 2.97 m RMS versus the decoupled filter's
    48.8 m, winning 97 of 100 trials
    — the clock fix sharpens position only through the correlation
    the decoupled pack discards. This completes the Kalman-correctness validation suite (Joseph form,
    PSD safety, NEES/NIS consistency, and now the coupled-filter ensemble).
  • Orbit determination pipeline (batch + sequential). A new src/orbit_determination.rs recovers
    a satellite's orbital state [r, v] from ground-station range tracking, composing three shipped
    pieces: the two-body + J2 force model (src/forces.rs) and RK4 integrator (src/integrator.rs)
    propagate a candidate state across the arc, a range measurement model predicts each station range,
    and the Gauss–Newton batch corrector (src/batch_ls.rs) drives the candidate onto the best-fit
    state (determine_orbit_batch). The same dynamics and range model also drive a sequential
    recursive determination on the shipped unscented filter (determine_orbit_sequential). Four tests
    validate it: range prediction across the arc; batch recovery to sub-metre / mm·s⁻¹ from noiseless
    ranges
    ; batch recovery to ~2 m with a post-fit residual at the 5 m noise floor (the signature
    of a consistent least-squares fit); and sequential recovery to within tens of metres. Honest scope:
    range-rate/Doppler and angle measurements, an analytic J2 state-transition matrix, and station
    visibility masking are follow-ons.
  • Tightly-coupled GNSS/INS UKF navigator. A new src/fusion/tightly_coupled.rs wires the
    shipped unscented Kalman core (src/fusion/ukf.rs) into a working tightly-coupled navigator over
    the eight-state [px,py,pz,vx,vy,vz,b,d] (ECEF position/velocity plus receiver clock bias and
    drift in range units). It ingests the raw satellite measurementspseudorange
    (ρ = |p − sᵢ| + b) and range_rate/Doppler (ρ̇ = (p − sᵢ)·(v − ṡᵢ)/|p − sᵢ| + d) — rather
    than a pre-formed position fix, so TightlyCoupled (with propagate/propagate_orbital/
    update_gnss) keeps correcting with fewer than four satellites and coasts through GNSS
    outages on its propagated dynamics. Five tests validate it end-to-end, including the milestone
    acceptance scenarios: the pseudorange/Doppler geometry against hand values; noiseless convergence
    to sub-metre on five satellites; a three-satellite case converging from ~212 m to ~13 m
    where a snapshot PVT cannot even be formed; a constant-velocity 120-second outage within 50 m;
    and — the headline acceptance — a 30-minute curving LEO pass (real two-body + J2 orbit) with a
    120-second GNSS outage, held to 0.77 m pass RMS and 2.9 m worst-case through the
    outage
    . That orbital coast composes the shipped gravity force model (src/forces.rs) and RK4
    integrator (src/integrator.rs) into the UKF process model (propagate_orbital), so the filter
    follows the orbit's curvature — which a constant-velocity coast cannot (curvature alone is ~58 km
    over 120 s at LEO). Honest scope: the orbital coast uses the two-body + J2 force model rather than
    raw IMU specific-force (for an unpowered orbital platform these coincide); folding in a
    strapdown-IMU error state and in-loop iono/tropo corrections remain follow-ons.
  • Map-matching measurement model (terrain-/gravity-referenced navigation). A new
    src/mapmatch.rs supplies the measurement model that turns the shipped...
Read more

v0.10.0

04 Jun 14:06

Choose a tag to compare

Changed

  • Real-data validation. The multi-GNSS RINEX navigation parser, the GLONASS
    RK4 propagator, and the SP3 reader are now exercised against genuine IGS/DLR
    files (a real RINEX 3 mixed broadcast nav file and an IGS SP3-c orbit product),
    not only self-authored samples — asserting non-empty satellite sets and finite,
    physically-sized ECEF positions. The fixtures are test-only (excluded from the
    published crate); see tests/fixtures/igs/NOTICE.
  • RAIM on real reference-orbit geometry. The snapshot, solution-separation
    (MHSS), and ARAIM protection-level cores are now validated against the real IGS
    precise-orbit (SP3) geometry, not synthetic constellations alone: the line-of-sight
    geometry is built from the first SP3 epoch at a real ground station, and the tests
    assert metre-level, APV-I-available protection levels, that a 60 m pseudorange bias
    trips the χ² monitor, that solution separation identifies the faulted satellite,
    and that ARAIM's levels meet the allocated P_HMI. Closes the
    validated-on-synthetic-geometry-only gap (receiver-domain gLAB parity over a full
    RINEX arc remains a roadmap item — it needs a pseudorange solution).

Added

  • Per-node confidence intervals for the N-D parameter sweep (sweep::nd_sweep_ensemble).
    Each grid node of the N-dimensional Cartesian-product sweep can now be evaluated as a
    Monte-Carlo ensemble of seeds, reporting the metric's mean, percentiles, and a
    percentile-bootstrap 95% CI per node (for both clocks) — a statistically honest sweep
    rather than one draw per node. Reuses the ensemble/bootstrap machinery (metric_stat);
    deterministic; runs = 1 reduces exactly to the single-seed nd_sweep. (Generalising
    the sweep across all packs, entangled with the typed-Scenario refactor, and parallel
    execution remain.)
  • NaveGo cross-validation of the IMU-noise pipeline (tests/navego_imu_crossval.rs).
    An external cross-check against NaveGo (R. Gonzalez's open-source INS/GNSS toolbox):
    reproduces the synthetic round-trip of navego_example_allan.m on its published
    Microstrain 3DM-GX3-35 reference profile, confirming our overlapping-ADEV estimator
    recovers NaveGo's velocity- and angle-random-walk coefficients (ADEV(1 s) = σ·√dt)
    to under 5% with the expected −1/2 white-noise slope. (The 40 MB recorded STIM300
    .mat log is not ingested — binary-format-gated.)
  • Tightly-coupled (pseudorange) GNSS/INS update. GnssInsEkf::update_tightly_coupled
    (and the ClosedLoopInsGnss::fuse_tightly_coupled wrapper) implement the
    previously-stubbed range-domain measurement: the innovation is the predicted
    range from the INS position to each satellite versus the measured pseudorange,
    with a line-of-sight Jacobian on the position error. Because each satellite is a
    scalar measurement, the filter keeps correcting with fewer than four
    satellites
    — where a loosely-coupled PVT fix does not exist. Five tests cover
    four-satellite nulling, two-satellite correction (no PVT possible), single-
    satellite along-line-of-sight observability, and input validation. Pseudorange-
    only; carrier phase and an explicit receiver-clock state remain roadmap. The
    unused tight_coupling cargo feature (which gated the old error stub) is removed.
  • Loosely-coupled GNSS/INS scenario pack (kind = "gnss-ins", src/fusion/pack.rs).
    Wires the three-axis strapdown navigator and the 15-state error-state EKF
    (closed_loop / gnss_ins_ekf) into a runnable scenario with a figure of merit —
    the EKF disciplines the mechanization against noisy GNSS fixes while coverage is
    up, then coasts through the outage, replacing the legacy 1-DOF scalar pack's
    truth-snap reset with genuine fusion. The result reports the fused horizontal
    error series, the scored position FoM (availability / outage RMS / holdover), and
    the open-loop free-INS RMS for comparison; a quantum/classical IMU pair differs
    only in true bias. Dispatched from the CLI/Python/wasm entry point with a
    scenarios/gnss-ins.toml example. Honest framing: loosely-coupled only, one
    deterministic trajectory, and the fused outage error is floor-limited by the
    hand-over attitude error (so it is not claimed to scale with bias) — the robust
    findings are that fusion beats unaided dead-reckoning for a biased sensor and that
    a lower-bias sensor has the better unaided coast.
  • Constellation design on the validated SGP4 core (src/walker.rs). A new
    walker module emits a designed Walker-delta pattern (i: T/P/F) as SGP4
    mean elements, so the synthetic constellation propagates through the same
    SGP4 path validated to 4.12 mm against the AIAA 2006-6753 vectors — not the
    analytic Keplerian generator. On top of it: pdop_sweep tabulates coverage and
    median/worst PDOP over a {planes × sats × inclination} design grid, and
    coverage_revisit reports the coverage fraction and revisit gaps (worst/mean)
    at a ground point. Validated by the physical monotonicities a trade must obey
    (more satellites ⇒ higher coverage, lower PDOP, shorter revisit). Separately, a
    genuine Celestrak gps-ops TLE snapshot (2021-07-28, 30 operational GPS
    satellites) is added as a test-only fixture and the real-TLE → SGP4 → ECEF
    geometry path validated against it (full MEO shell within 1%, nine-satellite
    all-in-view at PDOP 1.64), alongside the existing SP3 and RINEX real-data paths.
  • Noise-type-specific effective degrees of freedom for the Allan confidence
    intervals.
    allan::edf_overlapping_adev implements the NIST SP 1065 Table 5
    closed forms (the Stable32 simple set) for all five canonical power-law noise
    types — white/flicker PM, white/flicker FM, random-walk FM — replacing the
    conservative non-overlapping count as the χ² degrees of freedom. A new
    PowerLawNoise enum and classify_power_law identify the dominant type from
    the record's modified Allan-deviation slope (MDEV separates white from
    flicker PM where ADEV cannot), and overlapping_adev_curve now attaches the
    identified noise type, its edf, and a 95% confidence band to every point of the
    exported ADEV curve (AdevPoint gains noise/edf/ci_lo/ci_hi, additive
    with serde defaults). Validated two ways: the five formulas match hand-evaluated
    values to 1e-12, and a 4 000-record Monte-Carlo white-FM ensemble confirms the
    formula predicts the estimator's actual chi-squared edf within 20% (and that it
    materially beats the conservative count). Eight new tests.
  • Two-way time-transfer stochastic model. timetransfer::TwoWayLink replaces the
    white-only sampler with a physically-grounded model: the reciprocal (common-mode) path
    delay cancels in the (m_AB - m_BA)/2 estimate (two_way_offset_estimate, so two
    independent one-way measurements average to 1/sqrt(2)), and the residual is the
    non-reciprocal differential delay — modelled as a colored white-FM + random-walk-FM
    process (the validated ClockModel), giving the synchronization-error series a realistic
    Allan signature (sigma_y^2(tau) = q_rw*tau/3) instead of flat white noise. LinkCfg
    gains q_wf_s/q_rw_s (serde default 0 ⇒ the legacy white-only behaviour, bit-for-bit),
    the link FoM reports adev_tau0 (the model's Allan deviation at the base step), and the
    timetransfer scenario/CLI surface it. Golden FoM re-pinned. Six hand-derived tests
    (common-mode cancellation, the sqrt(2) two-way gain, the RWFM tau/3 law via the link's
    own step(), legacy-equivalence at q=0, determinism, and end-to-end FoM exposure).
  • Stable32 numeric parity for the Allan-family estimators (NBS14). tests/allan_reference.rs
    validates the overlapping ADEV, modified ADEV, time deviation, and overlapping Hadamard
    estimators against the Stable32 reference deviations for the canonical NBS14 dataset
    (W. J. Riley, Handbook of Frequency Stability Analysis, NIST SP 1065, ~p.107) at
    tau = 1, 2 to a 1e-4 relative tolerance — actual agreement ~1e-6. This pins the
    estimator mathematics against the de-facto reference implementation, not just against
    the estimators' own analytic self-consistency. Only the public reference numbers are
    used; no third-party code.
  • Vertical Stanford integrity diagram exported by the integrity scenario. The
    runnable integrity scenario kind now exports a vertical Stanford(-ESA) diagram
    alongside the HPL/VPL availability map: at each protected epoch a seeded, reproducible
    no-fault range-error draw is mapped through the geometry to an actual vertical position
    error and classified against the VPL and the vertical alert limit (Available /
    System-Unavailable / Misleading / Hazardously-Misleading). The diagram (per-epoch
    points + region counts) is carried in the result JSON and the integrity-event / HMI
    counts in the CLI summary, so the Stanford classifier — previously library-only — is
    reachable end-to-end. IntegrityScenario gains a seed field (default 0) controlling
    the error realization; the availability map itself remains geometry-only and seed
    independent.
  • ARAIM integrity-risk (P_HMI) budget for the protection levels. raim::araim_raim
    derives the horizontal and vertical protection levels from an explicit integrity-risk
    budget rather than a fixed K_md multiplier: for the all-in-view solution and every
    single-satellite exclusion sub-solution it builds the per-mode (prior, detection threshold, σ) on each axis, then araim_protection_level solves the smallest PL whose
    summed probability of hazardously-misleading information (araim_integrity_risk,
    P_HMI = Σ_k p_fault,k · Q((PL − T_k)/σ_k), Blanch et al. Baseline ARAIM) meets the
    allocated P_HMI. The result reports the integrity risk the levels actually achieve, so
    a user can trade integrity against the alert limit explicitly. Six hand-derived tests
    (fault-free and thresholded single-mode closed forms, multi-mode summation/mono...
Read more

v0.9.2

03 Jun 13:42

Choose a tag to compare

Added

  • Archival DOI. Releases are now deposited to Zenodo and assigned a citable DOI.

Full changelog: CHANGELOG.md · Docs: README