2025-07-28 11:56:50 +08:00
|
|
|
|
#include "headfile.h"
|
2025-08-26 15:00:47 +08:00
|
|
|
|
#include <fstream>
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
#include <ctime>
|
2025-08-25 10:53:22 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-08-14 11:16:24 +08:00
|
|
|
|
std::vector<float> heart_rate;
|
2025-07-28 11:56:50 +08:00
|
|
|
|
|
2025-08-25 10:53:22 +08:00
|
|
|
|
// 辅助函数:获取数据类型名称
|
|
|
|
|
|
std::string get_data_type_name(DataType data_type) {
|
|
|
|
|
|
switch (data_type) {
|
|
|
|
|
|
case DataType::EEG: return "EEG (脑电)";
|
|
|
|
|
|
case DataType::ECG_2LEAD: return "ECG_2LEAD (胸腹设备)";
|
|
|
|
|
|
case DataType::SNORE: return "SNORE (鼾声)";
|
|
|
|
|
|
case DataType::RESPIRATION: return "RESPIRATION (呼吸/姿态/环境光)";
|
|
|
|
|
|
case DataType::ECG_12LEAD: return "ECG_12LEAD (12导联心电)";
|
|
|
|
|
|
case DataType::PPG: return "PPG (血氧)";
|
|
|
|
|
|
case DataType::STETHOSCOPE: return "STETHOSCOPE (听诊器)";
|
|
|
|
|
|
default: return "未知类型";
|
2025-07-28 11:56:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-14 11:16:24 +08:00
|
|
|
|
|
2025-08-25 10:53:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 新增:完整的信号数据处理流程 - 整合所有步骤
|
|
|
|
|
|
void complete_signal_processing_pipeline() {
|
2025-07-28 11:56:50 +08:00
|
|
|
|
try {
|
2025-08-25 10:53:22 +08:00
|
|
|
|
std::cout << "=== 开始完整的信号数据处理流程 ===" << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 读取原始二进制文件
|
|
|
|
|
|
std::cout << "步骤1: 读取原始数据..." << std::endl;
|
2025-08-26 15:00:47 +08:00
|
|
|
|
std::vector<uint8_t> file_content = FileManager::readBinaryFile("raw_data/ecg_data_raw.dat");
|
2025-08-25 10:53:22 +08:00
|
|
|
|
std::cout << "原始文件大小: " << file_content.size() << " 字节" << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 解析设备数据包
|
|
|
|
|
|
std::cout << "步骤2: 解析设备数据包..." << std::endl;
|
2025-07-28 11:56:50 +08:00
|
|
|
|
std::vector<SensorData> all_data = parse_device_data(file_content);
|
2025-08-25 10:53:22 +08:00
|
|
|
|
std::cout << "数据解析完成,共解析出 " << all_data.size() << " 个数据对象" << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 通道映射 (MAPPER)
|
|
|
|
|
|
std::cout << "步骤3: 执行通道映射..." << std::endl;
|
|
|
|
|
|
Mapper mapper;
|
|
|
|
|
|
for(size_t i = 0; i < all_data.size(); ++i) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
std::cout << "映射数据对象 " << i + 1 << "/" << all_data.size() << "...";
|
|
|
|
|
|
all_data[i] = mapper.DataMapper(all_data[i]);
|
|
|
|
|
|
std::cout << " 完成" << std::endl;
|
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
|
std::cerr << " 失败: " << e.what() << std::endl;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-08-14 11:16:24 +08:00
|
|
|
|
}
|
2025-08-25 10:53:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 保存映射后的数据
|
2025-08-26 15:00:47 +08:00
|
|
|
|
save_to_csv(all_data, "data_generated/channel_data_mapped_.csv");
|
|
|
|
|
|
std::cout << "通道映射完成,结果已保存到 data_generated/channel_data_mapped_.csv" << std::endl;
|
2025-08-25 10:53:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 4. 信号预处理 (滤波等)
|
|
|
|
|
|
std::cout << "步骤4: 执行信号预处理..." << std::endl;
|
|
|
|
|
|
SignalProcessor processor;
|
|
|
|
|
|
std::vector<SensorData> processed_data;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
processed_data = processor.process_channel_based_filtering_simple(all_data);
|
|
|
|
|
|
std::cout << "信号预处理完成,处理了 " << processed_data.size() << " 个数据对象" << std::endl;
|
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
|
std::cerr << "信号预处理失败: " << e.what() << std::endl;
|
|
|
|
|
|
std::cout << "使用映射后的数据继续处理..." << std::endl;
|
|
|
|
|
|
processed_data = all_data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存预处理后的数据
|
2025-08-26 15:00:47 +08:00
|
|
|
|
save_to_csv(processed_data, "data_generated/channel_data_processed_.csv");
|
|
|
|
|
|
std::cout << "预处理后的数据已保存到 data_generated/channel_data_processed_.csv" << std::endl;
|
2025-08-25 10:53:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 5. 指标计算
|
|
|
|
|
|
std::cout << "步骤5: 计算生理指标..." << std::endl;
|
|
|
|
|
|
MetricsCalculator calculator;
|
|
|
|
|
|
const float sample_rate = 250.0f;
|
|
|
|
|
|
|
|
|
|
|
|
// 创建详细指标文件
|
2025-08-26 15:00:47 +08:00
|
|
|
|
std::ofstream metrics_file("data_generated/calculated_metrics_detailed.csv");
|
2025-08-25 10:53:22 +08:00
|
|
|
|
if (!metrics_file.is_open()) {
|
|
|
|
|
|
std::cerr << "无法创建指标保存文件" << std::endl;
|
|
|
|
|
|
return;
|
2025-08-14 11:16:24 +08:00
|
|
|
|
}
|
2025-08-25 10:53:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 写入CSV表头
|
|
|
|
|
|
metrics_file << "数据对象,数据类型,包序号,时间戳,信号质量指数,";
|
|
|
|
|
|
metrics_file << "心率(bpm),T波振幅(mV),QRS宽度(ms),ST偏移(mV),";
|
|
|
|
|
|
metrics_file << "血氧饱和度(%),灌注指数(%),脉搏波宽度,红光红外光比值,";
|
|
|
|
|
|
metrics_file << "SDNN(ms),RMSSD(ms),pNN50(%),三角指数,";
|
|
|
|
|
|
metrics_file << "均值,标准差,最小值,最大值,峰峰值,信号质量评分(%)\n";
|
|
|
|
|
|
|
|
|
|
|
|
// 计算每个数据对象的指标
|
|
|
|
|
|
for (size_t i = 0; i < processed_data.size(); ++i) {
|
|
|
|
|
|
const auto& data = processed_data[i];
|
|
|
|
|
|
std::cout << "计算数据对象 " << i + 1 << "/" << processed_data.size() << " ("
|
|
|
|
|
|
<< get_data_type_name(data.data_type) << ") 的指标..." << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
// 写入基本信息
|
|
|
|
|
|
metrics_file << i << "," << get_data_type_name(data.data_type) << ","
|
|
|
|
|
|
<< data.packet_sn << "," << data.timestamp << "," << data.sqi << ",";
|
|
|
|
|
|
|
|
|
|
|
|
// 根据数据类型计算指标
|
|
|
|
|
|
if (data.data_type == DataType::ECG_12LEAD || data.data_type == DataType::ECG_2LEAD) {
|
|
|
|
|
|
// ECG指标
|
|
|
|
|
|
auto ecg_metrics = calculator.calculate_all_ecg_metrics(data, sample_rate);
|
|
|
|
|
|
metrics_file << ecg_metrics["heart_rate"] << ","
|
|
|
|
|
|
<< ecg_metrics["t_wave_amplitude"] << ","
|
|
|
|
|
|
<< ecg_metrics["qrs_width"] << ","
|
|
|
|
|
|
<< ecg_metrics["st_offset"] << ","
|
|
|
|
|
|
<< "0,0,0,0," // PPG指标填充0
|
|
|
|
|
|
<< ecg_metrics["sdnn"] << ","
|
|
|
|
|
|
<< ecg_metrics["rmssd"] << ","
|
|
|
|
|
|
<< ecg_metrics["pnn50"] << ","
|
|
|
|
|
|
<< ecg_metrics["triangular_index"] << ","
|
|
|
|
|
|
<< ecg_metrics["mean"] << ","
|
|
|
|
|
|
<< ecg_metrics["std_dev"] << ","
|
|
|
|
|
|
<< ecg_metrics["min_value"] << ","
|
|
|
|
|
|
<< ecg_metrics["max_value"] << ","
|
|
|
|
|
|
<< ecg_metrics["peak_to_peak"] << ","
|
|
|
|
|
|
<< ecg_metrics["signal_quality"];
|
|
|
|
|
|
|
|
|
|
|
|
} else if (data.data_type == DataType::PPG) {
|
|
|
|
|
|
// PPG指标
|
|
|
|
|
|
auto ppg_metrics = calculator.calculate_all_ppg_metrics(data, sample_rate);
|
|
|
|
|
|
metrics_file << "0,0,0,0," // ECG指标填充0
|
|
|
|
|
|
<< ppg_metrics["spo2"] << ","
|
|
|
|
|
|
<< ppg_metrics["perfusion_index"] << ","
|
|
|
|
|
|
<< ppg_metrics["pulse_width"] << ","
|
|
|
|
|
|
<< ppg_metrics["amplitude_ratio"] << ","
|
|
|
|
|
|
<< "0,0,0,0," // HRV指标填充0
|
|
|
|
|
|
<< ppg_metrics["mean"] << ","
|
|
|
|
|
|
<< ppg_metrics["std_dev"] << ","
|
|
|
|
|
|
<< ppg_metrics["min_value"] << ","
|
|
|
|
|
|
<< ppg_metrics["max_value"] << ","
|
|
|
|
|
|
<< ppg_metrics["peak_to_peak"] << ","
|
|
|
|
|
|
<< ppg_metrics["signal_quality"];
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 其他数据类型
|
|
|
|
|
|
metrics_file << "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
metrics_file << "\n";
|
2025-08-14 11:16:24 +08:00
|
|
|
|
}
|
2025-07-28 11:56:50 +08:00
|
|
|
|
|
2025-08-25 10:53:22 +08:00
|
|
|
|
metrics_file.close();
|
|
|
|
|
|
std::cout << "指标计算完成,结果已保存到 calculated_metrics_detailed.csv" << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
// 6. 创建指标汇总文件
|
|
|
|
|
|
std::cout << "步骤6: 生成指标汇总..." << std::endl;
|
2025-08-26 15:00:47 +08:00
|
|
|
|
std::ofstream summary_file("data_generated/metrics_summary.csv");
|
2025-08-25 10:53:22 +08:00
|
|
|
|
if (summary_file.is_open()) {
|
|
|
|
|
|
summary_file << "数据类型,数据对象数量,平均心率(bpm),平均信号质量(%),平均QRS宽度(ms),平均ST偏移(mV)\n";
|
|
|
|
|
|
|
|
|
|
|
|
// 按数据类型分组统计
|
|
|
|
|
|
std::map<DataType, std::vector<size_t>> type_groups;
|
|
|
|
|
|
for (size_t i = 0; i < processed_data.size(); ++i) {
|
|
|
|
|
|
type_groups[processed_data[i].data_type].push_back(i);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto& [data_type, indices] : type_groups) {
|
|
|
|
|
|
if (indices.empty()) continue;
|
|
|
|
|
|
|
|
|
|
|
|
std::string type_name = get_data_type_name(data_type);
|
|
|
|
|
|
int count = static_cast<int>(indices.size());
|
|
|
|
|
|
|
|
|
|
|
|
// 计算该类型的平均指标
|
|
|
|
|
|
float total_hr = 0.0f, total_quality = 0.0f, total_qrs = 0.0f, total_st = 0.0f;
|
|
|
|
|
|
int valid_hr = 0, valid_quality = 0, valid_qrs = 0, valid_st = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t idx : indices) {
|
|
|
|
|
|
const auto& data = processed_data[idx];
|
|
|
|
|
|
|
|
|
|
|
|
if (data.data_type == DataType::ECG_12LEAD || data.data_type == DataType::ECG_2LEAD) {
|
|
|
|
|
|
auto ecg_metrics = calculator.calculate_all_ecg_metrics(data, sample_rate);
|
|
|
|
|
|
|
|
|
|
|
|
if (ecg_metrics["heart_rate"] > 0) {
|
|
|
|
|
|
total_hr += ecg_metrics["heart_rate"];
|
|
|
|
|
|
valid_hr++;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ecg_metrics["signal_quality"] > 0) {
|
|
|
|
|
|
total_quality += ecg_metrics["signal_quality"];
|
|
|
|
|
|
valid_quality++;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ecg_metrics["qrs_width"] > 0) {
|
|
|
|
|
|
total_qrs += ecg_metrics["qrs_width"];
|
|
|
|
|
|
valid_qrs++;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ecg_metrics["st_offset"] != 0) {
|
|
|
|
|
|
total_st += ecg_metrics["st_offset"];
|
|
|
|
|
|
valid_st++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算平均值
|
|
|
|
|
|
float avg_hr = valid_hr > 0 ? total_hr / valid_hr : 0.0f;
|
|
|
|
|
|
float avg_quality = valid_quality > 0 ? total_quality / valid_quality : 0.0f;
|
|
|
|
|
|
float avg_qrs = valid_qrs > 0 ? total_qrs / valid_qrs : 0.0f;
|
|
|
|
|
|
float avg_st = valid_st > 0 ? total_st / valid_st : 0.0f;
|
|
|
|
|
|
|
|
|
|
|
|
summary_file << type_name << "," << count << ","
|
|
|
|
|
|
<< std::fixed << std::setprecision(2) << avg_hr << ","
|
|
|
|
|
|
<< avg_quality << "," << avg_qrs << "," << avg_st << "\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
std::cin.get();
|
|
|
|
|
|
summary_file.close();
|
|
|
|
|
|
std::cout << "指标汇总已保存到 metrics_summary.csv" << std::endl;
|
|
|
|
|
|
}
|
2025-07-28 11:56:50 +08:00
|
|
|
|
std::cin.get();
|
2025-08-25 10:53:22 +08:00
|
|
|
|
// 7. 流程完成总结
|
|
|
|
|
|
std::cout << "\n=== 完整信号数据处理流程完成 ===" << std::endl;
|
|
|
|
|
|
std::cout << "生成的文件:" << std::endl;
|
2025-08-26 15:00:47 +08:00
|
|
|
|
std::cout << "1. data_generated/channel_data_mapped_.csv - 通道映射后的数据" << std::endl;
|
|
|
|
|
|
std::cout << "2. data_generated/channel_data_processed_.csv - 预处理后的数据" << std::endl;
|
|
|
|
|
|
std::cout << "3. data_generated/calculated_metrics_detailed.csv - 详细指标数据" << std::endl;
|
|
|
|
|
|
std::cout << "4. data_generated/metrics_summary.csv - 指标汇总统计" << std::endl;
|
2025-07-28 11:56:50 +08:00
|
|
|
|
std::cin.get();
|
2025-08-25 10:53:22 +08:00
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
|
std::cerr << "完整流程执行错误: " << e.what() << std::endl;
|
|
|
|
|
|
}
|
2025-07-28 11:56:50 +08:00
|
|
|
|
}
|
2025-08-25 10:53:22 +08:00
|
|
|
|
|
2025-08-26 15:00:47 +08:00
|
|
|
|
// PPG数据处理函数 - 专门处理A50伤后6h-1.txt文件
|
|
|
|
|
|
void process_ppg_a50_data() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
std::cout << "=== 开始处理PPG数据 (A50伤后6h-1.txt) ===" << std::endl;
|
|
|
|
|
|
std::cin.get();
|
|
|
|
|
|
// 1. 读取PPG数据文件
|
|
|
|
|
|
std::cout << "步骤1: 读取PPG数据文件..." << std::endl;
|
|
|
|
|
|
std::string ppg_file_path = "raw_data/A50_6h_1.txt";
|
|
|
|
|
|
std::cin.get();
|
|
|
|
|
|
std::ifstream ppg_file(ppg_file_path);
|
|
|
|
|
|
if (!ppg_file.is_open()) {
|
|
|
|
|
|
std::cerr << "错误: 无法打开PPG数据文件: " << ppg_file_path << std::endl;
|
|
|
|
|
|
std::cout << "请确保文件存在于 raw_data/ 文件夹中" << std::endl;
|
|
|
|
|
|
std::cin.get();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 解析PPG数据
|
|
|
|
|
|
std::cout << "步骤2: 解析PPG数据..." << std::endl;
|
|
|
|
|
|
std::vector<float> red_channel, ir_channel;
|
|
|
|
|
|
std::string line;
|
|
|
|
|
|
int line_count = 0;
|
|
|
|
|
|
|
|
|
|
|
|
while (std::getline(ppg_file, line)) {
|
|
|
|
|
|
line_count++;
|
|
|
|
|
|
if (line.empty()) continue;
|
|
|
|
|
|
|
|
|
|
|
|
// 解析每行的两个数值 (红光,红外光)
|
|
|
|
|
|
std::istringstream iss(line);
|
|
|
|
|
|
std::string red_str, ir_str;
|
|
|
|
|
|
|
|
|
|
|
|
if (std::getline(iss, red_str, ',') && std::getline(iss, ir_str)) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
float red_val = std::stof(red_str);
|
|
|
|
|
|
float ir_val = std::stof(ir_str);
|
|
|
|
|
|
|
|
|
|
|
|
red_channel.push_back(red_val*0.879);
|
|
|
|
|
|
ir_channel.push_back(ir_val*0.879);
|
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
|
std::cerr << "警告: 第 " << line_count << " 行数据解析失败: " << line << std::endl;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
std::cerr << "警告: 第 " << line_count << " 行格式不正确: " << line << std::endl;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ppg_file.close();
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "PPG数据解析完成,共读取 " << red_channel.size() << " 个数据点" << std::endl;
|
|
|
|
|
|
std::cout << "红光通道范围: [" << *std::min_element(red_channel.begin(), red_channel.end())
|
|
|
|
|
|
<< ", " << *std::max_element(red_channel.begin(), red_channel.end()) << "]" << std::endl;
|
|
|
|
|
|
std::cout << "红外光通道范围: [" << *std::min_element(ir_channel.begin(), ir_channel.end())
|
|
|
|
|
|
<< ", " << *std::max_element(ir_channel.begin(), ir_channel.end()) << "]" << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 创建SensorData对象
|
|
|
|
|
|
std::cout << "步骤3: 创建PPG数据对象..." << std::endl;
|
|
|
|
|
|
SensorData ppg_data;
|
|
|
|
|
|
ppg_data.data_type = DataType::PPG;
|
|
|
|
|
|
ppg_data.packet_sn = 1;
|
|
|
|
|
|
ppg_data.timestamp = std::time(nullptr);
|
|
|
|
|
|
ppg_data.sqi = 0.8f; // 默认信号质量指数
|
|
|
|
|
|
|
|
|
|
|
|
// 将单通道数据转换为多通道格式
|
|
|
|
|
|
std::vector<std::vector<float>> channels = {red_channel, ir_channel};
|
|
|
|
|
|
ppg_data.channel_data = channels;
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 信号预处理
|
|
|
|
|
|
std::cout << "步骤4: 执行PPG信号预处理..." << std::endl;
|
|
|
|
|
|
SignalProcessor processor;
|
|
|
|
|
|
std::vector<SensorData> ppg_data_vector = {ppg_data};
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<SensorData> processed_ppg_data;
|
|
|
|
|
|
try {
|
|
|
|
|
|
processed_ppg_data = processor.process_channel_based_filtering_simple(ppg_data_vector);
|
|
|
|
|
|
std::cout << "PPG信号预处理完成" << std::endl;
|
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
|
std::cerr << "PPG信号预处理失败: " << e.what() << std::endl;
|
|
|
|
|
|
std::cout << "使用原始数据继续处理..." << std::endl;
|
|
|
|
|
|
processed_ppg_data = ppg_data_vector;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 5. 保存预处理后的数据
|
|
|
|
|
|
std::cout << "步骤5: 保存预处理后的PPG数据..." << std::endl;
|
|
|
|
|
|
save_to_csv(processed_ppg_data, "data_generated/ppg_a50_processed.csv");
|
|
|
|
|
|
std::cout << "预处理后的PPG数据已保存到 data_generated/ppg_a50_processed.csv" << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
// 6. 计算PPG生理指标
|
|
|
|
|
|
std::cout << "步骤6: 计算PPG生理指标..." << std::endl;
|
|
|
|
|
|
MetricsCalculator calculator;
|
|
|
|
|
|
const float sample_rate = 50.0f; // PPG采样率,请根据实际情况调整
|
|
|
|
|
|
|
|
|
|
|
|
auto ppg_metrics = calculator.calculate_all_ppg_metrics(processed_ppg_data[0], sample_rate);
|
|
|
|
|
|
|
|
|
|
|
|
// 7. 保存指标计算结果
|
|
|
|
|
|
std::cout << "步骤7: 保存PPG指标计算结果..." << std::endl;
|
|
|
|
|
|
std::ofstream metrics_file("data_generated/ppg_a50_metrics.csv");
|
|
|
|
|
|
if (metrics_file.is_open()) {
|
|
|
|
|
|
metrics_file << "指标名称,数值,单位\n";
|
|
|
|
|
|
metrics_file << "心率," << ppg_metrics["heart_rate"] << ",bpm\n";
|
|
|
|
|
|
metrics_file << "血氧饱和度," << ppg_metrics["spo2"] << ",%\n";
|
|
|
|
|
|
metrics_file << "灌注指数," << ppg_metrics["perfusion_index"] << ",%\n";
|
|
|
|
|
|
metrics_file << "脉搏波宽度," << ppg_metrics["pulse_width"] << ",ms\n";
|
|
|
|
|
|
metrics_file << "红光红外光比值," << ppg_metrics["amplitude_ratio"] << ",无单位\n";
|
|
|
|
|
|
metrics_file << "信号质量评分," << ppg_metrics["signal_quality"] << ",%\n";
|
|
|
|
|
|
metrics_file << "均值," << ppg_metrics["mean"] << ",mV\n";
|
|
|
|
|
|
metrics_file << "标准差," << ppg_metrics["std_dev"] << ",mV\n";
|
|
|
|
|
|
metrics_file << "最小值," << ppg_metrics["min_value"] << ",mV\n";
|
|
|
|
|
|
metrics_file << "最大值," << ppg_metrics["max_value"] << ",mV\n";
|
|
|
|
|
|
metrics_file << "峰峰值," << ppg_metrics["peak_to_peak"] << ",mV\n";
|
|
|
|
|
|
metrics_file.close();
|
|
|
|
|
|
std::cout << "PPG指标已保存到 data_generated/ppg_a50_metrics.csv" << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 8. 显示关键指标
|
|
|
|
|
|
std::cout << "\n=== PPG数据处理完成 ===" << std::endl;
|
|
|
|
|
|
std::cout << "关键指标:" << std::endl;
|
|
|
|
|
|
std::cout << "- 心率: " << ppg_metrics["heart_rate"] << " bpm" << std::endl;
|
|
|
|
|
|
std::cout << "- 血氧饱和度: " << ppg_metrics["spo2"] << " %" << std::endl;
|
|
|
|
|
|
std::cout << "- 灌注指数: " << ppg_metrics["perfusion_index"] << " %" << std::endl;
|
|
|
|
|
|
std::cout << "- 信号质量: " << ppg_metrics["signal_quality"] << " %" << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "\n生成的文件:" << std::endl;
|
|
|
|
|
|
std::cout << "1. data_generated/ppg_a50_processed.csv - 预处理后的PPG数据" << std::endl;
|
|
|
|
|
|
std::cout << "2. data_generated/ppg_a50_metrics.csv - PPG生理指标" << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "\n按Enter键退出..." << std::endl;
|
|
|
|
|
|
std::cin.get();
|
|
|
|
|
|
|
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
|
std::cerr << "PPG数据处理错误: " << e.what() << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 11:56:50 +08:00
|
|
|
|
int main() {
|
2025-08-26 15:00:47 +08:00
|
|
|
|
|
2025-08-25 10:53:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 选择要运行的测试
|
|
|
|
|
|
std::cout << "请选择测试模式:" << std::endl;
|
|
|
|
|
|
std::cout << "1. 测试MIT-BIH数据处理" << std::endl;
|
|
|
|
|
|
std::cout << "2. 运行完整信号数据处理流程 (推荐)" << std::endl;
|
2025-08-26 15:00:47 +08:00
|
|
|
|
std::cout << "3. 处理PPG数据 (A50伤后6h-1.txt)" << std::endl;
|
|
|
|
|
|
std::cout << "请输入选择 (1, 2 或 3): ";
|
2025-08-25 10:53:22 +08:00
|
|
|
|
|
|
|
|
|
|
int choice;
|
|
|
|
|
|
std::cin >> choice;
|
|
|
|
|
|
|
|
|
|
|
|
if (choice == 1) {
|
2025-08-26 15:00:47 +08:00
|
|
|
|
|
2025-08-25 10:53:22 +08:00
|
|
|
|
} else if (choice == 2) {
|
|
|
|
|
|
complete_signal_processing_pipeline(); // 运行完整信号数据处理流程
|
2025-08-26 15:00:47 +08:00
|
|
|
|
} else if (choice == 3) {
|
|
|
|
|
|
process_ppg_a50_data(); // 处理PPG数据
|
2025-08-25 10:53:22 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
std::cout << "无效选择,运行默认测试..." << std::endl;
|
2025-08-26 15:00:47 +08:00
|
|
|
|
|
2025-08-25 10:53:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 11:56:50 +08:00
|
|
|
|
return 0;
|
2025-08-14 11:16:24 +08:00
|
|
|
|
}
|