Skip to content

v0.13.0

Choose a tag to compare

@ashfordeOU ashfordeOU released this 08 Jun 08:23
· 49 commits to main since this release

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 secular
    variation; coefficients machine-generated from the official igrf14coeffs.txt
    by tools/gen_igrf.py into src/igrf_data.rs, bit-for-bit reproducible). A
    Schmidt-normalised synthesis returns the field vector (north/east/down) and
    derived elements (declination, inclination, horizontal/total intensity) at any
    geodetic location/date, plus the geomagnetic pole and dipole strength — the
    magnetic counterpart to the gravity-map matcher for alternative-PNT navigation.
    Validated self-contained: the synthesis matches the exact closed-form tilted
    dipole, the full degree-13 analytic field matches a finite-difference of the
    scalar potential, the dipole axis reproduces the known geomagnetic pole
    (~80.7°N, −72.7°E) and ~29.7 µT strength, and the global field is physical.
  • Typed Python bindings (src/python.rs). Beyond the string-in/string-out
    run/run_full, the module now exposes a typed RunOutput class (.json,
    .svg, .summary, and a .data() accessor that returns the result parsed into
    a native Python dict — no JSON re-parsing, NumPy-wrappable), plus run_typed,
    scenario_kinds() (parsed list of metadata dicts), and validate_toml() (a
    non-raising list of error messages). Ships a PEP 561 type stub (kshana.pyi +
    py.typed) for mypy/pyright/editors and a docs/PYTHON_API.md quickstart.
    The existing functions are unchanged.
  • First-class output frames for propagators (src/orbit.rs Frame enum +
    position_in_frame + state_gcrs).
    Any Propagator (Kepler, SGP4, RINEX,
    GLONASS, SP3) can now emit its position in TEME, GCRS (≈ J2000), or ITRS
    (Earth-fixed) — TEME native, GCRS via the validated TEME→GCRS reduction, ITRS by
    chaining that into the IAU 2006/2000A CIO gcrs_to_itrs rotation — and its full
    GCRS state (position + velocity) via state_gcrs. The of-date inertial output is
    no longer TEME-only.
  • CIO-based IAU 2006/2000A celestial-to-terrestrial reduction (src/cio.rs).
    The modern, equinox-free GCRS↔CIRS↔ITRS chain: CIP coordinates X, Y read off
    the IAU 2006/2000A bias-precession-nutation matrix (reusing the validated FW
    precession + 2000A nutation with the eraNut06a P03 adjustment), the 66-term
    CIO-locator s series (eraS06, machine-generated from the ERFA reference by
    tools/gen_s06.py into src/cio_s06_data.rs, bit-for-bit reproducible), the
    GCRS→CIRS matrix (eraC2ixys), the Earth rotation angle (eraEra00), and the
    full GCRS→ITRS rotation (eraC2tcio, composed with the existing IERS polar
    motion). Validated bit-for-bit against the published eraXys06a
    (X=0.5791308482835292617e-3, Y=0.4020580099454020310e-4,
    s=-0.1220032294164579896e-7 at JD_TT 2453736.5), eraC2ixys, and eraEra00
    test vectors. The CIO chain and the legacy equinox/GMST-1982 TEME reduction are
    shown to agree up to their documented ≈2·(equation of equinoxes) sidereal-time
    convention difference. This is the rigorous reduction the equinox/GMST path
    approximated.
  • Full IAU 2000A nutation series (src/nutation.rs nutation_iau2000a,
    nutation_matrix_2000a).
    The complete MHB2000 model — 678 luni-solar + 687
    planetary terms — accurate to < 0.1 mas, alongside the existing 77-term 2000B
    truncation. The tables are machine-generated from the IAU SOFA / ERFA nut00a
    reference by tools/gen_nut00a.py into src/nutation_iau2000a_data.rs (the
    generator reproduces the committed file bit-for-bit), and the whole series —
    both the IERS-2003 and MHB2000 fundamental-argument sets and the planetary
    longitudes — is validated bit-for-bit against the published eraNut00a
    test vector (Δψ = −0.9630909107115518e-5, Δε = 0.4063239174001679e-4 at
    JD_TT 2453736.5, to 1e-13 rad). The default TEME→GCRS reduction keeps the 2000B
    series (~1 mas, below the chain's velocity-frame-rotation simplification);
    nutation_matrix_2000a exposes the < 0.1 mas of-date matrix for callers that
    need it.
  • Runnable lunar-integrity scenario (kind = "lunar-integrity", scenarios/lunanet-araim.toml).
    Wires the lunar south-pole protection-level pass (src/lunar.rs LunarScenario
    south_pole_hpl_pass) into the scenario runner with a JSON LunarReport and an SVG
    HPL-vs-time chart, so the cislunar integrity case is reachable straight from the CLI.
    It honestly surfaces the gap: with the 30 m LANS σ_URE the south-pole HPL (≈ 260–450 m)
    exceeds a 50 m alert limit (0 % available) — lunar PNT integrity is not yet met.
  • Dual-constellation ARAIM availability on real GPS+Galileo TLEs, and scenario-runner
    wiring (src/raim.rs, src/orbit.rs, scenarios/araim-gps-galileo.toml).
    Adds
    araim_dual_constellation_availability (the advanced ARAIM engine —
    single-satellite and constellation-wide faults — run over a time grid) and
    visible_positions_labeled, and wires it into the IntegrityScenario runner via an
    araim_dual flag so a multi-GNSS ARAIM study is reachable straight from TOML. A
    real-data test (tests/araim_dual_real_data.rs) on vendored 2026-06-07 Celestrak
    GPS+Galileo snapshots shows pooling Galileo lifts ARAIM availability from 0.21 to
    0.67 under a demanding 12 m VAL (10.5→21.8 satellites in view), while the
    constellation-fault-robust mode is fundamentally limited with only two constellations
    — the quantitative reason robust dual-constellation integrity drives toward a third
    constellation or SBAS. Honest residual: the numerically exact EU ARAIM TN Table A-3
    reproduction against a single version-locked epoch, and a Zenodo fixture record.
  • Circular restricted three-body problem (CR3BP) for the Earth–Moon system
    (src/cr3bp.rs).
    A new cislunar-dynamics core the two-body/SGP4 propagators
    cannot provide: rotating-frame equations of motion (cr3bp_accel), an RK4
    propagator (propagate_cr3bp), the Jacobi-constant integral (jacobi_constant),
    and the five Lagrange points (lagrange_points). Validated against closed-form /
    published anchors: the Earth–Moon collinear points (L1 ≈ 0.83692, L2 ≈ 1.15568,
    L3 ≈ −1.00506), the exact equilateral L4/L5 = (½−μ, ±√3/2, 0), all five confirmed
    as field equilibria, Jacobi conserved to integrator precision under propagation,
    and the out-of-plane restoring force that makes halo/NRHO orbits possible. This is
    the foundation for representing a real NRHO. Honest residual: differential-corrected
    periodic 9:2 NRHO initial conditions, the eccentric/ephemeris (DE) model, and the
    de-normalised transform into the selenocentric frames of src/lunar.rs.
  • IERS polar motion and the TEME→ITRF reduction (src/frames.rs). Adds
    polar_motion_matrix (SOFA iauPom00: W = Rx(−y_p)·Ry(−x_p)·Rz(s′) with the TIO
    locator s′), pef_to_itrf / itrf_to_pef, and teme_to_itrf — the GMST-based
    TEME→PEF rotation followed by polar motion — completing an ITRF-precise Earth-fixed
    position on top of the GMST-only teme_to_ecef (polar motion is a tens-of-metres
    effect at orbital radius). x_p/y_p are observed IERS quantities the caller
    supplies. Honest residual: a fully CIO-based (X, Y, s) chain and an ANISE/SPICE
    <10 m numerical cross-check remain follow-ons.
  • Cold-atom-interferometer systematics, drift sweep, and a published-device
    validation (src/inertial/quantum_imu.rs, docs/QUANTUM.md).
    Extends the
    first-principles CAI accelerometer with the two leading deterministic systematics:
    the Coriolis/rotation phase Φ_cor = 2·k_eff·v_⊥·Ω·T² (coriolis_phase, with
    the equivalent acceleration bias 2·Ω×v via coriolis_accel_bias) and the
    AC-Stark light-shift phase Φ_LS = (δ_LS,1 − δ_LS,3)/Ω_eff (ac_stark_phase,
    which cancels by π/2–π–π/2 symmetry for a constant shift). Adds cai_drift_sweep
    (dead-reckoning position drift vs cycle time — the core of a quantum-vs-classical
    comparison) and a validation test against the Freier et al. 2016 mobile gravimeter
    (arXiv:1512.05660): the modelled quantum-projection-noise floor lies below, and
    within ~2 orders of, the published 96 nm/s²/√Hz short-term noise. docs/QUANTUM.md
    updated. Honest residual: wavefront/beam-pointing systematics, fringe-ambiguity
    resolution, the exact CARIOQA-PMP / Boeing-AOSense flight-test reproduction (needs
    published platform PSDs), and a JS playground preset.
  • Cislunar frame reduction and a lunar south-pole integrity pass (src/lunar.rs).
    Extends the lunar ARAIM engine with the MCI↔MCMF (Moon-centered inertial ↔
    Moon-fixed) rotation (mci_to_mcmf / mcmf_to_mci, a simplified mean-rotation
    model at the lunar sidereal rate), selenographic latitude/longitude/altitude
    (mcmf_to_selenographic / selenographic_to_mcmf), and south_pole_hpl_pass
    a landed Artemis-region receiver against a representative LunaNet relay set over a
    24 h pass, which honestly quantifies the integrity gap: with the nominal 30 m LANS
    σ_URE the protection level is finite but exceeds a 50 m surface-ops alert limit.
    Honest residual: the precise LANS NRHO ephemeris (a 3-body cislunar orbit), the
    physical libration / precessing lunar pole (DE421/SPICE), and a LunaNet TOML
    scenario remain follow-ons.
  • ARAIM integrity support message, Stanford-diagram SVG, and the open ARAIM
    reference (src/raim.rs, docs/ARAIM_REFERENCE.md).
    Adds an explicit
    IntegritySupportMessage (σ_URA / σ_URE / b_nom / P_sat / P_const, with the WG-C
    GPS+Galileo reference values and .fault_priors() / .dual_fault_priors()
    converters into the single-fault araim_raim and constellation-wide
    araim_dual_raim engines), a standalone stanford_svg renderer of the Stanford
    integrity diagram (the four zones, the PL = error boundary, the alert-limit
    guides, one colour-coded marker per epoch), and docs/ARAIM_REFERENCE.md
    documenting the algorithm, the ISM, the fault hypotheses, the protection-level
    contract, and the dual-constellation benefit. Tests demonstrate the
    geometry/redundancy gain (pooling a second constellation tightens the single-fault
    HPL) and constellation-fault tolerance (the dual user survives losing a whole
    constellation; a single-constellation user cannot). Honest residual: numerically
    reproducing the EU ARAIM TN Table A-3 / the 15–25 % availability figure against a
    version-locked real TLE snapshot, a Zenodo fixture record, and wiring
    araim_dual_raim into the scenario-file runner.
  • IAU 2000B nutation and the full TEME→GCRS/J2000 inertial reduction
    (src/nutation.rs).
    Adds the second and third pieces of a true inertial frame
    reduction on top of the shipped IAU 2006 precession: the 77-term luni-solar MHB2000
    nutation series (nutation_iau2000b, the standard IAU 2000B truncation accurate to
    ~1 mas) with the Delaunay fundamental arguments and the SOFA iauNumat nutation
    matrix, and the Vallado AIAA-2006-6980 chain TEME→TOD (equation of the equinoxes) →
    TOD→MOD (nutation) → MOD→GCRS (bias-precession) exposed as teme_to_gcrs(r, v, jd_tt)
    / gcrs_to_teme. The series, arguments and unit constants are transcribed from the
    IAU SOFA / ERFA nut00b reference and validated bit-for-bit against the published
    eraNut00b test vector (Δψ, Δε to 1e-13 rad). Honest residual: the full IAU 2000A
    678-term series (<0.1 mas), an ANISE/SPICE <10 m numerical cross-check, and polar
    motion remain follow-ons (see ROADMAP.md).

Full changelog: CHANGELOG.md · Docs: README