Tutorial 2

June 8, 2026 · View on GitHub

Kind: clock · Scenario: scenarios/clock-holdover.toml (teaching copy: scenarios/clock.toml) · Difficulty: beginner · ~20 min

By the end you will have run a GNSS-denied clock holdover, read the timing figure of merit, and understood the √(q_wf·T) drift law that explains why the optical clock outlasts the chip-scale one — with the law sourced from NIST, not invented.

What this scenario is

When GNSS goes away, a system keeps time on its own onboard clock. That clock’s phase slowly drifts, and once the drift exceeds the operational timing spec you are out of service. Holdover is how long you stay in spec after GNSS loss — the headline autonomy figure of merit.

The scenario runs a 2 h timeline: 10 min of GNSS sync, then ~1.8 h denied, against a 20 ns timing spec. It compares two clocks on identical code with their own published noise:

  • Quantum: a strontium optical lattice clock, space goal σ_y(1 s) = 1×10⁻¹⁵ (arXiv:1503.08457) — a ground-demonstrator target, not flown.
  • Classical: a Microchip SA.45s chip-scale atomic clock (CSAC), σ_y(1 s) = 3×10⁻¹⁰ (datasheet) — a deployed commercial part.

Run it

cargo run -- scenarios/clock-holdover.toml

Python:

import json, kshana
r = json.loads(kshana.run(open("scenarios/clock-holdover.toml").read()))
print(r["quantum"]["fom"]["holdover_s"], r["classical"]["fom"]["holdover_s"])

Read the one-line summary

With seed = 42, the 20 ns spec, and the 1.8 h outage:

scenario 5ba83a232b94 | quantum holdover 6600s p95 0.0ns integrity 1.000 security 0.997 | classical holdover 2610s p95 19.7ns integrity 1.000 security 0.000
  • quantum holdover 6600s — the optical clock holds the entire 6600 s outage without breaching 20 ns. Its 95th-percentile phase error is 0.0 ns (rounded): it barely moves.
  • classical holdover 2610s — the CSAC breaches the 20 ns spec at ~2610 s, less than half the outage. Its p95 phase error (19.7 ns) sits right at the spec line.
  • security 0.997 vs 0.000 — the optical clock’s tight detection floor gives it spoof-detection margin; the CSAC’s own coast noise over the window already exceeds 20 ns, so it has none. (That’s the Tutorial 3 story.)
  • integrity 1.000 — here this is filter self-consistency (the fraction of outage samples inside the Kalman filter’s own k-sigma bound), not an aviation HPL/VPL figure. See docs/INTEGRITY.md.

The non-circular oracle: why 2610 s for the CSAC?

For a white-FM clock the 1-σ phase-error grows as σ_x(T) ≈ √(q_wf · T), where q_wf = σ_y(1 s)² has units of s². This relation is from NIST Special Publication 1065 (Riley, Handbook of Frequency Stability Analysis) — the σ_y(τ)↔phase relations — the same SP-1065 relation that tests/calibration.rs validates the engine’s Allan deviation against to ~2 %.

For the CSAC, q_wf = (3×10⁻¹⁰)² = 9×10⁻²⁰ s². Solve for the time the 1-σ phase reaches 20 ns = 2×10⁻⁸ s:

T ≈ (2e-8)^2 / 9e-20 = 4e-16 / 9e-20 ≈ 4444 s   (1-sigma crossing)

The engine’s spec-cross at ~2610 s is the percentile/threshold convention applied to that same growth law (a k-σ / p95 bound crosses 20 ns earlier than the 1-σ level), and it is grid-quantised: with step_s = 10, 2610 s is the first 10 s grid point past the crossing. So you should expect a value in the ~2600–4400 s band, not an exact match to the continuous prediction — and that is exactly what the test asserts.

The datasheet anchors themselves are external, cited in the scenario’s provenance strings: optical Sr lattice goal 1×10⁻¹⁵ (arXiv:1503.08457); Microchip SA.45s CSAC 3×10⁻¹⁰ (datasheet). And the exported adev_curve matches the datasheet σ_y(τ) to ~2 % (tests/calibration.rs, NIST SP 1065) — plot it as a log-log “Clock stability (ADEV)” chart in the playground.

What the test pins

tests/tutorials.rs::tutorial2_clock_holdover_holds:

  • quantum holdover >= classical holdover (the optical clock must hold at least as long),
  • quantum holdover ≈ 6600 s (holds the full outage),
  • classical holdover ∈ [2000, 3200] s — a tolerance band around the SP-1065 white-FM prediction, not a magic number. The oracle is the law, not the value.

Pitfalls and units

  • Timing figures are in nanoseconds, never metres. (Position holdover is a different pack — see Tutorial 3’s inertial section.)
  • q_wf has units s² and equals σ_y(1 s)². That’s the bridge from a datasheet Allan number to the model.
  • Holdover is a grid-quantised lower bound (step_s). Don’t over-read the exact value; read the band.
  • integrity here is filter self-consistency, not aviation integrity.

Where next

  • Tier 2: tighten threshold_ns from 20 to 10 and watch the CSAC holdover drop (monotone), or use kind = "sweep" to tabulate holdover vs spec (scenarios/sweep-clock-stability.toml).
  • Tier 3: add runs = 200 to turn this into a Monte-Carlo ensemble and read the [p05–p95] holdover band (scenarios/clock-ensemble.toml).
  • Then the capstone: Tutorial 3 — Quantum vs classical resilience.