非接触式生命体征监测:从雷达回波到呼吸心跳分离

📅 发布时间:2026/7/8 19:24:59 👁️ 浏览次数:
非接触式生命体征监测:从雷达回波到呼吸心跳分离
1. 非接触式生命体征监测为什么它如此重要想象一下你家里有一位年迈的长辈或者医院里有一位全身烧伤的病人。传统的生命体征监测比如夹在手指上的血氧仪或者绑在胸口的电极片对他们来说可能是一种负担甚至根本无法使用。前者会觉得麻烦不愿意配合后者则因为皮肤创伤根本不允许粘贴任何接触式传感器。这时候一种“隔空”就能测量呼吸和心跳的技术就显得尤为重要了。这就是非接触式生命体征监测而雷达技术正是实现这一目标的“火眼金睛”。我接触这个领域已经有些年头了从最早的学术研究到后来的产品落地踩过不少坑也收获了很多惊喜。简单来说这项技术的核心目标就一个在不接触人体的情况下精准地“看”到胸腔那微乎其微的起伏并把其中混杂在一起的呼吸和心跳信号像剥洋葱一样一层层分开。这听起来有点像科幻电影里的场景但背后的原理其实很接地气。呼吸时胸腔的起伏幅度相对较大大概有几毫米到一厘米而心跳引起的胸腔振动则要微弱得多通常只有零点几毫米频率也更快。雷达发射电磁波碰到人体胸腔后反射回来这个“回波”里就编码了这些微小的运动信息。我们的任务就是当一回“信号侦探”从一堆复杂的回波数据中把呼吸和心跳这两个“主角”给找出来。这项技术的应用场景远比你想象的广泛。除了刚才提到的养老院健康监护和烧伤科特殊护理它还能用于婴儿睡眠监测避免穿戴设备带来的风险、长期慢性病患者的家庭日常跟踪甚至在驾驶疲劳监测、搜救等领域也有用武之地。它的魅力在于“无感”用户完全不需要改变任何行为习惯监测就在不知不觉中完成了。这不仅仅是技术上的进步更是一种人文关怀的体现。接下来我们就一起拆解一下这双“隔空感知”的手是如何工作的。2. 雷达如何“看见”呼吸与心跳核心原理拆解要理解雷达怎么测生命体征咱们可以先忘掉那些复杂的公式打个比方。你可以把雷达想象成一个超级灵敏的“声呐”只不过它发射的不是声波而是无线电波。我们站在水池边向平静的水面扔一颗小石子会看到一圈圈涟漪扩散出去碰到池壁再反射回来。如果池壁在微微晃动那么反射回来的涟漪波纹就会发生细微的改变。雷达测生命体征道理类似它持续发射电磁波“涟漪”这些波碰到人体胸腔后反射回来。由于呼吸和心跳胸腔就像一个微微晃动的“池壁”导致反射波的某些特性比如波走过的路程专业上叫“相位”发生了极其细微的、有规律的变化。这个变化到底有多细微呢我实测过很多次对于24GHz或60GHz的毫米波雷达心跳引起的胸腔位移可能只相当于电磁波波长的几百分之一。这就好比要你用一把米尺去测量一张纸厚度级别的变化难度可想而知。所以雷达硬件本身必须非常精密能够捕捉到这种纳米级甚至更小的等效位移。目前常用的有连续波雷达和超宽带脉冲雷达。连续波雷达结构相对简单成本低适合对精度要求不那么极致的场景而超宽带脉冲雷达就像它的名字一样发射的脉冲很窄频谱很宽因此具有极高的距离分辨率和抗干扰能力穿透性也更好能隔着被子、薄墙进行检测在专业医疗和高端监护场景里更常见。那么回波信号具体包含了什么呢这里就要引入一个简单的信号模型了别怕我们把它说人话。假设胸腔的运动是呼吸和心跳两种规律运动的叠加呼吸就像一个大而慢的波浪心跳则是叠加在上面的小而快的涟漪。雷达接收到的基带信号可以理解为处理过的、便于分析的回波核心部分其相位变化就直接反映了胸腔相对于雷达的距离变化。这个距离变化函数可以近似看作是两个余弦函数的叠加一个频率低呼吸比如0.2-0.5赫兹一个频率高心跳0.8-2.0赫兹。我们的目标就是从这一个叠加的信号里把这两个频率成分准确地估计出来。听起来是不是有点像从一首混音歌曲里单独把贝斯和鼓点的节奏给扒出来3. 从混沌到清晰信号处理的关键三步拿到了原始的雷达回波信号就像拿到了一块未经雕琢的璞玉里面虽然藏着珍宝呼吸心跳信息但也混杂着大量的“石屑”噪声和干扰。直接看它的频谱往往是一团糟心跳信号完全被呼吸信号的谐波和噪声淹没。这就需要一套系统的信号处理流程来“去伪存真”。根据我的经验这个过程通常可以分为三个关键阶段预处理与信号提取、呼吸与心跳的初步分离、以及精细分析与特征增强。3.1 第一步预处理与信号提取雷达收集到的原始数据是海量的包含了环境中所有物体的反射信息。我们首先要做的就是“定位”到人。这通常通过生成距离-多普勒谱来实现。你可以把它想象成一张热力图横轴代表距离人离雷达多远纵轴代表速度人动得多快。静止的人体会在某个特定距离上产生一个明亮的“斑点”因为胸腔微动产生了多普勒频移。找到这个斑点对应的距离单元我们就锁定了目标。锁定目标后我们只提取这个距离单元上随时间变化的信号序列。这个序列的相位信息就蕴含着胸腔微动的全部秘密。但是这个相位信号可能是不连续的相位缠绕而且包含各种高频噪声。所以我们需要先进行相位解缠把它恢复成平滑的距离变化曲线这个曲线就是我们后续分析的基石——微动信号。有时候这个微动信号里还夹杂着人体无意识的轻微移动比如翻身我们需要先用高通滤波器或趋势移除的方法把这些低频大幅度的干扰先去掉得到一个相对“干净”的、主要由呼吸心跳构成的微动信号。3.2 第二步呼吸与心跳的粗分离拿到了干净的微动信号我们面临第一个核心挑战呼吸和心跳在时域上完全混叠在一起怎么分开最直观的想法是利用它们频率的不同。呼吸频率低0.1-0.5 Hz心跳频率高0.8-2.0 Hz。一个经典且有效的方法是移动平均或低通滤波。具体操作上我会用一个时间窗口比如10秒对微动信号做平滑。因为心跳是高频的在这个平均过程中基本被抵消掉了而低频的呼吸信号则被保留下来。这样我们就得到了一个估计的呼吸信号。然后用原始的微动信号减去这个估计的呼吸信号理论上剩下的就主要是心跳信号了。我最早尝试这个方法时效果确实有但很不理想。减完之后的心跳信号里仍然残留着很强的呼吸谐波分量波形看起来还是很乱。这是因为呼吸并非理想的正弦波它的谐波成分可能会延伸到心跳的频段。这就引出了下一步。3.3 第三步精细分析与特征增强经过粗分离我们得到了一个以心跳为主但包含大量残留噪声和呼吸谐波的信号。这时候就需要更精细的工具了。带通滤波是首当其冲的根据心跳的生理知识通常0.9Hz到1.6Hz设计一个窄带的带通滤波器只让这个频率范围内的信号通过。这能滤掉大部分残留的呼吸低频和更高频的噪声。滤波后的信号会清晰很多心跳的周期性开始显现。但有时候在强噪声背景下单纯滤波后信号的信噪比还是不够高频谱上的心跳峰值不明显。这时候一些更高级的谱估计方法就派上用场了。比如MUSIC算法它特别适合处理由几个正弦信号叠加而成的信号。它的思路很巧妙假设信号由少数几个正弦波心跳可能包含基频和谐波加上白噪声组成通过数学方法把信号空间和噪声空间分开。然后我们扫描不同的频率看哪个频率对应的正弦波向量与噪声空间最“正交”垂直哪个频率就最有可能是真实的心跳频率。这种方法在低信噪比下估计频率的精度往往比直接做FFT快速傅里叶变换要高得多。然而无论是FFT还是MUSIC都假设信号是平稳的统计特性不随时间变。但实际中人的呼吸和心跳频率在短时间内是可能波动的为了看到这种动态变化我们就需要时频分析工具。短时傅里叶变换是我常用的工具之一。它的思想是把整个信号切成一小段一小段加窗对每一小段分别做FFT这样就能看到频率成分随时间是如何演变的。从STFT时频图上你能清晰地看到一条代表呼吸的、随时间缓慢变化的亮带和一条代表心跳的、频率更高的亮带它们各自的起伏和波动一目了然。这对于分析睡眠分期不同睡眠阶段心率变异性不同或者情绪波动引起的生理变化特别有用。4. 算法实战从理论到代码的跨越光说不练假把式咱们直接上点干货看看部分核心算法如何用代码实现。这里我用Python来演示因为它的库生态丰富便于理解和实验。假设我们已经完成了预处理得到了一个名为micro_motion的微动信号数组以及采样率fs。4.1 呼吸信号的提取移动平均法import numpy as np import matplotlib.pyplot as plt from scipy import signal def extract_respiration_by_moving_average(micro_motion, fs, window_seconds5): 使用移动平均法提取呼吸信号。 参数 micro_motion: 输入的微动信号一维数组 fs: 采样率 (Hz) window_seconds: 移动平均窗口长度秒 返回 respiration: 估计的呼吸信号 heartbeat_rough: 初步分离的心跳信号残留大量噪声 window_length int(window_seconds * fs) # 使用卷积实现移动平均modesame保持输出长度一致 kernel np.ones(window_length) / window_length respiration np.convolve(micro_motion, kernel, modesame) # 初步心跳信号 原信号 - 估计的呼吸信号 heartbeat_rough micro_motion - respiration return respiration, heartbeat_rough # 使用示例 # respiration, heartbeat_rough extract_respiration_by_moving_average(micro_motion, fs, 5)这个方法简单快捷能快速得到一个呼吸趋势但正如前面所说分离出的heartbeat_rough质量很差需要进一步处理。4.2 心跳信号的带通滤波接下来我们对粗糙的心跳信号进行带通滤波聚焦于心跳频段。def bandpass_filter_heartbeat(heartbeat_rough, fs, lowcut0.9, highcut2.0): 设计一个带通滤波器来提取心跳信号。 参数 heartbeat_rough: 初步分离的心跳信号 fs: 采样率 lowcut: 通带低频截止频率 (Hz) highcut: 通带高频截止频率 (Hz) 返回 heartbeat_filtered: 滤波后的心跳信号 # 设计一个巴特沃斯带通滤波器 nyquist 0.5 * fs low lowcut / nyquist high highcut / nyquist b, a signal.butter(N4, Wn[low, high], btypeband) # 应用滤波器使用filtfilt进行零相位滤波避免相位失真 heartbeat_filtered signal.filtfilt(b, a, heartbeat_rough) return heartbeat_filtered # 使用示例 # heartbeat_bp bandpass_filter_heartbeat(heartbeat_rough, fs, 0.9, 2.0)滤波之后信号会干净不少。你可以通过绘制频谱图来观察效果def plot_spectrum(signal, fs, title): 绘制信号的频谱图。 n len(signal) freqs np.fft.rfftfreq(n, 1/fs) fft_vals np.abs(np.fft.rfft(signal)) plt.figure() plt.plot(freqs, fft_vals) plt.xlabel(频率 (Hz)) plt.ylabel(幅度) plt.title(title) plt.grid(True) plt.xlim([0, 3]) # 聚焦于0-3Hz范围 plt.show() # 绘制滤波前后的频谱对比 # plot_spectrum(heartbeat_rough, fs, “粗略心跳信号频谱”) # plot_spectrum(heartbeat_bp, fs, “带通滤波后心跳信号频谱”)4.3 使用短时傅里叶变换进行时频分析为了观察心跳频率随时间的变化我们可以使用STFT。def compute_stft(signal, fs, nperseg256): 计算并绘制信号的STFT时频图。 参数 nperseg: 每个时间窗口的长度点数影响时间/频率分辨率 f, t, Zxx signal.stft(signal, fs, npersegnperseg, noverlapnperseg//2) plt.figure(figsize(10, 6)) plt.pcolormesh(t, f, np.abs(Zxx), shadinggouraud, cmapjet) plt.colorbar(label强度) plt.ylabel(频率 [Hz]) plt.xlabel(时间 [秒]) plt.title(微动信号的STFT时频分析) plt.ylim([0, 2.5]) # 将频率轴限制在呼吸和心跳主要范围 plt.show() # 使用示例 # compute_stft(micro_motion, fs, npersegfs*4) # 使用4秒的窗口从生成的时频图上你应该能看到一条在1Hz附近波动的亮带心跳以及一条在底部0.3Hz附近的亮带呼吸。如果心跳频率在监测期间有变化比如从1.0Hz加速到1.2Hz这条亮带就会呈现出上升或下降的趋势。5. 工程实践中的挑战与应对策略在实验室理想环境下跑通算法只是第一步真正要把这套系统做成产品或者在复杂场景下部署会遇到一大堆让人头疼的问题。我结合自己踩过的坑分享几个最常见的挑战和应对思路。第一个大敌是环境杂波和干扰。雷达不仅会收到人体的回波还会收到墙壁、家具、甚至窗外摇晃的树叶的反射。这些静止物体的回波是固定的“直流”分量相对容易通过高通滤波去掉。但如果是晃动的窗帘、运行的空调风扇它们产生的微动频率可能正好落在呼吸心跳的频段内这就很难办了。我的经验是多天线雷达阵列是解决这个问题的利器。通过多个接收天线我们可以估计信号到来的方向形成空间滤波。也就是说我只接收从人体所在方向来的信号其他方向的干扰比如旁边的风扇就会被抑制。这相当于在空间上装了一个“聚焦镜”。第二个挑战是人体姿态和动作干扰。人不可能一直躺着不动翻身、抬手、挠痒痒这些动作产生的雷达回波幅度比心跳要大好几个数量级瞬间就会让信号饱和导致一段时间内的数据失效。对于这个问题自适应阈值检测和动作标记是关键。我们需要实时监测信号的幅度或能量一旦发现超过正常生理微动阈值的大幅度变化就把这段时间的数据标记为“无效”或“大动作期”不进行生命体征分析。等信号恢复平稳后再重新开始计算。更高级的方法会尝试区分动作类型比如区分出翻身长时间干扰和咳嗽瞬时干扰。第三个难点是多目标情况。一个房间里如果有多个人雷达回波就混在了一起。怎么区分出张三的呼吸和李四的心跳这非常困难也是当前研究的前沿。目前可行的思路包括结合超分辨率算法和空间分离技术。如果雷达有足够好的距离分辨率比如超宽带雷达并且两个人距离雷达的初始距离不同我们可以先在距离维度上将他们分开。如果距离上分不开但角度上略有不同就可以利用波达方向估计技术进行角度维的分离。当然如果两个人紧挨着且朝向一致现有技术就很难了通常需要引入其他传感器如摄像头进行辅助定位和关联。第四个是算法实时性与功耗的平衡。尤其是在电池供电的便携或可穿戴设备上复杂的算法如MUSIC、小波变换计算量大耗电快。在实际产品中我们往往采用分层处理策略。大部分时间运行一个极其精简的“监护模式”算法比如只做带通滤波和峰值检测用于判断生命体征是否存在以及是否在正常范围。只有当检测到异常如呼吸暂停、心率过快或用户主动查询时才触发后台运行更复杂的“诊断模式”算法进行精确分析和波形还原。同时选择低功耗的硬件平台和优化代码如使用定点数运算、利用硬件加速单元也至关重要。最后数据标注和模型训练也是个现实问题。为了提升算法在复杂场景下的鲁棒性现在越来越多地引入机器学习方法。但雷达生命体征数据很难获取精准的标签同步的、医疗级的心跳呼吸波形。我们当时的做法是自己搭建实验环境让志愿者佩戴医疗级的接触式设备如心电图ECG和呼吸带作为金标准同步采集雷达数据从而构建一个有标签的数据集。虽然过程繁琐但这是提升算法性能最扎实的路径。有了数据就可以训练一些模型比如用深度学习网络直接从时频图或原始相位信号中回归出心率、呼吸率甚至分类不同的睡眠阶段。做这个方向既需要扎实的信号处理功底也要有很强的工程问题解决能力。每当看到算法成功地从一堆噪声中稳定地提取出那条规律的心跳曲线时那种成就感就是支撑我们不断攻克难题的动力。希望这些分享能让你对非接触式生命体征监测这个既充满挑战又意义非凡的领域有一个更具体、更生动的认识。如果你正准备踏入这个领域不妨从搭建一个简单的雷达模块开始亲自采集一些数据动手实现一下本文提到的这些基础算法相信你会有更深刻的体会。