news 2026/11/4 18:37:37

FMCW雷达在非接触式心跳监测中的信号处理与优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FMCW雷达在非接触式心跳监测中的信号处理与优化

1. 从“看见”到“感知”:FMCW雷达如何捕捉心跳

你可能觉得心跳监测是智能手表或者医疗监护仪的专利,得贴着皮肤才能测。但你知道吗,现在有一种技术,可以让你隔着一米远,甚至隔着被子,就能精准地“听”到一个人的心跳。这听起来有点像科幻电影里的场景,但它背后的核心技术,其实就藏在很多我们身边的产品里,比如一些高端的智能家居传感器、睡眠监测仪,甚至是汽车里的驾驶员状态监测系统。这项技术,就是FMCW雷达。

FMCW,全称是调频连续波雷达。这个名字听起来有点唬人,但原理其实挺直观的。想象一下,你站在一个空旷的山谷里,对着远处的山崖大喊一声,然后听回声。通过回声回来的时间,你就能大概估算出山崖离你有多远。传统雷达就是这个原理。但FMCW雷达更“聪明”一点,它发出的不是一声固定的“啊——”,而是一段音调从低到高连续变化的“歌声”。当这段“歌声”碰到目标(比如人的胸口)反射回来时,由于目标在微微运动(心跳和呼吸),反射回来的“歌声”音调会和原来发出的“歌声”音调有一个微小的差异。这个差异,专业上叫“频差”,就包含了目标距离和运动速度的全部信息。

对于心跳监测来说,我们关心的就是这个由胸口起伏带来的、极其微小的运动。一次心跳引起的胸腔位移,可能只有零点几毫米,比一张纸还薄。FMCW雷达的厉害之处就在于,它能捕捉到这种毫米甚至亚毫米级别的微动。我刚开始接触这个领域时,也觉得不可思议:一个无线电波,怎么能“看”到这么细微的变化?但当你理解了它的信号处理流程,就会明白这其实是一系列精妙“算法魔术”的结果。整个过程,就是从原始的、充满噪声的无线电波中,一步步“提纯”出那个代表心跳的、有规律的微弱信号。接下来,我就带你深入这个“魔术”的后台,看看我们是怎么把心跳信号从一堆干扰里“揪”出来的。

2. 信号处理的起点:IQ基带信号解调

雷达天线接收到的信号,就像一盘录下了各种环境噪音、设备干扰和微弱心跳回声的“原始录音带”。我们的第一步,就是把这盘“录音带”转换成我们能处理的“数字音频文件”。这个转换过程,就是基带信号解调。FMCW雷达通常会输出两路信号,我们称之为I路和Q路。你可以把它们理解为一对双胞胎,它们携带的信息几乎一样,但彼此之间永远保持着90度的“相位差”,就像一个正弦波和一个余弦波的关系。

为什么需要两路?这其实是为了解决一个关键问题:盲点问题。如果只有一路信号,当目标的距离恰好使得回波信号的相位处于某个特定值时,解调出来的信号幅度可能会变得非常小,甚至为零,导致我们丢失目标信息。有了I和Q这两路正交的信号,就像有了两个观察角度,总能保证至少有一路信号是清晰的,从而避免了信息丢失。我在实际调试硬件时,就遇到过单路信号在某些距离上周期性衰减的问题,加上Q路后,信号就稳定多了。

拿到I、Q两路原始的基带信号后,它们还不能直接用,因为里面混杂着很多我们不想要的成分。最主要的是直流偏置和IQ失衡。直流偏置就像是录音里的底噪,是硬件电路本身产生的固定偏移。IQ失衡则像是双胞胎一个声音大、一个声音小,或者反应稍微有点不同步,这是由于两路模拟电路不可能做到完全一致导致的。如果不处理掉它们,后续的分析就会误差很大。

常用的解调方法主要有两种:反正切解调和复数解调。

反正切解调非常直观,它的核心公式是:相位 = arctan(Q / I)。通过计算I和Q比值的反正切,我们可以直接得到目标相位随时间的变化,而这个相位变化直接对应着胸腔的位移。这个方法的优点是直接、计算量相对小,能线性地还原出位移信号。但它对IQ失衡和噪声比较敏感,如果I、Q两路信号质量不高,解算出的相位会跳变,产生所谓的“相位缠绕”问题。

复数解调则更“数学”一些。它把I路信号当作复数的实部,Q路信号当作虚部,构造出一个复数信号:S(t) = I(t) + j * Q(t)(这里的j是虚数单位)。然后,我们计算这个复数信号的相位角,同样可以得到位移信息。复数解调在数学上更完备,能更好地处理信号,并且为后续的频谱分析提供了便利。在实际项目中,我通常更倾向于使用复数解调,因为它为滤波和频谱分析提供了更统一的框架,虽然计算上稍微复杂一点,但换来的是更好的鲁棒性。

提示:选择哪种解调方法,取决于你的具体应用和硬件条件。如果追求简单快速,且信号质量很好,反正切法够用。如果信号环境复杂,或者你需要做更精细的频谱分析,复数解调是更强大的工具。

3. 去芜存菁:滤波优化与生命体征分离

解调出来的相位信号(也就是胸腔位移信号),现在是一锅“大杂烩”。里面最强的信号通常是呼吸,因为呼吸的起伏幅度大(几毫米到一厘米),频率低(0.1-0.5 Hz)。而我们要找的心跳信号,则微弱得多(幅度不到1毫米),频率却高一些(0.8-3 Hz,通常是1-1.7 Hz)。除此之外,信号里还混杂着人体无意识的微动、环境物体的晃动、以及电路本身的各种噪声。我们的任务,就是设计一个高效的“筛子”,把心跳这颗“金砂”筛出来。

第一步,是滤除呼吸信号。这通常用一个高通滤波器来实现。比如,我们可以设置一个截止频率在0.7 Hz左右的高通滤波器,把频率更低的呼吸信号和一部分超低频漂移给滤掉。但这里有个坑:呼吸和心跳的频谱有时会靠得很近,特别是当呼吸急促时。如果高通滤波器的截止频率设得太高,可能会伤及心跳的低频部分;设得太低,又滤不干净呼吸残留。我常用的做法是采用一个过渡带比较陡峭的FIR(有限长单位冲激响应)滤波器。FIR滤波器没有反馈,是绝对稳定的,而且可以设计出严格的线性相位,这意味着它不会扭曲信号的时间关系,对于后续分析波形形态很重要。

第二步,是进一步净化心跳频带。滤掉呼吸后,信号里主要剩下心跳和噪声。这时我们需要一个带通滤波器,只让大概0.8 Hz到3 Hz这个频率范围(心跳可能出现的范围)的信号通过,把更高频的噪声和可能残留的极低频干扰进一步滤除。这个带通滤波器的设计也很有讲究。窗函数的选择(比如汉宁窗、汉明窗)、滤波器的阶数,都会影响效果。阶数太高,计算量大,还可能引入不必要的纹波;阶数太低,滤波效果又不好。我一般会先用一个阶数适中的滤波器做初步处理,观察频谱,再微调参数。

第三步,也是最具挑战性的一步:处理谐波和互调干扰。呼吸和心跳都不是完美的单一频率正弦波,它们会有谐波。呼吸的二次谐波(比如0.3 Hz呼吸的二次谐波是0.6 Hz)可能会落到心跳的频带内,被误认为是心跳。更麻烦的是,由于系统的非线性,呼吸和心跳信号可能会产生互调,生成新的频率成分,比如“呼吸频率+心跳频率”或“呼吸频率-心跳频率”,这些成分也可能干扰对真实心跳频率的判断。为了解决这个问题,仅仅靠时域滤波就不够了,我们需要结合频域分析和自适应算法。

一种有效的策略是频谱追踪与剔除。我们先对信号做短时傅里叶变换,在时频谱上找到能量最强的呼吸频率成分(假设是f_b),然后主动在信号中生成一个与f_b及其主要谐波(如2*f_b,3*f_b)相对应的正弦波,再从原始信号中减去这些成分。这个过程有点像“主动降噪”。实测下来,这个方法对于抑制呼吸谐波干扰非常有效。

4. 从时频域中锁定心跳:特征提取与算法优化

经过层层滤波,我们得到了一条相对干净的、主要包含心跳信息的信号。但这还不够,我们需要从中精确地提取出心率值,并尽可能还原出心跳波形(如心冲击图),这对健康分析更有价值。

心率提取最经典的方法是快速傅里叶变换。把一段时间的信号(比如30秒)从时域转换到频域,看看在0.8-3 Hz这个范围内,哪个频率点的能量最高,那个频率就对应着心率(需要乘以60转换成每分钟心跳次数,BPM)。但FFT有个缺点:它假设信号在这段时间内是平稳的,心率不变。实际上,人的心率是时刻变化的。为了解决这个问题,我们会用短时傅里叶变换或者小波变换。STFT就像用一个滑动的时间窗,一段一段地做FFT,从而得到一个“时频谱”,能看到心率随时间的变化趋势。小波变换则能提供更好的时频分辨率,尤其适合分析像心跳这样瞬变的信号。

仅仅找到主峰频率有时会出错,比如遇到前面提到的谐波干扰,或者人突然动了一下产生一个干扰脉冲。因此,我们需要一些后处理算法来“纠错”。常用的方法包括:

  • 峰值检测:直接在时域信号上寻找每个心跳周期的峰值点,计算相邻峰值的间隔,再换算成瞬时心率。这个方法能捕捉心率的瞬时变化,但对信号质量要求高,容易受噪声影响产生误检或漏检。
  • 频谱质心跟踪:不只看最高的峰,而是计算心跳频带内所有频率分量的加权平均频率,作为心率的估计。这种方法更稳健,抗单频干扰能力强。
  • 卡尔曼滤波或粒子滤波:这是一种更高级的状态估计方法。我们把心率看作一个随时间变化的“状态”,建立状态方程和观测方程(即我们测到的信号)。滤波器会根据之前的估计和新的观测值,最优地估计出当前最可能的心率值。这种方法特别适合处理噪声大、心率变化快的情况,我在做运动状态下的心率监测项目时,就大量使用了卡尔曼滤波来平滑结果,效果比简单平均好很多。

为了让你更直观地理解这个过程,我写一段简化的Python处理流程的核心代码框架。这只是一个示意,真实的工程代码要复杂得多,会包含大量的参数调整和错误处理。

import numpy as np from scipy import signal, fft import matplotlib.pyplot as plt # 假设我们已经有了解调后的位移信号 `displacement_signal` 和采样率 `fs` # 1. 设计高通滤波器滤除呼吸(假设截止频率为0.7 Hz) b_high, a_high = signal.butter(4, 0.7/(fs/2), 'high') filtered_signal = signal.filtfilt(b_high, a_high, displacement_signal) # 使用filtfilt实现零相位滤波 # 2. 设计带通滤波器提取心跳频带(0.8 Hz - 3 Hz) b_band, a_band = signal.butter(4, [0.8/(fs/2), 3.0/(fs/2)], 'bandpass') heartbeat_signal = signal.filtfilt(b_band, a_band, filtered_signal) # 3. 计算频谱,寻找心率 N = len(heartbeat_signal) freqs = fft.rfftfreq(N, 1/fs) spectrum = np.abs(fft.rfft(heartbeat_signal)) # 将频率范围限制在心跳范围内 mask = (freqs >= 0.8) & (freqs <= 3.0) heartbeat_freqs = freqs[mask] heartbeat_spectrum = spectrum[mask] # 找到频谱峰值对应的频率 dominant_freq = heartbeat_freqs[np.argmax(heartbeat_spectrum)] heart_rate_bpm = dominant_freq * 60 # 转换为每分钟心跳次数 print(f"估计的心率为: {heart_rate_bpm:.1f} BPM") # 4. (进阶)简单的时域峰值检测 peaks, _ = signal.find_peaks(heartbeat_signal, distance=fs*0.4) # 假设心跳间隔至少0.4秒 if len(peaks) > 1: intervals = np.diff(peaks) / fs # 峰值间隔(秒) instant_hr = 60 / intervals # 瞬时心率 print(f"瞬时心率序列 (BPM): {instant_hr}")

5. 实战挑战与性能提升技巧

理论很美好,但一上实际项目,坑就来了。我总结了几类最常见的挑战和我的应对“土方”。

第一类挑战:环境与运动干扰。这是非接触监测最大的敌人。除了人体自身的微动,风扇的转动、窗帘的飘动、甚至远处汽车的震动,都可能被雷达捕捉到。我的策略是多通道与自适应降噪。如果硬件条件允许,使用多天线雷达,通过比较不同天线接收信号的差异,可以一定程度上区分运动方向,抑制来自非监测方向的干扰。在算法上,可以引入参考通道,比如用另一个雷达或麦克风监测环境振动,然后从主信号中自适应地减去相关噪声。

第二类挑战:个体差异与姿势。不同体型的人(胖瘦)、不同的穿着(厚薄)、不同的睡姿(平躺、侧卧),对雷达波的反射特性影响巨大。侧卧时,胸腔的径向运动幅度会减小,信号变弱。解决这个问题需要算法具有鲁棒性。我们不能把滤波器的参数写死,而需要根据信号质量自适应调整。例如,可以先估计出当前信号的信噪比,如果信噪比低,就使用更强的平滑滤波;如果检测到姿势可能发生改变,可以短暂地提高更新率,重新锁定信号。

第三类挑战:硬件限制与校准。廉价的雷达芯片可能存在I/Q不平衡严重、相位噪声大、直流偏移不稳定等问题。这就需要在信号处理的最前端下功夫。上电后,先进行一段时间的空场景采集,估计并扣除直流偏移。对于I/Q不平衡,可以通过采集一个静止的强反射体(比如一个金属板)的回波,来校准两路的增益和相位差。这些校准步骤虽然增加了复杂度,但对于提升最终监测的准确性和稳定性是至关重要的。我踩过的坑就是,忽略了对新批次硬件的校准,导致同一套算法在不同设备上效果差异很大。

为了更系统地对比不同优化方法的效果,我整理了一个简单的表格,总结了在不同场景下的策略选择:

面临的挑战可能的原因推荐的优化策略预期效果
心率读数不稳定,跳动大1. 环境噪声干扰
2. 呼吸谐波干扰
3. 算法更新率过高
1. 增强带通滤波,降低带宽
2. 采用呼吸谐波抑制算法
3. 引入心率平滑算法(如移动平均、卡尔曼滤波)
心率曲线更平滑, outlier(异常值)减少
侧卧时信号丢失胸腔径向运动幅度减小,信噪比降低1. 切换至复数解调分析相位变化
2. 降低检测阈值,提高接收增益(如果硬件支持)
3. 尝试从信号中提取次优特征
提高侧卧等非理想姿势下的检测成功率
不同人测量偏差大个体生理结构差异,穿着影响1. 采用自适应的信号幅度归一化
2. 在算法中引入基于体型的简单分类器,微调参数
提升算法对不同人群的普适性
存在周期性虚假心率强周期性环境干扰(如风扇)1. 进行环境频谱学习与 notch filter(陷波滤波)
2. 使用多周期估计算法,选择最符合生理规律的频率
有效抑制特定频率的环境干扰

最后,我想分享一个很重要的心得:没有一劳永逸的“最优参数”。我在实验室里对着静止目标调得非常好的参数,一到真实的卧室环境,可能就不好用了。因此,构建一个参数可配置、甚至可在线学习的信号处理流水线非常重要。把滤波器的截止频率、谱分析的窗长、峰值检测的阈值等都做成可调节的,通过大量的实测数据去迭代优化。有时候,针对特定场景(比如专用于睡眠监测)做精细调优,比追求一个泛化能力强但精度一般的通用算法,更能做出好产品。信号处理既是科学,也是艺术,需要不断地在理论指导和实验反馈之间寻找平衡点。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/4 18:36:18

TranslucentTB Windows 11 23H2 任务栏透明失效问题解决方案

TranslucentTB Windows 11 23H2 任务栏透明失效问题解决方案 【免费下载链接】TranslucentTB 项目地址: https://gitcode.com/gh_mirrors/tra/TranslucentTB 问题现象&#xff1a;多场景下的兼容性故障表现 TranslucentTB作为Windows系统备受欢迎的任务栏美化工具&…

作者头像 李华
网站建设 2026/10/5 0:06:47

手把手教你配置Cisco串行接口:从Se2/0物理连接到IP地址设置

从零到一&#xff1a;掌握Cisco串行接口的实战配置艺术 在当今的网络世界里&#xff0c;虽然以太网技术大行其道&#xff0c;但串行接口&#xff08;Serial Interface&#xff09;依然是连接广域网&#xff08;WAN&#xff09;、构建骨干链路以及进行设备间点对点通信的基石。对…

作者头像 李华
网站建设 2026/10/5 0:06:47

IC设计中的时序约束实战:set_input_delay与set_output_delay避坑指南

IC设计时序约束实战&#xff1a;深入解析set_input_delay与set_output_delay的工程陷阱与应对策略 在芯片设计的漫长流程中&#xff0c;静态时序分析&#xff08;STA&#xff09;是确保设计能够按预期频率稳定工作的关键环节。对于许多工程师而言&#xff0c;时序约束的编写看似…

作者头像 李华
网站建设 2026/10/5 0:06:47

手把手教你用老旧电脑安装ESXI全系列(6.7/7.0/8.0)实战指南

1. 为什么用老旧电脑玩ESXI&#xff1f;聊聊我的真实想法 你是不是也和我一样&#xff0c;家里有个“老伙计”——一台几年前甚至更早买的台式机或者笔记本&#xff0c;性能说不上多好&#xff0c;但扔了又可惜&#xff0c;卖也卖不了几个钱。放着吃灰吧&#xff0c;总觉得浪费…

作者头像 李华
网站建设 2026/10/5 0:07:05

CVPR2021小目标检测新突破:多尺度特征融合与注意力机制协同优化

1. 小目标检测的“老大难”问题&#xff0c;到底难在哪&#xff1f; 大家好&#xff0c;我是老张&#xff0c;在AI和计算机视觉这行摸爬滚打了十几年&#xff0c;做过不少智能硬件上的视觉项目。今天想和大家聊聊一个特别实际、也特别让人头疼的问题&#xff1a;小目标检测。你…

作者头像 李华
网站建设 2026/10/5 0:08:36

ESP-WRO0M-32(二):VS Code插件配置与工程调试实战

1. 从“能用”到“好用”&#xff1a;为什么你需要深度配置VS Code插件 上次我们聊了ESP-WRO0M-32开发环境的基础搭建&#xff0c;算是把“房子”的框架给立起来了。很多朋友跟着步骤走&#xff0c;最后看到板子上的LED闪烁&#xff0c;就觉得大功告成。但说实话&#xff0c;那…

作者头像 李华