wifi-densepose/docs/references/espectre-gap-analysis.md

6.3 KiB
Raw Blame History

ESPectre Gap Analysis (full Pace Part-2 vs. RuView as of 2026-05-17)

Companion to espectre-techniques.md. That doc is the technique catalogue; this one is the what's still missing breakdown, structured exactly along the sections of Pace's How I Turned My Wi-Fi Into a Motion Sensor — Part 2.

Problem #1: NBVI subcarrier selection

Pace step Status in RuView
Formula α·σ/μ² + (1-α)·σ/μ, α = 0.5 ADR-102
Step 1: quiet-window finder ADR-102 v2
Step 2: 25 %-percentile dead-zone gate ADR-102
Step 3: rank + validate (run motion detector on the calibration buffer, pick K with lowest FP rate) raw ranking accepted
Step 4: pick top-K (K=12) ADR-102
Amplitude only (no phase) same

Step 3 absence means a noisy WiFi neighbour with energy concentrated on our top-12 subcarriers would still get picked. Defence: validate.

Problem #2: Gain Lock (AGC + FFT)

All done — ADR-100. Median over 300 packets, MIN_SAFE_AGC=30 skip-on-strong-signal safety, ESP32-S3/C3/C6 platform guards.

Problem #3: Universal threshold via baseline-variance normalization

Done — ADR-103 D3. Pace's scale = 0.25 / baseline_variance implemented as norm_cv = cv / baseline_cv with universal gates 3× (moving) / 6× (active). Falls back to absolute gates when no calibration loaded.

Two-phase boot calibration (~10 s total)

Pace runs both phases as a single atomic boot sequence on the device:

PHASE 1 (3 s)  collect AGC/FFT → median → lock
PHASE 2 (7 s)  rank subcarriers with gain locked → save top-K to NVS
Phase Status in RuView
Phase 1 in FW ADR-100 (csi_collector.c::rv_gain_lock_process)
Phase 2 in FW after Phase 1 NBVI lives in the server as a rolling refresh, not a boot-time freeze
NVS save of both lock + selection each FW boot re-calibrates gain; NBVI re-ranks every server boot

Doing Phase 2 in FW would mean reboot → ready in 0.5 s instead of ~10 s. Trade-off: doesn't adapt to room changes without explicit re-calibration.

Persisted calibration (NVS on the sensor)

Pace stores everything the algorithm needs in NVS on first boot, so post-reboot the sensor is back in detect mode in well under a second:

  • AGC lock value
  • FFT lock value
  • Selected subcarrier indices
  • Baseline variance
  • User-tuned threshold
Item Status in RuView
WiFi creds + collector IP in NVS csi_cfg namespace
Gain lock NVS persistence recomputed on every FW boot
NBVI selection NVS persistence recomputed on every server boot
Baseline NVS persistence partial — server persists to disk (ADR-103), not on the sensor
Threshold NVS persistence universal threshold loaded from data/baseline.json server-side

If we ever ship to operators who don't run the Rust server (pure FW

  • HA), all of these become required.

The Game (Web Serial calibration UI)

Not done. Pace ships a browser-based reaction game at espectre.dev/game that talks to the ESP32 directly over Web Serial API (USB-CDC). The game shows a live motion bar, lets the user tune threshold while playing, and persists the chosen threshold to NVS.

Our closest analogue is the read-only raw.html calibration console (per-node amplitude bars + RSSI traces + classification badges) served by sensing-server on /static/raw.html. No interactive threshold tuning; no Web Serial path; no game.

Testing

Pace ships RuView has
500+ unit tests small smoke tests in some crates
90 % code coverage not tracked
Fixed 2 000-packet reference capture (1 000 idle + 1 000 motion) none — we test live on the operator's deployment
PlatformIO + pytest + ESPHome + Codecov on every push partial — Rust cargo test only; 2 parser regression tests added by parallel agent (csi.rs:751)

This is the largest reliability gap. A 2 000-packet replay against the classifier would protect against silent regressions when we re-tune thresholds or refactor NBVI.

Native Home Assistant integration via ESPHome

Not done. Pace's sensor shows up in HA the moment it's flashed — binary_sensor.motion_<room> entity with attributes. ESPHome handles MQTT / native API / device discovery automatically.

RuView publishes via WebSocket and REST only; would need either an ESPHome component, an MQTT bridge, or a custom HA integration.

Hardware support

  • Pace supports ESP32-S3, ESP32-C3, ESP32-C5, ESP32-C6. Gain-lock is guarded on these targets only; ESP32 + ESP32-S2 fall back to no gain lock.
  • RuView gain-lock code has the same #if guard so the same hardware list works — but we only have hands-on test data for ESP32-S3.

What Pace announces for Part 3 (not yet shipped, not yet on our

radar either)

  • Gesture recognition
  • Fall detection
  • Person vs. pet classification

Priority for RuView, ranked by expected impact

# Item Net benefit Estimate
1 NVS persistence + boot-time NBVI freeze in FW reboot → ready in 0.5 s instead of ~10 s; survives server outage 3-4 h
2 FP-rate validation of NBVI Step 3 defence against noise-source subcarrier overlap 1 h
3 POST /api/v1/baseline/calibrate + button in raw.html calibrate from browser instead of CLI script 30 min
4 Auto-recalibrate on long-quiet periods drops the manual step entirely 1-2 h
5 HA via MQTT (lighter than full ESPHome rewrite) sensor as HA entity 1 day
6 Fixed-replay test suite (2 000 packets) regression protection 1 day
7 Per-subcarrier baseline comparison (ADR-104 draft) off-axis presence detection 1 h
8 Web Serial calibration game nice-to-have 1 day
9 ESPHome native component (instead of MQTT bridge) tighter HA integration 2-3 days

References

  • espectre-techniques.md — technique catalogue
  • ADR-100 — gain lock
  • ADR-101 — classifier
  • ADR-102 — NBVI
  • ADR-103 — baseline persistence
  • Pace, How I Turned My Wi-Fi Into a Motion Sensor — Part 2, Dec 2025
  • francescopace/espectre on GitHub (GPLv3)