Back to Ruview

ADR-063: 60 GHz mmWave Sensor Fusion with WiFi CSI

docs/adr/ADR-063-mmwave-sensor-fusion.md

0.7.013.5 KB
Original Source

ADR-063: 60 GHz mmWave Sensor Fusion with WiFi CSI

Status: Proposed Date: 2026-03-15 Deciders: @ruvnet Related: ADR-014 (SOTA signal processing), ADR-021 (vital sign extraction), ADR-029 (RuvSense multistatic), ADR-039 (edge intelligence), ADR-042 (CHCI coherent sensing)

Context

RuView currently senses the environment using WiFi CSI — a passive technique that analyzes how WiFi signals are disturbed by human presence and movement. While this works through walls and requires no line of sight, CSI-derived vital signs (breathing rate, heart rate) are inherently noisy because they rely on phase extraction from multipath-rich WiFi channels.

A complementary sensing modality exists: 60 GHz mmWave radar modules (e.g., Seeed MR60BHA2) that use active FMCW radar at 60 GHz to measure breathing and heart rate with clinical-grade accuracy. These modules are inexpensive (~$15), run on ESP32-C6/C3, and output structured vital signs over UART.

Live hardware capture (COM4, 2026-03-15) from a Seeed MR60BHA2 on an ESP32-C6 running ESPHome:

[D][sensor:093]: 'Real-time respiratory rate': Sending state 22.00000
[D][sensor:093]: 'Real-time heart rate': Sending state 92.00000 bpm
[D][sensor:093]: 'Distance to detection object': Sending state 0.00000 cm
[D][sensor:093]: 'Target Number': Sending state 0.00000
[D][binary_sensor:036]: 'Person Information': Sending state OFF
[D][sensor:093]: 'Seeed MR60BHA2 Illuminance': Sending state 0.67913 lx

The Opportunity

Fusing WiFi CSI with mmWave radar creates a sensor system that is greater than the sum of its parts:

CapabilityWiFi CSI AlonemmWave AloneFused
Through-wall sensingYes (5m+)No (LoS only, ~3m)Yes — CSI for room-scale, mmWave for precision
Heart rate accuracy±5-10 BPM±1-2 BPM±1-2 BPM (mmWave primary, CSI cross-validates)
Breathing accuracy±2-3 BPM±0.5 BPM±0.5 BPM
Presence detectionGood (adaptive threshold)Excellent (range-gated)Excellent + through-wall
Multi-personVia subcarrier clusteringVia range-Doppler binsCombined spatial + RF resolution
Fall detectionPhase accelerationRange/velocity + micro-DopplerDual-confirm reduces false positives to near-zero
Pose estimationVia trained modelNot availableCSI provides pose; mmWave provides ground-truth vitals for training
CoverageWhole room (passive)~120° cone, 3m rangeFull room + precision zone
Cost per node~$9 (ESP32-S3)~$15 (ESP32-C6 + MR60BHA2)~$24 combined

RuVector Integration Points

The RuVector v2.0.4 stack (already integrated per ADR-016) provides the signal processing backbone:

RuVector ComponentRole in mmWave Fusion
ruvector-attention (bvp.rs)Blood Volume Pulse estimation — mmWave heart rate can calibrate the WiFi CSI BVP phase extraction
ruvector-temporal-tensor (breathing.rs)Breathing rate estimation — mmWave provides ground-truth for adaptive filter tuning
ruvector-solver (triangulation.rs)Multilateration — mmWave range-gated distance + CSI amplitude = 3D position
ruvector-attn-mincut (spectrogram.rs)Time-frequency decomposition — mmWave Doppler complements CSI phase spectrogram
ruvector-mincut (metrics.rs, DynamicPersonMatcher)Multi-person association — mmWave target IDs help disambiguate CSI subcarrier clusters

RuvSense Integration Points

The RuvSense multistatic sensing pipeline (ADR-029) gains new capabilities:

RuvSense ModulemmWave Integration
pose_tracker.rs (AETHER re-ID)mmWave distance + velocity as additional re-ID features for Kalman tracker
longitudinal.rs (Welford stats)mmWave vitals as reference signal for CSI drift detection
intention.rs (pre-movement)mmWave micro-Doppler detects pre-movement 100-200ms earlier than CSI
adversarial.rs (consistency check)mmWave provides independent signal to detect CSI spoofing/anomalies
coherence_gate.rsmmWave presence as additional gate input — if mmWave says "no person", CSI coherence gate rejects

Cross-Viewpoint Fusion Integration

The viewpoint fusion pipeline (ruvector/src/viewpoint/) extends naturally:

Viewpoint ModulemmWave Extension
attention.rs (CrossViewpointAttention)mmWave range becomes a new "viewpoint" in the attention mechanism
geometry.rs (GeometricDiversityIndex)mmWave cone geometry contributes to Fisher Information / Cramer-Rao bounds
coherence.rs (phase phasor)mmWave phase coherence as validation for WiFi phasor coherence
fusion.rs (MultistaticArray)mmWave node becomes a member of the multistatic array with its own domain events

Decision

Add 60 GHz mmWave radar sensor support to the RuView firmware and sensing pipeline with auto-detection and device-specific capabilities.

Architecture

┌─────────────────────────────────────────────────────────┐
│                    Sensing Node                          │
│                                                          │
│  ┌──────────────┐    ┌──────────────┐    ┌────────────┐ │
│  │ ESP32-S3     │    │ ESP32-C6     │    │ Combined   │ │
│  │ WiFi CSI     │    │ + MR60BHA2   │    │ S3 + UART  │ │
│  │ (COM7)       │    │ 60GHz mmWave │    │ mmWave     │ │
│  │              │    │ (COM4)       │    │            │ │
│  │ Passive      │    │ Active radar │    │ Both modes │ │
│  │ Through-wall │    │ LoS, precise │    │            │ │
│  └──────┬───────┘    └──────┬───────┘    └─────┬──────┘ │
│         │                    │                   │       │
│         └────────┬───────────┘                   │       │
│                  ▼                               │       │
│         ┌────────────────┐                       │       │
│         │ Fusion Engine  │◄──────────────────────┘       │
│         │                │                               │
│         │ • Kalman fuse  │  Vitals packet (extended):    │
│         │ • Cross-validate│  magic 0xC5110004             │
│         │ • Ground-truth │  + mmwave_hr, mmwave_br       │
│         │   calibration  │  + mmwave_distance             │
│         │ • Fall confirm │  + mmwave_target_count         │
│         └────────────────┘  + confidence scores           │
└─────────────────────────────────────────────────────────┘

Three Deployment Modes

Mode 1: Standalone CSI (existing) — ESP32-S3 only, WiFi CSI sensing.

Mode 2: Standalone mmWave — ESP32-C6 + MR60BHA2, precise vitals in a single room.

Mode 3: Fused (recommended) — ESP32-S3 + mmWave module on UART, or two separate nodes with server-side fusion.

Auto-Detection Protocol

The firmware will auto-detect connected mmWave modules at boot:

  1. UART probe — On configured UART pins, send the MR60BHA2 identification command (0x01 0x01 0x00 0x01 ...) and check for valid response header
  2. Protocol detection — Identify the sensor family:
    • Seeed MR60BHA2 (breathing + heart rate)
    • Seeed MR60FDA1 (fall detection)
    • Seeed MR24HPC1 (presence + light sleep/deep sleep)
    • HLK-LD2410 (presence + distance)
    • HLK-LD2450 (multi-target tracking)
  3. Capability registration — Register detected sensor capabilities in the edge config:
c
typedef struct {
    uint8_t  mmwave_detected;      /** 1 if mmWave module found on UART */
    uint8_t  mmwave_type;          /** Sensor family (MR60BHA2, MR60FDA1, etc.) */
    uint8_t  mmwave_has_hr;        /** Heart rate capability */
    uint8_t  mmwave_has_br;        /** Breathing rate capability */
    uint8_t  mmwave_has_fall;      /** Fall detection capability */
    uint8_t  mmwave_has_presence;  /** Presence detection capability */
    uint8_t  mmwave_has_distance;  /** Range measurement capability */
    uint8_t  mmwave_has_tracking;  /** Multi-target tracking capability */
    float    mmwave_hr_bpm;        /** Latest heart rate from mmWave */
    float    mmwave_br_bpm;        /** Latest breathing rate from mmWave */
    float    mmwave_distance_cm;   /** Distance to nearest target */
    uint8_t  mmwave_target_count;  /** Number of detected targets */
    bool     mmwave_person_present;/** mmWave presence state */
} mmwave_state_t;

Supported Sensors

SensorFrequencyCapabilitiesUART ProtocolCost
Seeed MR60BHA260 GHzHR, BR, presence, illuminanceSeeed proprietary frames~$15
Seeed MR60FDA160 GHzFall detection, presenceSeeed proprietary frames~$15
Seeed MR24HPC124 GHzPresence, sleep stage, distanceSeeed proprietary frames~$10
HLK-LD241024 GHzPresence, distance (motion + static)HLK binary protocol~$3
HLK-LD245024 GHzMulti-target tracking (x,y,speed)HLK binary protocol~$5

Fusion Algorithms

1. Vital Sign Fusion (Kalman filter)

mmWave HR (high confidence, 1 Hz) ─┐
                                    ├─► Kalman fuse → fused HR ± confidence
CSI-derived HR (lower confidence)  ─┘

2. Fall Detection (dual-confirm)

CSI phase accel > thresh ──────┐
                               ├─► AND gate → confirmed fall (near-zero false positives)
mmWave range-velocity pattern ─┘

3. Presence Validation

CSI adaptive threshold ────┐
                           ├─► Weighted vote → robust presence
mmWave target count > 0 ──┘

4. Training Calibration

mmWave ground-truth vitals → train CSI BVP extraction model
mmWave distance → calibrate CSI triangulation
mmWave micro-Doppler → label CSI activity patterns

Vitals Packet Extension

Extend the existing 32-byte vitals packet (magic 0xC5110002) with a new 48-byte fused packet:

c
typedef struct __attribute__((packed)) {
    /* Existing 32-byte vitals fields */
    uint32_t magic;            /* 0xC5110004 (fused vitals) */
    uint8_t  node_id;
    uint8_t  flags;            /* Bit0=presence, Bit1=fall, Bit2=motion, Bit3=mmwave_present */
    uint16_t breathing_rate;   /* Fused BPM * 100 */
    uint32_t heartrate;        /* Fused BPM * 10000 */
    int8_t   rssi;
    uint8_t  n_persons;
    uint8_t  mmwave_type;      /* Sensor type enum */
    uint8_t  fusion_confidence;/* 0-100 fusion quality score */
    float    motion_energy;
    float    presence_score;
    uint32_t timestamp_ms;
    /* New mmWave fields (16 bytes) */
    float    mmwave_hr_bpm;    /* Raw mmWave heart rate */
    float    mmwave_br_bpm;    /* Raw mmWave breathing rate */
    float    mmwave_distance;  /* Distance to nearest target (cm) */
    uint8_t  mmwave_targets;   /* Target count */
    uint8_t  mmwave_confidence;/* mmWave signal quality 0-100 */
    uint16_t reserved;
} edge_fused_vitals_pkt_t;

_Static_assert(sizeof(edge_fused_vitals_pkt_t) == 48, "fused vitals must be 48 bytes");

NVS Configuration

New provisioning parameters:

bash
python provision.py --port COM7 \
  --mmwave-uart-tx 17 --mmwave-uart-rx 18 \  # UART pins for mmWave module
  --mmwave-type auto \                         # auto-detect, or: mr60bha2, ld2410, etc.
  --fusion-mode kalman \                       # kalman, vote, mmwave-primary, csi-primary
  --fall-dual-confirm true                     # require both CSI + mmWave for fall alert

Implementation Phases

PhaseScopeEffort
Phase 1UART driver + MR60BHA2 parser + auto-detection2 weeks
Phase 2Fused vitals packet + Kalman vital sign fusion1 week
Phase 3Dual-confirm fall detection + presence voting1 week
Phase 4HLK-LD2410/LD2450 support + multi-target fusion2 weeks
Phase 5RuVector calibration pipeline (mmWave as ground truth)3 weeks
Phase 6Server-side fusion for separate CSI + mmWave nodes2 weeks

Consequences

Positive

  • Near-zero false positive fall detection (dual-confirm)
  • Clinical-grade vital signs when mmWave is present, with CSI as fallback
  • Self-calibrating CSI pipeline using mmWave ground truth
  • Backward compatible — existing CSI-only nodes work unchanged
  • Low incremental cost (~$3-15 per mmWave module)
  • Auto-detection means zero configuration for supported sensors
  • RuVector attention/solver/temporal-tensor modules gain a high-quality reference signal

Negative

  • Added firmware complexity (~2-3 KB RAM for mmWave state + UART buffer)
  • mmWave modules require line-of-sight (complementary to CSI, not replacement)
  • Multiple UART protocols to maintain (Seeed, HLK families)
  • 48-byte fused packet requires server parser update

Neutral

  • ESP32-C6 cannot run the full CSI pipeline (single-core RISC-V) but can serve as a dedicated mmWave bridge node
  • mmWave modules add ~15 mA power draw per node