
简介本资源是2021年FPGA类竞赛编号0007的完整实现方案面向电子信息、生物医学工程等专业的本科生与研究生聚焦心电信号实时监测与回放这一典型嵌入式AI应用场景。项目基于Xilinx PYNQ-Z1/Z2平台开发融合ADC采样、FPGA逻辑加速、Python上层控制及Web界面交互解决心电数据采集、滤波、QRS波检测、存储回放与可视化等全流程技术问题适用于毕业设计、课程设计、大创项目及学科竞赛备赛。压缩包共698个文件含437个Xilinx Vivado工程文件.xws、69组MIT-BIH标准心电数据.dat/.hea/.atr格式、70个标注文件及配套C/Makefile/Shell脚本等总容量70.66MB结构清晰、模块解耦支持开箱复现。已有74人下载学习资源附带经答辩验证的功能说明与高分设计报告参考代码全部通过实机测试可直接部署运行并支持在PYNQ框架下扩展机器学习模型或远程传输功能。1. 项目缘起从毕设选题到FPGA实战的跨越最近几年无论是电子、通信还是生物医学工程专业毕业设计和课程设计的选题都越来越“卷”。大家不再满足于做个简单的单片机温湿度计或者网页管理系统而是希望项目能结合前沿技术解决一个稍微有点挑战性的实际问题。我手头这个“基于PYNQ的心电信号监测和回放系统”项目就是在这种背景下诞生的一个典型例子。它最初可能只是一个竞赛或者毕设的题目但仔细拆解下来你会发现它几乎囊括了从模拟信号处理、数字逻辑设计、嵌入式软硬件协同到上位机应用开发的全链路知识点实战价值非常高。简单来说这个项目要干两件核心的事监测和回放。监测就是实时采集人体的心电信号ECG经过放大、滤波、数字化后进行关键特征比如心率、QRS波的提取与异常判断。回放则是将处理后的数据或预先存储的典型心电波形通过数模转换DAC或直接以数字形式“播放”出来用于教学演示、算法验证或者设备校准。而实现这一切的核心平台选择了PYNQ。PYNQ不是一块简单的FPGA开发板它是Xilinx推出的一个将FPGA可编程逻辑与ARM处理器系统PS紧密集成的平台并且用Python作为上层应用开发的主要语言大大降低了FPGA的开发门槛。对于学生和快速原型开发者来说这意味着你可以用Python轻松调用FPGA加速器而不用深陷于传统的RTL调试和驱动开发的泥潭。这个项目适合谁呢首先当然是面临毕设、课设、实训或者竞赛的电子类、生物医学工程类学生。其次对于想从单片机转向更高速、更并行处理的硬件开发者或者对医疗电子、边缘AI计算感兴趣的工程师这也是一个绝佳的入门练手项目。通过它你不仅能学到心电信号的基础知识更能亲手实践FPGA数据采集、数字滤波、PYNQ软硬件协同设计以及Python图形界面开发等一系列硬核技能。接下来我就结合这个项目的常见实现路径拆解其中的关键技术环节、设计思路以及那些容易踩坑的细节。2. 系统架构设计与核心模块选型拿到这样一个题目第一步不是急着写代码而是要把系统框图搭出来明确数据流和各个模块的职责。一个典型的基于PYNQ的心电信号监测回放系统其核心架构可以划分为传感前端、FPGA逻辑PL、处理器系统PS和上位机应用四大部分。2.1 传感前端从微伏信号到可靠数字量心电信号非常微弱典型幅度只有0.5mV到5mV并且混杂了大量的工频干扰50/60Hz、肌电噪声和基线漂移。因此前端模拟电路的设计至关重要它直接决定了后续数字处理的质量。放大与滤波电路通常采用仪表放大器如AD620, INA128进行第一级差分放大以抑制共模干扰。随后需要设计高通滤波器截止频率约0.05Hz来消除基线漂移以及低通滤波器截止频率约100-150Hz来限制带宽、抑制高频噪声。一个50/60Hz的陷波器带阻滤波器也几乎是标配用于强力抑制最强的工频干扰。这部分电路建议先在Multisim或LTspice等软件中进行仿真确保增益、带宽和噪声性能满足要求。在实际制作时布局布线要非常小心尽量采用屏蔽线连接电极电源去耦要到位否则引入的噪声可能会让后续的数字处理功亏一篑。模数转换ADC将调理后的模拟信号转换为数字信号。这里的选择与PYNQ开发板的具体型号密切相关。如果你的PYNQ板如Pynq-Z2自带XADC接口那么可以直接利用FPGA内部的XADC核它是一个12位、1MSPS的ADC对于心电信号带宽150Hz来说采样率完全够用精度也尚可。你需要设计一个简单的接口电路将调理后的单端信号0-1V或0-3V连接到FPGA的专用模拟输入引脚。另一种更专业的做法是使用外置的高精度ADC芯片如ADI的AD717x系列TI的ADS129x系列通过SPI或I2C接口与FPGA通信。这种方式性能更好但需要自己编写ADC的控制器IP核复杂度更高。对于毕设项目优先推荐使用板载XADC它能简化硬件设计让你更专注于算法和系统集成。2.2 FPGA逻辑PL设计高速并行的数据处理引擎这是项目的核心加速部分所有对实时性要求高的处理都放在这里。在Vivado中我们需要为PYNQ的PL部分设计一系列IP核。1. 数据采集与控制IP核这个IP核负责与ADC通信。如果使用XADC你需要通过AXI4-Lite接口配置XADC的采样通道、采样率等参数并持续读取其DRP动态重配置端口输出的数据。如果使用外置ADC则需要实现一个SPI/I2C Master控制器。这个IP核的输出应该是一个连续的心电数据流通过AXI4-Stream接口送出这是PYNQ框架下高效数据传递的标准方式。2. 实时数字滤波IP核尽管前端有模拟滤波但数字滤波可以更灵活、更精确地去除残留噪声。这里通常需要实现一个FIR有限脉冲响应带通滤波器。为什么是FIR而不是IIR因为FIR滤波器具有线性相位特性不会导致心电波形失真这对于后续的波形特征识别至关重要。你可以使用Vivado的FIR Compiler IP核只需导入用MATLAB或PythonSciPy设计的滤波器系数例如通带0.5Hz-40Hz。这个IP核也配置为AXI4-Stream接口直接对接数据采集IP的输出。一个关键细节需要根据采样率和数据位宽仔细计算滤波器的阶数和所需的硬件资源DSP48、BRAM避免资源溢出。3. 特征提取与心率计算IP核可选但推荐这是体现FPGA并行计算优势的地方。可以在PL端实现一个实时QRS波检测算法如经典的Pan-Tompkins算法。该算法包括微分、平方、滑动积分等步骤非常适合用FPGA的流水线结构实现。检测到R波峰值后就能实时计算瞬时心率IBI和平均心率。将心率值和R波标记信号通过AXI4-Lite接口提供给PS端可以极大减轻处理器的负担实现真正的实时监测。4. 数据缓存与回放控制IP核为了实现回放功能需要在PL端开辟一块BRAM或通过AXI接口连接DDR内存作为波形数据的缓冲区。回放模式时PS端将预存的波形数据如正常窦性心律、室性早搏等通过DMA写入缓冲区然后由PL端的一个控制状态机以设定的速率循环读取并通过AXI4-Stream接口输出。如果需要模拟输出这个数据流会连接到一个DAC IP核如果板载有DAC如Pynq-Z2的音频编解码器或者通过PMOD接口连接外置DAC模块。2.3 处理器系统PS与PYNQ框架灵活的系统协调者PYNQ的PS部分ARM Cortex-A9/A53运行Linux系统它通过PythonJupyter Notebook与PL端的硬件逻辑交互。PS端主要负责系统配置与启动通过Overlay类加载编译好的比特流文件.bit将自定义的IP核映射为Python可操作的对象。数据管理与通信使用xlnk管理PL与PS共享的内存通过DMA进行大数据块的高速传输。例如将PL端滤波后的数据流通过DMA实时搬运到PS端的内存中。高级算法与逻辑控制运行无法在PL端实现的复杂算法如高级心律失常分析、业务逻辑如报警阈值判断以及控制回放模式的启停、速度等。对外通信通过以太网、Wi-Fi将数据或结果发送到上位机或者接收上位机的控制指令。2.4 上位机应用可选但建议有一个图形化的上位机可以极大提升项目的完整度和展示效果。可以使用Python的Tkinter、PyQt或者更简单的Matplotlib动画来开发。上位机的主要功能包括实时波形显示通过Socket或HTTP从PYNQ板接收数据动态绘制心电波形图。参数显示与报警实时显示心率值并在心率过高、过低或检测到疑似异常波形时进行视觉和声音报警。回放控制界面提供按钮或下拉菜单选择不同的预存心电案例进行回放并控制回放速度。数据记录将一段时间的ECG数据记录到本地文件如CSV格式供后续分析。整个系统的数据流是双向的监测时信号从前端→ADC→PL滤波/特征提取→PS→上位机显示回放时数据从上位机或PS存储区→PL回放控制→DAC→输出或直接数字流输出。3. 开发环境搭建与关键工程配置工欲善其事必先利其器。这个项目的开发涉及硬件描述语言、嵌入式Linux和Python环境搭建稍微复杂但按照步骤来并不难。3.1 硬件平台选择与准备最常用的PYNQ开发板是Pynq-Z2它性价比高社区资源丰富。确认你手头的板子型号并准备好以下硬件PYNQ开发板及电源。心电模拟前端电路板可以自己焊接也可以购买模块化的ECG模拟器或生物电放大器模块如AD8232模块但需要注意其输出特性是否匹配PYNQ的ADC输入范围。连接线杜邦线、屏蔽线。微SD卡≥8GB用于烧录PYNQ系统镜像。网线用于连接板和电脑进行通信和编程。3.2 软件环境安装PYNQ系统镜像从PYNQ官方网站下载对应你开发板型号的最新系统镜像.img文件。使用BalenaEtcher或Rufus等工具将其烧录到SD卡中。Vivado设计套件这是进行FPGA逻辑设计的核心工具。需要安装Vivado HLx版本如2019.1或2020.1并确保在安装时勾选了对应你PYNQ板芯片型号如Zynq-7000的器件支持包。Vivado体积庞大安装需要较长时间和足够的磁盘空间。Python环境PYNQ板本身已经内置了Python和Jupyter。在你的开发电脑上建议也安装Python3.6以上并安装pynq库pip install pynq这样可以在本地编写和测试部分代码。上位机开发也会用到numpy,matplotlib,pyserial如果串口通信等库。3.3 Vivado工程创建与IP集成流程这是FPGA开发的核心步骤也是最容易出错的地方。创建工程与添加PYNQ板支持打开Vivado创建新工程选择对应的FPGA器件型号如xc7z020clg400-1 for Pynq-Z2。在创建Block Design时首先要添加Zynq Processing System IP核。配置Zynq PS双击Zynq IP核进行关键配置。这里必须与PYNQ官方提供的预设保持一致否则系统无法启动。通常需要在Peripheral I/O Pins中根据板子原理图使能相应的接口如UART用于串口终端、以太网、SD卡等。在Clock Configuration中确保FCLK_CLK0通常为100MHz已启用它将作为PL部分的主时钟。在DDR Configuration中选择正确的DDR型号如MT41J256M16 RE-125。一个必踩的坑务必在PS-PL Configuration-HP Slave AXI Interface下使能至少一个S AXI HP接口。这是PS与PL之间进行高速DMA数据传输的通道如果不开启后续DMA IP核无法添加或性能极差。添加并连接自定义IP使用Create and Package IP功能将你的数据采集、滤波等Verilog/VHDL模块封装成带AXI接口的IP核然后添加到Block Design中。使用Run Connection Automation可以自动连接时钟、复位和AXI接口但一定要仔细检查连接是否正确特别是中断信号如果有。地址分配与生成输出产品在Address Editor标签页中为每个IP核分配唯一的地址空间。最后Generate Output Products-Create HDL Wrapper-Generate Bitstream。生成比特流成功后导出硬件File - Export - Export Hardware注意要勾选Include bitstream。同时使用File - Export - Export Block Design将.tcl文件导出后续在PYNQ的Python环境中可以用这个tcl文件来动态构建Overlay这是一种更灵活的方式。3.4 PYNQ板卡启动与基础测试将烧录好镜像的SD卡插入板子上电。用网线连接板子和路由器或直接与电脑直连配置静态IP。通过路由器管理页面或使用arp -a命令查找板子的IP地址。在浏览器中输入http://board_ip_address:9090即可访问Jupyter Notebook界面。在这里你可以新建Notebook开始编写Python代码来控制你的硬件逻辑。首先可以进行一个最简单的测试将比特流文件和.tcl文件拷贝到板子的/home/xilinx目录下然后在Notebook中运行from pynq import Overlay overlay Overlay(‘your_design.bit’) print(overlay.ip_dict) # 查看已加载的IP核如果能看到你定义的IP核名称说明硬件Overlay加载成功。4. 核心算法实现心电信号处理链的FPGA实现有了硬件框架接下来就要用代码填充血肉。心电信号处理链是项目的算法核心我们重点看如何在PL端高效实现。4.1 基于XADC的数据采集驱动假设我们使用Pynq-Z2的XADC。在PL端我们需要一个IP核来与XADC交互。XADC内部有一个DRP接口我们可以通过它来读取转换结果。在Verilog中关键步骤是状态机控制初始化状态等待XADC上电完成。配置状态通过DRP写入配置寄存器选择我们连接的模拟输入通道如VAUXP[0]/VAUXN[0]设置采样平均等参数。循环读取状态发起DRP读操作读取指定通道的数据寄存器。XADC的数据是16位的但有效位是12位需要根据手册进行对齐和转换。数据输出将读取到的数据放入一个FIFO或者直接通过AXI4-Stream接口输出。为了与后续模块同步通常会在输出时附带一个tvalid信号。在PS端的Python驱动则通过映射到该IP核的寄存器来启动/停止采集或直接通过DMA从IP核输出的Stream接口读取数据。注意XADC的采样率由FPGA的时钟和DRP访问时序决定需要精确计算以避免数据丢失或重复。4.2 FIR数字滤波器的设计与实现如前所述我们使用Vivado的FIR Compiler IP核。关键在于滤波器系数的生成和IP核的配置。系数生成使用Python的SciPy库设计一个带通FIR滤波器。import scipy.signal as signal fs 1000 # 采样率假设为1kHz nyq fs / 2.0 low 0.5 / nyq # 通带低端0.5Hz high 40.0 / nyq # 通带高端40Hz numtaps 101 # 滤波器阶数奇数阶数越高性能越好但延迟和资源消耗越大 taps signal.firwin(numtaps, [low, high], pass_zeroFalse) # 生成带通系数 # 将系数保存为COE文件供Vivado使用 with open(‘ecg_filter.coe’, ‘w’) as f: f.write(‘radix10;\n’) f.write(‘coefdata\n’) for i, coef in enumerate(taps): f.write(f’{coef:.18f}‘) if i ! len(taps)-1: f.write(‘,\n’) else: f.write(‘;’)IP核配置在Vivado中双击FIR Compiler IP核。Filter Specification选择Coefficient File导入上面生成的.coe文件。Channel Specification设置输入通道数通常为1。Implementation选择Hardware Oversampling Specification这里Clock Frequency填你的IP核工作时钟如100MHzSample Frequency填数据采样率如1kHz。这会决定IP核内部的多相结构是节省资源的关键。Detailed Implementation选择Coefficient Structure为Symmetric因为我们的系数是对称的可以节省近一半的乘法器资源。数据位宽根据ADC输出设置如16位有符号数。资源与延迟权衡numtaps阶数直接影响滤波器的陡峭程度和群延迟。阶数越高滤波效果越好但消耗的DSP48和BRAM资源越多并且信号通过滤波器的延迟也越大。对于实时心率监测这个延迟需要被考虑。可以通过仿真在Vivado中或使用Python来评估不同阶数下的滤波效果和延迟选择一个平衡点。4.3 实时QRS波检测的FPGA逻辑设计Pan-Tompkins算法是经典的心电特征检测算法其FPGA实现是一个很好的流水线设计案例。算法主要步骤包括带通滤波我们已经用FIR滤波器完成了。微分计算相邻采样点的差分强调QRS波的高频特性。可以用一个简单的减法和寄存器实现。平方将微分后的值平方使所有点变为正并进一步放大QRS成分。在FPGA中这就是一个乘法器。滑动窗口积分对平方后的信号进行一段固定长度如150ms对应N个采样点的移动平均。这能生成一个平滑的包络其中R波对应一个明显的凸起。实现时可以使用一个加法器树或更高效的循环累加器加一个新值减一个旧值。在FPGA中我们可以将这些步骤设计成一条流水线。每个时钟周期输入一个新样本经过若干周期后在积分器输出端就能得到一个对应的值。检测逻辑则持续监控这个积分值当它超过一个自适应的阈值时就判定检测到一个QRS波并记录下该时刻对应原始信号的R波峰值位置。阈值可以根据最近检测到的几个R波的幅度进行动态更新以适应信号强度的变化。实现细节与避坑定点数运算为了节省资源整个流水线应使用定点数Fix-point而非浮点数。需要仔细确定每一步的位宽和小数点位宽防止溢出和精度损失过大。例如原始数据可能是16位有符号整数平方后变成32位积分后位宽需要进一步扩展。时序约束流水线的每一级组合逻辑不能太长必须满足你的时钟频率如100MHz要求。如果逻辑太复杂需要在中间插入寄存器流水线打拍来切割关键路径。检测后的处理检测到R波后可以产生一个脉冲信号r_peak_valid并输出当前的心跳间期RR Interval。这个信息可以通过一个简单的AXI4-Lite从设备接口暴露给PS端PS端只需周期性地读取心率值即可无需处理大量原始数据。5. 软硬件协同与系统集成调试当PL端的各个IP核和PS端的Python框架都准备好后真正的挑战在于让它们协同工作。这个阶段会暴露很多设计时未考虑的问题。5.1 DMA数据传输的配置与性能优化DMA是PS与PL之间大数据量传输的桥梁。在PYNQ中我们使用pynq.lib.DMA模块。一个典型的从PL流接口读取数据到PS内存的示例如下from pynq import Overlay, allocate import numpy as np ol Overlay(‘design.bit’) dma ol.axi_dma_0 # 假设你的DMA IP核叫这个名字 input_buffer allocate(shape(1024,), dtypenp.int32) # 分配连续内存 # 启动DMA接收 dma.recvchannel.transfer(input_buffer) # ... (等待或处理其他事情) dma.recvchannel.wait() # 等待传输完成 # 此时input_buffer中已填充了数据常见问题与优化传输尺寸对齐DMA对传输的字节数可能有对齐要求如32字节对齐。确保你分配的内存大小和发起传输的长度符合要求。缓存一致性当PS端的CPU和DMA共同访问同一块内存时存在缓存一致性问题。pynq.allocate()函数默认会分配缓存一致性的内存这是正确的做法。如果你自己用其他方式分配内存如numpy.array可能需要手动刷新缓存xlnk.cma_flush_cache()否则读到的可能是旧数据。双缓冲与连续传输为了实现实时不间断采集可以使用双缓冲机制。同时发起两个DMA传输当其中一个在后台传输时PS端处理另一个缓冲区中的数据。PYNQ的DMA库支持transfer和wait异步操作可以方便地实现这种乒乓操作。带宽瓶颈如果数据速率很高需要检查DMA连接的AXI总线位宽通常是64位和时钟频率。确保你的数据产生速率没有超过DMA总线的理论带宽。5.2 Python Overlay与硬件IP的交互Overlay加载后你的自定义IP核会变成Python对象。你需要知道它们的存储器映射地址和寄存器定义。# 访问一个AXI-Lite控制的IP核寄存器 my_ip ol.my_filter_ip_0 # 假设寄存器0是控制寄存器写1启动 my_ip.write(0x00, 1) # 读取状态寄存器 status my_ip.read(0x04)关键点在Vivado中封装IP时必须正确定义每个寄存器的偏移地址、访问属性只读/只写/读写和功能。最好编写一个对应的Python类将这些寄存器操作封装成易于理解的方法如start_acquisition(),get_heart_rate()等提高代码可读性和可维护性。5.3 实时波形显示与系统联调在上位机或Jupyter Notebook中使用Matplotlib的动画功能可以实现实时波形显示。import matplotlib.pyplot as plt import matplotlib.animation as animation from collections import deque # 创建一个固定长度的队列来保存最近的数据点 data_buffer deque(maxlen1000) fig, ax plt.subplots() line, ax.plot([], []) def update(frame): # 从DMA缓冲区获取最新一批数据例如100个点 new_data get_new_data_from_dma() data_buffer.extend(new_data) line.set_data(range(len(data_buffer)), list(data_buffer)) ax.relim() ax.autoscale_view() return line, ani animation.FuncAnimation(fig, update, interval50) # 每50ms更新一次 plt.show()联调技巧分模块调试不要试图一次性集成所有功能。先确保ADC能读到数据可以用一个固定电压测试然后单独测试滤波器IP输入正弦波看输出是否正确再测试QRS检测最后整合。利用ILA集成逻辑分析仪Vivado的ILA是调试FPGA逻辑的神器。你可以将关键内部信号如ADC数据、滤波后数据、积分器输出、检测阈值连接到ILA核上在板子上实时抓取波形直观地看到算法每一步的运行情况。这对于调试检测算法的误触发、漏触发等问题至关重要。模拟信号源在开发初期不要急于连接人体。使用函数发生器产生一个模拟心电波形可以搜索“ECG仿真信号参数”或者用Python生成一个带噪声的仿真ECG数据通过PS端写入PL端的回放缓冲区再让采集链路去处理这个“回放”的信号。这样可以建立一个可控的、可重复的测试环境。性能监控在Jupyter中可以实时打印心率、计算丢包率等监控系统运行状态。如果发现数据不连续或心率计算不稳定需要回溯检查DMA传输、缓冲区大小或算法阈值设置。6. 项目扩展与进阶思考完成基本功能后这个项目还有很大的扩展空间可以进一步提升其复杂度和实用性。6.1 从监测到初步诊断心律失常算法集成基础的心率监测之外可以尝试在PS端集成更高级的心律失常分析算法。例如室性早搏PVC识别检测异常的QRS波形宽度过大、形态怪异。可以在PL端提取更多特征如QRS宽度、面积传给PS端由Python进行模式匹配或简单的规则判断。心房颤动AFib检测分析RR间期的不规则性。计算连续RR间期的标准差、变异系数等当不规则性超过阈值时报警。这类算法计算量不大完全可以在PS端实时运行。使用机器学习将一段时间的ECG特征心率、RR间期序列、波形形态特征输入一个轻量级的机器学习模型如Scikit-learn训练的模型进行更复杂的分类。PYNQ的PS端运行Python ML库毫无压力。6.2 低功耗与无线化设计如果考虑便携式应用功耗和无线传输就成为关键。PL端功耗优化对于固定功能在Vivado综合时可以使用opt_design的功耗优化选项。更根本的方法是降低时钟频率在满足处理实时性的前提下、使用时钟门控、对空闲模块进行动态部分重配置PR以关闭其电源。PS端功耗管理在Linux系统中可以调整CPU频率、关闭不必要的内核和外设。无线传输Pynq-Z2板载Wi-Fi和蓝牙。可以使用Python的socket库或MQTT协议将心电数据和报警信息无线发送到手机App或云端服务器。需要注意数据传输的功耗和稳定性。6.3 系统稳定性与鲁棒性提升一个演示系统和一个可靠系统之间差的就是对各种异常情况的处理。电极脱落检测当信号幅度长时间为0或接近0且伴有高频噪声时很可能是电极脱落。可以在PL或PS端增加一个检测电路一旦发现立即触发报警并暂停无效数据记录。运动伪迹抑制这是可穿戴心电监测的最大挑战之一。除了硬件上的改进如使用干电极、更好的机械固定可以在算法上尝试自适应滤波利用加速度计信号作为参考噪声来抵消运动伪迹。数据安全与隐私如果涉及无线传输应考虑对ECG数据进行加密。在PS端可以使用简单的AES加密算法然后再发送。这个“基于PYNQ的心电信号监测和回放系统”项目就像是一个微型的、软硬协同的边缘计算系统原型。它强迫你去思考从模拟世界到数字世界、从硬件并行到软件灵活性的完整链条。过程中踩过的每一个坑解决的每一个时序警告调通的每一段DMA传输都是实实在在的成长。无论是用于毕设答辩还是技能展示这样一个有深度、有广度、有展示度的项目无疑会比一个简单的单片机项目更有分量。本文还有配套的精品资源点击获取