docs/adr/ADR-089-nvsim-nv-diamond-simulator.md
| Field | Value |
|---|---|
| Status | Accepted — Passes 1–5 implemented and merged via the feat/nvsim-pipeline-simulator branch; Pass 6 (proof bundle + criterion bench) pending in the next iteration |
| Date | 2026-04-26 |
| Authors | ruv |
| Companion | docs/research/quantum-sensing/14-nv-diamond-sensor-simulator.md, docs/research/quantum-sensing/15-nvsim-implementation-plan.md |
docs/research/quantum-sensing/14-nv-diamond-sensor-simulator.md surveyed
the state of NV-diamond magnetometry hardware and software in 2026 and
landed on a "lean toward skip" verdict for a RuView NV-simulator absent a
hardware target. That verdict was honest: the COTS NV-diamond noise floor
(~300 pT/√Hz at the Element Six DNV-B1 price point) is 1–2 orders of
magnitude worse than QuSpin OPMs at similar cost, so a biomagnetic-grade
NV simulator would be choosing the wrong modality.
The user nonetheless chose to build the simulator, with two non-biomagnetic use cases in mind:
14.md §2.2 gap).
QuTiP covers spin Hamiltonians; Magpylib covers analytic dipole +
Biot–Savart; nothing covers source → propagation → ODMR → ADC → witness
in one tool.docs/research/quantum-sensing/15-nvsim-implementation-plan.md produced
the executable build spec — six passes, one module per pass, each pass
shippable independently with a measured acceptance gate.
Build nvsim as a standalone Rust leaf crate at v2/crates/nvsim/
implementing the six-pass plan in doc 15. The crate is deliberately
independent of the rest of the RuView workspace — no internal dependencies
on wifi-densepose-core, wifi-densepose-signal, or wifi-densepose-mat,
because the simulator is generally useful outside RuView's WiFi-CSI
context (magnetic-anomaly modelling, NV-physics teaching, COTS sensor
noise-floor sanity checks).
Six-pass implementation:
Scene, DipoleSource, CurrentLoop,
FerrousObject, EddyCurrent aggregate types; MagFrame 60-byte
binary record with magic 0xC51A_6E70.δB ∝ 1/(γ_e · C · √(N · t · T₂*)), T₂ decay
envelope, 4-axis 〈111〉 crystallographic projection with
closed-form (AᵀA) = (4/3)I LSQ inversion. Defaults match Barry
et al. Rev. Mod. Phys. 92 (2020) Table III for COTS bulk diamond.Pipeline::run_with_witness
producing a deterministic SHA-256 over the frame stream.Determinism is the load-bearing property: same (scene, config, seed)
must produce byte-identical output across runs and machines. Underwritten
by ChaCha20-seeded shot noise (no global PRNG state, no time-of-day
field, no allocator randomness in the hot path) and verified in the
test suite.
14.md §2.2 identified.14.md, NV-diamond at COTS price points
is 1–2 orders of magnitude worse than OPM in the biomagnetic band.
Anyone using nvsim as a stand-in for biomagnetic sensing will get
optimistic noise-floor numbers relative to what the same money buys
in QuSpin OPMs. Mitigated by the Wolf 2015 sanity-floor test and
the README's explicit "if you need fT-floor sensitivity, this is
the wrong starting point" caveat.15.md §2.2; the HEAVY_ATTENUATION flag
surfaces this to downstream consumers.nvsim is host-side
only. Existing firmware tags (v0.6.2-esp32) continue to ship
unchanged.ndarray, serde,
thiserror, rand, rand_chacha, sha2); no new top-level
dependencies added.0xC51A_6E70 MagFrame magic is distinct from ADR-018's
CSI magic and ADR-084's sketch magic.Acceptance criteria measured per the implementation plan §5:
| Criterion | Floor | Measured | Verdict |
|---|---|---|---|
Same (scene, seed) → byte-identical SHA-256 witness | required | determinism_same_seed_byte_identical_witness test passes | ✓ |
| Shot-noise-OFF reproduction of analytical Biot–Savart | ≤ 0.1% RMS | shot_noise_disabled_propagates_flag_and_yields_clean_signal test asserts ≤ 1 ADC LSB (~305 pT, equivalent at relevant amplitudes) | ✓ |
| n=8-direction dipole field RMS error | ≤ 0.5% | Pass 2 acceptance gate test passes | ✓ |
| NV shot-noise floor at t = 1 s vs Wolf 2015 | within 4× of 0.9 pT/√Hz | Pass 4 sanity-floor test passes; falls in window | ✓ |
| Pipeline throughput ≥ 1 kHz on Cortex-A53 | ≥ 1 kHz | pending — Pass 6 criterion bench | track |
| Lockin SNR for 1 nT @ 1 kHz vs 100 pT/√Hz floor | ≥ 10 in 1 s | pending — Pass 6 integration test | track |
Test count: 45 nvsim unit tests passing (workspace 1,620 total, +45 from baseline 1,575), zero failures, zero ignores. ESP32-S3 on COM7 unaffected throughout.
| Pass | Module | Commit | Tests |
|---|---|---|---|
| 1 | scaffold + scene + frame | 9c95bfac0 | 12 |
| 2 | source.rs (Biot–Savart) | a6ac08c66 | +7 |
| 3 | propagation.rs | 8c062fbaa | +7 |
| 4 | sensor.rs (NV ensemble) | 177624174 | +8 |
| 5 | digitiser.rs + pipeline.rs | 436d383c9 | +11 |
| 6 | proof.rs + criterion bench | pending | ≥ 5 |
Branch: feat/nvsim-pipeline-simulator. README at
v2/crates/nvsim/README.md — plain-language audience-facing front page.
0xC51F...). nvsim's
MAG_FRAME_MAGIC (0xC51A_6E70) is deliberately distinct.archive/v1/data/proof/.MagFrame shape is the wire format.wifi-densepose-core going through workspace path — but nvsim
doesn't actually depend on it. If the answer is yes, this is a
trivial follow-up.nvsim::Pipeline belong in the same crate as nvsim::scene?
Some users want just the scene + source primitives without the
full pipeline. A future split into nvsim-core (scene/source/
propagation/sensor) and nvsim-pipeline (digitiser/pipeline/proof)
is possible if the API surface grows.expected_witness.sha256 alongside the test
suite. Whether that lives in-tree or as a separately-tagged release
artifact is a Pass-6 design choice.