radar-vital-signs
End-to-end pipeline for extracting heart rate (HR) and breathing rate (BR) from raw short-range radar I/Q captures — both continuous-wave (CW, 24 GHz clinical boards) and FMCW mmWave (60/77 GHz, TI IWR/AWR)
Install / Use
npx skills add benchflow-ai/skillsbench --skill radar-vital-signsInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
AutomationSupported Platforms
Our assessment of radar-vital-signs
radar-vital-signs scores 85/100 on our quality scale, 1807th of 2,877 Automation skills we index.
Its SKILL.md is 6.1 KB long, well organised into 8 sections and no code examples: a thorough specification that gives an agent plenty to work with.
With 1,813 GitHub stars, it is one of the more widely adopted skills in the catalogue.
Maintenance, license and trust
- The repository was last updated about 2 months ago, so radar-vital-signs is actively maintained.
- It is released under the Apache-2.0 license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
radar-vital-signs compared with similar skills
All 4 of these similar skills score higher than radar-vital-signs; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| radar-vital-signs (this skill)by benchflow-ai | 85 | 1.8k | 2mo ago | SKILL.md |
| Agent-Reachby Panniantong | 100 | 92.1k | 20d ago | CLAUDE.md |
| Scraplingby D4Vinci | 100 | 85.9k | today | MCP Server |
| rufloby ruvnet | 100 | 73.9k | today | MCP Server |
| algorithmic-artby anthropics | 100 | 177.9k | 13d ago | SKILL.md |
Frequently asked questions
- How do I install radar-vital-signs?
- Run
npx skills add benchflow-ai/skillsbench --skill radar-vital-signs. The install tabs above show the steps for each supported agent. - Which AI agents does radar-vital-signs work with?
- It is written for Claude Code, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is radar-vital-signs safe to use?
- It is Apache-2.0-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is radar-vital-signs still maintained?
- The repository was last updated about 2 months ago, so radar-vital-signs is actively maintained.
Skill content
View source on GitHubname: radar-vital-signs description: End-to-end pipeline for extracting heart rate (HR) and breathing rate (BR) from raw short-range radar I/Q captures — both continuous-wave (CW, 24 GHz clinical boards) and FMCW mmWave (60/77 GHz, TI IWR/AWR). Use when Claude needs to parse interleaved I/Q binary, do a Range FFT on FMCW chirps, remove static clutter, pick a subject range bin, extract phase with unwrapping, design HR/BR bandpass filters, pick a peak frequency via PSD, reject the HR second harmonic that often dominates the fundamental, or handle respiration-harmonic leakage on slow breathers. Not for pulse/UWB range gating, MIMO beamforming, Doppler-only gesture radar, arrhythmia detection, or multi-subject source separation.
Radar Vital-Sign Extraction
End-to-end pipeline: raw radar I/Q → cleaned phase signal → HR and BR in bpm.
Full pipeline (every step, in order)
-
Parse binary I/Q into a complex 1-D array (CW) or 2-D range matrix (FMCW). Use the JSON/YAML sidecar to determine format — never assume. See references/iq-formats.md.
-
(FMCW only) Range FFT across fast-time samples of each chirp → range matrix
R[n_chirp, n_range_bin]. CW skips this step. -
Remove static clutter. Subtract the temporal mean:
- CW:
iq -= iq.mean() - FMCW:
R -= R.mean(axis=0, keepdims=True)
- CW:
-
(FMCW only) Pick the subject range bin within a physical prior window (e.g., 0.3–1.5 m for a seated subject). See references/range-bin.md.
-
Extract phase with unwrap:
phase = np.unwrap(np.angle(iq_or_bin)) phase -= phase.mean() -
Decimate to ~50 Hz if
fs >= 500 Hz(sub-Hz filtering at kHz is numerically unstable):from scipy.signal import decimate phase_ds = decimate(phase, q=int(fs/50), ftype='iir', zero_phase=True) fs_new = fs / int(fs/50) -
Two separate bandpasses — BR and HR:
b_br, a_br = butter(4, [0.08, 0.5], btype='band', fs=fs_new) b_hr, a_hr = butter(4, [0.7, 3.0], btype='band', fs=fs_new) br_sig = filtfilt(b_br, a_br, phase_ds) hr_sig = filtfilt(b_hr, a_hr, phase_ds) -
Peak frequency via zero-padded Welch PSD (each band):
nperseg = min(len(x), int(fs_new * 25)) f, p = welch(x, fs=fs_new, nperseg=nperseg, noverlap=nperseg//2, nfft=8*nperseg, detrend='constant') mask = (f >= lo) & (f <= hi) peak_hz = f[mask][np.argmax(p[mask])] -
HR harmonic rejection — always run:
f_sub = f_peak_hr / 2.0 if 0.7 <= f_sub <= 3.0: p_sub = np.interp(f_sub, f, p) p_top = np.interp(f_peak_hr, f, p) if p_sub > 0.5 * p_top: f_peak_hr = f_sub # peak was the 2nd harmonic hr_bpm = f_peak_hr * 60See references/harmonic-pitfalls.md for why this matters and mitigations for slow-breather respiration harmonics leaking into the HR band.
-
Cross-check with autocorrelation (optional but recommended):
ac = np.correlate(x - x.mean(), x - x.mean(), mode='full') ac = ac[len(ac)//2:] / ac[len(ac)//2] lag = int(fs_new/f_hi) + np.argmax(ac[int(fs_new/f_hi):int(fs_new/f_lo)]) bpm_ac = 60 * fs_new / lagIf
abs(bpm_ac - bpm_psd) > 5, flag as low confidence.
Critical rules
| rule | why |
|---|---|
| Use phase, not magnitude | 1 mm motion at 24 GHz ≈ 1 rad; magnitude costs ~40 dB of SNR. np.abs(iq) is almost always wrong for mm-scale motion |
| Clutter removal before np.angle | DC offset anchors phase off zero, eats the ±π unwrap budget |
| Decimate before sub-Hz bandpass | SciPy biquad silently NaNs at very-low normalized cutoffs |
| Two separate BR / HR bandpasses | HR is 10×–100× smaller than BR; single wide filter can't separate them |
| Zero-pad Welch PSD (nfft=8*nperseg) | Raw bin spacing fs/nperseg is often coarser than tolerance |
| Always run HR sub-harmonic check | 2nd harmonic of cardiac pulse frequently dominates fundamental |
| Never argmax(magnitude) across all range bins (FMCW) | DC bin and static reflectors dominate; restrict to subject-range window |
Band edges: use these, not textbook 0.1–0.5 / 0.8–2.5
| band | use | textbook | why | |---|---|---|---| | BR lower | 0.08 Hz (4.8 bpm) | 0.1 Hz (6 bpm) | slow breathers (supine, meditation, sleep) routinely below 6 bpm | | HR lower | 0.7 Hz (42 bpm) | 0.8 Hz (48 bpm) | bradycardia (athletes, post-tilt-down, β-blockers) below 48 bpm | | HR upper | 3.0 Hz (180 bpm) | 2.5 Hz (150 bpm) | post-exercise and children exceed 150 bpm |
Widen only with specific justification. See references/band-rationale.md.
Decision rules
| If | Then |
|---|---|
| f_peak/2 in HR band and p_sub > 0.5 × p_top | Pick sub-harmonic (fundamental) |
| PSD and autocorrelation disagree > 5 bpm | Flag low confidence; don't commit to one value |
| BR estimate < 10 bpm (slow breather) | Expect HR-band contamination — notch 2·BR, 3·BR. See harmonic-pitfalls.md |
| HR > 150 bpm (tachycardia) | Widen HR band upper to 3.3 Hz, re-estimate |
| Clip < 15 s | PSD resolution > tolerance — prefer autocorrelation, or flag inconclusive |
Sanity checks before reporting
- BR < HR always for a live adult at rest. Violated ⇒ swapped bands.
- HR × duration_minutes ≈ peak count in
find_peaks(bandpassed_hr). Off by 2× ⇒ harmonic error slipped through. - Resting adult plausibility: HR 50–90 bpm, BR 10–20 bpm. Way outside ⇒ re-check band edges, decimation, and harmonic rejection.
When things go wrong
If output looks like garbage, walk through references/debugging.md — fast checks that catch most ingestion and SNR bugs.
Not in scope
- Pulse / UWB range-gated radar (different pipeline entirely).
- MIMO angle-of-arrival — needs beamforming first.
- Doppler-only gesture radar — use slow-time FFT, not bin phase.
- Arrhythmia / irregular rhythms — use R-peak / foot detection + RR-interval analysis, not PSD.
- Multiple subjects in one signal — run source separation first.
- Rapidly non-stationary rate (exercise ramp) — use a spectrogram, not single-window PSD.
Related Skills
Agent-Reach
92.1kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
Scrapling
85.9k🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev
ruflo
73.9k🌊 The original agent harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive memory, self-learning intelligence, federation, vector RAG integration, and native Claude Code / Codex / Hermes and many more Integrated
algorithmic-art
177.9kCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
