medical_SDK/main.cpp

386 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "headfile.h"
#include <fstream>
#include <sstream>
#include <ctime>
#include <windows.h> // 引入 Windows API 头文件
std::vector<float> heart_rate;
// 辅助函数:获取数据类型名称
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 "未知类型";
}
}
// 新增:完整的信号数据处理流程 - 整合所有步骤
void complete_signal_processing_pipeline() {
try {
std::cout << "=== 开始完整的信号数据处理流程 ===" << std::endl;
// 1. 读取原始二进制文件
std::cout << "步骤1: 读取原始数据..." << std::endl;
std::vector<uint8_t> file_content = FileManager::readBinaryFile("raw_data/ecg_data_raw.dat");
std::cout << "原始文件大小: " << file_content.size() << " 字节" << std::endl;
// 2. 解析设备数据包
std::cout << "步骤2: 解析设备数据包..." << std::endl;
std::vector<SensorData> all_data = parse_device_data(file_content);
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;
}
}
// 保存映射后的数据
save_to_csv(all_data, "data_generated/channel_data_mapped_.csv");
std::cout << "通道映射完成,结果已保存到 data_generated/channel_data_mapped_.csv" << std::endl;
// 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;
}
// 保存预处理后的数据
save_to_csv(processed_data, "data_generated/channel_data_processed_.csv");
std::cout << "预处理后的数据已保存到 data_generated/channel_data_processed_.csv" << std::endl;
// 5. 指标计算
std::cout << "步骤5: 计算生理指标..." << std::endl;
MetricsCalculator calculator;
const float sample_rate = 250.0f;
// 创建详细指标文件
std::ofstream metrics_file("data_generated/calculated_metrics_detailed.csv");
if (!metrics_file.is_open()) {
std::cerr << "无法创建指标保存文件" << std::endl;
return;
}
// 写入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";
}
metrics_file.close();
std::cout << "指标计算完成,结果已保存到 calculated_metrics_detailed.csv" << std::endl;
// 6. 创建指标汇总文件
std::cout << "步骤6: 生成指标汇总..." << std::endl;
std::ofstream summary_file("data_generated/metrics_summary.csv");
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;
}
std::cin.get();
// 7. 流程完成总结
std::cout << "\n=== 完整信号数据处理流程完成 ===" << std::endl;
std::cout << "生成的文件:" << std::endl;
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;
std::cin.get();
} catch (const std::exception& e) {
std::cerr << "完整流程执行错误: " << e.what() << std::endl;
}
}
// 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;
}
}
int main() {
SetConsoleOutputCP(CP_UTF8);
// 选择要运行的测试
std::cout << "请选择测试模式:" << std::endl;
std::cout << "1. 测试MIT-BIH数据处理" << std::endl;
std::cout << "2. 运行完整信号数据处理流程 (推荐)" << std::endl;
std::cout << "3. 处理PPG数据 (A50伤后6h-1.txt)" << std::endl;
std::cout << "请输入选择 (1, 2 或 3): ";
int choice;
std::cin >> choice;
if (choice == 1) {
} else if (choice == 2) {
complete_signal_processing_pipeline(); // 运行完整信号数据处理流程
} else if (choice == 3) {
process_ppg_a50_data(); // 处理PPG数据
} else {
std::cout << "无效选择,运行默认测试..." << std::endl;
}
return 0;
}