Stimulate/工作交接文档_ECG十二导联信号生成系统.md

11 KiB
Raw Permalink Blame History

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芯片AD5328BRUZ8通道12位DAC
  • 通信接口SPI2DAC控制、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);    // 通道0I导联
    
    voltage = ecg_generator_get_next_sample(&g_ecg_gen_ii);
    set_channel_voltage(1, voltage);    // 通道1II导联
    
    voltage = ecg_generator_get_next_sample(&g_ecg_gen_v1);
    set_channel_voltage(2, voltage);    // 通道2V1导联
    
    // ... 其他通道
}

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. 启动流程

  1. 硬件初始化I2C、SPI、GPIO配置
  2. DAC初始化SPI总线、设备、控制引脚
  3. ECG系统初始化9个导联生成器、查找表生成
  4. 定时器启动50μs周期20kHz
  5. 主循环LED指示、内存监控

2. 实时信号生成

  1. 定时器中断每50μs触发一次
  2. 信号生成:各导联生成器产生下一个样本
  3. DAC输出8个通道同时更新电压
  4. 相位同步:所有导联保持同步

3. 内存管理

  • 查找表存储PSRAMheap_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.048V12位分辨率
  • 查找表大小最大10,000点
  • 内存使用PSRAM存储避免DRAM溢出

硬件接口

  • SPI2DAC控制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-IDFv5.0+
  • 编译器GCC for RISC-V
  • 调试工具ESP-IDF Monitor

依赖组件

  • esp_lcd_portLCD显示
  • lvgl:图形界面
  • esp_lcd_touch_ft5x06:触摸屏

构建命令

idf.py build
idf.py flash monitor
---


**交接完成日期**2025年10月9日
**系统版本**v1.0