Tutorials

June 29, 2026 · View on GitHub

Hands-on, worked examples that take you from “run a shipped scenario” to “quantify and defend a result.” Every number quoted in these tutorials is a real engine output, anchored to an external (non-circular) authoritative oracle, and pinned by an integration test (tests/tutorials.rs) — so a tutorial can never silently drift from what the engine actually does. If a tutorial says the optical clock holds 6600 s, the test fails the build the day that stops being true.

New to the project? Read the concepts primer and the glossary first, then come back here.

The three worked examples

#TutorialWhat you learnScenario kindDifficulty~Time
1My first orbit: where are the GPS satellitespropagate a real GPS constellation, read availability / PDOP / position accuracy, and export where the satellites actually are (SP3)orbitbeginner15 min
2Clock holdover: how long can you coastrun a GNSS-denied clock holdover, read the timing figure of merit, and understand the √(q_wf·T) growth law behind itclockbeginner20 min
3Quantum vs classical GNSS resiliencethe capstone: a spoofing detector (spoof) and a full fused PNT suite (hybrid), and how to read security / integrity / dead-reckoning togetherspoof + hybridintermediate35 min

How to run a tutorial

Every tutorial runs the same scenario three ways — pick whichever fits you. They all call the one engine, so the numbers are identical (mirrors the README Usage section).

Command line — dispatches on the scenario’s kind field and writes <scenario>.result.json and <scenario>.chart.svg next to the input:

cargo run -- scenarios/orbit-sgp4-gps.toml

Python — build the extension once with maturin, then call kshana.run:

pip install maturin
maturin develop --features python
import json, kshana
result = json.loads(kshana.run(open("scenarios/orbit-sgp4-gps.toml").read()))
print(result["geometry"]["best_pdop"])

Browser playground — zero install: open the playground, pick a scenario, edit the parameters, and read the result. Nothing is uploaded; the engine runs client-side as WebAssembly.

The tutorials quote the CLI, but every command has the Python and playground equivalent above. Each result is reproducible from scenario + seed + engine version — run it twice and you get bit-identical output.

Annotated teaching scenarios

For each capability domain there is one heavily-commented .toml under scenarios/ — a teaching copy of a canonical scenario with every field explained inline, the cited oracle named, and the expected one-line summary recorded as an # expected: comment. The field values are byte-for-byte identical to the parent in the repo’s top-level scenarios/ directory, so the documented output stays true (and the golden hashes are untouched — a comment never changes a scenario hash).

DomainTeaching fileKindDerived from
Clock holdoverscenarios/clock.tomlclockscenarios/clock-holdover.toml
Orbit & geometryscenarios/orbit.tomlorbitscenarios/orbit-sgp4-gps.toml
Integrity (RAIM)scenarios/integrity.tomlintegrityscenarios/integrity-raim.toml
Security (spoofing)scenarios/security.tomlspoofscenarios/spoof-attack.toml
Hybrid PNTscenarios/hybrid.tomlhybridscenarios/hybrid-pnt.toml
Inertial dead-reckoningscenarios/inertial.tomlinertialscenarios/imu-deadreckoning.toml
Time transferscenarios/timetransfer.tomltimetransferscenarios/timetransfer.toml
GNSS measurement domainscenarios/gnss-sim.tomlgnss-simscenarios/gnss-sim-raim.toml

The teaching file for security uses kind = "spoof" inside — the Security figure of merit (1 − P_md) is produced by the spoof pack. The file name follows the capability (security), the kind follows the pack (spoof). The header of that file calls this out.

The full scenario-kind catalogue

The engine dispatches on the scenario’s kind. The table below lists the most commonly-used kinds (the eight tutorial domains above plus their nearest neighbours). It is not the complete set: src/api.rs::list_scenario_kinds() returns all 44 built-in kinds — that function (exposed as list_kinds() in the Python/WASM bindings, and enumerated in ARCHITECTURE.md §4) is the authoritative, always-current catalogue. tests/tutorials.rs::tutorial_scenarios_use_real_kinds enforces that every kind a tutorial documents is a real dispatch kind, so nothing in this table can name a kind that does not exist.

KindWhat it does
clockClock holdover vs spec; optional Monte-Carlo ensemble (runs > 1).
inertial1-DOF inertial dead-reckoning during a GNSS outage.
orbitGNSS availability + DOP from a constellation (Walker / TLE / RINEX).
integritySnapshot / solution-separation / ARAIM RAIM with HPL/VPL + Stanford diagram.
lunar-integrityLunar south-pole ARAIM protection-level pass vs a LunaNet relay set.
timetransferOptical vs RF two-way time/frequency transfer.
hybridHybrid PNT capstone: clock + IMU + time-transfer aiding.
fusionJoint Kalman sensor-fusion PNT over the same hybrid inputs.
gnss-insLoosely- and tightly-coupled GNSS/INS error-state EKF.
gnss-simMeasurement-domain pseudorange sim (Klobuchar iono, Saastamoinen/Niell tropo) + RAIM.
jammingLink-budget jamming: J/S → effective C/N₀ → loss of lock.
spoofStochastic time-spoof detector (Neyman–Pearson / χ²₁) with MC P_fa/P_md.
sweep1-D trade-study sweep over a clock-pack parameter.
sweep-ndGeneric N-D sweep over any pack via dotted TOML keys / JSON metric paths.

Graded exercises

Work through the ladder. Each tier is harder and more defensible than the last; reference solutions live in exercises/.

TierGoalWhat you doReference solution
Tier 1 — run & readrun a shipped scenario unchanged and read one figure of meritRun scenarios/clock-holdover.toml; print the quantum vs classical holdover_s. CLI, playground, or a one-line Python call.exercises/tier1_run.py
Tier 2 — edit & sweepchange one parameter and observe a monotone effectTighten the clock spec (threshold_ns) or lengthen the outage and watch holdover drop; or use kind = "sweep"/"sweep-nd" to tabulate it.exercises/tier2_sweep.py
Tier 3 — quantify & defendMonte-Carlo, confidence bands, reproducibility, and a protection levelRun a clock ensemble (runs = N), read the [p05–p95] band, confirm two runs give an identical scenario_hash, and read an integrity / Stanford result.exercises/tier3_montecarlo.py

Want fresh data?

The headline numbers in these tutorials run entirely from scenarios already in the repo — nothing is fetched, which is what keeps them reproducible and CI-safe. For the “extend it” exercises you can pull live data: