340 lines
13 KiB
C++
340 lines
13 KiB
C++
#include <iostream>
|
||
#include <vector>
|
||
#include <cmath>
|
||
#include <fstream>
|
||
#include <random>
|
||
#include <algorithm>
|
||
|
||
// 模拟PPG信号生成函数,包含运动伪迹
|
||
std::vector<float> generate_test_ppg_with_artifacts(int sample_rate, float duration_seconds) {
|
||
int num_samples = static_cast<int>(sample_rate * duration_seconds);
|
||
std::vector<float> signal(num_samples);
|
||
|
||
std::random_device rd;
|
||
std::mt19937 gen(rd());
|
||
std::normal_distribution<float> noise_dist(0.0f, 0.05f);
|
||
std::uniform_real_distribution<float> artifact_dist(0.0f, 1.0f);
|
||
|
||
for (int i = 0; i < num_samples; ++i) {
|
||
float t = static_cast<float>(i) / sample_rate;
|
||
|
||
// 基础PPG信号(心率约60bpm)
|
||
float ppg_component = 0.5 * sin(2 * M_PI * 1.0 * t);
|
||
|
||
// 呼吸调制
|
||
float respiration = 0.1 * sin(2 * M_PI * 0.2 * t);
|
||
|
||
// 基线漂移
|
||
float baseline_drift = 0.05 * sin(2 * M_PI * 0.01 * t);
|
||
|
||
// 高频噪声
|
||
float high_freq_noise = 0.02 * sin(2 * M_PI * 10.0 * t) +
|
||
0.02 * sin(2 * M_PI * 15.0 * t);
|
||
|
||
// 运动伪迹(随机出现)
|
||
float motion_artifact = 0.0f;
|
||
if (artifact_dist(gen) < 0.01f) { // 1%概率出现运动伪迹
|
||
float artifact_type = artifact_dist(gen);
|
||
if (artifact_type < 0.3f) {
|
||
// 尖峰伪迹
|
||
motion_artifact = 0.8f * exp(-std::pow((t - static_cast<int>(t)) * 10, 2));
|
||
} else if (artifact_type < 0.6f) {
|
||
// 基线跳跃
|
||
motion_artifact = 0.3f * (artifact_dist(gen) - 0.5f);
|
||
} else {
|
||
// 高频振荡
|
||
motion_artifact = 0.2f * sin(2 * M_PI * 25.0 * t) * exp(-std::pow((t - static_cast<int>(t)) * 5, 2));
|
||
}
|
||
}
|
||
|
||
// 组合所有成分
|
||
signal[i] = ppg_component + respiration + baseline_drift + high_freq_noise + motion_artifact + noise_dist(gen);
|
||
}
|
||
|
||
return signal;
|
||
}
|
||
|
||
// 简化的增强版运动伪迹检测算法(用于测试)
|
||
std::vector<float> enhanced_motion_artifact_removal(const std::vector<float>& signal, double sample_rate) {
|
||
if (signal.empty()) return signal;
|
||
|
||
std::vector<float> result = signal;
|
||
const size_t min_window_size = static_cast<size_t>(0.1 * sample_rate);
|
||
|
||
if (signal.size() < min_window_size) return result;
|
||
|
||
// 多尺度检测窗口
|
||
std::vector<size_t> window_sizes = {
|
||
static_cast<size_t>(0.1 * sample_rate),
|
||
static_cast<size_t>(0.5 * sample_rate),
|
||
static_cast<size_t>(1.0 * sample_rate)
|
||
};
|
||
|
||
std::vector<bool> artifact_mask(signal.size(), false);
|
||
|
||
// 统计特征检测
|
||
for (size_t ws : window_sizes) {
|
||
if (signal.size() < ws) continue;
|
||
|
||
for (size_t i = ws; i < signal.size(); ++i) {
|
||
std::vector<float> window_data;
|
||
for (size_t j = i - ws; j < i; ++j) {
|
||
window_data.push_back(signal[j]);
|
||
}
|
||
|
||
// 计算统计特征
|
||
float sum = 0.0f, sum_sq = 0.0f;
|
||
for (float val : window_data) {
|
||
sum += val;
|
||
sum_sq += val * val;
|
||
}
|
||
|
||
float mean = sum / ws;
|
||
float variance = (sum_sq / ws) - (mean * mean);
|
||
|
||
if (variance > 1e-6f) {
|
||
float std_dev = std::sqrt(variance);
|
||
float current_val = signal[i];
|
||
float z_score = std::abs(current_val - mean) / (std_dev + 1e-6f);
|
||
|
||
// 检测异常值
|
||
if (z_score > 4.0f) {
|
||
artifact_mask[i] = true;
|
||
}
|
||
|
||
// 梯度异常检测
|
||
if (i > 0) {
|
||
float gradient = std::abs(current_val - signal[i-1]);
|
||
float avg_gradient = 0.0f;
|
||
for (size_t j = 1; j < std::min(ws, i); ++j) {
|
||
avg_gradient += std::abs(signal[i-j] - signal[i-j-1]);
|
||
}
|
||
avg_gradient /= std::min(ws, i);
|
||
|
||
if (gradient > 3.0f * avg_gradient) {
|
||
artifact_mask[i] = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 形态学检测
|
||
for (size_t i = 2; i < signal.size() - 2; ++i) {
|
||
float current = signal[i];
|
||
float prev = signal[i-1];
|
||
float next = signal[i+1];
|
||
|
||
// 尖峰检测
|
||
if ((current > prev && current > next &&
|
||
current - prev > 2.0f * std::abs(next - prev)) ||
|
||
(current < prev && current < next &&
|
||
prev - current > 2.0f * std::abs(next - prev))) {
|
||
artifact_mask[i] = true;
|
||
}
|
||
}
|
||
|
||
// 智能修复
|
||
size_t artifact_count = 0;
|
||
for (size_t i = 0; i < signal.size(); ++i) {
|
||
if (artifact_mask[i]) {
|
||
artifact_count++;
|
||
|
||
// 使用中值插值
|
||
std::vector<float> neighbors;
|
||
for (int offset = -2; offset <= 2; ++offset) {
|
||
int idx = static_cast<int>(i) + offset;
|
||
if (idx >= 0 && idx < static_cast<int>(signal.size()) && !artifact_mask[idx]) {
|
||
neighbors.push_back(signal[idx]);
|
||
}
|
||
}
|
||
|
||
if (!neighbors.empty()) {
|
||
if (neighbors.size() >= 3) {
|
||
std::sort(neighbors.begin(), neighbors.end());
|
||
result[i] = neighbors[neighbors.size() / 2];
|
||
} else {
|
||
float sum = 0.0f;
|
||
for (float val : neighbors) sum += val;
|
||
result[i] = sum / neighbors.size();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
std::cout << "检测到 " << artifact_count << " 个运动伪迹点" << std::endl;
|
||
return result;
|
||
}
|
||
|
||
// 计算信号质量指标
|
||
struct SignalQualityMetrics {
|
||
float snr_db;
|
||
float variance;
|
||
float peak_to_peak;
|
||
float artifact_ratio;
|
||
};
|
||
|
||
SignalQualityMetrics calculate_signal_quality(const std::vector<float>& signal, double sample_rate) {
|
||
SignalQualityMetrics metrics;
|
||
|
||
if (signal.empty()) {
|
||
metrics.snr_db = 0.0f;
|
||
metrics.variance = 0.0f;
|
||
metrics.peak_to_peak = 0.0f;
|
||
metrics.artifact_ratio = 0.0f;
|
||
return metrics;
|
||
}
|
||
|
||
// 计算基本统计量
|
||
float sum = 0.0f, sum_sq = 0.0f;
|
||
float min_val = signal[0], max_val = signal[0];
|
||
|
||
for (float val : signal) {
|
||
sum += val;
|
||
sum_sq += val * val;
|
||
min_val = std::min(min_val, val);
|
||
max_val = std::max(max_val, val);
|
||
}
|
||
|
||
float mean = sum / signal.size();
|
||
metrics.variance = (sum_sq / signal.size()) - (mean * mean);
|
||
metrics.peak_to_peak = max_val - min_val;
|
||
|
||
// 计算SNR
|
||
float signal_power = 0.0f;
|
||
float noise_power = 0.0f;
|
||
|
||
for (float val : signal) {
|
||
signal_power += std::pow(val - mean, 2);
|
||
}
|
||
signal_power /= signal.size();
|
||
|
||
for (size_t i = 1; i < signal.size(); ++i) {
|
||
float diff = signal[i] - signal[i-1];
|
||
noise_power += diff * diff;
|
||
}
|
||
noise_power /= (signal.size() - 1);
|
||
|
||
if (noise_power > 1e-6f) {
|
||
metrics.snr_db = 10.0f * std::log10(signal_power / noise_power);
|
||
} else {
|
||
metrics.snr_db = 0.0f;
|
||
}
|
||
|
||
// 估算伪迹比例(通过异常梯度检测)
|
||
size_t artifact_count = 0;
|
||
for (size_t i = 1; i < signal.size(); ++i) {
|
||
float gradient = std::abs(signal[i] - signal[i-1]);
|
||
if (gradient > 3.0f * std::sqrt(metrics.variance)) {
|
||
artifact_count++;
|
||
}
|
||
}
|
||
|
||
metrics.artifact_ratio = static_cast<float>(artifact_count) / signal.size();
|
||
|
||
return metrics;
|
||
}
|
||
|
||
// 保存信号到CSV文件
|
||
void save_signal_to_csv(const std::vector<float>& signal, const std::string& filename, double sample_rate) {
|
||
std::ofstream file(filename);
|
||
if (!file.is_open()) {
|
||
std::cerr << "无法创建文件: " << filename << std::endl;
|
||
return;
|
||
}
|
||
|
||
file << "Time(s),Amplitude\n";
|
||
for (size_t i = 0; i < signal.size(); ++i) {
|
||
float time = static_cast<float>(i) / sample_rate;
|
||
file << time << "," << signal[i] << "\n";
|
||
}
|
||
file.close();
|
||
std::cout << "信号已保存到: " << filename << std::endl;
|
||
}
|
||
|
||
int main() {
|
||
std::cout << "=== 增强版运动伪迹检测和去除算法测试 ===" << std::endl;
|
||
|
||
// 测试参数
|
||
const int sample_rate = 100; // 100Hz采样率
|
||
const float duration = 10.0f; // 10秒数据
|
||
|
||
std::cout << "采样率: " << sample_rate << "Hz" << std::endl;
|
||
std::cout << "信号长度: " << duration << "秒" << std::endl;
|
||
|
||
// 1. 生成包含运动伪迹的测试信号
|
||
std::cout << "\n1. 生成测试信号..." << std::endl;
|
||
std::vector<float> original_signal = generate_test_ppg_with_artifacts(sample_rate, duration);
|
||
std::cout << "测试信号生成完成,长度: " << original_signal.size() << " 样本" << std::endl;
|
||
|
||
// 2. 计算原始信号质量
|
||
std::cout << "\n2. 分析原始信号质量..." << std::endl;
|
||
SignalQualityMetrics original_metrics = calculate_signal_quality(original_signal, sample_rate);
|
||
std::cout << "原始信号质量指标:" << std::endl;
|
||
std::cout << " SNR: " << original_metrics.snr_db << " dB" << std::endl;
|
||
std::cout << " 方差: " << original_metrics.variance << std::endl;
|
||
std::cout << " 峰峰值: " << original_metrics.peak_to_peak << std::endl;
|
||
std::cout << " 伪迹比例: " << (original_metrics.artifact_ratio * 100) << "%" << std::endl;
|
||
|
||
// 3. 应用运动伪迹检测和去除
|
||
std::cout << "\n3. 应用增强版运动伪迹检测和去除..." << std::endl;
|
||
std::vector<float> cleaned_signal = enhanced_motion_artifact_removal(original_signal, sample_rate);
|
||
|
||
// 4. 计算处理后信号质量
|
||
std::cout << "\n4. 分析处理后信号质量..." << std::endl;
|
||
SignalQualityMetrics cleaned_metrics = calculate_signal_quality(cleaned_signal, sample_rate);
|
||
std::cout << "处理后信号质量指标:" << std::endl;
|
||
std::cout << " SNR: " << cleaned_metrics.snr_db << " dB" << std::endl;
|
||
std::cout << " 方差: " << cleaned_metrics.variance << std::endl;
|
||
std::cout << " 峰峰值: " << cleaned_metrics.peak_to_peak << std::endl;
|
||
std::cout << " 伪迹比例: " << (cleaned_metrics.artifact_ratio * 100) << "%" << std::endl;
|
||
|
||
// 5. 计算改善效果
|
||
std::cout << "\n5. 改善效果分析..." << std::endl;
|
||
float snr_improvement = cleaned_metrics.snr_db - original_metrics.snr_db;
|
||
float variance_reduction = (original_metrics.variance - cleaned_metrics.variance) / original_metrics.variance * 100;
|
||
float artifact_reduction = (original_metrics.artifact_ratio - cleaned_metrics.artifact_ratio) / original_metrics.artifact_ratio * 100;
|
||
|
||
std::cout << "改善效果:" << std::endl;
|
||
std::cout << " SNR改善: " << snr_improvement << " dB" << std::endl;
|
||
std::cout << " 方差减少: " << variance_reduction << "%" << std::endl;
|
||
std::cout << " 伪迹减少: " << artifact_reduction << "%" << std::endl;
|
||
|
||
// 6. 保存结果
|
||
std::cout << "\n6. 保存结果..." << std::endl;
|
||
save_signal_to_csv(original_signal, "original_signal_with_artifacts.csv", sample_rate);
|
||
save_signal_to_csv(cleaned_signal, "cleaned_signal.csv", sample_rate);
|
||
|
||
// 7. 生成对比报告
|
||
std::ofstream report("motion_artifact_removal_report.txt");
|
||
if (report.is_open()) {
|
||
report << "=== 运动伪迹检测和去除算法测试报告 ===" << std::endl;
|
||
report << "测试时间: " << std::time(nullptr) << std::endl;
|
||
report << "采样率: " << sample_rate << "Hz" << std::endl;
|
||
report << "信号长度: " << duration << "秒" << std::endl;
|
||
report << "\n原始信号质量:" << std::endl;
|
||
report << " SNR: " << original_metrics.snr_db << " dB" << std::endl;
|
||
report << " 方差: " << original_metrics.variance << std::endl;
|
||
report << " 峰峰值: " << original_metrics.peak_to_peak << std::endl;
|
||
report << " 伪迹比例: " << (original_metrics.artifact_ratio * 100) << "%" << std::endl;
|
||
report << "\n处理后信号质量:" << std::endl;
|
||
report << " SNR: " << cleaned_metrics.snr_db << " dB" << std::endl;
|
||
report << " 方差: " << cleaned_metrics.variance << std::endl;
|
||
report << " 峰峰值: " << cleaned_metrics.peak_to_peak << std::endl;
|
||
report << " 伪迹比例: " << (cleaned_metrics.artifact_ratio * 100) << "%" << std::endl;
|
||
report << "\n改善效果:" << std::endl;
|
||
report << " SNR改善: " << snr_improvement << " dB" << std::endl;
|
||
report << " 方差减少: " << variance_reduction << "%" << std::endl;
|
||
report << " 伪迹减少: " << artifact_reduction << "%" << std::endl;
|
||
report.close();
|
||
std::cout << "测试报告已保存到: motion_artifact_removal_report.txt" << std::endl;
|
||
}
|
||
|
||
std::cout << "\n=== 测试完成 ===" << std::endl;
|
||
std::cout << "请检查生成的CSV文件和测试报告" << std::endl;
|
||
|
||
return 0;
|
||
}
|
||
|
||
|