信号质量评估(Signal Quality Assessment)¶
📋 学习目标¶
完成本章学习后,您将能够:
- ✅ 理解信号质量评估的重要性
- ✅ 掌握常用的信号质量指标(SQI)
- ✅ 实现实时信号质量评估算法
- ✅ 应用质量评估改善医疗监护系统
- ✅ 处理低质量信号的策略
前置知识¶
- 数字信号处理基础
- 统计学基础
- 医疗信号特征(ECG、PPG等)
- C/C++编程
1. 信号质量评估基础¶
1.1 为什么需要信号质量评估?¶
临床问题: - ❌ 运动伪影导致误报警 - ❌ 电极脱落未被检测 - ❌ 低质量信号影响诊断 - ❌ 假阳性增加医护负担
解决方案: - ✅ 实时评估信号质量 - ✅ 抑制低质量信号的报警 - ✅ 提示用户改善信号采集 - ✅ 自动选择最佳导联
1.2 信号质量指标(SQI)分类¶
| 类别 | 指标 | 适用信号 |
|---|---|---|
| 时域 | SNR、峰值检测率 | ECG、PPG |
| 频域 | 功率谱比、频带能量 | ECG、EEG |
| 统计 | 峰度、偏度 | 通用 |
| 模板匹配 | 相关系数 | ECG、PPG |
| 机器学习 | SVM、神经网络 | 通用 |
2. ECG信号质量评估¶
2.1 基于SNR的质量评估¶
#include <stdint.h>
#include <math.h>
/**
* @brief 计算ECG信号的信噪比(SNR)
* @param ecg_signal ECG信号
* @param length 信号长度
* @param qrs_positions QRS波位置数组
* @param qrs_count QRS波数量
* @return SNR值(dB)
*/
float ecg_calculate_snr(const float* ecg_signal, uint16_t length,
const uint16_t* qrs_positions, uint8_t qrs_count) {
if (qrs_count < 2) {
return -1.0f; // 数据不足
}
// 1. 估计信号功率(QRS波段)
float signal_power = 0.0f;
uint16_t signal_samples = 0;
for (uint8_t i = 0; i < qrs_count; i++) {
uint16_t qrs_pos = qrs_positions[i];
// QRS波前后各50ms(假设250Hz采样率,约12个样本)
for (int j = -12; j <= 12; j++) {
uint16_t index = qrs_pos + j;
if (index < length) {
signal_power += ecg_signal[index] * ecg_signal[index];
signal_samples++;
}
}
}
signal_power /= signal_samples;
// 2. 估计噪声功率(基线段)
float noise_power = 0.0f;
uint16_t noise_samples = 0;
for (uint8_t i = 0; i < qrs_count - 1; i++) {
uint16_t start = qrs_positions[i] + 50; // QRS后50个样本
uint16_t end = qrs_positions[i + 1] - 50; // 下一个QRS前50个样本
if (end > start) {
for (uint16_t j = start; j < end; j++) {
noise_power += ecg_signal[j] * ecg_signal[j];
noise_samples++;
}
}
}
if (noise_samples == 0) {
return -1.0f;
}
noise_power /= noise_samples;
// 3. 计算SNR(dB)
if (noise_power < 1e-10f) {
return 100.0f; // 噪声极小
}
float snr_db = 10.0f * log10f(signal_power / noise_power);
return snr_db;
}
/**
* @brief 基于SNR的质量分级
*/
typedef enum {
ECG_QUALITY_EXCELLENT = 4, // SNR > 20dB
ECG_QUALITY_GOOD = 3, // 15-20dB
ECG_QUALITY_FAIR = 2, // 10-15dB
ECG_QUALITY_POOR = 1, // 5-10dB
ECG_QUALITY_UNACCEPTABLE = 0 // < 5dB
} ECGQualityLevel;
ECGQualityLevel ecg_classify_quality(float snr_db) {
if (snr_db >= 20.0f) return ECG_QUALITY_EXCELLENT;
if (snr_db >= 15.0f) return ECG_QUALITY_GOOD;
if (snr_db >= 10.0f) return ECG_QUALITY_FAIR;
if (snr_db >= 5.0f) return ECG_QUALITY_POOR;
return ECG_QUALITY_UNACCEPTABLE;
}
2.2 基于模板匹配的质量评估¶
/**
* @brief 计算ECG波形与模板的相关系数
* @param ecg_segment ECG片段
* @param template_waveform 模板波形
* @param length 长度
* @return 相关系数(0-1)
*/
float ecg_template_correlation(const float* ecg_segment,
const float* template_waveform,
uint16_t length) {
// 计算均值
float mean_ecg = 0.0f, mean_template = 0.0f;
for (uint16_t i = 0; i < length; i++) {
mean_ecg += ecg_segment[i];
mean_template += template_waveform[i];
}
mean_ecg /= length;
mean_template /= length;
// 计算相关系数
float numerator = 0.0f;
float denom_ecg = 0.0f, denom_template = 0.0f;
for (uint16_t i = 0; i < length; i++) {
float diff_ecg = ecg_segment[i] - mean_ecg;
float diff_template = template_waveform[i] - mean_template;
numerator += diff_ecg * diff_template;
denom_ecg += diff_ecg * diff_ecg;
denom_template += diff_template * diff_template;
}
float denominator = sqrtf(denom_ecg * denom_template);
if (denominator < 1e-10f) {
return 0.0f;
}
float correlation = numerator / denominator;
// 确保在[0, 1]范围内
if (correlation < 0.0f) correlation = 0.0f;
if (correlation > 1.0f) correlation = 1.0f;
return correlation;
}
/**
* @brief 构建ECG模板(平均多个心跳)
*/
void ecg_build_template(const float* ecg_signal, uint16_t length,
const uint16_t* qrs_positions, uint8_t qrs_count,
float* template_waveform, uint16_t template_length) {
// 初始化模板为0
memset(template_waveform, 0, template_length * sizeof(float));
uint8_t valid_beats = 0;
// 累加所有心跳
for (uint8_t i = 0; i < qrs_count; i++) {
uint16_t qrs_pos = qrs_positions[i];
uint16_t start = qrs_pos - template_length / 2;
// 检查边界
if (start + template_length > length) {
continue;
}
// 累加
for (uint16_t j = 0; j < template_length; j++) {
template_waveform[j] += ecg_signal[start + j];
}
valid_beats++;
}
// 平均
if (valid_beats > 0) {
for (uint16_t i = 0; i < template_length; i++) {
template_waveform[i] /= valid_beats;
}
}
}
2.3 综合质量指标¶
typedef struct {
float snr_db; // 信噪比
float template_corr; // 模板相关系数
float baseline_wander; // 基线漂移
float powerline_noise; // 工频干扰
uint8_t qrs_detection_rate; // QRS检测率(%)
ECGQualityLevel overall_quality; // 综合质量
} ECGQualityMetrics;
/**
* @brief 综合评估ECG信号质量
*/
void ecg_assess_quality(const float* ecg_signal, uint16_t length,
uint16_t sampling_rate,
ECGQualityMetrics* metrics) {
// 1. 检测QRS波
uint16_t qrs_positions[100];
uint8_t qrs_count = detect_qrs_peaks(ecg_signal, length,
sampling_rate, qrs_positions);
// 2. 计算SNR
metrics->snr_db = ecg_calculate_snr(ecg_signal, length,
qrs_positions, qrs_count);
// 3. 构建模板并计算相关系数
float template[200]; // 约0.8秒的模板
ecg_build_template(ecg_signal, length, qrs_positions, qrs_count,
template, 200);
float total_corr = 0.0f;
for (uint8_t i = 0; i < qrs_count; i++) {
uint16_t start = qrs_positions[i] - 100;
if (start + 200 <= length) {
float corr = ecg_template_correlation(&ecg_signal[start],
template, 200);
total_corr += corr;
}
}
metrics->template_corr = (qrs_count > 0) ? (total_corr / qrs_count) : 0.0f;
// 4. 评估基线漂移(低频能量)
metrics->baseline_wander = estimate_baseline_wander(ecg_signal, length,
sampling_rate);
// 5. 评估工频干扰
metrics->powerline_noise = estimate_powerline_noise(ecg_signal, length,
sampling_rate);
// 6. 计算QRS检测率
float expected_hr = 70.0f; // 假设心率70bpm
float duration_sec = (float)length / sampling_rate;
uint8_t expected_qrs = (uint8_t)(expected_hr * duration_sec / 60.0f);
metrics->qrs_detection_rate = (expected_qrs > 0) ?
(qrs_count * 100 / expected_qrs) : 0;
// 7. 综合评分
int score = 0;
// SNR权重:40%
if (metrics->snr_db >= 20.0f) score += 40;
else if (metrics->snr_db >= 15.0f) score += 30;
else if (metrics->snr_db >= 10.0f) score += 20;
else if (metrics->snr_db >= 5.0f) score += 10;
// 模板相关性权重:30%
if (metrics->template_corr >= 0.9f) score += 30;
else if (metrics->template_corr >= 0.8f) score += 20;
else if (metrics->template_corr >= 0.7f) score += 10;
// QRS检测率权重:20%
if (metrics->qrs_detection_rate >= 90) score += 20;
else if (metrics->qrs_detection_rate >= 80) score += 15;
else if (metrics->qrs_detection_rate >= 70) score += 10;
// 噪声权重:10%
if (metrics->baseline_wander < 0.1f && metrics->powerline_noise < 0.1f) {
score += 10;
} else if (metrics->baseline_wander < 0.2f && metrics->powerline_noise < 0.2f) {
score += 5;
}
// 分级
if (score >= 80) metrics->overall_quality = ECG_QUALITY_EXCELLENT;
else if (score >= 60) metrics->overall_quality = ECG_QUALITY_GOOD;
else if (score >= 40) metrics->overall_quality = ECG_QUALITY_FAIR;
else if (score >= 20) metrics->overall_quality = ECG_QUALITY_POOR;
else metrics->overall_quality = ECG_QUALITY_UNACCEPTABLE;
}
3. PPG信号质量评估¶
3.1 灌注指数(Perfusion Index)¶
/**
* @brief 计算PPG灌注指数
* @param ppg_signal PPG信号
* @param length 信号长度
* @return 灌注指数(%)
*/
float ppg_calculate_perfusion_index(const float* ppg_signal, uint16_t length) {
// 找到最大值和最小值
float max_val = -1e6f, min_val = 1e6f;
float sum = 0.0f;
for (uint16_t i = 0; i < length; i++) {
if (ppg_signal[i] > max_val) max_val = ppg_signal[i];
if (ppg_signal[i] < min_val) min_val = ppg_signal[i];
sum += ppg_signal[i];
}
float mean_val = sum / length;
// AC分量(脉动)
float ac_component = (max_val - min_val) / 2.0f;
// DC分量(基线)
float dc_component = mean_val;
// 灌注指数 = (AC / DC) * 100%
if (dc_component < 1e-6f) {
return 0.0f;
}
float perfusion_index = (ac_component / dc_component) * 100.0f;
return perfusion_index;
}
/**
* @brief 基于灌注指数的质量评估
*/
typedef enum {
PPG_QUALITY_EXCELLENT = 4, // PI > 1.0%
PPG_QUALITY_GOOD = 3, // 0.5-1.0%
PPG_QUALITY_FAIR = 2, // 0.2-0.5%
PPG_QUALITY_POOR = 1, // 0.1-0.2%
PPG_QUALITY_UNACCEPTABLE = 0 // < 0.1%
} PPGQualityLevel;
PPGQualityLevel ppg_classify_quality_by_pi(float perfusion_index) {
if (perfusion_index >= 1.0f) return PPG_QUALITY_EXCELLENT;
if (perfusion_index >= 0.5f) return PPG_QUALITY_GOOD;
if (perfusion_index >= 0.2f) return PPG_QUALITY_FAIR;
if (perfusion_index >= 0.1f) return PPG_QUALITY_POOR;
return PPG_QUALITY_UNACCEPTABLE;
}
3.2 峰值检测质量¶
/**
* @brief 评估PPG峰值检测质量
*/
float ppg_assess_peak_quality(const float* ppg_signal, uint16_t length,
const uint16_t* peak_positions,
uint8_t peak_count) {
if (peak_count < 3) {
return 0.0f; // 峰值太少
}
// 1. 计算峰间间隔(IBI)
float ibi[99];
for (uint8_t i = 0; i < peak_count - 1; i++) {
ibi[i] = (float)(peak_positions[i + 1] - peak_positions[i]);
}
// 2. 计算IBI的变异系数(CV)
float mean_ibi = 0.0f;
for (uint8_t i = 0; i < peak_count - 1; i++) {
mean_ibi += ibi[i];
}
mean_ibi /= (peak_count - 1);
float std_ibi = 0.0f;
for (uint8_t i = 0; i < peak_count - 1; i++) {
float diff = ibi[i] - mean_ibi;
std_ibi += diff * diff;
}
std_ibi = sqrtf(std_ibi / (peak_count - 1));
float cv = std_ibi / mean_ibi;
// 3. 质量评分(CV越小越好)
float quality_score;
if (cv < 0.1f) quality_score = 1.0f; // 优秀
else if (cv < 0.2f) quality_score = 0.8f; // 良好
else if (cv < 0.3f) quality_score = 0.6f; // 一般
else if (cv < 0.5f) quality_score = 0.4f; // 较差
else quality_score = 0.2f; // 很差
return quality_score;
}
4. 实时质量监控¶
4.1 滑动窗口质量评估¶
#define QUALITY_WINDOW_SIZE 250 // 1秒窗口(250Hz采样)
typedef struct {
float signal_buffer[QUALITY_WINDOW_SIZE];
uint16_t buffer_index;
uint16_t sample_count;
float current_quality;
float quality_history[10]; // 最近10秒的质量
uint8_t history_index;
uint8_t low_quality_count; // 连续低质量计数
} RealTimeQualityMonitor;
void quality_monitor_init(RealTimeQualityMonitor* monitor) {
memset(monitor, 0, sizeof(RealTimeQualityMonitor));
monitor->current_quality = 1.0f; // 初始假设质量良好
}
/**
* @brief 添加新样本并更新质量评估
*/
void quality_monitor_update(RealTimeQualityMonitor* monitor, float new_sample) {
// 添加到缓冲区
monitor->signal_buffer[monitor->buffer_index] = new_sample;
monitor->buffer_index = (monitor->buffer_index + 1) % QUALITY_WINDOW_SIZE;
if (monitor->sample_count < QUALITY_WINDOW_SIZE) {
monitor->sample_count++;
return; // 数据不足
}
// 每秒评估一次质量
if (monitor->buffer_index == 0) {
// 计算当前窗口的质量指标
float snr = calculate_window_snr(monitor->signal_buffer, QUALITY_WINDOW_SIZE);
float stability = calculate_signal_stability(monitor->signal_buffer,
QUALITY_WINDOW_SIZE);
// 综合质量评分
monitor->current_quality = (snr * 0.6f + stability * 0.4f);
// 更新历史
monitor->quality_history[monitor->history_index] = monitor->current_quality;
monitor->history_index = (monitor->history_index + 1) % 10;
// 检测连续低质量
if (monitor->current_quality < 0.5f) {
monitor->low_quality_count++;
} else {
monitor->low_quality_count = 0;
}
// 触发报警
if (monitor->low_quality_count >= 5) {
// 连续5秒低质量,触发报警
trigger_low_quality_alarm();
}
}
}
/**
* @brief 获取平均质量(最近10秒)
*/
float quality_monitor_get_average(const RealTimeQualityMonitor* monitor) {
float sum = 0.0f;
uint8_t count = 0;
for (uint8_t i = 0; i < 10; i++) {
if (monitor->quality_history[i] > 0.0f) {
sum += monitor->quality_history[i];
count++;
}
}
return (count > 0) ? (sum / count) : 0.0f;
}
5. 质量驱动的报警管理¶
/**
* @brief 质量感知的报警决策
*/
typedef struct {
float alarm_threshold; // 报警阈值
float quality_threshold; // 质量阈值
uint8_t confirmation_count; // 确认计数
uint8_t required_confirms; // 需要的确认次数
} QualityAwareAlarm;
/**
* @brief 处理报警(考虑信号质量)
* @return 1触发报警,0抑制报警
*/
int process_alarm_with_quality(QualityAwareAlarm* alarm,
float measured_value,
float signal_quality) {
// 如果信号质量太低,抑制报警
if (signal_quality < alarm->quality_threshold) {
alarm->confirmation_count = 0;
return 0; // 抑制报警
}
// 检查是否超过阈值
if (measured_value > alarm->alarm_threshold) {
alarm->confirmation_count++;
// 根据质量调整确认次数
uint8_t required = alarm->required_confirms;
if (signal_quality >= 0.9f) {
required = alarm->required_confirms / 2; // 高质量,快速报警
}
if (alarm->confirmation_count >= required) {
return 1; // 触发报警
}
} else {
alarm->confirmation_count = 0;
}
return 0; // 未触发
}
6. 最佳实践¶
6.1 质量评估策略¶
| 应用场景 | 推荐方法 | 更新频率 |
|---|---|---|
| 实时监护 | 滑动窗口SNR | 1秒 |
| 诊断ECG | 综合质量指标 | 每次记录 |
| 可穿戴设备 | 灌注指数 | 实时 |
| 远程监护 | 质量驱动报警 | 实时 |
6.2 常见陷阱¶
❌ 错误1:忽略信号质量直接报警
// 错误
if (heart_rate > 120) {
trigger_alarm(); // 可能是伪影!
}
// 正确
if (heart_rate > 120 && signal_quality > 0.7f) {
trigger_alarm();
}
❌ 错误2:质量阈值设置不当
// 错误:阈值太高,丢失有用数据
if (quality < 0.95f) {
discard_data();
}
// 正确:根据应用场景设置
if (quality < 0.5f) { // 诊断级
discard_data();
}
7. 参考资料¶
论文¶
- "Signal Quality Indices for the Electrocardiogram and Photoplethysmogram" (2015)
- "A Review of Signal Quality Assessment Methods for Physiological Signals" (2019)
标准¶
- IEC 60601-2-27: ECG监护设备
- ISO 80601-2-61: 脉搏血氧仪
相关模块¶
下一步: 综合应用所学的信号处理技术,构建完整的医疗监护系统。
💬 讨论区
欢迎在这里分享您的想法、提出问题或参与讨论。需要 GitHub 账号登录。