Add WiFiSenseDemo: Wi-Fi motion sensing from beamforming reports#176
Merged
Conversation
A runnable example (examples/sense/) that turns two supported Realtek adapters into a motion/presence sensor with no SDR and no cooperating AP. One binary drives a sounder and a beamformee on the same host: the sounder injects an NDPA (the MAC hardware-generates the NDP), the beamformee returns a VHT compressed beamforming report, and the sounder self-captures it on a concurrent RX loop (the existing self-sounding path). The per-tone Givens angles track the channel between the two adapters, so a moving person makes them jitter frame-to-frame. New/changed: - src/BfReportDecode.h — header-only decoder for VHT/HT compressed beamforming reports (LSB-first Givens-angle unpack + dequant) and a MotionMeter that measures the per-tone cross-frame circular variance of the phase angle. pick_split() enforces the 802.11 codebook relationship b_phi = b_psi + 2 (uniquely (6,4) for a 10-bit 2x1 report); a naive min-variance search is fooled by a trivially-constant coarse psi into a bit-misaligned split whose phi decodes to noise. - examples/sense/main.cpp — the WiFiSenseDemo binary: two-adapter bring-up (separate libusb contexts), the sounding loop, an AdaptiveDetector (self-calibrating CFAR floor + hysteresis, so no fixed per-rig threshold), a live sigma readout, a report-stream stall watchdog, and a deadlock-proof shutdown. - examples/sense/bf_report_decode_selftest.cpp — headless ctest guarding the decoder against a real captured report; asserts the (6,4) split. Registered as the bf_report_decode test. - examples/sense/README.md — comprehensive hands-on guide: hardware, placement, every knob, the decoding/detector maths, and a capture->analyse loop for experimenting with your own formulas. - src/logger.h — add a verbosity Level to Logger (default Debug, unchanged behaviour) so a demo can quiet the library and own the console. - src/jaguar1/RadioManagementModule.cpp — a channel-set trace was logged at error level; demote to info. - docs/beamforming-victim-sensing.md — trim the "Try it" section to a quickstart that points at the full guide. Active two-adapter mode is validated on hardware (still->CLEAR, wave->MOTION, clean shutdown). A passive AP-sniffing mode and a single-radio self mode are noted as unimplemented follow-ups rather than shipped untested. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two portability breaks in examples/sense/main.cpp caught by the windows-cl and build-mingw CI jobs (macOS/Linux were green): - windows.h (pulled in via libusb.h) defines min/max macros, so std::max(...) failed to compile (C2589). Define NOMINMAX before the libusb include. - MSVC/MinGW have no POSIX setenv. Add a portable set_env() wrapper (_putenv_s on Windows, setenv elsewhere) and route the five arming-flag writes through it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The build-mingw job builds an explicit target subset and (per its own comment) every registered test's binary must be listed or ctest reports it Not Run. The new bf_report_decode test's binary was missing, so mingw ctest failed with "Could not find executable BfReportDecodeSelftest.exe". Add it to the target list. (The MSVC matrix cell builds all targets, so it needs no change.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
josephnef
added a commit
that referenced
this pull request
Jul 5, 2026
…tigation, named knobs (#180) A review of this week's merged PRs surfaced building blocks that already exist in the tree but weren't captured in `docs/adaptive-link-building-blocks.md`. This adds them, keeping the doc's conceptual + reference tone (knobs as hooks). - **Motion / presence sensing** (#176 WiFiSenseDemo — from the self-sounded beamforming report) — a new *environment* sensor class. It is the signal that drives the fade-state receive-chain lever the doc already discusses. - **Interference-mitigation actuators** — the narrowband notch (`DEVOURER_RX_NBI`) and the per-tone de-weighting mask (`DEVOURER_RX_CSI_MASK`) — the *act* half paired with the per-tone localizer's *sense* half, closing that loop (the doc previously had only the sensor). - **Named the concrete knobs** behind existing lever rows: the RX-path mask (`DEVOURER_RX_PATHS`), the hopping / fast-retune channel lever (`DEVOURER_HOP_*`), the 5/10 MHz narrowband re-clock, and the per-layer FEC ladder (`DEVOURER_SVC_LADDER` / `fused-fec.md`). Consistency pass: all links + tool paths resolve; terminology matches the related docs; cross-links added to `pseudo-preamble-puncturing.md` and `beamforming-victim-sensing.md`. Also fixed the README cont-TX entry, which implied the carrier feeds the probe — the probe uses a decoupled beacon feed. Docs only; no code change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A runnable example —
examples/sense/(WiFiSenseDemo) — that turns twosupported Realtek adapters into a motion / presence sensor, with no SDR and
no cooperating AP. One binary drives a sounder and a beamformee on the
same host: the sounder injects an NDPA (the MAC hardware-generates the sounding
NDP), the beamformee returns a VHT compressed beamforming report, and the sounder
self-captures it on a concurrent RX loop (the existing beamforming self-sounding
path). The per-tone Givens angles are a beamformee-side measurement of the channel
between the two adapters, so a person moving makes them jitter frame-to-frame —
the mechanism behind published work like Wi-BFI / BeamSense.
Contents
src/BfReportDecode.h— header-only decoder for VHT/HT compressedbeamforming reports (LSB-first Givens-angle unpack + dequant) and a
MotionMeterthat measures the per-tone cross-frame circular variance of thephase angle.
pick_split()enforces the 802.11 codebook relationshipb_phi = b_psi + 2— uniquely(6,4)for a 10-bit 2×1 report. (A naivemin-cross-frame-variance search is fooled by a trivially-constant coarse
psiinto a bit-misaligned split whose
phidecodes to noise and reads as constantmotion — a real bug found on hardware and now pinned by the self-test.)
examples/sense/main.cpp— theWiFiSenseDemobinary: two-adapter bring-up(separate libusb contexts), the sounding loop, an
AdaptiveDetector(self-calibrating CFAR floor + rising-edge dwell + hold, so no fixed per-rig
threshold), a live
σreadout, a report-stream stall watchdog, and adeadlock-proof shutdown.
examples/sense/bf_report_decode_selftest.cpp— headlessctest(
bf_report_decode) guarding the decoder against a real captured report;asserts the
(6,4)split.examples/sense/README.md— comprehensive hands-on guide: hardware,placement, every knob, the decoding/detector maths, and a capture→analyse loop
for experimenting with your own formulas.
src/logger.h— add a verbosityLeveltoLogger(defaultDebug,unchanged behaviour) so a demo can quiet the library and own the console.
src/jaguar1/RadioManagementModule.cpp— a channel-set trace was logged aterrorlevel; demoted toinfo.docs/beamforming-victim-sensing.md— trim the "Try it" section to aquickstart that points at the full guide.
Validation
CLEAR(0 falsealarms over a deliberate hands-away capture), hand wave →
MOTION(verified byreplaying a labelled still/wave capture through the exact detector logic). Clean
SIGINTexit; stall watchdog exits cleanly when the beamformee stops responding.ctestself-test (green) decodes a real captured report and pinsthe Givens split.
Scope (deliberately honest)
--mode selfvariant are documented as unimplemented follow-ups rather than shipped untested —
passive needs a real AP actively sounding VHT beamforming, which couldn't be
validated against here.
🤖 Generated with Claude Code