# 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 导联类型定义 ```c 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生成器结构体 ```c 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点时,需要限制表大小防止内存溢出,但会导致相位失真。 **解决方案**:按比例重复采样 ```c // 计算理想表大小和实际表大小 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 导联特定参数设置 每个导联都有独特的波形特征: ```c 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导联特有) ```c // 在波形计算中 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 系统初始化函数 ```c 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 多通道输出函数 ```c 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初始化 ```c // 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数据发送 ```c 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 系统初始化流程 ```c 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 定时器中断处理 ```c 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. 内存管理 - **查找表存储**: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**:触摸屏 ### 构建命令 ```bash idf.py build idf.py flash monitor --- **交接完成日期**:2025年10月9日 **系统版本**:v1.0