3. 血压监测仪
任务说明
本案例实现一个基于示波法的无创血压监测仪核心逻辑:通过压力传感器采集袖带压力,在放气过程中检测脉搏波振荡幅度,依据振荡幅度包络计算收缩压与舒张压,并在LCD上显示结果。案例聚焦于示波法核心算法与数据采集流程,不涉及实际气泵电机驱动硬件细节。
示波法原理与测量流程
示波法测量血压的物理基础是:袖带放气过程中,动脉搏动引起袖带内压力产生微小振荡。当袖带压力等于平均动脉压时,振荡幅度最大;收缩压和舒张压分别对应振荡幅度包络上升到最大幅度的50%~60%和下降到最大幅度的70%~80%的位置。本案例采用比例判定法:收缩压对应包络上升段达到最大幅度55%处的袖带压力,舒张压对应包络下降段达到最大幅度75%处的袖带压力。
核心代码实现
// 血压监测仪 - 示波法核心算法
// 文件: 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采样数据,并确保袖带压力与振荡信号同步采集。