当毫米波雷达的电磁波穿透衣物照射到人体表面时,胸腔的微动会形成独特的调制信号。这种非接触式检测方式正在医疗监护、睡眠监测等领域引发革命。本文将手把手带您用Python构建完整的信号处理流水线,从原始信号中提取出心跳与呼吸的"生命密码"。
工欲善其事,必先利其器。我们需要搭建一个专业的信号处理环境:
python复制# 核心工具库
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
from scipy.fft import fft, fftfreq
# 专业信号处理扩展
import pywt # 小波分析
import heartpy as hp # 心率分析专用库
实测数据获取通常有三种途径:
python复制# 仿真信号生成示例
fs = 100 # 采样率100Hz
t = np.arange(0, 60, 1/fs) # 60秒时长
respiration = 0.5 * np.sin(2*np.pi*0.2*t) # 0.2Hz呼吸
heartbeat = 0.2 * np.sin(2*np.pi*1.2*t) # 1.2Hz心跳
noise = 0.1 * np.random.normal(size=len(t))
raw_signal = respiration + heartbeat + noise
原始信号往往包含多种干扰:
滑动平均去基线漂移:
python复制window_size = int(fs * 1.5) # 1.5秒窗口
baseline = np.convolve(raw_signal, np.ones(window_size)/window_size, mode='same')
filtered = raw_signal - baseline
小波阈值去噪实战:
python复制coeffs = pywt.wavedec(filtered, 'db4', level=5)
sigma = np.median(np.abs(coeffs[-1])) / 0.6745
threshold = sigma * np.sqrt(2*np.log(len(filtered)))
coeffs[1:] = [pywt.threshold(c, threshold, mode='soft') for c in coeffs[1:]]
denoised = pywt.waverec(coeffs, 'db4')
注意:小波去噪后可能出现边界效应,建议截去首尾各5%的数据
巴特沃斯滤波器的核心优势在于通带内最大平坦响应,特别适合生物信号处理。我们需要设计两个滤波器:
呼吸信号提取(低通0.4Hz):
python复制low_cutoff = 0.4 # Hz
sos_resp = signal.butter(4, low_cutoff, btype='lowpass', fs=fs, output='sos')
respiration_signal = signal.sosfiltfilt(sos_resp, denoised)
心跳信号提取(带通0.7-2Hz):
python复制low, high = 0.7, 2.0 # Hz
sos_heart = signal.butter(4, [low, high], btype='bandpass', fs=fs, output='sos')
heartbeat_signal = signal.sosfiltfilt(sos_heart, denoised)
关键参数选择指南:
| 参数 | 呼吸信号 | 心跳信号 | 理论依据 |
|---|---|---|---|
| 阶数 | 4阶 | 4阶 | 兼顾陡峭度与相位线性 |
| 截止频率 | 0.4Hz | 0.7-2Hz | 成人呼吸<0.5Hz,心率0.9-1.7Hz |
| 滤波方式 | 零相位filtfilt | 零相位filtfilt | 消除相位失真 |
FFT是频率分析的利器,但需要掌握正确使用方法:
python复制def compute_psd(signal, fs):
n = len(signal)
yf = fft(signal)
xf = fftfreq(n, 1/fs)[:n//2]
return xf, 2/n * np.abs(yf[0:n//2])
# 呼吸频谱
f_resp, psd_resp = compute_psd(respiration_signal, fs)
resp_peak = f_resp[np.argmax(psd_resp[:20])] # 前20个点对应0-2Hz
# 心跳频谱
f_heart, psd_heart = compute_psd(heartbeat_signal, fs)
heart_peak = f_heart[np.argmax(psd_heart[10:40])+10] # 0.7-2Hz范围
频谱优化技巧:
python复制window = np.hanning(len(heartbeat_signal))
yf_windowed = fft(heartbeat_signal * window)
python复制f, Pxx = signal.welch(heartbeat_signal, fs, nperseg=1024)
实际应用中需要关注的三大核心指标:
信噪比(SNR)优化
动态范围调整
python复制# 自动增益控制实现
target_max = 0.8
gain = target_max / np.max(np.abs(raw_signal))
normalized = raw_signal * gain
典型问题排查表:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 心率检测值偏高 | 呼吸谐波干扰 | 降低低通截止频率到0.3Hz |
| 频谱峰不明显 | SNR过低 | 检查雷达配置,增加采样时间 |
| 结果波动大 | 运动伪影 | 增加加速度计补偿 |
将各模块整合为端到端处理流水线:
python复制class VitalSignProcessor:
def __init__(self, fs=100):
self.fs = fs
self.resp_filter = signal.butter(4, 0.4, btype='lowpass', fs=fs, output='sos')
self.heart_filter = signal.butter(4, [0.7, 2.0], btype='bandpass', fs=fs, output='sos')
def process(self, raw_signal):
# 去基线
baseline = np.convolve(raw_signal, np.ones(150)/150, mode='same')
filtered = raw_signal - baseline
# 小波去噪
coeffs = pywt.wavedec(filtered, 'db4', level=5)
sigma = np.median(np.abs(coeffs[-1])) / 0.6745
threshold = sigma * np.sqrt(2*np.log(len(filtered)))
coeffs[1:] = [pywt.threshold(c, threshold, mode='soft') for c in coeffs[1:]]
denoised = pywt.waverec(coeffs, 'db4')[75:-75] # 去除边界
# 滤波分离
respiration = signal.sosfiltfilt(self.resp_filter, denoised)
heartbeat = signal.sosfiltfilt(self.heart_filter, denoised)
# 频谱分析
f_resp, psd_resp = compute_psd(respiration, self.fs)
f_heart, psd_heart = compute_psd(heartbeat, self.fs)
return {
'respiration_rate': f_resp[np.argmax(psd_resp[:20])] * 60,
'heart_rate': f_heart[np.argmax(psd_heart[10:40])+10] * 60
}
在真实项目中,这个处理器类可以进一步扩展为支持实时流处理、异常检测等功能。记得在部署前用不同体型的测试者数据进行充分验证——我曾在实际项目中遇到过BMI>30的测试者信号需要特殊处理的情况,这时将巴特沃斯阶数提高到6阶能获得更好效果。