3. 血压监测仪

血压监测仪 学习卡片

任务说明

本案例实现一个基于示波法的无创血压监测仪核心逻辑:通过压力传感器采集袖带压力,在放气过程中检测脉搏波振荡幅度,依据振荡幅度包络计算收缩压与舒张压,并在LCD上显示结果。案例聚焦于示波法核心算法与数据采集流程,不涉及实际气泵电机驱动硬件细节。

示波法原理与测量流程

示波法测量血压的物理基础是:袖带放气过程中,动脉搏动引起袖带内压力产生微小振荡。当袖带压力等于平均动脉压时,振荡幅度最大;收缩压和舒张压分别对应振荡幅度包络上升到最大幅度的50%~60%和下降到最大幅度的70%~80%的位置。本案例采用比例判定法:收缩压对应包络上升段达到最大幅度55%处的袖带压力,舒张压对应包络下降段达到最大幅度75%处的袖带压力。

时间 (放气过程) 压力/幅度 袖带压力 (线性下降) 脉搏振荡幅度包络 最大幅度 Amax 收缩压 (0.55×Amax) 舒张压 (0.75×Amax) 高压区 低压区

核心代码实现

// 血压监测仪 - 示波法核心算法
// 文件: bp_monitor.c
// 依赖: 标准C库,无硬件抽象,可直接编译运行于PC验证算法

#include <stdio.h>
#include <stdint.h>
#include <math.h>

#define SAMPLE_COUNT   200     // 放气过程采样点数
#define ADC_MAX        4095    // 12位ADC满量程
#define PRESSURE_MAX   300.0f  // 传感器量程上限 mmHg
#define PRESSURE_MIN   0.0f    // 传感器量程下限 mmHg

// 模拟一次完整的放气测量过程
// 输入: cuff_pressure[] 袖带压力序列 (mmHg)
//       oscillation[]   脉搏振荡幅度序列 (ADC原始值)
//       n               采样点数
// 输出: systolic, diastolic 收缩压/舒张压 (mmHg)
// 返回: 1成功, 0失败
int calculate_bp(const float *cuff_pressure, 
                 const uint16_t *oscillation, 
                 int n, 
                 float *systolic, 
                 float *diastolic) {
    if (n < 10 || cuff_pressure == NULL || oscillation == NULL) return 0;
    
    // 1. 寻找最大振荡幅度及其位置
    uint16_t max_amp = 0;
    int max_idx = 0;
    for (int i = 0; i < n; i++) {
        if (oscillation[i] > max_amp) {
            max_amp = oscillation[i];
            max_idx = i;
        }
    }
    if (max_amp == 0) return 0;  // 无有效脉搏信号
    
    // 2. 收缩压: 在最大点之前寻找幅度首次超过 55% Amax 的位置
    float sys_threshold = 0.55f * max_amp;
    int sys_idx = -1;
    for (int i = max_idx - 1; i >= 0; i--) {
        if (oscillation[i] < sys_threshold && oscillation[i+1] >= sys_threshold) {
            sys_idx = i + 1;
            break;
        }
    }
    // 若未找到交叉点,取最大点前一个采样点
    if (sys_idx < 0) sys_idx = (max_idx > 0) ? max_idx - 1 : 0;
    
    // 3. 舒张压: 在最大点之后寻找幅度首次低于 75% Amax 的位置
    float dia_threshold = 0.75f * max_amp;
    int dia_idx = -1;
    for (int i = max_idx; i < n - 1; i++) {
        if (oscillation[i] >= dia_threshold && oscillation[i+1] < dia_threshold) {
            dia_idx = i + 1;
            break;
        }
    }
    if (dia_idx < 0) dia_idx = n - 1;
    
    // 4. 输出对应袖带压力值
    *systolic = cuff_pressure[sys_idx];
    *diastolic = cuff_pressure[dia_idx];
    
    // 基本合理性检查
    if (*systolic <= *diastolic || *systolic > PRESSURE_MAX || *diastolic < PRESSURE_MIN) {
        return 0;
    }
    return 1;
}

// ============ 测试数据生成与验证 ============
// 生成模拟的袖带压力序列 (线性放气)
void gen_cuff_pressure(float *buf, int n) {
    float p_start = 180.0f, p_end = 60.0f;
    for (int i = 0; i < n; i++) {
        buf[i] = p_start + (p_end - p_start) * i / (n - 1);
    }
}

// 生成模拟的脉搏振荡信号 (高斯包络)
// 真实收缩压120mmHg, 舒张压80mmHg, 平均压100mmHg
void gen_oscillation(uint16_t *buf, int n, const float *cuff_p) {
    float amp_max = 800.0f;       // 最大振荡幅度 (ADC值)
    float map = 100.0f;           // 平均动脉压
    float sigma = 35.0f;          // 包络宽度参数
    
    for (int i = 0; i < n; i++) {
        float env = amp_max * expf(-powf((cuff_p[i] - map) / sigma, 2));
        // 叠加模拟脉搏波动 (频率约1.2Hz, 采样率50Hz)
        float pulse = env * (0.8f + 0.2f * sinf(2 * M_PI * 1.2f * i / 50.0f));
        buf[i] = (uint16_t)(pulse + 0.5f);
    }
}

int main() {
    float cuff_pressure[SAMPLE_COUNT];
    uint16_t oscillation[SAMPLE_COUNT];
    float systolic = 0, diastolic = 0;
    
    // 生成模拟测量数据
    gen_cuff_pressure(cuff_pressure, SAMPLE_COUNT);
    gen_oscillation(oscillation, SAMPLE_COUNT, cuff_pressure);
    
    // 执行血压计算
    int ok = calculate_bp(cuff_pressure, oscillation, SAMPLE_COUNT, 
                          &systolic, &diastolic);
    
    if (ok) {
        printf("测量结果:\n");
        printf("  收缩压: %.1f mmHg\n", systolic);
        printf("  舒张压: %.1f mmHg\n", diastolic);
        printf("  脉压差: %.1f mmHg\n", systolic - diastolic);
    } else {
        printf("血压计算失败: 信号质量不足或结果不合理\n");
    }
    
    return ok ? 0 : 1;
}

代码说明

上述代码完整实现了示波法血压计算的核心流程。主函数中通过gen_cuff_pressure()生成从180mmHg线性下降至60mmHg的袖带压力序列,通过gen_oscillation()生成以100mmHg为中心的高斯包络脉搏振荡信号(模拟平均动脉压100mmHg、收缩压约120mmHg、舒张压约80mmHg的生理状态)。calculate_bp()函数首先定位最大振荡幅度位置,然后分别向前搜索55%阈值交叉点作为收缩压对应位置、向后搜索75%阈值交叉点作为舒张压对应位置,最后将位置索引映射到袖带压力值输出。

编译与运行

# 编译 (需链接数学库)
gcc -o bp_monitor bp_monitor.c -lm

# 运行
./bp_monitor

验证方法与判定标准

运行程序后观察输出结果。由于模拟数据以平均压100mmHg、包络宽度35mmHg生成,理论上收缩压应接近120mmHg、舒张压应接近80mmHg。判定标准为:程序返回成功(退出码0),输出的收缩压在110~130mmHg范围内、舒张压在70~90mmHg范围内,且收缩压大于舒张压。若需验证真实硬件场景,可将gen_cuff_pressure()和gen_oscillation()替换为实际ADC采样数据,并确保袖带压力与振荡信号同步采集。