11 KiB
11 KiB
ECG十二导联信号生成系统 - 工作交接文档
项目概述
本项目是一个基于ESP32-S3的ECG(心电图)十二导联信号生成系统,能够同时生成并输出I、II、III导联以及V1-V6胸导联的ECG信号,通过DAC芯片输出到8个独立通道。
主要功能
- 十二导联ECG信号生成:I、II、III、V1-V6导联
- 多通道DAC输出:8个独立通道同时输出
- 高精度波形生成:20kHz采样率,支持10,000点查找表
- 内存优化:PSRAM存储,防止DRAM溢出
- 实时信号处理:50μs定时器中断
系统架构
硬件平台
- 主控芯片:ESP32-S3
- DAC芯片:AD5328BRUZ(8通道12位DAC)
- 通信接口:SPI2(DAC控制)、I2C0(触摸屏)
- 显示:ST7789 LCD + FT5x06触摸屏
软件架构
main/
├── main.c # 主程序入口
├── esp32_s3_szp.c # 硬件驱动(SPI、I2C、LCD)
├── esp32_s3_szp.h # 硬件定义
└── app_ui.c # UI界面
components/signal_generators/
├── include/
│ ├── ecg_generator.h # ECG生成器接口
│ └── sine_generator.h # 正弦波生成器接口
└── src/
├── ecg_generator.c # ECG生成器实现
└── sine_generator.c # 正弦波生成器实现
核心代码功能详解
1. ECG信号生成器 (ecg_generator.c)
1.1 导联类型定义
typedef enum {
ECG_LEAD_I = 0, // I导联:右手到左手
ECG_LEAD_II = 1, // II导联:右手到左腿
ECG_LEAD_III = 2, // III导联:左手到左腿
ECG_LEAD_V1 = 3, // V1导联:胸骨右缘第四肋间
ECG_LEAD_V2 = 4, // V2导联
ECG_LEAD_V3 = 5, // V3导联:过渡区
ECG_LEAD_V4 = 6, // V4导联:高R波
ECG_LEAD_V5 = 7, // V5导联
ECG_LEAD_V6 = 8 // V6导联
} ecg_lead_t;
1.2 ECG生成器结构体
typedef struct {
// 用户参数
float heart_rate; // 心率 (次/分)
float amplitude; // 幅值 (V)
ecg_lead_t lead; // 当前导联
// 内部状态
uint32_t sample_count; // 样本计数器
float sample_rate; // 采样率 (Hz)
bool is_running; // 运行状态
// 导联特定参数
float p_amp_ratio; // P波幅度比例
float q_amp_ratio; // Q波幅度比例
float r_amp_ratio; // R波幅度比例
float s_amp_ratio; // S波幅度比例
float t_amp_ratio; // T波幅度比例
bool p_bidirectional; // P波是否双向(V1导联特有)
// 查找表相关
float* ecg_lookup_table; // ECG查找表
uint32_t table_size; // 查找表大小
uint32_t table_index; // 当前索引
// 按比例重复采样(防止相位失真)
uint32_t ideal_table_size; // 理想表大小
uint32_t samples_per_point; // 每个表点对应的样本数
uint32_t sample_counter; // 当前表点的样本计数器
} ecg_generator_t;
1.3 关键算法:按比例重复采样
问题:当理想表大小超过10,000点时,需要限制表大小防止内存溢出,但会导致相位失真。
解决方案:按比例重复采样
// 计算理想表大小和实际表大小
generator->ideal_table_size = (uint32_t)(generator->sample_rate / generator->frequency);
const uint32_t MAX_TABLE_SIZE = 10000;
generator->table_size = generator->ideal_table_size;
if (generator->table_size > MAX_TABLE_SIZE) {
generator->table_size = MAX_TABLE_SIZE;
}
// 计算每个表点需要重复的样本数
generator->samples_per_point = generator->ideal_table_size / generator->table_size;
// 在get_next_sample中实现重复采样
if (generator->sample_counter >= generator->samples_per_point) {
generator->sample_counter = 0;
generator->table_index = (generator->table_index + 1) % generator->table_size;
}
1.4 导联特定参数设置
每个导联都有独特的波形特征:
void ecg_generator_set_lead_parameters(ecg_generator_t *generator, ecg_lead_t lead) {
switch (lead) {
case ECG_LEAD_I:
generator->p_amp_ratio = 0.12; // P波较小
generator->q_amp_ratio = 0.25;
generator->r_amp_ratio = 0.7; // R波中等
generator->s_amp_ratio = 0.3;
generator->t_amp_ratio = 0.3;
generator->p_bidirectional = false;
break;
case ECG_LEAD_V1:
generator->p_amp_ratio = 0.08; // P波双向
generator->q_amp_ratio = 0.0; // 无Q波
generator->r_amp_ratio = 0.25; // 小r波
generator->s_amp_ratio = 1.0; // 深S波
generator->t_amp_ratio = -0.15; // T波倒置
generator->p_bidirectional = true; // 双向P波
break;
// ... 其他导联
}
}
1.5 双向P波实现(V1导联特有)
// 在波形计算中
if (generator->p_bidirectional) {
// 双向P波:先正后负
float p_positive = p_amp * expf(-(t_norm - p_time_ratio) * (t_norm - p_time_ratio) /
(2.0f * p_width_ratio * p_width_ratio));
float p_negative = -p_amp * 0.6f * expf(-(t_norm - (p_time_ratio + 0.02f)) *
(t_norm - (p_time_ratio + 0.02f)) /
(2.0f * p_width_ratio * p_width_ratio));
p = p_positive + p_negative;
} else {
// 单向P波
p = p_amp * expf(-(t_norm - p_time_ratio) * (t_norm - p_time_ratio) /
(2.0f * p_width_ratio * p_width_ratio));
}
2. 十二导联系统封装
2.1 系统初始化函数
int ecg_generator_init_twelve_leads_system(float sample_rate, float amplitude, float heart_rate) {
// 初始化所有9个导联生成器
ecg_generator_init(&g_ecg_gen_i, sample_rate, ECG_LEAD_I);
ecg_param_set(&g_ecg_gen_i, amplitude, heart_rate);
ecg_generator_generate_lookup_table(&g_ecg_gen_i);
ecg_generator_start(&g_ecg_gen_i);
// ... 重复其他8个导联
return 0; // 成功
}
2.2 多通道输出函数
void ecg_generator_output_twelve_leads(void (*set_channel_voltage)(uint8_t channel, float voltage)) {
float voltage;
// 通道映射:0通道输出I导联,1通道输出II导联,2-7通道输出V1-V6导联
voltage = ecg_generator_get_next_sample(&g_ecg_gen_i);
set_channel_voltage(0, voltage); // 通道0:I导联
voltage = ecg_generator_get_next_sample(&g_ecg_gen_ii);
set_channel_voltage(1, voltage); // 通道1:II导联
voltage = ecg_generator_get_next_sample(&g_ecg_gen_v1);
set_channel_voltage(2, voltage); // 通道2:V1导联
// ... 其他通道
}
3. 硬件驱动 (esp32_s3_szp.c)
3.1 SPI初始化
// SPI总线配置
spi_bus_config_t bus_config = {
.miso_io_num = GPIO_NUM_NC, // 不使用MISO
.mosi_io_num = PIN_MOSI, // GPIO12
.sclk_io_num = PIN_SCK, // GPIO13
.quadhd_io_num = GPIO_NUM_NC,
.quadwp_io_num = GPIO_NUM_NC,
};
// SPI设备配置
spi_device_interface_config_t dev_config = {
.clock_speed_hz = 1000000, // 1 MHz
.mode = 0, // SPI模式0
.spics_io_num = PIN_CS, // GPIO10
.queue_size = 1,
.flags = SPI_DEVICE_HALFDUPLEX, // 半双工
};
3.2 DAC数据发送
void set_channel_voltage(uint8_t channel, float voltage) {
// 电压转数字值(12位)
uint16_t dac_value = (uint16_t)((voltage / V_REF) * 4095);
// 组装SPI数据包(16位)
uint8_t tx_data[2] = {
((channel & 0x07) << 4) | ((dac_value >> 8) & 0x0F), // 高字节
(dac_value & 0xFF) // 低字节
};
// SPI事务
spi_transaction_t t = {
.length = 16,
.tx_buffer = tx_data,
.rx_buffer = NULL
};
esp_err_t ret = spi_device_transmit(handle, &t);
}
4. 主程序 (main.c)
4.1 系统初始化流程
void app_main(void) {
int led_count = 0;
// 1. 硬件初始化
init_hardware(); // I2C、LED、DAC初始化
// 2. ECG系统初始化
init_ecg_system(); // 初始化十二导联系统
// 3. 主循环
while (true) {
// LED状态指示
gpio_set_level(LED_PIN, 1);
vTaskDelay(pdMS_TO_TICKS(1000));
gpio_set_level(LED_PIN, 0);
vTaskDelay(pdMS_TO_TICKS(1000));
// 内存监控
if (++led_count % 10 == 0) {
displayMemoryUsage();
}
}
}
4.2 定时器中断处理
static void signal_timer_callback(void* arg) {
// ECG十二导联模式:使用十二导联输出函数
ecg_generator_output_twelve_leads(set_channel_voltage);
signal_sample_count++;
}
系统运行机制
1. 启动流程
- 硬件初始化:I2C、SPI、GPIO配置
- DAC初始化:SPI总线、设备、控制引脚
- ECG系统初始化:9个导联生成器、查找表生成
- 定时器启动:50μs周期(20kHz)
- 主循环:LED指示、内存监控
2. 实时信号生成
- 定时器中断:每50μs触发一次
- 信号生成:各导联生成器产生下一个样本
- DAC输出:8个通道同时更新电压
- 相位同步:所有导联保持同步
3. 内存管理
- 查找表存储:PSRAM(heap_caps_malloc with MALLOC_CAP_SPIRAM)
- 表大小限制:最大10,000点防止DRAM溢出
- 按比例采样:保持波形形状和相位连续性
4. 通道映射
DAC通道 → ECG导联
通道0 → I导联
通道1 → II导联
通道2 → V1导联
通道3 → V2导联
通道4 → V3导联
通道5 → V4导联
通道6 → V5导联
通道7 → V6导联
技术参数
性能指标
- 采样率:20kHz
- 心率范围:30-200 BPM
- 电压范围:0-2.048V(12位分辨率)
- 查找表大小:最大10,000点
- 内存使用:PSRAM存储,避免DRAM溢出
硬件接口
- SPI2:DAC控制(MOSI:GPIO12, SCK:GPIO13, CS:GPIO10)
- GPIO控制:LDAC(GPIO11), DAC_EN(GPIO17)
- I2C0:触摸屏通信(SDA:GPIO1, SCL:GPIO2)
波形特征
- I导联:R波中等,P波较小
- II导联:R波最大,P波明显
- III导联:波形介于I和II之间
- V1导联:双向P波,深S波,T波倒置
- V2-V6导联:过渡区到高R波区域
维护和调试
1. 常见问题排查
- 内存不足:检查PSRAM配置,调整查找表大小
- SPI通信失败:检查引脚配置和时钟频率
- 波形失真:验证按比例采样算法
- 相位不同步:检查定时器配置
2. 性能优化
- 内存优化:使用PSRAM存储大查找表
- 实时性:50μs定时器确保20kHz输出
- 精度优化:12位DAC提供高精度输出
3. 扩展功能
- 参数调节:心率、幅度、导联类型
- 波形存储:支持不同ECG模式
- 多设备支持:可扩展更多DAC通道
开发环境
编译环境
- ESP-IDF:v5.0+
- 编译器:GCC for RISC-V
- 调试工具:ESP-IDF Monitor
依赖组件
- esp_lcd_port:LCD显示
- lvgl:图形界面
- esp_lcd_touch_ft5x06:触摸屏
构建命令
idf.py build
idf.py flash monitor
---
**交接完成日期**:2025年10月9日
**系统版本**:v1.0