基于数字信号处理器的心电信号R波检测系统设计

博主简介:擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导,毕业论文、期刊论文经验交流。

 ✅ 具体问题可以私信或扫描文章底部二维码。


(1)疲劳驾驶的核心生理特征体现在自主神经系统的功能状态变化上,而心率变异性(HRV)作为评估自主神经系统活动的重要无创指标,能够敏感地反映出驾驶员的疲劳程度。当驾驶员处于疲劳状态时,其交感神经和副交感神经的平衡会被打破,通常表现为交感神经活动相对增强而副交感神经活动减弱,这种变化在HRV信号中会体现为时域指标(如SDNN、RMSSD)的降低,频域指标中低频功率(LF)与高频功率(HF)比值的升高,以及非线性动力学指标(如样本熵、复杂度)的改变。因此,通过持续监测驾驶员的心电信号(ECG),并从中精确提取出R波间期(RR间期)序列以计算HRV的各项特征参数,可以构建一个有效的疲劳状态评估模型。然而,在真实的驾驶环境中,通过接触式电极采集ECG信号会干扰驾驶操作,舒适度差,难以进行长时间监测。为解决这一难题,本研究创新性地采用了一种基于容性耦合原理的非接触式心电测量电极。该电极无需与皮肤直接接触,而是通过感应人体体表与电极板之间因心脏电活动引起的微小电容变化来获取信号。这种设计将电极嵌入驾驶座的头枕或座椅靠背中,驾驶员在自然坐姿下背部或头部与电极形成耦合,即可完成信号采集,极大地提升了穿戴舒适性和系统的可用性,为长时间、不间断的监测奠定了基础。

(2)由于非接触式电极采集到的原始心电信号极其微弱(通常在毫伏级别),并且淹没在强大的各种噪声中,包括来自车辆发动机点火系统的电磁干扰、驾驶员身体移动带来的运动伪迹、电极与衣物之间摩擦产生的噪声以及工频干扰等,因此必须设计一个高性能的专用模拟前端放大器对其进行预处理。本研究设计并制作了一个基于“两级放大、三级滤波”架构的专用心电信号放大器。第一级采用高输入阻抗、高共模抑制比(CMRR)的仪表放大器,主要目的是提取微弱的差分心电信号并抑制共模干扰;第二级采用同相比例运算放大器,对信号进行进一步放大,使其幅度满足后续模数转换器的输入要求。三级滤波则分别针对不同的噪声源:第一级为高通滤波,截止频率设置为0.5Hz左右,用于滤除因呼吸和缓慢身体移动带来的基线漂移;第二级为低通滤波,截止频率设置在100Hz左右,用于滤除高频肌电噪声和杂散射频干扰;第三级为一个陷波器,中心频率为50Hz(或60Hz,根据地区工频而定),专门用于滤除强大的工频干扰。经过此模拟调理电路处理后,原本信噪比极低的原始信号被放大和初步净化,在示波器上已经可以观察到清晰可辨的QRS波群,为后续的数字信号处理算法提供了高质量的输入信号。

(3)将模拟放大器输出的信号经过ADC采样转化为数字信号后,需要一套高效且鲁棒的数字信号处理算法来最终完成HRV的提取和疲劳状态的判断。该算法主要在MATLAB环境中进行设计和仿真,主要包括两个核心部分:IIR数字滤波和R波峰值检测。首先,虽然模拟前端已经进行了滤波,但数字域需要再进行一次更精确的滤波以进一步提升信噪比。设计了一个截止频率为5-15Hz的带通滤波器(例如利用双线性变换法设计的切比雪夫II型或椭圆滤波器),这个频带范围能够最大限度地保留QRS波的能量而抑制其他干扰。然后,采用经典的Pan-Tompkins算法或其改进算法进行R波检测。该算法通过一系列处理步骤来增强R波特征:先对滤波后的信号进行微分以突出信号的斜率信息,再进行平方处理使所有点变为正值并进一步放大高频分量,接着采用滑动窗口积分器对信号进行平滑以生成一个包含R波位置信息的包络,最后通过自适应阈值检测算法在包络上精确地定位每个R波的峰值点。一旦检测到R波序列,就可以计算出连续的RR间期序列,即HRV分析的原始数据。在此基础上,计算时域指标(SDNN、RMSSD)、频域指标(通过FFT或AR模型计算LF、HF功率及比值)和非线性指标。为了将算法部署到实际的嵌入式系统中,本研究基于德州仪器(TI)的TMS320VC5509A DSP平台进行了完整的移植和优化。利用TI的Chip Support Library(CSL)进行外设(如ADC、DMA、定时器)的初始化配置,确保数据流的实时采集;利用DSP Library中的数学函数和滤波函数,将MATLAB中设计的IIR滤波器转换为高效的C语言代码;并精心优化了R波检测算法的逻辑,减少乘加运算,使其满足DSP的实时处理要求。通过TI的RTDX技术和MATLAB的CCSLink插件,搭建了一个强大的联合调试环境,实现了PC上的MATLAB与目标DSP板之间的实时数据交换,从而可以在MATLAB中直观地监控DSP内部的算法运行结果,进行性能分析和调试,最终确保了整个监测系统能够脱离上位机独立、实时、准确地运行。

import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
from scipy.fft import fft, fftfreq

class HRVFatigueAnalyzer:
    """
    基于心率变异性的疲劳驾驶分析算法核心类
    (模拟MATLAB算法设计,为最终DSP C代码实现提供原型)
    """
    def __init__(self, fs=250):
        """
        初始化分析器
        :param fs: 采样频率 (Hz)
        """
        self.fs = fs
        self.r_peaks = []  # 检测到的R波位置索引
        self.rr_intervals = []  # RR间期序列 (ms)
        self.hrv_features = {}  # 计算出的HRV特征字典

        # 设计带通滤波器 (5-15 Hz) 以突出QRS波
        self.bp_sos = signal.cheby2(4, 40, [5, 15], 'bandpass', fs=fs, output='sos')
        # 设计50Hz陷波器
        self.notch_sos = signal.iirnotch(50, 30, fs=fs)

    def preprocess_ecg(self, raw_ecg):
        """
        心电信号预处理:滤波去噪
        :param raw_ecg: 原始ECG信号数组
        :return: 滤波后的ECG信号
        """
        # 应用陷波滤波器去除工频干扰
        ecg_notched = signal.sosfilt(self.notch_sos, raw_ecg)
        # 应用带通滤波器提取QRS频带
        ecg_filtered = signal.sosfilt(self.bp_sos, ecg_notched)
        return ecg_filtered

    def detect_r_peaks(self, filtered_ecg):
        """
        使用改进的Pan-Tompkins算法检测R波峰值
        :param filtered_ecg: 预处理后的ECG信号
        :return: R波峰值位置列表
        """
        # 1. 微分
        diff_ecg = np.diff(filtered_ecg)
        # 2. 平方
        squared_ecg = diff_ecg ** 2
        # 3. 滑动窗口积分 (窗口宽度约为100ms)
        window_width = int(0.1 * self.fs)
        integrated_ecg = np.convolve(squared_ecg, np.ones(window_width)/window_width, mode='same')
        
        # 4. 自适应阈值检测
        peaks = []
        noise_peak = 0.0
        signal_peak = np.max(integmented_ecg) * 0.5  # 初始信号峰值估计
        threshold = noise_peak + 0.25 * (signal_peak - noise_peak)
        
        for i in range(1, len(integmented_ecg)-1):
            if integrated_ecg[i] > integrated_ecg[i-1] and integrated_ecg[i] > integrated_ecg[i+1]:
                if integrated_ecg[i] > threshold:
                    # 在积分信号峰值附近寻找原始滤波信号的精确峰值
                    search_start = max(0, i - window_width//2)
                    search_end = min(len(filtered_ecg), i + window_width//2)
                    local_max_idx = search_start + np.argmax(filtered_ecg[search_start:search_end])
                    peaks.append(local_max_idx)
                    # 更新信号峰值和阈值 (模拟自适应过程)
                    signal_peak = 0.875 * signal_peak + 0.125 * integrated_ecg[i]
                else:
                    noise_peak = 0.875 * noise_peak + 0.125 * integrated_ecg[i]
                threshold = noise_peak + 0.25 * (signal_peak - noise_peak)
        
        #  refractory period 限制 (避免一个R波被检测多次)
        min_rr = int(0.3 * self.fs)  # 最小RR间期对应样本数
        refined_peaks = []
        last_peak = -min_rr
        for p in peaks:
            if p - last_peak > min_rr:
                refined_peaks.append(p)
                last_peak = p
        self.r_peaks = refined_peaks
        return refined_peaks

    def compute_rr_intervals(self):
        """
        计算RR间期序列 (单位: 毫秒)
        """
        if len(self.r_peaks) < 2:
            return []
        self.rr_intervals = np.diff(self.r_peaks) * (1000.0 / self.fs)  # 转换为毫秒
        return self.rr_intervals

    def analyze_hrv(self, rr_intervals):
        """
        计算HRV的时域和频域特征
        :param rr_intervals: RR间期序列 (ms)
        """
        if len(rr_intervals) < 5:
            return {}
        
        # 时域分析
        self.hrv_features['SDNN'] = np.std(rr_intervals)  # RR间期标准差
        self.hrv_features['RMSSD'] = np.sqrt(np.mean(np.diff(rr_intervals)**2))  # 相邻RR间期差值的均方根
        
        # 频域分析 (使用Lomb-Scargle周期图处理非均匀采样序列)
        t = np.cumsum(rr_intervals) / 1000.0  # 时间点 (秒)
        f = np.linspace(0.01, 0.5, 500)  # 频率范围 (Hz)
        pxx = signal.lombscargle(t, rr_intervals - np.mean(rr_intervals), f, normalize=True)
        
        # 计算LF (0.04-0.15Hz) 和 HF (0.15-0.4Hz) 功率
        lf_mask = (f >= 0.04) & (f <= 0.15)
        hf_mask = (f >= 0.15) & (f <= 0.4)
        lf_power = np.trapz(pxx[lf_mask], f[lf_mask])
        hf_power = np.trapz(pxx[hf_mask], f[hf_mask])
        total_power = lf_power + hf_power
        
        self.hrv_features['LF'] = lf_power
        self.hrv_features['HF'] = hf_power
        self.hrv_features['LF/HF'] = lf_power / hf_power if hf_power > 0 else 0
        self.hrv_features['LF_norm'] = 100 * lf_power / total_power
        self.hrv_features['HF_norm'] = 100 * hf_power / total_power
        
        return self.hrv_features

    def assess_fatigue(self, hrv_features):
        """
        基于HRV特征评估疲劳状态
        :param hrv_features: HRV特征字典
        :return: 疲劳分数和状态
        """
        # 基于文献的简单线性模型 (实际应用中应使用机器学习模型)
        # SDNN和RMSSD下降,LF/HF升高指示疲劳
        sdnn_score = max(0, min(100, (hrv_features.get('SDNN', 0) - 20) / 30 * 100))
        rmssd_score = max(0, min(100, (hrv_features.get('RMSSD', 0) - 15) / 25 * 100))
        lfhf_score = max(0, min(100, (3 - hrv_features.get('LF/HF', 3)) / 2 * 100))
        
        fatigue_score = 0.4 * (100 - sdnn_score) + 0.3 * (100 - rmssd_score) + 0.3 * lfhf_score
        fatigue_state = "正常" if fatigue_score < 40 else "轻度疲劳" if fatigue_score < 70 else "严重疲劳"
        
        return fatigue_score, fatigue_state

# 示例使用
if __name__ == "__main__":
    # 生成模拟ECG信号 (用于算法测试)
    fs = 250
    t = np.arange(0, 60, 1/fs)  # 60秒数据
    # 模拟基础心率 + 噪声 + R波
    ecg_sim = 0.5 * np.sin(2 * np.pi * 1 * t)  # 呼吸基线漂移
    ecg_sim += 0.1 * np.random.randn(len(t))   # 高斯白噪声
    
    # 添加模拟R波 (心率从70逐渐下降到55 BPM,模拟疲劳)
    heart_rate = np.linspace(70, 55, len(t))
    rr_intervals = 60 / heart_rate * fs  # 以样本数为单位的RR间期
    peak_times = np.cumsum(rr_intervals).astype(int)
    peak_times = peak_times[peak_times < len(t)]
    ecg_sim[peak_times] += 2.0  # 添加R波峰值

    # 实例化分析器
    analyzer = HRVFatigueAnalyzer(fs=fs)
    
    # 信号预处理
    ecg_processed = analyzer.preprocess_ecg(ecg_sim)
    
    # R波检测
    r_peaks = analyzer.detect_r_peaks(ecg_processed)
    
    # RR间期计算
    rr_intervals = analyzer.compute_rr_intervals()
    
    # HRV分析
    hrv_features = analyzer.analyze_hrv(rr_intervals)
    
    # 疲劳评估
    fatigue_score, fatigue_state = analyzer.assess_fatigue(hrv_features)
    
    print(f"检测到 {len(r_peaks)} 个R波")
    print(f"HRV特征: {hrv_features}")
    print(f"疲劳评分: {fatigue_score:.2f}, 状态: {fatigue_state}")

    # 绘制结果
    plt.figure(figsize=(12, 8))
    plt.subplot(2, 1, 1)
    plt.plot(t, ecg_sim, label='原始模拟ECG')
    plt.plot(t, ecg_processed, label='滤波后ECG')
    plt.plot(r_peaks/fs, ecg_processed[r_peaks], 'ro', label='检测到的R波')
    plt.legend()
    plt.title('ECG信号与R波检测')
    
    plt.subplot(2, 1, 2)
    plt.plot(rr_intervals, 'b-')
    plt.ylabel('RR间期 (ms)')
    plt.xlabel('心跳序号')
    plt.title('RR间期序列 (心率变异性)')
    plt.tight_layout()
    plt.show()


如有问题,可以直接沟通

👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坷拉博士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值