当前位置: 首页 > news >正文

基于Arduino的心电信号采集系统:从模拟电路到心率检测

1. 项目概述:从零搭建一个桌面级心电信号采集系统

心电信号,也就是我们常说的ECG,是心脏肌肉在收缩和舒张过程中产生的微弱电信号。对于电子爱好者、生物医学工程的学生,或者任何对生理信号采集感兴趣的人来说,能够亲手搭建一个系统,从自己身上采集并看到实时的心跳波形,是一件极具成就感的事情。这个项目,就是围绕Arduino Uno,设计并实现一个完整的心电信号采集与显示系统。它不仅仅是一个简单的“传感器读数”项目,而是融合了模拟电路设计(信号放大与滤波)、生物信号特性理解以及嵌入式系统编程的综合实践。

整个系统的核心目标很明确:从人体体表拾取仅有毫伏级别的微弱心电信号,经过一系列电路处理,将其放大、净化,最终通过Arduino转换为数字信号,在电脑上实时绘制出清晰的心电图波形,并计算出实时心率。你最终会得到一套可以放在桌面上运行的设备,通过几个电极贴片连接到身体(通常是手腕和脚踝),就能在电脑的串口绘图仪上看到自己的心跳。需要强调的是,这个系统是一个教学和实验性质的设备,它的精度、安全性和可靠性都无法与专业的医疗诊断设备相提并论,绝不能用于任何形式的医疗诊断或健康评估,其价值在于学习和理解生物信号采集的基本原理与工程实现。

2. 系统核心设计思路与方案选型

为什么选择这样的架构?这背后是一连串的工程权衡。心电信号极其微弱,典型幅度只有0.5mV到2mV,而环境中充斥着各种噪声,尤其是50Hz(国内)或60Hz(国外)的工频干扰,其强度可能远大于心电信号本身。因此,直接用一个Arduino的模拟输入口(分辨率为5V/1024 ≈ 4.9mV)去读取,信号早就淹没在噪声里了。所以,我们必须设计一个前端的模拟信号调理电路,完成“放大”和“滤波”两大任务。

2.1 为什么是三级电路?

我们采用了经典的三级模拟电路串联方案:仪表放大器 -> 陷波滤波器 -> 低通滤波器。这是一种逐级解决问题的思路。

  • 第一级:仪表放大器。它的首要任务是“放大”。我们需要将毫伏信号放大到伏特级别,以便Arduino能够有效分辨。为什么选择仪表放大器而不是普通运放?因为从人体采集的信号是差分信号(两个测量点之间的电位差),仪表放大器具有极高的共模抑制比,能有效抑制同时出现在两个输入端的干扰(比如工频干扰),只放大我们需要的差分信号。这是获取干净信号的第一步。
  • 第二级:陷波滤波器。它的任务是“精准剔除”。经过放大,信号变大了,但噪声也被放大了。其中,50/60Hz的工频干扰是最顽固、最强大的单一频率噪声源。陷波滤波器就像一个频率“陷阱”,专门针对这一个特定频率进行深度衰减(理想情况下在该频率点增益为0),从而将其从信号中剔除。
  • 第三级:低通滤波器。它的任务是“模糊处理”。心电信号的有效频率成分一般在0.05Hz到100Hz左右,超过150Hz的成分大多是肌电干扰(肌肉活动)、电极接触噪声等无用高频噪声。一个截止频率在100-150Hz的低通滤波器,可以平滑地衰减这些高频噪声,使波形看起来更干净。

2.2 核心器件选型考量

  • 运算放大器 uA741:这是一个古老而经典的通用型运放。选择它主要是因为其易得、廉价且文档丰富,非常适合教学和原型验证。但它并非最优选择,其输入偏置电流较大、带宽有限。在实际追求更高性能的项目中,可以考虑如AD620(专用仪表放大器芯片)、OPA系列(低噪声、高精度运放)等。本项目使用uA741,完全足以验证原理并得到可见波形。
  • Arduino Uno:选择它是因为其庞大的社区支持和简单的开发环境。它的10位ADC(模拟-数字转换器)对于这个项目来说精度足够(放大后的信号峰值控制在0-5V范围内)。其内置的串口通信和强大的Serial Plotter(串口绘图仪)工具,使得实时波形显示变得异常简单,无需编写复杂的上位机软件。
  • 电源:使用两节9V电池为运放电路供电,构成±9V的双电源系统。这是关键!大多数运放需要正负双电源才能输出正负摆幅的信号(心电信号有正有负)。电池供电也彻底隔离了市电,避免了通过电源线引入的额外工频干扰,这是生物信号采集中的常见技巧。

注意:电路中的电阻、电容值并非绝对不可变。原文作者也提到了因手头元件进行的替换。在电子制作中,理解电路原理比死记硬背元件值更重要。只要通过公式计算,保持电路的时间常数、截止频率等关键参数在目标范围内,使用相近值的元件是完全可以的。

3. 硬件电路详解与搭建要点

这一部分,我们将深入每一级电路的原理、计算和搭建时的“坑”。

3.1 仪表放大器:把微伏信号“喊大声”

仪表放大器的核心在于其差分放大结构。我们使用三个uA741运放搭建经典的三运放仪表放大器电路。

  • 增益计算:仪表放大器的差分增益公式为G = (1 + 2*R1/Rg) * (R3/R2)。在典型电路中,通常令R2 = R3,公式简化为G = 1 + 2*R1/Rg。原文设定目标增益为2000。假设我们选择R1 = 100kΩ,那么根据公式2000 = 1 + 2*100k / Rg,可以反推出增益电阻Rg ≈ 100Ω。这是一个非常小的电阻,在实际中可能需要用精密电位器仔细调节。
  • 实操要点:
    1. 布局与走线:这是高增益放大电路,布局至关重要。输入线(来自电极的导线)要尽可能短,最好使用屏蔽线,并将屏蔽层单点接地(通常在Arduino的GND点)。所有连接要牢固,避免使用过长、松散的跳线。
    2. 电源去耦:必须在每个运放的电源引脚(V+和V-)附近,紧贴着芯片放置一个0.1μF的陶瓷电容到地,用于滤除电源线上的高频噪声。这是保证运放稳定工作、避免自激振荡的必须步骤,很多初学者会忽略这一点导致电路异常。
    3. 偏置通路:uA741需要提供输入偏置电流的返回路径。由于我们通过电极连接人体,而人体对直流可以视为开路,因此需要在两个输入端(通过大电阻,如1MΩ - 10MΩ)连接到地,为运放的输入晶体管提供微小的偏置电流通路,否则输出可能会饱和到电源电压。

3.2 双T型陷波滤波器:精准狙击50/60Hz干扰

我们采用经典的双T型有源陷波滤波器。它的传递函数在中心频率处有一个很深的凹陷。

  • 中心频率计算:对于对称双T网络,陷波中心频率f0 = 1 / (2πRC)。目标是滤除50Hz(国内)或60Hz(国外)干扰。以60Hz为例,如果我们选择C = 0.1μF (0.1 × 10^-6 F),那么可以计算出R = 1 / (2π * 60 * 0.1e-6) ≈ 26.5 kΩ。在实际电路中,为了精确调谐,常会用一个固定电阻串联一个精密电位器来微调这个R值。
  • 品质因数Q值:Q值决定了陷波的“尖锐”程度。Q值越高,陷波越深越窄。通过调整双T网络与运放反馈网络中的电阻比例,可以调节Q值。对于工频干扰,一个中等Q值的陷波器即可,太窄可能因为市电频率微小波动而失效,太宽则会过度损伤心电信号中靠近该频率的有用成分。
  • 实操心得:搭建好后,最好用函数发生器和示波器进行验证。输入一个正弦波,从低频到高频扫频,观察输出幅度。你应该能看到在50/60Hz附近,输出信号幅度急剧下降。如果没有示波器,可以临时用Arduino的ADC读取滤波前后的信号,在50/60Hz输入下,观察读数是否显著降低。

3.3 二阶低通滤波器:给信号“磨皮”

采用压控电压源型的二阶低通滤波器。它结构简单,性能适中。

  • 截止频率计算:截止频率fc = 1 / (2π * sqrt(R1*R2*C1*C2))。通常为了设计方便,令R1 = R2 = RC1 = C2 = C,则公式简化为fc = 1 / (2πRC)。假设我们设定截止频率为100Hz,选择C = 0.1μF,则R ≈ 15.9 kΩ
  • 巴特沃斯响应:通过调整电容C1和C2的比例(例如,令C2 = 2*C1),可以获得巴特沃斯响应,即在通带内具有最平坦的幅度特性。这对于希望保持波形形状不失真的心电信号来说是比较好的选择。
  • 搭建检查:低通滤波器的验证同样可以通过扫频进行。输入一个高频信号(如500Hz),输出应衰减到很小;输入一个低频信号(如10Hz),输出应几乎无衰减地通过。

3.4 电极连接与身体导联

这是信号进入系统的“门户”,其质量直接决定了最终结果的成败。

  • 导联配置:本项目采用标准的肢体导联II配置。具体接法是:
    • 红色电极(正输入)-> 左腿(或左脚踝)。
    • 黄色电极(负输入)-> 右臂(或右手腕)。
    • 黑色电极(参考地)-> 右腿(或右脚踝)。 这个配置产生的心电波形通常P波、QRS波群和T波都非常明显。
  • 电极使用技巧:
    1. 皮肤处理:用酒精棉片清洁电极粘贴部位的皮肤,去除油脂和死皮,能显著降低接触阻抗和运动伪影。
    2. 导电膏:如果使用可重复使用的电极片,涂抹少量导电膏可以极大改善信号质量。一次性电极片通常自带导电凝胶。
    3. 保持静止:在测量时,尽量保持身体和四肢静止。轻微的肌肉运动都会产生肌电信号(EMG),其幅度可能与ECG相当,干扰严重。
    4. 导线固定:将电极导线用胶带或夹子固定在身体或衣服上,避免导线悬空摆动,这种摆动会产生摩擦生电的噪声。

4. 软件编程与Arduino数据处理逻辑

硬件电路输出的已经是比较干净的模拟心电信号了,接下来Arduino的工作是采样、简单的数字处理以及数据发送。

4.1 模拟信号采样

Arduino Uno的ADC是10位精度,参考电压默认为5V。这意味着它将0-5V的输入电压映射为0-1023的整数值。

int sensorValue = analogRead(A0); // 从A0引脚读取原始值 float voltage = sensorValue * (5.0 / 1023.0); // 转换为电压值(单位:伏特)

在连接电路时,需要确保放大滤波后的信号峰值在0-5V之间,最好居中(如偏置在2.5V附近),以充分利用ADC的动态范围,同时避免信号削顶(超过5V)或削底(低于0V)。

4.2 心率检测算法解析

原文提供的代码使用了一种简单的阈值检测法来识别QRS波(心电图中最高大的波峰),进而计算心率。这是嵌入式系统中一种经典且高效的轻量级算法。

int UpperThreshold = 50; // 峰值检测阈值 int LowerThreshold = 90; // 回落检测阈值(注意:此值高于峰值阈值,原文可能有误) int reading = 0; bool IgnoreReading = false; unsigned long FirstPulseTime = 0; unsigned long SecondPulseTime = 0; unsigned long PulseInterval = 0; void loop() { reading = analogRead(A0); // 检测心跳上升沿(QRS波峰值) if(reading > UpperThreshold && IgnoreReading == false){ if(FirstPulseDetected == false){ FirstPulseTime = millis(); FirstPulseDetected = true; } else { SecondPulseTime = millis(); PulseInterval = SecondPulseTime - FirstPulseTime; // 计算两次心跳间隔 FirstPulseTime = SecondPulseTime; // 更新时间点 } IgnoreReading = true; // 标记为已检测,防止在同一个波峰内重复计数 } // 检测心跳下降沿(信号回落) if(reading < LowerThreshold){ IgnoreReading = false; // 重置标记,准备检测下一个波峰 } // 计算心率(次/分钟) if(PulseInterval > 0){ // 避免除以零 BPM = 60000 / PulseInterval; // 60000毫秒 = 1分钟 } Serial.print("BPM: "); Serial.println(BPM); }

算法核心逻辑:

  1. 设置一个UpperThreshold。当采样值超过它时,认为可能检测到了一个QRS波峰。
  2. 一旦检测到波峰,立即设置一个“忽略区”(IgnoreReading = true),防止在同一个宽大的QRS波内因信号波动而多次触发。
  3. 设置一个较低的LowerThreshold。只有当信号回落到这个阈值以下时,才解除“忽略区”(IgnoreReading = false),系统才准备检测下一个QRS波。
  4. 记录连续两个QRS波峰的时间点,其时间差即为心跳间隔(PulseInterval),据此计算心率(BPM)。

重要纠偏与优化建议:原文代码中LowerThreshold = 90且判断条件为reading < LowerThreshold && reading > 2,这看起来有些矛盾。通常,LowerThreshold低于UpperThreshold,用于判断信号是否已从峰值充分回落。一个更合理的设置是:UpperThreshold = 520(对应约2.5V),LowerThreshold = 480(对应约2.35V),具体值需要根据你实际放大后的信号幅度来调整。优化方向:简单的阈值法易受基线漂移和噪声干扰。更鲁棒的算法可以加入滑动窗口均值滤波来动态估算基线,或者使用导数法(检测R波更陡峭的上升沿)来提高准确性。

4.3 串口数据输出与波形显示

这是最直观的部分。Arduino通过串口同时发送两样东西:

  1. 原始电压值:用于绘制波形。Serial.println(voltage);
  2. 计算出的心率值:用于数字显示。Serial.print("BPM: "); Serial.println(BPM);

在Arduino IDE中,打开工具 -> 串口绘图仪。正确配置波特率(与代码中Serial.begin()一致,如74880或更常见的9600、115200),你就能看到一个实时滚动的波形图,并在下方看到不断更新的心率数值。串口绘图仪会自动将接收到的数字绘制成曲线,将“BPM: 72”这样的文本显示在角落。

5. 系统集成、调试与故障排查实录

当所有模块搭建完毕,集成调试才是真正的挑战。以下是我在多次实践中总结的步骤和常见问题。

5.1 上电前终极检查

  1. 电源极性:反复检查±9V电池是否正确连接到运放的V+和V-引脚,切勿反接!用万用表确认电压。
  2. 接地一致性:确保整个系统只有一个“地”参考点。将所有电路的地、Arduino的GND、电池的中间抽头(如果是双电池供电的虚拟地)可靠地连接在一起。
  3. 元件值:对照电路图,用万用表的电阻档和电容档抽查关键位置的电阻、电容值,特别是决定增益和频率的元件。

5.2 分级调试法(强烈推荐)不要一次性连接所有电路。采用“从前到后”或“从后到前”的分级调试。

  • 方法A(从后到前):
    1. 先不接电极,用函数发生器给低通滤波器的输入注入一个1Hz-100Hz的正弦波(幅度约1V)。用示波器观察其输出,确认低通滤波器工作正常(高频衰减)。
    2. 将信号源移到陷波滤波器的输入,输入一个50/60Hz正弦波。观察输出是否被极大衰减。再输入一个30Hz或100Hz信号,观察是否正常通过。
    3. 最后测试仪表放大器。在其输入端接入一个很小的差分信号(可用两个电阻分压产生几毫伏的电压差),测量其输出增益是否符合设计。
  • 方法B(使用Arduino验证):如果没有示波器,可以在每一级电路的输出端,临时连接到Arduino的A0口,通过串口监视器观察数值变化。输入不同的频率和幅度,看读数变化是否符合滤波器特性(例如,输入60Hz时读数应最小)。

5.3 连接人体测试与信号优化当模拟测试通过后,断开函数发生器,连接电极到身体。

  1. 初始状态:先不要运行心率计算代码,只运行发送原始电压值的代码。打开串口绘图仪,观察原始波形。
  2. 常见问题与对策:
    • 问题1:信号幅度太小或太大。
      • 排查:检查仪表放大器增益电阻Rg。信号太小则减小Rg,太大则增大Rg。确保信号峰值在0-5V范围内,且最好有正负摆动。
    • 问题2:波形上有规律的50/60Hz正弦波干扰。
      • 排查:陷波滤波器未调准或失效。检查双T网络的R、C值,尝试微调电阻。确保电路接地良好,电极导线使用屏蔽线。
    • 问题3:波形基线缓慢上下漂移(基线漂移)。
      • 原因:这是心电采集的典型问题,由呼吸、电极接触电位变化引起。
      • 对策:在软件中加入数字高通滤波(即基线漂移校正)。最简单的方法是在Arduino代码中计算一个滑动平均作为“动态基线”,然后从每个采样点中减去这个基线值。
    • 问题4:波形毛刺多,不光滑。
      • 排查:高频噪声。确认低通滤波器截止频率是否合适。检查电源去耦电容是否焊好。确保测量时身体和导线保持静止。
    • 问题5:心率计算完全不准确或乱跳。
      • 排查:调整UpperThresholdLowerThreshold。它们必须根据你实际的信号幅度来设置。打开串口绘图仪,观察稳定的QRS波峰值和谷值对应的ADC读数,将阈值设在其间。例如,峰值读数为800,谷值读数为200,则UpperThreshold可设为700,LowerThreshold可设为300。

5.4 提升系统稳定性的进阶技巧

  1. 右腿驱动电路:这是一个高级但非常有效的技巧。它不是简单地将右腿接地,而是通过一个运放将身体共模信号反相放大后,再驱动右腿电极。这能主动抵消从身体感应的共模干扰(主要是工频干扰),可以显著提升信号质量。
  2. 软件数字滤波:在Arduino上实现简单的数字滤波器,如移动平均滤波(去毛刺)或一阶高通滤波(去基线漂移),可以弥补硬件电路的不足,且灵活可调。
  3. 使用专用仪表放大器芯片:如AD620或INA128。它们将三运放仪表放大器集成在一颗芯片内,匹配精度高,共模抑制比远超分立元件搭建的电路,能极大简化设计并提升性能。

当你按照以上步骤,最终在屏幕上看到随着自己呼吸和心跳而规律跳动的清晰波形时,所有的调试和折腾都是值得的。这个项目就像一座桥梁,连接了抽象的电子学原理与鲜活的生命现象。它教会你的远不止如何连接几个运放和写几行代码,更是一种系统性的工程思维:从需求分析、方案设计、模块实现、集成调试到问题解决。你可以在此基础上继续探索,比如加入SD卡存储、OLED本地显示、蓝牙传输到手机,甚至尝试更复杂的心律失常算法检测。

http://www.rkmt.cn/news/1434934.html

相关文章:

  • 为什么87%的出海企业Gemini API调用被拦截?揭秘HTTP Header中缺失的3个X-Forwarded-*关键标头
  • 从Arduino原型到PCB实战:基于ATmega328P的Pong游戏电路板设计全流程
  • Gemini首次使用体验优化指南:3个被90%团队忽略的引导断点及修复代码级方案
  • 如何彻底掌控你的微信聊天记录:WeChatMsg数据导出完全指南
  • 终极免费LaTeX写作解决方案:WebLaTeX完整指南,无需安装即可专业排版
  • 3分钟极速上手:零代码网页转应用神器PakePlus完整指南
  • 终极指南:用GTA圣安地列斯存档编辑器重塑你的游戏体验
  • Arduino入门:从LED交替闪烁掌握GPIO控制与嵌入式开发基础
  • 潍坊天宝汽车音响 门店详细介绍 - Reaihenh
  • 零基础也能修好损坏的二维码!QRazyBox实战指南 [特殊字符]️
  • 【Gemini退役决策内幕】:从技术债累积到战略收缩,一位前Google Cloud架构师的12页闭门分析报告
  • 双显卡笔记本福音:Ubuntu下NVIDIA驱动安装与PRIME渲染切换全攻略
  • 抖音内容批量管理的终极解决方案:3步实现效率翻倍
  • 5大核心场景全面实战:AtlasOS让你的Windows系统性能飙升40%
  • Arduino超声波感应互动南瓜灯:从传感器到执行器的完整项目实践
  • 基于图像处理的铁路裂缝检测系统
  • 郑州市 二七区 清洁收纳|维小达 日常保洁、开荒保洁、窗户保洁、收纳整理、暖气家电清洗一站式服务 - 维小达科技
  • D2DX宽屏补丁:让经典《暗黑破坏神2》在现代PC上完美运行的终极指南
  • 中山苏易房屋修缮|专业免砸砖防水堵漏 厨卫飘窗屋面地下室本地专修 - 吉修匠
  • 年省18万增收50万:换热器哪家强案例解析 - 资讯纵览
  • 鸣潮自动化工具ok-ww:5分钟快速上手指南,释放你的游戏时间
  • 2026年电线电缆厂家:解读三大核心发展趋势 - 资讯纵览
  • 基于线性执行器的上肢辅助外骨骼DIY:从机电一体化到康复应用
  • 东莞东城装修公司哪家好?2026年最新实地考察报告 - liuminghui
  • 【紧急预警】Gemini同类AI项目92%公关失败源于这1个被忽视的合规盲区
  • Python之strformat包语法、参数和实际应用案例
  • Ubuntu 20.04下搞定Cadence Virtuoso AMS仿真:从INCISIVE151安装到GCC版本避坑全记录
  • PC版微信QQ防撤回终极指南:5分钟搞定消息永久保存
  • 2026东莞装修公司口碑榜TOP5:东城双雄领跑,业主真实体验大公开 - liuminghui
  • 陀螺仪防抖神器Gyroflow:3步让运动视频如专业拍摄般稳定