Respiration and heart rate from Wi-Fi CSI: what works, what does not

2026-10-11 · 2 min read

The idea is simple: chest movement changes multipath, and that shows up in CSI amplitude/phase (see the CSI sensing survey [1]). Engineering it is hard, because you must extract 0.1–0.5 Hz (breathing) and 0.8–2.0 Hz (heart rate) from noisy data.

Sampling is usually not the bottleneck

Our measured ~95 records/s across 8 chains is far above the Nyquist needs of a 2 Hz signal. The real limits are:

  1. phase noise (CFO/SFO, hardware drift),
  2. body motion (talking, shifting) swamping micro-motion,
  3. too-short observation windows (spectral resolution).

Runnable pipeline

import numpy as np
from numpy.fft import rfft, rfftfreq

def bandpass(x, fs, lo, hi):
    n = len(x); X = rfft(x - x.mean()); f = rfftfreq(n, 1 / fs)
    X[(f < lo) | (f > hi)] = 0
    return np.fft.irfft(X, n)

def estimate(signal, fs=95.0, band=(0.1, 0.5)):
    n = len(signal); x = bandpass(signal, fs, *band)
    spec = np.abs(rfft(x * np.hanning(n))); freqs = rfftfreq(n, 1 / fs)
    mask = (freqs >= band[0]) & (freqs <= band[1])
    return freqs[mask][np.argmax(spec[mask])] * 60.0   # bpm

Order matters: unwrap → remove linear CFO/SFO drift → band-pass → window → peak — the canonical phase-based vital-signs work is PhaseBeat [3]. Resample by timestamp; never assume a constant frame rate.

When it can work

Condition Why
subject seated / lying still motion dominates breathing otherwise
stable reflection path line-of-sight or stable multipath
window ≥ 20 s 30 s ≈ 0.033 Hz resolution (~2 bpm)
stable frame rate, timestamp-resampled jitter creates fake peaks
single subject multiple people blend in phase

Honest limits

  1. Not a medical device — no diagnostics, no medical claims;
  2. heart rate is much harder than breathing (smaller amplitude, harmonics interference);
  3. parameters must be re-calibrated per room/pose;
  4. our platform's vitals module is gated (returns Unavailable when motion/SNR conditions fail) — that is more honest than printing a number anyway.

Published work reports the same distance/environment dependence: FarSense extended the respiration range using the CSI ratio of two antennas [2] — "it can sense" and "it can sense in any room" are different claims.

Related: Python pipeline · datasets · Wi-Fi CSI explained

References and data sources

Every external claim carries a source and an evidence grade (grading scheme). Grade E marks first-party, reproducible measurements from this project.

  1. Grade A · standard/review WiFi Sensing with Channel State Information: A Survey
    W. Ma, W. Zhou, X. Wang · ACM Computing Surveys · 2019
    doi:10.1145/3310194 · citations 857 · verified: CrossRef API, 2026-10-11 · The field's most-cited CSI sensing survey (857 citations, verified via CrossRef).
  2. Grade B · peer-reviewed FarSense: Pushing the Range Limit of WiFi-based Respiration Sensing with CSI Ratio of Two Antennas
    Y. Zeng, D. Wu, J. Xiong, et al. · Proceedings of the ACM on Interactive, Mobile, Wearable and Ubiquitous Technologies (IMWUT) · 2019
    doi:10.1145/3351279 · citations 461 · verified: CrossRef API, 2026-10-11 · Range limits for respiration sensing and the two-antenna CSI ratio method (461 citations).
  3. Grade B · peer-reviewed PhaseBeat: Exploiting CSI Phase Data for Vital Sign Monitoring with Commodity WiFi Devices
    X. Wang, C. Yang, S. Mao · IEEE ICDCS 2017 · 2017
    doi:10.1109/icdcs.2017.206 · citations 325 · verified: CrossRef API, 2026-10-11 · A representative work on respiration/heart-rate monitoring from CSI phase (325 citations).