mirror of
https://github.com/ruvnet/RuView
synced 2026-08-03 19:21:42 +00:00
177624174e
Pass 4 of the implementation plan — the load-bearing physics module.
Linear-readout proxy for ODMR ensemble magnetometry per Barry et al.
*Rev. Mod. Phys.* 92, 015004 (2020) §III.A. Full Hamiltonian + Lindblad
dynamics is *out of scope* (plan §6); the leading-order formulae below
are validated as adequate for ensemble magnetometers in the linear
regime.
Public API (re-exported from lib.rs):
- NvSensorConfig — gamma_fwhm_hz / t1_s / t2_s / t2_star_s / contrast /
n_spins / shot_noise_disabled. Defaults match Barry 2020 Table III
for COTS bulk diamond.
- NvSensor::cots_defaults() / new(config)
- NvSensor::lorentzian(δν) — normalised Lorentzian, 1.0 on resonance,
0.5 at half-width
- NvSensor::t2_envelope(t) — exp(-t/T2)
- NvSensor::shot_noise_floor_t_sqrt_hz(t) — δB ∝ 1/(γ_e·C·√(N·t·T2*))
- NvSensor::sample(B_in, dt, seed) -> NvReading — projects B onto 4 NV
axes, adds shot noise, recovers via LSQ inversion, returns:
b_recovered, sigma_per_axis, noise_floor_t_sqrt_hz, odmr_nu_plus_hz
- nv_axes() — 4 〈111〉 crystallographic axes (Doherty 2013 §3)
LSQ inversion uses the closed-form (AᵀA) = (4/3) I for the regular
tetrahedron — verified by `nv_axes_form_orthogonal_set_in_aggregate`.
Determinism (plan §5): shot noise is sampled from a ChaCha20 PRNG
seeded explicitly per `sample` call. Same (B_in, dt, seed) ⇒
byte-identical NvReading. New rand + rand_chacha deps, both
crates.io-pinned.
8 new tests:
- lorentzian_fwhm_within_5_percent (FWHM = 1.0 ± 0.05 MHz)
- shot_noise_scales_as_one_over_sqrt_t_over_5_decades
(Barry 2020 Eq. 35; 5 decades from 1 µs to 100 ms)
- t2_envelope_is_exp_minus_t_over_t2
- lsq_recovery_residual_below_one_percent_with_noise_off
(4-axis LSQ inversion exactness)
- zero_input_with_noise_yields_approximately_zero_mean
(n=1024 sample mean ≤ σ_mean of zero per axis)
- shot_noise_floor_within_4x_of_wolf_2015_reference
(Pass-4 acceptance gate per plan §3 / §7-2)
- determinism_same_seed_produces_byte_identical_reading
- nv_axes_form_orthogonal_set_in_aggregate
((AᵀA) = (4/3)I tetrahedron property)
Pass 4 acceptance gate: shot-noise floor at t=1s lands within 4× of
Wolf 2015's 0.9 pT/√Hz bulk-diamond reference. Gate PASSED — no
abort under §7-2.
Validated:
- cargo test -p nvsim → 34 passed (was 26; +8).
- cargo test --workspace --no-default-features → 1,609 passed,
0 failed, 8 ignored (was 1,601; +8).
- ESP32-S3 on COM7 unaffected.
Co-Authored-By: claude-flow <ruv@ruv.net>
33 lines
1.3 KiB
TOML
33 lines
1.3 KiB
TOML
[package]
|
|
name = "nvsim"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
authors.workspace = true
|
|
license.workspace = true
|
|
description = "Deterministic NV-diamond magnetometer pipeline simulator (source -> propagation -> NV ensemble -> ADC + lockin demod)"
|
|
repository.workspace = true
|
|
keywords = ["nv-diamond", "magnetometer", "simulator", "physics", "biot-savart"]
|
|
categories = ["science", "simulation"]
|
|
readme = "README.md"
|
|
|
|
# `nvsim` is a standalone leaf crate. It deliberately has NO internal RuView
|
|
# dependencies — see `docs/research/quantum-sensing/15-nvsim-implementation-plan.md`
|
|
# §1.1 for the rationale. RuView integration (frame format alignment with
|
|
# `wifi-densepose-core::FrameKind`, ruvector trace compression, etc.) is
|
|
# tracked as Optional Integrations in a follow-up section of the README and
|
|
# lands behind feature flags after the core simulator is shipping.
|
|
[dependencies]
|
|
serde = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
thiserror = { workspace = true }
|
|
tracing = { workspace = true }
|
|
|
|
# Pass 4: deterministic ChaCha20 PRNG for shot-noise sampling. Same
|
|
# `(scene, seed)` produces byte-identical outputs across runs and machines —
|
|
# the determinism commitment in plan §5.
|
|
rand = "0.8"
|
|
rand_chacha = "0.3"
|
|
|
|
[dev-dependencies]
|
|
approx = "0.5"
|