v0.10.0
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); seetests/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 allocatedP_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 = 1reduces exactly to the single-seednd_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 ofnavego_example_allan.mon 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
.matlog is not ingested — binary-format-gated.) - Tightly-coupled (pseudorange) GNSS/INS update.
GnssInsEkf::update_tightly_coupled
(and theClosedLoopInsGnss::fuse_tightly_coupledwrapper) 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
unusedtight_couplingcargo 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.tomlexample. 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
walkermodule 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_sweeptabulates coverage and
median/worst PDOP over a{planes × sats × inclination}design grid, and
coverage_revisitreports 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 Celestrakgps-opsTLE 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_adevimplements 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
PowerLawNoiseenum andclassify_power_lawidentify the dominant type from
the record's modified Allan-deviation slope (MDEV separates white from
flicker PM where ADEV cannot), andoverlapping_adev_curvenow attaches the
identified noise type, its edf, and a 95% confidence band to every point of the
exported ADEV curve (AdevPointgainsnoise/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::TwoWayLinkreplaces the
white-only sampler with a physically-grounded model: the reciprocal (common-mode) path
delay cancels in the(m_AB - m_BA)/2estimate (two_way_offset_estimate, so two
independent one-way measurements average to1/sqrt(2)), and the residual is the
non-reciprocal differential delay — modelled as a colored white-FM + random-walk-FM
process (the validatedClockModel), giving the synchronization-error series a realistic
Allan signature (sigma_y^2(tau) = q_rw*tau/3) instead of flat white noise.LinkCfg
gainsq_wf_s/q_rw_s(serde default 0 ⇒ the legacy white-only behaviour, bit-for-bit),
the link FoM reportsadev_tau0(the model's Allan deviation at the base step), and the
timetransferscenario/CLI surface it. Golden FoM re-pinned. Six hand-derived tests
(common-mode cancellation, the sqrt(2) two-way gain, the RWFMtau/3law via the link's
ownstep(), legacy-equivalence atq=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
integrityscenario. The
runnableintegrityscenario 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.IntegrityScenariogains aseedfield (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 fixedK_mdmultiplier: for the all-in-view solution and every
single-satellite exclusion sub-solution it builds the per-mode(prior, detection threshold, σ)on each axis, thenaraim_protection_levelsolves 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
allocatedP_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/monotonicity,
end-to-end fault-free protection with a 10⁵× tighter budget raising the PL, fault
detection/identification, and the six-satellite redundancy floor). Single-fault MHSS is
the ARAIM baseline; simultaneous multi-SV-subset faults, the constellation-wide fault
mode, and gLAB reference-dataset validation are documented extensions. - Two-speed coning/sculling compensation for the strapdown mechanization.
inertial::mechanization::coning_sculling_compensatefolds the high-rate coning
(attitude) and rotation+sculling (velocity) terms out of a coarse update's
ordered sub-interval IMU increments, so a moderate-rateNavState::step_increments
reproduces vibration-rectified motion a coarse step over the raw sums misses. A
validation test drives a 10 Hz coning+sculling environment for 60 s and compares
fine-rate truth, naive coarse integration, and the folded coarse integration:
the fold cuts the position error by ~18× (metres of naive drift → sub-decimetre),
confirming the coning/sculling terms are load-bearing. AScalarErrorBudget
type alias names the legacy 1-DOFAccelModelfor what it is, distinct from the
three-axisNavStatenavigator. - RINEX observation-file parser. New
rinex_obsmodule reads the RINEX 3.0x /
4.00 observation file — the receiver's actual measurements — completing the
RINEX pair alongside the existing navigation-message parser.parse_obsdecodes
the header (version/type, the per-systemSYS / # / OBS TYPESlists with
continuation lines, approximate position, interval, time of first observation)
and each epoch's per-satellite records: pseudorange, carrier phase, Doppler, and
signal strength, keyed by their RINEX 3 observation code (C1C,L1C, …) with
the loss-of-lock (LLI) and signal-strength (SSI) flags, a blank field preserved
as absent rather than zero. Honest scope: this is the standards-format ingest
(a real RTKLIB/gLAB/IGS-station observation log in, typed measurements out), not
a positioning engine — no pseudorange solution, PPP, or RTK here. - CCSDS OEM (Orbit Ephemeris Message) writer. New
oemmodule exports a
propagated constellation as a valid CCSDS 502.0-B OEM 2.0 message —
the KVN ephemeris format GMAT, Orekit, STK, and most flight-dynamics tools
ingest.OemFile::from_propagatorssamples each satellite's inertial
(TEME) state — position and velocity, taken straight from the propagator
with no Earth-fixed rotation, unlike the SP3 export — onto a time grid, and
OemFile::to_oem_stringserialises theCCSDS_OEM_VERS/CREATION_DATE/
ORIGINATORheader plus oneMETA_START … META_STOPsegment per satellite
(OBJECT_NAME/OBJECT_ID/CENTER_NAME/REF_FRAME = TEME/TIME_SYSTEM = GPS/
START_TIME/STOP_TIME) followed by itsepoch X Y Z X_DOT Y_DOT Z_DOT
lines (km, km/s). TheCREATION_DATEis caller-supplied, never wall-clock, so
output is byte-identical across runs (the reproducibility contract). This is the
spacecraft-ephemeris counterpart to the GNSS SP3 export: a Kshana orbit can now
be handed to a flight-dynamics tool in a standard format. - SP3 precise ephemeris as a propagation source.
Sp3File::interpolator
builds a per-satelliteSp3Interpolatorthat fills the position between the
tabulated SP3 epochs with a 9th-order Lagrange polynomial (standard IGS
practice) and rotates it into the shared TEME frame, exposed as
Propagator::Sp3Precise. An IGS/analysis-centre precise-orbit file can now drive
the same geometry/visibility/integrity pipeline as the broadcast and analytic
propagators. Validated round-trip: a Kepler orbit written to SP3 and re-read
through the interpolator matches the original to sub-metre at the nodes and
< 100 m mid-interval. Clock interpolation is next. - GLONASS broadcast ephemeris (completes multi-GNSS RINEX nav). New
glonass
module: GLONASS doesn't broadcast Keplerian elements but a PZ-90 Earth-fixed
state vector (position, velocity, luni-solar acceleration).parse_glonass_nav
reads the RINEX 3Rrecords, and the satellite position at any time is obtained
by 4th-order Runge–Kutta integration of the GLONASS ICD equations of motion
(central gravity +J2+ Earth-rotation Coriolis/centrifugal terms + the
broadcast acceleration). Exposed asPropagator::Glonass, so GLONASS satellites
flow through the constellation/visibility/integrity pipeline alongside the
Keplerian systems; a singlerinexconstellation block can now mix GPS, Galileo,
QZSS, BeiDou, and GLONASS. - Multi-GNSS RINEX navigation (GPS, Galileo, QZSS, BeiDou). The RINEX 3
navigation parser now decodes Galileo (E), QZSS (J), and BeiDou (C,
MEO/IGSO) records alongside GPS (G) — they share the Keplerian layout and user
algorithm — each evaluated with its own gravitational constant and Earth-rotation
rate (Galileo/BeiDou μ, BeiDou Ω̇ₑ). A mixed-constellation file yields all of
them, flowing through the constellation/visibility/integrity pipeline as
Propagator::Rinex. BeiDou geostationary satellites use a different coordinate
rotation and are skipped pending a reference fixture to validate against. The
record walker uses per-system line counts, fixing a latent bug where four-line
GLONASS/SBAS records were skipped as if eight lines long. GLONASS (a state-vector
model) is next. - SP3-c/d precise-ephemeris reader and writer. New
sp3module parses
IGS/analysis-centre SP3 precise orbit files (parse_sp3) — the post-processed
ECEF position/clock product that PPP engines (Ginan, RTKLIB, gLAB) treat as
reference — into a structuredSp3File(header, epoch grid, per-satellite
position km→m, clock µs, and velocity dm/s→m/s forVproducts), preserving the
SP3 bad-value sentinels. The reverse direction is also covered:
Sp3File::from_propagatorsbuilds an SP3 from a propagated constellation
(TEME→ECEF per epoch) andto_sp3_stringserialises it, so Kshana orbits can be
exported in the format external PPP tools ingest — the read↔write round trip.
Epoch interpolation and an SP3 propagator source are next. - RINEX broadcast ephemeris as a runnable constellation source. A
constellation now accepts an inlinerinexblock (RINEX 3 GPS navigation
text) alongside the existingtleoption, so a real broadcast file drives a
scenario end-to-end from the CLI, Python, or the in-browser playground — RINEX
in, PNT geometry out. Newscenarios/orbit-rinex.tomldemonstrates GNSS
availability and DOP from eight GPS satellites built straight from broadcast
records. (GPS LNAV only; multi-GNSS and SP3 are next.) - RINEX broadcast ephemeris as a propagation source. A parsed
RinexEphemerisnow converts to anorbit::Propagator(Propagator::Rinex):
position is the IS-GPS-200 broadcast orbit rotated from ECEF into the shared
TEME inertial frame (sv_position_teme, with leap-second-correct GPS→UT1 time),
velocity by central finite difference, and the Keplerian orbital period. Real
GPS broadcast data can now drive the same geometry, visibility, and integrity
(RAIM) pipeline as the analytic SGP4/Keplerian propagators. (Not yet exposed as
a RINEX-file scenario kind — that and multi-GNSS/SP3 are next.)
Full changelog: CHANGELOG.md · Docs: README