| Field | Value |
|---|---|
| Status | Partially Implemented |
| Date | 2026-02-28 |
| Deciders | ruv |
| Relates to | ADR-013 (Feature-Level Sensing Commodity Gear), ADR-014 (SOTA Signal Processing), ADR-016 (RuVector Integration), ADR-018 (ESP32 Dev Implementation), ADR-021 (Vital Sign Detection) |
The current Windows WiFi mode in wifi-densepose-sensing-server (:main.rs:382-464) spawns a netsh wlan show interfaces subprocess every 500ms, extracting a single RSSI% value from the connected AP. This creates a pseudo-single-subcarrier Esp32Frame with:
- 1 amplitude value (signal%)
- 0 phase information
- ~2 Hz effective sampling rate (process spawn overhead)
- No spatial diversity (single observation point)
This is insufficient for any meaningful DensePose estimation. The ESP32 path provides 56 subcarriers with I/Q data at 100+ Hz, while the Windows path provides 1 scalar at 2 Hz -- a 2,800x data deficit.
A standard Windows WiFi environment exposes 10-30+ BSSIDs via netsh wlan show networks mode=bssid. Testing on the target machine (Intel Wi-Fi 7 BE201 320MHz) reveals:
| Property | Value |
|---|---|
| Adapter | Intel Wi-Fi 7 BE201 320MHz (NDIS 6.89) |
| Visible BSSIDs | 23 |
| Bands | 2.4 GHz (channels 3,5,8,11), 5 GHz (channels 36,48) |
| Radio types | 802.11n, 802.11ac, 802.11ax |
| Signal range | 18% to 99% |
Each BSSID travels a different physical path through the environment. A person's body reflects/absorbs/diffracts each path differently depending on the AP's relative position, frequency, and channel. This creates spatial diversity equivalent to pseudo-subcarriers.
| Tier | Method | Subcarriers | Sample Rate | Implementation |
|---|---|---|---|---|
| Current | netsh show interfaces |
1 | ~2 Hz | Subprocess spawn |
| Tier 1 | netsh show networks mode=bssid |
23 | ~2 Hz | Parse multi-BSSID output |
| Tier 2 | Windows WLAN API (wlanapi.dll FFI) |
23 | 10-20 Hz | Native FFI, no subprocess |
| Tier 3 | Intel Wi-Fi Sensing SDK (802.11bf) | 56+ | 100 Hz | Vendor SDK integration |
This ADR covers Tier 1 and Tier 2. Tier 3 is deferred to a future ADR pending Intel SDK access.
The vendor/ruvector crate ecosystem provides signal processing primitives that transform multi-BSSID RSSI vectors into meaningful sensing data:
| RuVector Primitive | Role in Windows WiFi Enhancement |
|---|---|
PredictiveLayer (nervous-system) |
Suppresses static BSSIDs (no body interaction), transmits only residual changes. At 23 BSSIDs, 80-95% are typically static. |
ScaledDotProductAttention (attention) |
Learns which BSSIDs are most body-sensitive per environment. Attention query = body-motion spectral profile, keys = per-BSSID variance profiles. |
RuvectorLayer (gnn) |
Builds cross-correlation graph over BSSIDs. Nodes = BSSIDs, edges = temporal cross-correlation. Message passing identifies BSSID clusters affected by the same person. |
OscillatoryRouter (nervous-system) |
Isolates breathing-band (0.1-0.5 Hz) oscillations in multi-BSSID variance for coarse respiratory sensing. |
ModernHopfield (nervous-system) |
Template matching for BSSID fingerprint patterns (standing, sitting, walking, empty). |
SpectralCoherenceScore (coherence) |
Measures spectral gap in BSSID correlation graph; strong gap = good signal separation. |
TieredStore (temporal-tensor) |
Stores multi-BSSID time series with adaptive quantization (8/5/3-bit tiers). |
AdaptiveThresholds (ruQu) |
Self-tuning presence/motion thresholds with Welford stats, EMA, outcome-based learning. |
DriftDetector (ruQu) |
Detects environmental changes (AP power cycling, furniture movement, new interference sources). 5 drift profiles: Stable, Linear, StepChange, Oscillating, VarianceExpansion. |
FilterPipeline (ruQu) |
Three-filter gate (Structural/Shift/Evidence) for signal quality assessment. Only PERMITs readings with statistically rigorous confidence. |
SonaEngine (sona) |
Per-environment micro-LoRA adaptation of BSSID weights and filter parameters. |
Implement an Enhanced Windows WiFi sensing pipeline as a new module within the wifi-densepose-sensing-server crate (and partially in a new wifi-densepose-wifiscan crate), using Domain-Driven Design with bounded contexts. The pipeline scans all visible BSSIDs, constructs multi-dimensional pseudo-CSI frames, and processes them through the RuVector signal pipeline to achieve ESP32-comparable presence/motion detection and coarse vital sign estimation.
- Multi-BSSID as pseudo-subcarriers: Each visible BSSID maps to a subcarrier slot in the existing
Esp32Framestructure, enabling reuse of all downstream signal processing. - Progressive enhancement: Tier 1 (netsh parsing) ships first with zero new dependencies. Tier 2 (wlanapi FFI) adds
windows-sysbehind a feature flag. - Graceful degradation: When fewer BSSIDs are visible (<5), the system falls back to single-AP RSSI mode with reduced confidence scores.
- Environment learning: SONA adapts BSSID weights and thresholds per deployment via micro-LoRA, stored in
TieredStore. - Same API surface: The output is a standard
SensingUpdatemessage, indistinguishable from ESP32 mode to the UI.
┌─────────────────────────────────────────────────────────────────────────────┐
│ WiFi DensePose Windows Enhancement │
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────┐ │
│ │ BSSID Acquisition │ │ Signal Intelligence │ │ Sensing Output │ │
│ │ (Supporting Domain) │ │ (Core Domain) │ │ (Generic Domain) │ │
│ │ │ │ │ │ │ │
│ │ • WlanScanner │ │ • BssidAttention │ │ • FrameBuilder │ │
│ │ • BssidRegistry │ │ • SpatialCorrelator │ │ • UpdateEmitter │ │
│ │ • ScanScheduler │ │ • MotionEstimator │ │ • QualityGate │ │
│ │ • RssiNormalizer │ │ • BreathingExtractor │ │ • HistoryStore │ │
│ │ │ │ • DriftMonitor │ │ │ │
│ │ Port: WlanScanPort │ │ • EnvironmentAdapter │ │ Port: SinkPort │ │
│ │ Adapter: NetshScan │ │ │ │ Adapter: WsSink │ │
│ │ Adapter: WlanApiScan│ │ Port: SignalPort │ │ Adapter: RestSink│ │
│ └──────────────────────┘ └──────────────────────┘ └──────────────────┘ │
│ │ │ │ │
│ │ Anti-Corruption │ Anti-Corruption │ │
│ │ Layer (ACL) │ Layer (ACL) │ │
│ └────────────────────────┘────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ Shared Kernel │ │
│ │ • BssidId, RssiDbm, SignalPercent, ChannelInfo, BandType │ │
│ │ • Esp32Frame (reused as universal frame type) │ │
│ │ • SensingUpdate, FeatureInfo, ClassificationInfo │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
Aggregate Root: BssidRegistry
Tracks all visible BSSIDs across scans, maintaining identity stability (BSSIDs appear/disappear as APs beacon).
/// Value Object: unique BSSID identifier
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct BssidId(pub [u8; 6]); // MAC address
/// Value Object: single BSSID observation
#[derive(Clone, Debug)]
pub struct BssidObservation {
pub bssid: BssidId,
pub rssi_dbm: f64,
pub signal_pct: f64,
pub channel: u8,
pub band: BandType,
pub radio_type: RadioType,
pub ssid: String,
pub timestamp: std::time::Instant,
}
#[derive(Clone, Debug, PartialEq)]
pub enum BandType { Band2_4GHz, Band5GHz, Band6GHz }
#[derive(Clone, Debug, PartialEq)]
pub enum RadioType { N, Ac, Ax, Be }
/// Aggregate Root: tracks all visible BSSIDs
pub struct BssidRegistry {
/// Known BSSIDs with sliding window of observations
entries: HashMap<BssidId, BssidEntry>,
/// Ordered list of BSSID IDs for consistent subcarrier mapping
/// (sorted by first-seen time for stability)
subcarrier_map: Vec<BssidId>,
/// Maximum tracked BSSIDs (maps to max subcarriers)
max_bssids: usize,
}
/// Entity: tracked BSSID with history
pub struct BssidEntry {
pub id: BssidId,
pub meta: BssidMeta,
/// Ring buffer of recent RSSI observations
pub history: RingBuffer<f64>,
/// Welford online stats (mean, variance)
pub stats: RunningStats,
/// Last seen timestamp (for expiry)
pub last_seen: std::time::Instant,
/// Subcarrier index in the pseudo-frame (-1 if unmapped)
pub subcarrier_idx: Option<usize>,
}Port: WlanScanPort (Hexagonal architecture)
/// Port: abstracts WiFi scanning backend
#[async_trait::async_trait]
pub trait WlanScanPort: Send + Sync {
/// Perform a scan and return all visible BSSIDs
async fn scan(&self) -> Result<Vec<BssidObservation>>;
/// Get the connected BSSID (if any)
async fn connected(&self) -> Option<BssidObservation>;
/// Trigger an active scan (may not be supported)
async fn trigger_active_scan(&self) -> Result<()>;
}Adapter 1: NetshBssidScanner (Tier 1)
/// Tier 1 adapter: parses `netsh wlan show networks mode=bssid`
pub struct NetshBssidScanner;
#[async_trait::async_trait]
impl WlanScanPort for NetshBssidScanner {
async fn scan(&self) -> Result<Vec<BssidObservation>> {
let output = tokio::process::Command::new("netsh")
.args(["wlan", "show", "networks", "mode=bssid"])
.output()
.await?;
let text = String::from_utf8_lossy(&output.stdout);
parse_bssid_scan_output(&text)
}
// ...
}
/// Parse multi-BSSID netsh output into structured observations
fn parse_bssid_scan_output(output: &str) -> Result<Vec<BssidObservation>> {
// Parses blocks like:
// SSID 1 : MyNetwork
// BSSID 1 : aa:bb:cc:dd:ee:ff
// Signal : 84%
// Radio type : 802.11ax
// Band : 2.4 GHz
// Channel : 5
// Returns Vec<BssidObservation> with all fields populated
todo!()
}Adapter 2: WlanApiBssidScanner (Tier 2, feature-gated)
/// Tier 2 adapter: uses wlanapi.dll via FFI for 10-20 Hz polling
#[cfg(all(target_os = "windows", feature = "wlanapi"))]
pub struct WlanApiBssidScanner {
handle: WlanHandle,
interface_guid: GUID,
}
#[cfg(all(target_os = "windows", feature = "wlanapi"))]
#[async_trait::async_trait]
impl WlanScanPort for WlanApiBssidScanner {
async fn scan(&self) -> Result<Vec<BssidObservation>> {
// WlanGetNetworkBssList returns WLAN_BSS_LIST with per-BSSID:
// - RSSI (i32, dBm)
// - Link quality (u32, 0-100)
// - Channel (from PHY)
// - BSS type, beacon period, IEs
// Much faster than netsh (~5ms vs ~200ms per call)
let bss_list = unsafe {
wlanapi::WlanGetNetworkBssList(
self.handle.0,
&self.interface_guid,
std::ptr::null(),
wlanapi::dot11_BSS_type_any,
0, // security disabled
std::ptr::null_mut(),
std::ptr::null_mut(),
)
};
// ... parse WLAN_BSS_ENTRY structs into BssidObservation
todo!()
}
async fn trigger_active_scan(&self) -> Result<()> {
// WlanScan triggers a fresh scan; results arrive async
unsafe { wlanapi::WlanScan(self.handle.0, &self.interface_guid, ...) };
Ok(())
}
}Domain Service: ScanScheduler
/// Coordinates scan timing and BSSID registry updates
pub struct ScanScheduler {
scanner: Box<dyn WlanScanPort>,
registry: BssidRegistry,
/// Scan interval (Tier 1: 500ms, Tier 2: 50-100ms)
interval: Duration,
/// Adaptive scan rate based on motion detection
adaptive_rate: bool,
}
impl ScanScheduler {
/// Run continuous scanning loop, updating registry
pub async fn run(&mut self, frame_tx: mpsc::Sender<MultiApFrame>) {
let mut ticker = tokio::time::interval(self.interval);
loop {
ticker.tick().await;
match self.scanner.scan().await {
Ok(observations) => {
self.registry.update(&observations);
let frame = self.registry.to_pseudo_frame();
let _ = frame_tx.send(frame).await;
}
Err(e) => tracing::warn!("Scan failed: {e}"),
}
}
}
}This is where RuVector primitives compose into a sensing pipeline.
Domain Service: WindowsWifiPipeline
/// Core pipeline that transforms multi-BSSID scans into sensing data
pub struct WindowsWifiPipeline {
// ── Stage 1: Predictive Gating ──
/// Suppresses static BSSIDs (no body interaction)
/// ruvector-nervous-system::routing::PredictiveLayer
predictive: PredictiveLayer,
// ── Stage 2: Attention Weighting ──
/// Learns BSSID body-sensitivity per environment
/// ruvector-attention::ScaledDotProductAttention
attention: ScaledDotProductAttention,
// ── Stage 3: Spatial Correlation ──
/// Cross-correlation graph over BSSIDs
/// ruvector-gnn::RuvectorLayer (nodes=BSSIDs, edges=correlation)
correlator: BssidCorrelator,
// ── Stage 4: Motion/Presence Estimation ──
/// Multi-BSSID motion score with per-AP weighting
motion_estimator: MultiApMotionEstimator,
// ── Stage 5: Coarse Vital Signs ──
/// Breathing extraction from body-sensitive BSSID oscillations
/// ruvector-nervous-system::routing::OscillatoryRouter
breathing: CoarseBreathingExtractor,
// ── Stage 6: Quality Gate ──
/// ruQu three-filter pipeline + adaptive thresholds
quality_gate: VitalCoherenceGate,
// ── Stage 7: Fingerprint Matching ──
/// Hopfield template matching for posture classification
/// ruvector-nervous-system::hopfield::ModernHopfield
fingerprint: BssidFingerprintMatcher,
// ── Stage 8: Environment Adaptation ──
/// SONA micro-LoRA per deployment
/// sona::SonaEngine
adapter: SonaEnvironmentAdapter,
// ── Stage 9: Drift Monitoring ──
/// ruQu drift detection per BSSID baseline
drift: Vec<DriftDetector>,
// ── Storage ──
/// Tiered storage for BSSID time series
/// ruvector-temporal-tensor::TieredStore
store: TieredStore,
config: WindowsWifiConfig,
}Value Object: WindowsWifiConfig
pub struct WindowsWifiConfig {
/// Maximum BSSIDs to track (default: 32)
pub max_bssids: usize,
/// Scan interval for Tier 1 (default: 500ms)
pub tier1_interval_ms: u64,
/// Scan interval for Tier 2 (default: 50ms)
pub tier2_interval_ms: u64,
/// PredictiveLayer residual threshold (default: 0.05)
pub predictive_threshold: f32,
/// Minimum BSSIDs for multi-AP mode (default: 3)
pub min_bssids: usize,
/// BSSID expiry after no observation (default: 30s)
pub bssid_expiry_secs: u64,
/// Enable coarse breathing extraction (default: true)
pub enable_breathing: bool,
/// Enable fingerprint matching (default: true)
pub enable_fingerprint: bool,
/// Enable SONA adaptation (default: true)
pub enable_adaptation: bool,
/// Breathing band (Hz) — relaxed for low sample rate
pub breathing_band: (f64, f64),
/// Motion variance threshold for presence detection
pub motion_threshold: f64,
}
impl Default for WindowsWifiConfig {
fn default() -> Self {
Self {
max_bssids: 32,
tier1_interval_ms: 500,
tier2_interval_ms: 50,
predictive_threshold: 0.05,
min_bssids: 3,
bssid_expiry_secs: 30,
enable_breathing: true,
enable_fingerprint: true,
enable_adaptation: true,
breathing_band: (0.1, 0.5),
motion_threshold: 0.15,
}
}
}Domain Service: Stage-by-Stage Processing
impl WindowsWifiPipeline {
pub fn process(&mut self, frame: &MultiApFrame) -> Option<EnhancedSensingResult> {
let n = frame.bssid_count;
if n < self.config.min_bssids {
return None; // Too few BSSIDs, degrade to legacy
}
// ── Stage 1: Predictive Gating ──
// Convert RSSI dBm to linear amplitude for PredictiveLayer
let amplitudes: Vec<f32> = frame.rssi_dbm.iter()
.map(|&r| 10.0f32.powf((r as f32 + 100.0) / 20.0))
.collect();
let has_change = self.predictive.should_transmit(&litudes);
self.predictive.update(&litudes);
if !has_change {
return None; // Environment static, no body present
}
// ── Stage 2: Attention Weighting ──
// Query: variance profile of breathing band per BSSID
// Key: current RSSI variance per BSSID
// Value: amplitude vector
let query = self.compute_breathing_variance_query(frame);
let keys = self.compute_bssid_variance_keys(frame);
let key_refs: Vec<&[f32]> = keys.iter().map(|k| k.as_slice()).collect();
let val_refs: Vec<&[f32]> = amplitudes.chunks(1).collect(); // per-BSSID
let weights = self.attention.compute(&query, &key_refs, &val_refs);
// ── Stage 3: Spatial Correlation ──
// Build correlation graph: edge(i,j) = pearson_r(bssid_i, bssid_j)
let correlation_features = self.correlator.forward(&frame.histories);
// ── Stage 4: Motion Estimation ──
let motion = self.motion_estimator.estimate(
&weights,
&correlation_features,
&frame.per_bssid_variance,
);
// ── Stage 5: Coarse Breathing ──
let breathing = if self.config.enable_breathing && motion.level == MotionLevel::Minimal {
self.breathing.extract_from_weighted_bssids(
&weights,
&frame.histories,
frame.sample_rate_hz,
)
} else {
None
};
// ── Stage 6: Quality Gate (ruQu) ──
let reading = PreliminaryReading {
motion,
breathing,
signal_quality: self.compute_signal_quality(n, &weights),
};
let verdict = self.quality_gate.gate(&reading);
if matches!(verdict, Verdict::Deny) {
return None;
}
// ── Stage 7: Fingerprint Matching ──
let posture = if self.config.enable_fingerprint {
self.fingerprint.classify(&litudes)
} else {
None
};
// ── Stage 8: Environment Adaptation ──
if self.config.enable_adaptation {
self.adapter.end_trajectory(reading.signal_quality);
}
// ── Stage 9: Drift Monitoring ──
for (i, drift) in self.drift.iter_mut().enumerate() {
if i < n {
drift.push(frame.rssi_dbm[i]);
}
}
// ── Stage 10: Store ──
let tick = frame.sequence as u64;
self.store.put(
ruvector_temporal_tensor::BlockKey::new(0, tick),
&litudes,
ruvector_temporal_tensor::Tier::Hot,
tick,
);
Some(EnhancedSensingResult {
motion,
breathing,
posture,
signal_quality: reading.signal_quality,
bssid_count: n,
verdict,
})
}
}Domain Service: FrameBuilder
Converts EnhancedSensingResult to the existing SensingUpdate and Esp32Frame types for compatibility.
/// Converts multi-BSSID scan into Esp32Frame for downstream compatibility
pub struct FrameBuilder;
impl FrameBuilder {
pub fn to_esp32_frame(
registry: &BssidRegistry,
observations: &[BssidObservation],
) -> Esp32Frame {
let subcarrier_map = registry.subcarrier_map();
let n_sub = subcarrier_map.len();
let mut amplitudes = vec![0.0f64; n_sub];
let mut phases = vec![0.0f64; n_sub];
for obs in observations {
if let Some(idx) = registry.subcarrier_index(&obs.bssid) {
// Convert RSSI dBm to linear amplitude
amplitudes[idx] = 10.0f64.powf((obs.rssi_dbm + 100.0) / 20.0);
// Phase: encode channel as pseudo-phase (for downstream
// tools that expect phase data)
phases[idx] = (obs.channel as f64 / 48.0) * std::f64::consts::PI;
}
}
Esp32Frame {
magic: 0xC511_0002, // New magic for multi-BSSID frames
node_id: 0,
n_antennas: 1,
n_subcarriers: n_sub as u8,
freq_mhz: 2437, // Mixed; could use median
sequence: 0, // Set by caller
rssi: observations.iter()
.map(|o| o.rssi_dbm as i8)
.max()
.unwrap_or(-90),
noise_floor: -95,
amplitudes,
phases,
}
}
pub fn to_sensing_update(
result: &EnhancedSensingResult,
frame: &Esp32Frame,
registry: &BssidRegistry,
tick: u64,
) -> SensingUpdate {
let nodes: Vec<NodeInfo> = registry.subcarrier_map().iter()
.filter_map(|bssid| registry.get(bssid))
.enumerate()
.map(|(i, entry)| NodeInfo {
node_id: i as u8,
rssi_dbm: entry.stats.mean,
position: estimate_ap_position(entry),
amplitude: vec![frame.amplitudes.get(i).copied().unwrap_or(0.0)],
subcarrier_count: 1,
})
.collect();
SensingUpdate {
msg_type: "sensing_update".to_string(),
timestamp: chrono::Utc::now().timestamp_millis() as f64 / 1000.0,
source: format!("wifi:multi-bssid:{}", result.bssid_count),
tick,
nodes,
features: result.to_feature_info(),
classification: result.to_classification_info(),
signal_field: generate_enhanced_signal_field(result, tick),
}
}
}rust-port/wifi-densepose-rs/crates/wifi-densepose-wifiscan/
├── Cargo.toml
└── src/
├── lib.rs # Public API, re-exports
├── domain/
│ ├── mod.rs
│ ├── bssid.rs # BssidId, BssidObservation, BandType, RadioType
│ ├── registry.rs # BssidRegistry aggregate, BssidEntry entity
│ ├── frame.rs # MultiApFrame value object
│ └── result.rs # EnhancedSensingResult, PreliminaryReading
├── port/
│ ├── mod.rs
│ ├── scan_port.rs # WlanScanPort trait
│ └── sink_port.rs # SensingOutputPort trait
├── adapter/
│ ├── mod.rs
│ ├── netsh_scanner.rs # NetshBssidScanner (Tier 1)
│ ├── wlanapi_scanner.rs # WlanApiBssidScanner (Tier 2, feature-gated)
│ └── frame_builder.rs # FrameBuilder (to Esp32Frame / SensingUpdate)
├── pipeline/
│ ├── mod.rs
│ ├── config.rs # WindowsWifiConfig
│ ├── predictive_gate.rs # PredictiveLayer wrapper for multi-BSSID
│ ├── attention_weight.rs # AttentionSubcarrierWeighter for BSSIDs
│ ├── spatial_correlator.rs # GNN-based BSSID correlation
│ ├── motion_estimator.rs # Multi-AP motion/presence estimation
│ ├── breathing.rs # CoarseBreathingExtractor
│ ├── quality_gate.rs # ruQu VitalCoherenceGate
│ ├── fingerprint.rs # ModernHopfield posture fingerprinting
│ ├── drift_monitor.rs # Per-BSSID DriftDetector
│ ├── embedding.rs # BssidEmbedding (SONA micro-LoRA per-BSSID)
│ └── pipeline.rs # WindowsWifiPipeline orchestrator
├── application/
│ ├── mod.rs
│ └── scan_scheduler.rs # ScanScheduler service
└── error.rs # WifiScanError type
[package]
name = "wifi-densepose-wifiscan"
version = "0.1.0"
edition = "2021"
[features]
default = []
wlanapi = ["windows-sys"] # Tier 2: native WLAN API
full = ["wlanapi"]
[dependencies]
# Internal
wifi-densepose-signal = { path = "../wifi-densepose-signal" }
# RuVector (vendored)
ruvector-nervous-system = { path = "../../../../vendor/ruvector/crates/ruvector-nervous-system" }
ruvector-attention = { path = "../../../../vendor/ruvector/crates/ruvector-attention" }
ruvector-gnn = { path = "../../../../vendor/ruvector/crates/ruvector-gnn" }
ruvector-coherence = { path = "../../../../vendor/ruvector/crates/ruvector-coherence" }
ruvector-temporal-tensor = { path = "../../../../vendor/ruvector/crates/ruvector-temporal-tensor" }
ruvector-core = { path = "../../../../vendor/ruvector/crates/ruvector-core" }
ruqu = { path = "../../../../vendor/ruvector/crates/ruQu" }
sona = { path = "../../../../vendor/ruvector/crates/sona" }
# Async runtime
tokio = { workspace = true }
async-trait = "0.1"
# Serialization
serde = { workspace = true }
serde_json = { workspace = true }
# Logging
tracing = { workspace = true }
# Time
chrono = "0.4"
# Windows native API (Tier 2, optional)
[target.'cfg(target_os = "windows")'.dependencies]
windows-sys = { version = "0.52", features = [
"Win32_NetworkManagement_WiFi",
"Win32_Foundation",
], optional = true }Visible BSSIDs (23):
┌──────────────────┬─────┬──────┬──────┬─────────┐
│ BSSID (MAC) │ Ch │ Band │ RSSI │ SubIdx │
├──────────────────┼─────┼──────┼──────┼─────────┤
│ a6:aa:c3:52:1b:28│ 11 │ 2.4G │ -2dBm│ 0 │
│ 82:cd:d6:d6:c3:f5│ 8 │ 2.4G │ -1dBm│ 1 │
│ 16:0a:c5:39:e3:5d│ 5 │ 2.4G │-16dBm│ 2 │
│ 16:27:f5:b2:6b:ae│ 8 │ 2.4G │-17dBm│ 3 │
│ 10:27:f5:b2:6b:ae│ 8 │ 2.4G │-22dBm│ 4 │
│ c8:9e:43:47:a1:3f│ 3 │ 2.4G │-40dBm│ 5 │
│ 90:aa:c3:52:1b:28│ 11 │ 2.4G │ -2dBm│ 6 │
│ ... │ ... │ ... │ ... │ ... │
│ 92:aa:c3:52:1b:20│ 36 │ 5G │ -6dBm│ 20 │
│ c8:9e:43:47:a1:40│ 48 │ 5G │-78dBm│ 21 │
│ ce:9e:43:47:a1:40│ 48 │ 5G │-82dBm│ 22 │
└──────────────────┴─────┴──────┴──────┴─────────┘
Mapping rule: sorted by first-seen time (stable ordering).
New BSSIDs get the next available subcarrier index.
BSSIDs not seen for >30s are expired and their index recycled.
┌────[AP1: ch3]
│ │
body │ │ path A (partially blocked)
┌───┐ │ │
│ │──┤ ▼
│ P │ │ ┌──────────┐
│ │──┤ │ WiFi │
└───┘ │ │ Adapter │
│ │ (BE201) │
┌──────┤ └──────────┘
│ │ ▲
[AP2: ch11] │ │ path B (unobstructed)
│ │
└────[AP3: ch36]
│ path C (reflected off wall)
Person P attenuates path A by 3-8 dB, while paths B and C
are unaffected. This differential is the multi-BSSID body signal.
At different body positions/orientations, different AP combinations
show attenuation → spatial diversity ≈ pseudo-subcarrier diversity.
/// Convert RSSI dBm to linear amplitude (normalized)
/// RSSI range: -100 dBm (noise) to -20 dBm (very strong)
fn rssi_to_linear(rssi_dbm: f64) -> f64 {
// Map -100..0 dBm to 0..1 linear scale
// Using 10^((rssi+100)/20) gives log-scale amplitude
10.0f64.powf((rssi_dbm + 100.0) / 20.0)
}
/// Convert linear amplitude back to dBm
fn linear_to_rssi(amplitude: f64) -> f64 {
20.0 * amplitude.max(1e-10).log10() - 100.0
}Since RSSI provides no phase information, we encode channel and band as a pseudo-phase for downstream tools:
/// Encode BSSID channel/band as pseudo-phase
/// This preserves frequency-group identity for the GNN correlator
fn encode_pseudo_phase(channel: u8, band: BandType) -> f64 {
let band_offset = match band {
BandType::Band2_4GHz => 0.0,
BandType::Band5GHz => std::f64::consts::PI,
BandType::Band6GHz => std::f64::consts::FRAC_PI_2,
};
// Spread channels across [0, PI) within each band
let ch_phase = (channel as f64 / 48.0) * std::f64::consts::FRAC_PI_2;
band_offset + ch_phase
}| Pipeline Stage | RuVector Crate | Specific Type | Purpose |
|---|---|---|---|
| Predictive Gate | ruvector-nervous-system |
PredictiveLayer |
RMS residual gating (threshold 0.05); suppresses scans with no body-caused changes |
| Attention Weight | ruvector-attention |
ScaledDotProductAttention |
Query=breathing variance profile, Key=per-BSSID variance, Value=amplitude; outputs per-BSSID importance weights |
| Spatial Correlator | ruvector-gnn |
RuvectorLayer + LayerNorm |
Correlation graph over BSSIDs; single message-passing layer identifies co-varying BSSID clusters |
| Breathing Extraction | ruvector-nervous-system |
OscillatoryRouter |
0.15 Hz oscillator phase-locks to strongest breathing component in weighted BSSID variance |
| Fingerprint Matching | ruvector-nervous-system |
ModernHopfield |
Stores 4 templates: empty-room, standing, sitting, walking; exponential capacity retrieval |
| Signal Quality | ruvector-coherence |
SpectralCoherenceScore |
Spectral gap of BSSID correlation graph; higher gap = cleaner body signal |
| Quality Gate | ruQu |
FilterPipeline + AdaptiveThresholds |
Three-filter PERMIT/DENY/DEFER; self-tunes thresholds with Welford/EMA |
| Drift Monitor | ruQu |
DriftDetector |
Per-BSSID baseline tracking; 5 profiles (Stable/Linear/StepChange/Oscillating/VarianceExpansion) |
| Environment Adapt | sona |
SonaEngine |
Per-deployment micro-LoRA adaptation of attention weights and filter parameters |
| Tiered Storage | ruvector-temporal-tensor |
TieredStore |
8-bit hot / 5-bit warm / 3-bit cold; 23 BSSIDs × 1024 samples ≈ 24 KB hot |
| Pattern Search | ruvector-core |
VectorDB (HNSW) |
BSSID fingerprint nearest-neighbor lookup (<1ms for 1000 templates) |
| Metric | Tier 1 (netsh) | Tier 2 (wlanapi) |
|---|---|---|
| BSSIDs per scan | 23 | 23 |
| Scan rate | 2 Hz | 20 Hz |
| Samples/sec | 46 | 460 |
| Bytes/sec (raw) | 184 B | 1,840 B |
| Ring buffer memory (1024 samples × 23 BSSIDs × 8 bytes) | 188 KB | 188 KB |
| PredictiveLayer savings | 80-95% suppressed | 90-99% suppressed |
| Net processing rate | 2-9 frames/sec | 2-46 frames/sec |
| Metric | Current (1 RSSI) | Tier 1 (Multi-BSSID) | Tier 2 (+ Native API) |
|---|---|---|---|
| Presence detection accuracy | ~70% (threshold) | ~88% (multi-AP attention) | ~93% (temporal + spatial) |
| Presence detection latency | 500ms | 500ms | 50ms |
| Motion level classification | 2 levels | 4 levels (static/minimal/moderate/active) | 4 levels + direction |
| Room-level localization | None | Coarse (nearest AP cluster) | Moderate (3-AP trilateration) |
| Breathing rate detection | None | Marginal (0.3 confidence) | Fair (0.5-0.6 confidence) |
| Heart rate detection | None | None | None (need CSI for HR) |
| Posture classification | None | 4 classes (empty/standing/sitting/walking) | 4 classes + confidence |
| Environmental drift resilience | None | Good (ruQu adaptive) | Good (+ SONA adaptation) |
/// Signal quality as a function of BSSID count and variance spread
fn compute_signal_quality(
bssid_count: usize,
attention_weights: &[f32],
spectral_gap: f64,
) -> f64 {
// Factor 1: BSSID diversity (more APs = more spatial info)
let diversity = (bssid_count as f64 / 20.0).min(1.0);
// Factor 2: Attention concentration (body-sensitive BSSIDs dominate)
let max_weight = attention_weights.iter().copied().fold(0.0f32, f32::max);
let mean_weight = attention_weights.iter().sum::<f32>() / attention_weights.len() as f32;
let concentration = (max_weight / mean_weight.max(1e-6) - 1.0).min(5.0) as f64 / 5.0;
// Factor 3: Spectral gap (clean body signal separation)
let separation = spectral_gap.min(1.0);
// Combined quality
(diversity * 0.3 + concentration * 0.4 + separation * 0.3).clamp(0.0, 1.0)
}// In main(), extend auto-detection:
let source = match args.source.as_str() {
"auto" => {
if probe_esp32(args.udp_port).await {
"esp32"
} else if probe_multi_bssid().await {
"wifi-enhanced" // NEW: multi-BSSID mode
} else if probe_windows_wifi().await {
"wifi" // Legacy single-RSSI
} else {
"simulate"
}
}
other => other,
};
// Start appropriate background task
match source {
"esp32" => {
tokio::spawn(udp_receiver_task(state.clone(), args.udp_port));
tokio::spawn(broadcast_tick_task(state.clone(), args.tick_ms));
}
"wifi-enhanced" => {
// NEW: multi-BSSID enhanced pipeline
tokio::spawn(enhanced_wifi_task(state.clone(), args.tick_ms));
}
"wifi" => {
tokio::spawn(windows_wifi_task(state.clone(), args.tick_ms));
}
_ => {
tokio::spawn(simulated_data_task(state.clone(), args.tick_ms));
}
}async fn enhanced_wifi_task(state: SharedState, tick_ms: u64) {
let scanner: Box<dyn WlanScanPort> = {
#[cfg(feature = "wlanapi")]
{ Box::new(WlanApiBssidScanner::new().unwrap_or_else(|_| {
tracing::warn!("WLAN API unavailable, falling back to netsh");
Box::new(NetshBssidScanner)
})) }
#[cfg(not(feature = "wlanapi"))]
{ Box::new(NetshBssidScanner) }
};
let mut registry = BssidRegistry::new(32);
let mut pipeline = WindowsWifiPipeline::new(WindowsWifiConfig::default());
let mut interval = tokio::time::interval(Duration::from_millis(tick_ms));
let mut seq: u32 = 0;
info!("Enhanced WiFi multi-BSSID pipeline active (tick={}ms)", tick_ms);
loop {
interval.tick().await;
seq += 1;
let observations = match scanner.scan().await {
Ok(obs) => obs,
Err(e) => { warn!("Scan failed: {e}"); continue; }
};
registry.update(&observations);
let frame = FrameBuilder::to_esp32_frame(®istry, &observations);
// Run through RuVector-powered pipeline
let multi_frame = registry.to_multi_ap_frame();
let result = pipeline.process(&multi_frame);
let mut s = state.write().await;
s.source = format!("wifi-enhanced:{}", observations.len());
s.tick += 1;
let tick = s.tick;
let update = match result {
Some(r) => FrameBuilder::to_sensing_update(&r, &frame, ®istry, tick),
None => {
// Fallback: basic update from frame
let (features, classification) = extract_features_from_frame(&frame);
SensingUpdate {
msg_type: "sensing_update".into(),
timestamp: chrono::Utc::now().timestamp_millis() as f64 / 1000.0,
source: format!("wifi-enhanced:{}", observations.len()),
tick,
nodes: vec![],
features,
classification,
signal_field: generate_signal_field(
frame.rssi as f64, 1.0, 0.05, tick,
),
}
}
};
if let Ok(json) = serde_json::to_string(&update) {
let _ = s.tx.send(json);
}
s.latest_update = Some(update);
}
}| Stage | Tier 1 Latency | Tier 2 Latency | Notes |
|---|---|---|---|
| BSSID scan | ~200ms (netsh) | ~5ms (wlanapi) | Process spawn vs FFI |
| Registry update | <1ms | <1ms | HashMap lookup |
| PredictiveLayer gate | <10us | <10us | 23-element RMS |
| Attention weighting | <50us | <50us | 23×64 matmul |
| GNN correlation | <100us | <100us | 23-node single layer |
| Motion estimation | <20us | <20us | Weighted variance |
| Breathing extraction | <30us | <30us | Bandpass + peak detect |
| ruQu quality gate | <10us | <10us | Three comparisons |
| Fingerprint match | <50us | <50us | Hopfield retrieval |
| Total per tick | ~200ms | ~5ms | Scan dominates Tier 1 |
| Component | Memory |
|---|---|
| BssidRegistry (32 entries × history) | ~264 KB |
| PredictiveLayer (32-element) | <1 KB |
| Attention weights | ~8 KB |
| GNN layer | ~12 KB |
| Hopfield (32-dim, 10 templates) | ~3 KB |
| TieredStore (256 KB budget) | 256 KB |
| DriftDetector (32 instances) | ~32 KB |
| Total | ~576 KB |
- No raw BSSID data to UI: Only aggregated sensing updates are broadcast. Individual BSSID MACs, SSIDs, and locations are kept server-side to prevent WiFi infrastructure fingerprinting.
- BSSID anonymization: The
NodeInfo.node_iduses sequential indices, not MAC addresses. - Local-only processing: All signal processing occurs on-device. No scan data is transmitted externally.
- Scan permission:
netsh wlan show networksrequires no admin privileges.WlanGetNetworkBssListrequires the WLAN service to be running (default on Windows).
Improve the current single-RSSI path with better filtering and drift detection, without multi-BSSID.
Rejected: A single RSSI value lacks spatial diversity. No amount of temporal filtering can recover spatial information from a 1D signal. Multi-BSSID is the minimum viable path to meaningful presence sensing.
Put the WiFi adapter into monitor mode to capture raw 802.11 frames with per-subcarrier CSI.
Rejected for Windows: Monitor mode requires specialized drivers (nexmon, picoscenes) that are Linux-only for Intel adapters. Windows NDIS does not expose raw CSI. Tier 3 (Intel SDK) is the legitimate Windows path to CSI.
Use a separate USB adapter in monitor mode on Linux via WSL.
Rejected: Adds hardware dependency, WSL USB passthrough complexity, and defeats the "commodity gear, zero setup" value proposition.
Scan BLE beacons for additional spatial observations.
Deferred: Could complement multi-BSSID but adds BLE scanning complexity. Future enhancement, not core path.
- 10-20x data improvement: From 1 RSSI at 2 Hz to 23 BSSIDs at 2-20 Hz
- Spatial awareness: Different APs provide different body-interaction paths
- Reuses existing pipeline:
Esp32FrameandSensingUpdateare unchanged; UI works without modification - Zero hardware required: Uses commodity WiFi infrastructure already present
- RuVector composition: Leverages 8 existing crates; ~80% of the intelligence is pre-built
- Progressive enhancement: Tier 1 ships immediately, Tier 2 adds behind feature flag
- Environment-adaptive: SONA + ruQu self-tune per deployment
- Still no CSI phase: RSSI-only means no heart rate and limited breathing detection
- AP density dependent: Fewer visible APs = degraded fidelity (min 3 required)
- Scan latency: Tier 1 netsh is slow (~200ms); Tier 2 wlanapi required for real-time
- AP mobility: Moving APs (phones as hotspots) create false motion signals
- Cross-platform:
wlanapi.dllis Windows-only; Linux/macOS need separate adapters - New crate: Adds
wifi-densepose-wifiscanto workspace, increasing compile scope
- Create
wifi-densepose-wifiscancrate with DDD module structure - Implement
BssidId,BssidObservation,BandType,RadioTypevalue objects - Implement
BssidRegistryaggregate with ring buffer history and Welford stats - Implement
NetshBssidScanneradapter (parsenetsh wlan show networks mode=bssid) - Implement
MultiApFrame,EnhancedSensingResult,WlanScanPort, error types - All 42 unit tests passing (parser, domain types, registry, result types)
- Implement
FrameBuilder::to_esp32_frame()(multi-BSSID → pseudo-Esp32Frame) - Implement
ScanSchedulerwith configurable interval - Integration test: scan → registry → pseudo-frame → existing sensing pipeline
- Wire
enhanced_wifi_taskinto sensing servermain()
- Implement
PredictiveGatewrapper overPredictiveLayerfor multi-BSSID - Implement
AttentionSubcarrierWeighterwith breathing-variance query - Implement
BssidCorrelatorusingRuvectorLayercorrelation graph - Implement
MultiApMotionEstimatorwith weighted variance - Implement
CoarseBreathingExtractorwithOscillatoryRouter - Implement
VitalCoherenceGate(ruQu three-filter pipeline) - Implement
BssidFingerprintMatcherwithModernHopfieldtemplates - Implement
WindowsWifiPipelineorchestrator - Unit tests with synthetic multi-BSSID data
- Implement
WlanApiBssidScannerusingwindows-sysFFI - Benchmark: netsh vs wlanapi latency
- Implement
SonaEnvironmentAdapterfor per-deployment learning - Implement per-BSSID
DriftDetectorarray - Implement
TieredStorewrapper for BSSID time series - Performance benchmarking (latency budget validation)
- End-to-end integration test on real Windows WiFi
- Signal quality calibration against known ground truth
- Confidence score validation (presence/motion/breathing)
- BSSID anonymization in output messages
- Adaptive scan rate (faster when motion detected)
- Documentation and API reference
- Feature flag verification (
wlanapion/off)
The following issues were identified during code review against the vendored RuVector source and corrected in this ADR:
| # | Issue | Fix Applied |
|---|---|---|
| 1 | GnnLayer does not exist in ruvector-gnn; actual export is RuvectorLayer |
Renamed all references to RuvectorLayer |
| 2 | ScaledDotProductAttention has no .forward() method; actual API is .compute(query, keys, values) with &[&[f32]] slice-of-slices |
Updated Stage 2 code to use .compute() with correct parameter types |
| 3 | SonaEngine::new(SonaConfig{...}) incorrect; actual constructor is SonaEngine::with_config(config) and SonaConfig uses micro_lora_lr not learning_rate |
Fixed constructor and field names in Section 14 |
| 4 | apply_micro_lora returns nothing; actual signature writes into &mut [f32] output buffer |
Fixed to use mutable output buffer pattern |
| 5 | TieredStore.put(&data) missing required params; actual signature: put(key, data, tier, tick) |
Added BlockKey, Tier, and tick parameters |
| 6 | WindowsWifiPipeline mislabeled as "Aggregate Root"; it is a domain service/orchestrator |
Relabeled to "Domain Service" |
Open items from review (not yet addressed):
OscillatoryRouteris designed for gamma-band (30-90 Hz) neural synchronization; using it at 0.15 Hz for breathing extraction is a semantic stretch. Consider replacing with a dedicated IIR bandpass filter.- BSSID flapping/index recycling could invalidate GNN correlation graphs; needs explicit invalidation logic.
netshoutput is locale-dependent; parser may fail on non-English Windows. Consider positional parsing as fallback.- Tier 1 breathing detection at 2 Hz is marginal due to subprocess spawn timing jitter; should require Tier 2 for breathing feature.
#[cfg(test)]
mod tests {
// Domain: BssidRegistry
#[test]
fn registry_assigns_stable_subcarrier_indices();
#[test]
fn registry_expires_stale_bssids();
#[test]
fn registry_maintains_welford_stats();
// Adapter: NetshBssidScanner
#[test]
fn parse_bssid_scan_output_extracts_all_bssids();
#[test]
fn parse_bssid_scan_output_handles_multi_band();
#[test]
fn parse_bssid_scan_output_handles_empty_output();
// Pipeline: PredictiveGate
#[test]
fn predictive_gate_suppresses_static_environment();
#[test]
fn predictive_gate_transmits_body_caused_changes();
// Pipeline: MotionEstimator
#[test]
fn motion_estimator_detects_presence_from_multi_ap();
#[test]
fn motion_estimator_classifies_four_levels();
// Pipeline: BreathingExtractor
#[test]
fn breathing_extracts_rate_from_oscillating_bssid();
// Integration
#[test]
fn full_pipeline_produces_sensing_update();
#[test]
fn graceful_degradation_with_few_bssids();
}- Real
netshscan on CI Windows runner - Mock BSSID data for deterministic pipeline testing
- Benchmark: processing latency per tick
Raw RSSI values are noisy, device-dependent, and non-stationary. A -50 dBm reading from AP1 on channel 3 is not directly comparable to -50 dBm from AP2 on channel 36 (different propagation, antenna gain, PHY). Feeding raw RSSI into the RuVector pipeline produces suboptimal attention weights and fingerprint matches.
Instead of using raw RSSI, we learn a per-BSSID embedding that captures each AP's environmental signature using SONA's micro-LoRA adaptation:
use sona::{SonaEngine, SonaConfig, TrajectoryBuilder};
/// Per-BSSID learned embedding that captures environmental signature
pub struct BssidEmbedding {
/// SONA engine for micro-LoRA parameter adaptation
sona: SonaEngine,
/// Per-BSSID embedding vectors (d_embed dimensions per BSSID)
embeddings: Vec<Vec<f32>>,
/// Embedding dimension
d_embed: usize,
}
impl BssidEmbedding {
pub fn new(max_bssids: usize, d_embed: usize) -> Self {
Self {
sona: SonaEngine::with_config(SonaConfig {
hidden_dim: d_embed,
embedding_dim: d_embed,
micro_lora_lr: 0.001,
ewc_lambda: 100.0, // Prevent forgetting previous environments
..Default::default()
}),
embeddings: vec![vec![0.0; d_embed]; max_bssids],
d_embed,
}
}
/// Encode a BSSID observation into a learned embedding
/// Combines: RSSI, channel, band, radio type, variance, history
pub fn encode(&self, entry: &BssidEntry) -> Vec<f32> {
let mut raw = vec![0.0f32; self.d_embed];
// Static features (learned via micro-LoRA)
raw[0] = rssi_to_linear(entry.stats.mean) as f32;
raw[1] = entry.stats.variance().sqrt() as f32;
raw[2] = channel_to_norm(entry.meta.channel);
raw[3] = band_to_feature(entry.meta.band);
raw[4] = radio_to_feature(entry.meta.radio_type);
// Temporal features (from ring buffer)
if entry.history.len() >= 4 {
raw[5] = entry.history.delta(1) as f32; // 1-step velocity
raw[6] = entry.history.delta(2) as f32; // 2-step velocity
raw[7] = entry.history.trend_slope() as f32;
}
// Apply micro-LoRA adaptation: raw → adapted
let mut adapted = vec![0.0f32; self.d_embed];
self.sona.apply_micro_lora(&raw, &mut adapted);
adapted
}
/// Train embeddings from outcome feedback
/// Called when presence/motion ground truth is available
pub fn train(&mut self, bssid_idx: usize, embedding: &[f32], quality: f32) {
let trajectory = self.sona.begin_trajectory(embedding.to_vec());
self.sona.end_trajectory(trajectory, quality);
// EWC++ prevents catastrophic forgetting of previous environments
}
}Scan 1: Raw RSSI [AP1:-42, AP2:-58, AP3:-71, ...]
│
▼
BssidEmbedding.encode() → [e1, e2, e3, ...] (d_embed=16 per BSSID)
│
▼
AttentionSubcarrierWeighter (query=breathing_profile, key=embeddings)
│
▼
Pipeline produces: motion=0.7, breathing=16.2, quality=0.85
│
▼
User/system feedback: correct=true (person was present)
│
▼
BssidEmbedding.train(quality=0.85)
│
▼
SONA micro-LoRA updates embedding weights
EWC++ preserves prior environment learnings
│
▼
Scan 2: Same raw RSSI → BETTER embeddings → BETTER attention → BETTER output
| Aspect | Raw RSSI | Learned Embedding |
|---|---|---|
| Device normalization | No | Yes (micro-LoRA adapts per adapter) |
| AP gain compensation | No | Yes (learned per BSSID) |
| Channel/band encoding | Lost | Preserved as features |
| Temporal dynamics | Not captured | Velocity + trend features |
| Cross-environment transfer | No | EWC++ preserves learnings |
| Attention quality | Noisy | Clean (adapted features) |
| Fingerprint matching | Raw distance | Semantically meaningful distance |
The custom embeddings replace raw RSSI at the attention and fingerprint stages:
// In WindowsWifiPipeline::process():
// Stage 2 (MODIFIED): Attention on embeddings, not raw RSSI
let bssid_embeddings: Vec<Vec<f32>> = frame.entries.iter()
.map(|entry| self.embedding.encode(entry))
.collect();
let weights = self.attention.forward(
&self.compute_breathing_query(),
&bssid_embeddings, // Learned embeddings, not raw RSSI
&litudes,
);
// Stage 7 (MODIFIED): Fingerprint on embedding space
let posture = self.fingerprint.classify_embedding(&bssid_embeddings);wifi-densepose-wifiscancrate created with DDD bounded contextsMultiApFramevalue object with amplitudes, phases, variances, historiesBssidRegistryaggregate root with Welford running statistics (capacity 32, 30s expiry)NetshBssidScanneradapter parsingnetsh wlan show networks mode=bssid(56 unit tests)EnhancedSensingResultoutput type with motion, breathing, posture, quality- Hexagonal architecture:
WlanScanPorttrait for adapter abstraction
8-stage pure-Rust pipeline with 125 passing tests:
| Stage | Module | Implementation |
|---|---|---|
| 1 | predictive_gate |
EMA-based residual filter (replaces PredictiveLayer) |
| 2 | attention_weighter |
Softmax dot-product attention (replaces ScaledDotProductAttention) |
| 3 | correlator |
Pearson correlation + BFS clustering (replaces RuvectorLayer GNN) |
| 4 | motion_estimator |
Weighted variance + EMA smoothing |
| 5 | breathing_extractor |
IIR bandpass (0.1-0.5 Hz) + zero-crossing |
| 6 | quality_gate |
Three-filter gate (structural/shift/evidence), inspired by ruQu |
| 7 | fingerprint_matcher |
Cosine similarity templates (replaces ModernHopfield) |
| 8 | orchestrator |
WindowsWifiPipeline domain service |
Performance: ~2.1M frames/sec (debug), ~12M frames/sec (release).
- Wiring
WindowsWifiPipelineintowifi-densepose-sensing-server - Tier 2
WlanApiScannerasync adapter stub (upgrade path to native WLAN API) - Extended
SensingUpdatewith enhanced motion, breathing, posture, quality fields
- Native
wlanapi.dllFFI for 10-20 Hz scan rates - SONA adaptation layer for per-environment tuning
- Multi-environment benchmarking
- IEEE 802.11bf WiFi Sensing Standard (2024)
- Adib, F. et al. "See Through Walls with WiFi!" SIGCOMM 2013
- Ali, K. et al. "Keystroke Recognition Using WiFi Signals" MobiCom 2015
- Halperin, D. et al. "Tool Release: Gathering 802.11n Traces with Channel State Information" ACM SIGCOMM CCR 2011
- Intel Wi-Fi 7 BE200/BE201 Specifications (2024)
- Microsoft WLAN API Documentation:
WlanGetNetworkBssList,WlanScan - RuVector v2.0.4 crate documentation