* feat(sonic_ct): acoustic digital human workbench — Rust/WASM USCT + R3F UI Add `sonic_ct`, a research-grade Ultrasound Computed Tomography (USCT) simulator and reconstruction workbench. Core (crates/sonic-ct, pure Rust, zero deps, 17 tests): - procedural z-varying torso phantom (fat/muscle/organ shells, spine, ribs, pelvis, liver/spleen/kidneys/aorta, heart+lungs in thorax) - circular ring acquisition with straight-ray travel-time + attenuation - SART time-of-flight reconstruction (1 sweep == delay backprojection) - transparent speed-band segmentation with per-cell uncertainty - coordinate-ascent threshold training (mean Dice ~0.30 -> ~0.63) - RuVector-style acoustic memory: NSW vector index, longitudinal drift, warm-start, anatomical graph-coherence checks, .rvf-style serialization - 3-D volume sweep (truth / recon / error / confidence channels) - mock Butterfly Embedded acquisition boundary (trait, no hardware SDK) WASM (crates/sonic-ct-wasm): raw C-ABI cdylib (no wasm-bindgen, ~39 KB) exposing the single-slice + progressive volume pipeline. UI (examples/sonic-ct): React Three Fiber "Sonic Chamber" — water chamber, transducer ring(s), holographic torso with internal organ glows and class-tinted contour slices, live HUD (acoustic paths, phantom fidelity, path confidence, body composition), cranio-caudal scrubber. Driven entirely by real reconstruction data. Docs (docs/sonic-ct): 8 ADRs, SOTA research map, market brief, SPARC. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(sonic_ct ui): welcome modal + GLB body-model loader with procedural fallback - WelcomeModal: Simulate/Reconstruct/Analyze/Validate intro, Get Started cards, "show on startup" preference, research-only disclaimer. - BodyModel: loads a supplied GLB anatomy model (GLB_URL) and applies a ghost material override + per-organ tinting from organ_manifest.json; cleanly falls back to the procedural violet ghost (torso + internal organ glows) when no asset is supplied or it fails to load. GLB is a visual prior only — the Rust phantom stays the physics ground truth. - Refined holographic ghost: violet volumetric glow, class-tinted contour slices, twin transducer rings, glowing base, internal organ volumes. - docs/sonic-ct/BODY-MODELS.md: researched model sources (Zygote, BioDigital, SMPL/Meshcapade, Z-Anatomy, BodyParts3D) + GLB integration pipeline. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(sonic_ct ui): load open-source CesiumMan GLB as the ghost body shell - Ship CesiumMan (Khronos glTF Sample Assets, CC-BY 4.0) as public/models/human.glb, loaded via useGLTF, auto-fit to the chamber, and styled with the ghost-material override; procedural internal organ glows render inside it. - GLB_URL now points at the bundled model; missing/broken asset still falls back to the procedural torso shell via the error boundary. - Attribution recorded in organ_manifest.json and docs/sonic-ct/BODY-MODELS.md. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): organ-hypothesis detector, Darwin optimizer, rebrand Rename the app to MetaBioHacker (Acoustic Digital Human Workbench · Sonic Chamber) across HUD, welcome modal, and metadata. Organ inference (ADR-0009/0010): new `crates/sonic-ct/src/organ.rs` detects liver, spleen, kidneys, aorta, heart, and lungs from the reconstructed volume using anatomical priors (zone, side, size, posterior adjacency, slice-consistency) — never from speed alone. Each hypothesis carries a confidence and an evidence bitmask. Exposed via WASM (sct_organ_*, sct_quality_flag) and surfaced in a new HUD panel with per-organ confidence bars + quality flags (bone shadowing / sparse coverage / boundary uncertainty / gas). 18 Rust tests pass; clippy clean. Harness optimization (examples/sonic-ct/optimize.mjs): uses @metaharness/darwin ("freeze the model, evolve the harness") with cheap->frontier tiering and Pareto selection over the frozen WASM engine to evolve {elements, fan, iters}; lifts phantom fidelity ~0.53 -> ~0.59. Documented in docs/sonic-ct/OPTIMIZATION.md. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): faithful Darwin harness evolution + OpenRouter write layer - crates/sonic-ct/src/bin/serve.rs: the frozen acoustic engine as a JSON-over- stdio process (sonic_ct_serve) — the physics truth layer for the evolver. - examples/sonic-ct/src/optimizer/reconstructionEvolution.ts: typed genome (reconstruction/routing/scoring/safety), runFrozenRustEngine (spawns the real binary), cheap->frontier routeReconstruction (augments engine output, never rewrites anatomy), multi-objective scoreCandidate, mutateGenome, and evolveMetaBioHarness using Darwin mapLimit + paretoFront + an archive. - optimize.mjs: OpenRouter LLM "write layer" proposes harness mutations (cheap gpt-4o-mini / frontier gpt-4o), gated by routing policy, bounded budget, key read from env only; archive-based acceptance gate now PASSES (latency -92.8%, no regression). probeDarwin.mjs verifies the export surface. - Tests (npm test, Node type-stripping): mapLimit bounds concurrency; paretoFront keeps accurate+cheap trade-offs and drops dominated; frontier never bypasses the frozen engine. docs/sonic-ct/OPTIMIZATION.md updated. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * docs(metabiohacker): ADRs 0009-0019 — organ inference, harness evolution, multimodal data + governance Add 11 ADRs and an index covering the layers built and the medical-data architecture roadmap: Organ/inference layer (grounded in organ.rs / segmentation.rs / Hud.jsx): - 0009 five acoustic classes canonical (no organ identity from speed alone) - 0010 organ identity inferred from anatomical priors (evidence + confidence) - 0011 organ function requires dynamic/multiparametric channels ("not measured") - 0012 explainability mandatory (evidence bitmask surfaced in the UI) - 0013 no disease labels — research mode only Harness + data architecture: - 0014 freeze the physics engine, evolve the reconstruction harness (Darwin) - 0015 patient data as a graph of typed observations (MedicalObservation, provenance + uncertainty + consent scope) - 0016 adopt DICOM / FHIR / LOINC / SNOMED CT / OMOP + RuVector similarity index - 0017 typed multimodal fusion patterns (monitoring/research, not diagnosis) - 0018 governance & SaMD boundary (FDA GMLP/PCCP, Health Canada, Ontario PHIPA) - 0019 a medical signal operating system, not an AI doctor Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): benchmark harness on real CT data + synthetic corpus - Real-data ingestion: Grid::from_pgm (P5 parser), Phantom::from_intensity_grid (band a grayscale CT slice into the five acoustic classes), and pipeline::run_with_phantom (reconstruct a supplied phantom — engine unchanged). - sonic_ct_serve gains a phantomPgm path: reconstruct a real anatomical slice instead of a procedural one and emit the same score schema. - tools/fetchRealSlice.mjs: fetch a public-domain abdominal CT slice (Wikimedia Commons) and convert to a grayscale PGM (image not committed; fetched on demand, derived PGM gitignored). - benchmark.mjs (npm run benchmark): baseline vs Darwin-evolved harness over 12 reproducible synthetic phantoms + 1 real CT slice; writes docs/sonic-ct/ BENCHMARK.md + benchmark.report.json. Representative: evolved harness ~157% faster at equal Dice; real CT honestly harder (Dice ~0.27). - New integration test exercises the PGM/real-phantom reconstruction path (19 Rust tests pass). Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): scale benchmark — 40 synthetic seeds + multiple real CT slices, 95% CI - fetchRealSlice.mjs fetches several public-domain CT slices (abdomen, thorax, pelvis) resiliently, skipping unavailable ones. - benchmark.mjs now runs N synthetic seeds (default 40) + every fetched real slice, reports mean ± 95% CI, and writes docs/sonic-ct/BENCHMARK.md. Representative: 42 samples, evolved harness ~149% faster at equal Dice (±0.002 CI); real CT slices honestly harder (Dice ~0.30). Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): Multimodal Ingest V0 — observations, graph, fusion, ledger, ruvn evidence gate New package packages/metabiohacker (@metabiohacker/core, TS, 14 tests pass): - ingest/: canonical MedicalObservation + lab (CSV→LOINC), imaging (DICOM sidecar), and pathology adapters with provenance/uncertainty/consent. - graph/: auditable patient state graph + rule-based contradiction detection (low-quality, ≥2x same-test disagreement, unflagged review modalities). - fusion/: prior builder (data shapes priors, never forces conclusions), multimodal scoring (acoustic residual passed through unchanged), contradiction penalty, and a Darwin harness (mapLimit + paretoFront) selecting fusion policy. - evidence/: ruvn as the evidence-intelligence layer (off the hot path) — provider interface, A/B-or-blocked claim gate, deterministic cached provider + optional @ruvnet/ruvn CLI adapter (never a hard dep). Claims ship only on grade A/B with citations; pathology/biopsy/Pap/HPV/cytology force human review. - ledger/ + output/: stable-hash reconstruction run ledger (tamper-evident, verifiable) and the safe UI packet (uncertainty overlay, diagnosis blocked). Benchmark: +10% stability, ~37% uncertainty drop, residual unchanged, ledger verified, clinical-review mode forced by pathology. Docs: ADR-0020 (canonical observation), 0021 (graph+contradictions), 0022 (run ledger), 0023 (ruvn evidence layer); ADR index updated. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): real-slice calibration, domain-gap honesty gate, evidence refresh, CI gates Attacks the synthetic→real Dice gap honestly rather than hiding it. - Engine: sonic_ct_serve emits per-class (region) Dice on real slices. - calibration/: region-level Dice (diceByRegion), domain-gap scoring + honesty gate (classifyRealSliceResult: headline/researchOnly/exclude), centroid registration-error + boundary-complexity proxies. Real CT slices are calibration targets, not USCT. - benchmark.mjs: 3-section report (synthetic / real region-level / governance); headline separates speed from real fidelity. Real slices now classify as exclude/researchOnly and stay out of headline metrics (abdomen~0.30). - evidence:refresh (OpenRouter): grades modality evidence into docs/evidence/*.md + a candidate cache; promotion to the curated cache stays a reviewed step. Live run graded acoustic USCT = C (research-only), MRI = B. - CI gates (ciGates.test.ts + .github/workflows/metabiohacker-ci.yml): residual invariant, pathology review forced, A/B-only claims, real-slice honesty gate. 23 metabiohacker tests + 12 Rust integration tests pass. ADR-0024 added. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(sonic_ct): method comparison vs BP/SART/Landweber on Shepp-Logan with RMSE/PSNR/SSIM Bench reconstruction against recognised algorithms on a recognised target: - shepp_logan.rs: standard 10-ellipse Shepp-Logan phantom -> speed map. - reconstruction.rs: Method enum + reconstruct_speed_with; Landweber solver (gradient descent on ‖As−t‖²) alongside backprojection (1 sweep) and SART. - metrics.rs: standard image-quality metrics RMSE, PSNR (dB), SSIM. - sonic_ct_methods bin -> docs/sonic-ct/METHOD-BENCHMARK.md (deterministic). Measured: backprojection < SART < Landweber on every metric for both Shepp-Logan and abdomen (abdomen RMSE 130→99→51 m/s, SSIM 0.22→0.60→0.92) at ~4/28/100 ms. SART stays production default; Landweber is the higher-fidelity option. 2 new tests; 14 integration tests pass; clippy clean. ADR-0025 added. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(metabiohacker): rigid translation registration for real-slice calibration Replace the centroid-only proxy with registerByTranslation — finds the integer offset that maximises predicted/target body-mask overlap Dice, returning the offset, residual misalignment (errorPx), and aligned overlap. Gives the domain-gap honesty gate a real registration estimate (landmark refinement is the next step). +1 test (recovers a known offset; maximises overlap). 24 tests pass. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(sonic_ct): full-waveform inversion (FWI) — forward + adjoint-state gradient The SOTA step beyond straight-ray TOF (ADR-0004 roadmap), as a dependency-free 2-D reference: - fwi.rs: FDTD scalar-wave forward model (∂ₜ²p = κ∇²p + f), CFL-stable, damping sponge; adjoint-state gradient ∂χ/∂κ = Σ_t λ ∇²p; gradient descent with source/receiver-footprint muting, smoothing, and backtracking line search. - Proven by the gold-standard adjoint-vs-finite-difference gradient check (cosine > 0.85) + an inversion that cuts data misfit ≥15% and recovers a centrally-concentrated velocity anomaly. 2 new tests; 23 Rust tests pass; clippy clean. - Honest scope: single-frequency, unregularised — frequency continuation, regularisation, source encoding, and 3-D are the documented next steps; no quantitative clinical recovery claimed. ADR-0026 added. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 * feat(sonic-ct): add FWI frequency continuation (multiscale inversion) Add invert_multiscale + Stage to fwi.rs: chains low->high frequency FWI stages with between-stage model smoothing to avoid cycle-skipping. Low frequencies recover the smooth background first, keeping high-frequency stages out of local minima. Proven by a third FWI test: frequency continuation lowers the inclusion-region error below single-scale FWI at matched iteration count (deterministic). Adjoint-vs-FD gradient check and misfit-reduction tests still pass. Updates ADR-0026. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Mx4vKMfvsq5KBQgPRSoxM7 --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| src | ||
| tests | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
🔊 sonic_ct — Ultrasound Computed Tomography in Rust + WebAssembly
A dependency-free, browser-ready ultrasound CT (USCT) simulator and reconstruction toolkit. Synthetic phantoms · ring acquisition · time-of-flight SART reconstruction · tissue segmentation · self-learning acoustic memory — all in pure Rust, compiled to WebAssembly, visualised with React Three Fiber.
Keywords: ultrasound computed tomography, USCT, transmission ultrasound, time-of-flight tomography, SART reconstruction, full-waveform inversion, tissue segmentation, body composition imaging, Rust WebAssembly medical imaging, React Three Fiber visualization, RuVector vector memory.
What is this?
sonic_ct models a ring ultrasound CT scanner — the kind of architecture behind next-generation full-body scanners that immerse a subject in a water bath and surround them with a dense ring of ultrasound transducers. Every element transmits and receives, so sound passes through the body from hundreds of angles. From those measurements the system reconstructs maps of acoustic properties (speed of sound, attenuation), segments them into tissue classes, and scores the result against ground truth.
It is research/simulation software. It makes no diagnostic claim, and the hardware integration point (a "Butterfly Embedded"-style backend) is a mock adapter behind a trait, not a hardware SDK.
Live in the browser: ground truth · reconstruction + transducer ring · tissue segmentation. ~8,000 simulated measurements reconstructed in ~130 ms of WebAssembly compute.
Why it's interesting
| Property | Detail |
|---|---|
| Zero dependencies | The core crate uses no third-party crates — just std. Reproducible, auditable, tiny. |
| Runs anywhere | Native CLI, library, and wasm32-unknown-unknown from one codebase. |
| Raw WebAssembly | No wasm-bindgen, no wasm-pack — a 31 KB module with a stable C ABI and zero imports. |
| Real physics | Straight-ray time-of-flight tomography solved with SART (Simultaneous Algebraic Reconstruction). |
| It learns | A trainable segmentation model and a RuVector-style acoustic memory (vector index + anatomical graph checks). |
| It's honest | Bone reconstructs poorly with straight rays — and we say so. Full-waveform inversion is the documented next step. |
Quick start
Run the simulator (native)
cd crates/sonic-ct
# One-shot reconstruction → PGM images + metrics
cargo run --release --bin sonic_ct_demo /tmp/out
# Train the segmentation model on a synthetic corpus + build the acoustic memory
cargo run --release --bin sonic_ct_train 24 /tmp/out
# Run the full test suite (16 tests)
cargo test --release
Example demo output:
== sonic_ct demo ==
grid: 96x96
elements: 180
measurements: 8688
MAE (speed): 27.88 m/s
mean Dice: 0.63
coherence: bone↔water=0 organ↔water=… anomaly=…
Run the browser UI (React Three Fiber)
cd examples/sonic-ct
npm install
npm run dev # auto-builds the WASM via scripts/build-sonic-ct-wasm.sh
# open http://localhost:5184
Drag to orbit, scroll to zoom, move the sliders, and hit Run reconstruction to recompute live in WebAssembly.
Use as a library
use sonic_ct::pipeline::{run, PipelineConfig};
let scene = run(PipelineConfig::default()).unwrap();
println!("mean Dice = {:.3}", scene.quality.mean_dice);
println!("speed MAE = {:.1} m/s", scene.quality.mae_speed);
How it works
phantom ─▶ ring ─▶ acquisition ─▶ SART reconstruction ─▶ segmentation ─▶ metrics
│ │
└────────── acoustic memory ◀───────┘
- Phantom (
phantom.rs) — a deterministic, seed-controlled abdomen cross-section: a fat envelope, a muscle wall, organ parenchyma, and a vertebral bone disc. Reproducible "public" data with no external download. - Ring (
geometry.rs) — transducer positions on a circle, with transmit fans that skip grazing near-neighbour paths. - Acquisition (
acquisition.rs) — for every source/receiver pair, sound is integrated along a straight ray: travel time (vs. a water reference) and attenuation, with optional timing noise. - Reconstruction (
reconstruction.rs) — SART solves the tomography systemA·s = tfor per-cell slowness. One sweep equals the classic delay-backprojection baseline; more sweeps approach the least-squares image. - Segmentation (
segmentation.rs) — a transparent speed-band classifier assigns tissue labels and a per-cell uncertainty from each pixel's margin to the nearest decision boundary. - Metrics (
metrics.rs) — Dice per class, mean Dice, and mean-absolute speed error.
The acoustic memory (RuVector integration)
memory.rs is the sonic_ct analogue of RuVector's spatial memory. Each reconstruction becomes a mean-centred, L2-normalised descriptor stored in a navigable small-world (NSW) graph for sub-linear nearest-neighbour search. That enables:
- Longitudinal tracking — compare a subject's scans over time by semantic similarity, not brittle pixel alignment (
longitudinal_drift). - FWI warm-starting — retrieve the closest previously solved reconstruction as an initial model (
warm_start). - Anomaly detection —
check_coherencetreats the segmentation as a graph and flags anatomically impossible geometry (e.g. bone touching the water bath). - Portable, auditable archives — the index round-trips through a compact
.rvf-style binary container, satisfying the "preserve raw evidence" governance rule (ADR-0003).
Training the model
model.rs fits the segmentation thresholds by coordinate ascent over a labelled corpus, maximising mean Dice. On the synthetic data this roughly doubles mean Dice (≈0.30 → ≈0.63) versus literature-default boundaries — and the tuned model ships as the default in the live WASM demo.
Why raw WebAssembly?
Most Rust→WASM projects depend on wasm-bindgen + wasm-pack, which couple your build to a specific toolchain version. sonic_ct instead exports a small, stable C ABI (sct_run, scalar getters, and *_ptr buffer getters). The JS loader (examples/sonic-ct/src/sonicct.js) reads flat Float32Array/Uint8Array views straight from linear memory:
const sct = await SonicCT.load("sonic_ct.wasm");
const r = sct.run({ n: 96, elements: 180, fan: 90, iters: 6, seed: 1 });
console.log(r.meanDice, r.mae, r.reconSpeed); // typed-array, zero-copy
Result: a 31 KB, zero-import module that builds with a single cargo build --target wasm32-unknown-unknown — no extra tooling.
Testing
cargo test --release # 6 unit + 9 integration + 1 doctest = 16 tests
cargo clippy --release # lint-clean core library
The suite verifies the pipeline beats a flat-water prior, Dice scores stay in range, the NSW index matches brute-force top-1, the memory container round-trips, anatomical coherence flags impossible geometry, training never regresses, and the Butterfly mock backend matches direct simulation. A Node smoke test instantiates the WASM and exercises the full surface.
Honest limitations
- Bone is hard. Straight-ray time-of-flight blurs the small, high-contrast spine, so bone Dice is near zero. This is the textbook motivation for full-waveform inversion (FWI) — the documented next step on the roadmap.
- 2-D today.
volume3d.rsscaffolds the vertical-sweep geometry; full 3-D reconstruction is future work. - Simulated, not clinical. No real RF waveforms, no patient data, no diagnosis.
Roadmap
TOF SART (done) → finite-difference wave propagation → adjoint-state FWI → frequency continuation + source encoding → learned sparse completion → 3-D vertical-sweep reconstruction → DICOMweb / FHIR export adapters → quality-system + clinical-validation harness.
See docs/sonic-ct/ for the research map, market brief, SPARC analysis, and 8 ADRs.
License
Dual-licensed under MIT or Apache-2.0, at your option. Part of the RuVector ecosystem.