Commit Graph

3 Commits

Author SHA1 Message Date
ruv 8c062fbaa4 feat(nvsim): propagation.rs material attenuation [nvsim:pass3]
Pass 3 of the implementation plan. Adds per-material attenuation along
sensor–source line-of-sight segments. Free-space 1/r³ falloff stays in
source.rs (it's part of the dipole formula); this layer applies the
*additional* attenuation when LoS crosses material slabs.

Public API:

- Material enum: Air, Drywall, Brick, ConcreteDry,
  ReinforcedConcrete, SheetSteel
- LosSegment { material, path_m }
- material_loss_db_per_m(Material) -> f64 — table lookup
- material_is_heavy(Material) -> bool — gates HEAVY_ATTENUATION flag
- attenuate(B, segments) -> (Vec3, heavy_flag) — top-level transform
- Propagator struct as a stateless wrapper with room for future
  per-frequency parameters

Per-material loss values (DC–10 kHz) per plan §2.2:
- Air / Drywall / Brick: 0 dB/m (drywall + brick conjectural; no
  systematic primary source for residential-wall magnetic-field
  penetration loss at RuView geometry — gap flagged in plan §6.3)
- ConcreteDry: 0.5 dB/m (Ulrich NDT&E Int. 35, 2002 proxy — also
  conjectural)
- ReinforcedConcrete: 20 dB/m + heavy_flag
- SheetSteel: 100 dB/m representative DC bulk loss + heavy_flag

NaN-safety per Pass-3 acceptance gate: segments with non-finite or
non-positive `path_m` are silently skipped — no NaN/Inf propagates
to the digitiser. Asserted in
test_nan_or_negative_path_is_skipped_without_nan_in_output.

7 new tests:
- free_space_is_identity_transform
- drywall_is_approximately_zero_db
- dry_concrete_attenuates_at_half_db_per_meter
  (1 dB total = 10^(-1/20) ≈ 0.8913 linear)
- reinforced_concrete_attenuates_and_raises_heavy_flag
  (4 dB total = 10^(-0.2) ≈ 0.6310 linear)
- nan_or_negative_path_is_skipped_without_nan_in_output
  — Pass-3 NaN guard
- empty_los_returns_input_unchanged
- propagator_struct_dispatches_to_free_function

Validated:
- cargo test -p nvsim → 26 passed (was 19; +7).
- cargo test --workspace --no-default-features → 1,601 passed,
  0 failed, 8 ignored (was 1,594; +7).
- ESP32-S3 on COM7 streaming live CSI (cb #200, recent reboot).

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-26 16:24:58 -04:00
ruv a6ac08c662 feat(nvsim): source.rs Biot–Savart synthesis [nvsim:pass2]
Pass 2 of the implementation plan. Adds magnetic-field synthesis at
arbitrary sensor locations, all in f64 for near-field stability per
plan §7-1.

Public API (re-exported from lib.rs):

- dipole_field(&DipoleSource, sensor_pos) -> ([f64; 3], near_field_flag)
  Closed-form analytic dipole: B = (μ₀ / 4π r³)[3(m·r̂)r̂ − m]
  (Jackson 3e §5.6).
- current_loop_field(&CurrentLoop, sensor_pos) -> (Vec3, flag)
  Numerical Biot–Savart over n_segments straight chords (default 64);
  flag fires if any chord midpoint < R_MIN_M (1 mm) of sensor.
- ferrous_field(&FerrousObject, ambient_b, sensor_pos) -> (Vec3, flag)
  Linear induced moment m = χ·V·H_ambient (Cullity & Graham 2e §2),
  re-radiates as a dipole.
- scene_field_at(&Scene, sensor_pos) -> (Vec3, flag) — aggregate.
- scene_field_at_sensors(&Scene) -> Vec<(Vec3, flag)> — for every sensor.
- R_MIN_M = 1 mm — near-field clamp constant.

Pass 2 acceptance per plan §3 — n=8 RMS gate ≤ 0.5%. Test
`dipole_n8_directions_within_half_percent_rms` independently
recomputes the formula in-test rather than calling the implementation
twice, so the gate guards against an implementation that
accidentally agrees with a buggy reference.

7 new tests:
- on-axis dipole matches B_z = μ₀ m / (2π z³)
- equatorial dipole matches B_z = -μ₀ m / (4π r³)
- n=8 directions RMS ≤ 0.5% — Pass 2 acceptance gate
- on-axis current loop matches μ₀ I a² / [2(a²+z²)^(3/2)]
- near-field r < 1 mm clamps to (0, flag=true)
- zero-ambient ferrous object emits zero field
- two opposite dipoles aggregate to zero at colocated sensor

Validated:
- cargo test -p nvsim → 19 passed (was 12; +7).
- cargo test --workspace --no-default-features → 1,594 passed,
  0 failed, 8 ignored (was 1,587; +7).
- ESP32-S3 on COM7 streaming live CSI (cb #8900).

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-26 16:11:49 -04:00
ruv 9c95bfac0c feat(nvsim): scaffold + scene + frame [nvsim:pass1]
Pass 1 of the NV-diamond magnetometer pipeline simulator per
docs/research/quantum-sensing/15-nvsim-implementation-plan.md.

Standalone leaf crate at v2/crates/nvsim — deliberately NO internal
RuView dependencies. RuView ecosystem integrations
(wifi-densepose-core frame alignment, ruvector trace compression)
are tracked as Optional Integrations in README and land behind
feature flags after the core simulator ships.

Surfaces shipped:

- scene::Scene — aggregate ground-truth scene (dipoles, current loops,
  ferrous objects, eddy-current discs, sensor positions, ambient field)
- scene::DipoleSource — point magnetic dipole, SI units
- scene::CurrentLoop — planar current loop with 64-segment default
  Biot–Savart discretisation
- scene::FerrousObject — linearly-induced moment from ambient field
  (χ_steel ≈ 5000 default per Cullity & Graham 2e §2)
- scene::EddyCurrent — Faraday + Ohm eddy-current disc primitive
- frame::MagFrame — 60-byte fixed-layout binary record, magic
  0xC51A_6E70 (distinct from ADR-018 CSI 0xC51F... and ADR-084 sketch
  0xC511_0084)
- frame::flag::* — bit-set constants (saturation, ADC clip, heavy
  attenuation, shot-noise-disabled). Raw u16 to avoid pulling
  bitflags as a workspace dep.
- NvsimError — typed errors for parse / serialisation failures
- MU_0, GAMMA_E, D_GS — shared physics constants

12 unit tests covering:
- scene JSON round-trip preserves all primitive types
- magic locked to documented value (0xC51A_6E70)
- frame size fixed at 60 bytes
- frame round-trip is byte-exact
- frame deserialiser rejects short / bad-magic / bad-version inputs
- byte-order determinism across repeated serialisations
- flag set/check helpers

Acceptance per plan §3 Pass 1:
- cargo check -p nvsim --no-default-features → clean
- cargo test -p nvsim --no-default-features → 12 passed (target ≥6)
- Workspace test count 1,575 → 1,587 (+12)
- ESP32-S3 on COM7 unaffected (cb #625100, alive)

Two research documents committed alongside:
- 14-nv-diamond-sensor-simulator.md (469 lines, SOTA + verdict)
- 15-nvsim-implementation-plan.md (268 lines, 6-pass build spec)

Status: Pass 1 only. Passes 2-6 (source, propagation, sensor,
digitiser+pipeline, proof+bench) ship in subsequent commits per the
implementation plan.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-26 15:57:58 -04:00