2025-07-28 11:56:50 +08:00
|
|
|
#include "headfile.h"
|
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
|
|
|
|
|
|
|
|
void test_mit_bih() {
|
|
|
|
|
try {
|
|
|
|
|
// 读取MIT-BIH数据文件
|
|
|
|
|
std::vector<uint8_t> file_content = FileManager::readBinaryFile("C:/Users/29096/Desktop/work/mit-bih-arrhythmia-database-1.0.0/222.dat");
|
|
|
|
|
|
|
|
|
|
// 解析数据
|
|
|
|
|
std::vector<SensorData> all_data = parse_device_data(file_content);
|
|
|
|
|
|
|
|
|
|
// 保存结果
|
|
|
|
|
save_to_csv(all_data, "mit_bih_output.csv");
|
|
|
|
|
|
|
|
|
|
std::cout << "MIT-BIH数据处理完成" << std::endl;
|
|
|
|
|
std::cout << "Press Enter to exit..." << std::endl;
|
|
|
|
|
std::cin.get();
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
std::cerr << "处理错误: " << e.what() << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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-07-29 15:21:28 +08:00
|
|
|
std::vector<uint8_t> file_content = FileManager::readBinaryFile("C:/Users/29096/Documents/WeChat Files/wxid_sh93l5lycr8b22/FileStorage/File/2025-07/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-14 11:16:24 +08:00
|
|
|
save_to_csv(all_data, "channel_data_mapped_.csv");
|
2025-08-25 10:53:22 +08:00
|
|
|
std::cout << "通道映射完成,结果已保存到 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, "channel_data_processed_.csv");
|
|
|
|
|
std::cout << "预处理后的数据已保存到 channel_data_processed_.csv" << std::endl;
|
|
|
|
|
|
|
|
|
|
// 5. 指标计算
|
|
|
|
|
std::cout << "步骤5: 计算生理指标..." << std::endl;
|
|
|
|
|
MetricsCalculator calculator;
|
|
|
|
|
const float sample_rate = 250.0f;
|
|
|
|
|
|
|
|
|
|
// 创建详细指标文件
|
|
|
|
|
std::ofstream metrics_file("calculated_metrics_detailed.csv");
|
|
|
|
|
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;
|
|
|
|
|
std::ofstream summary_file("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;
|
|
|
|
|
}
|
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;
|
|
|
|
|
std::cout << "1. channel_data_mapped_.csv - 通道映射后的数据" << std::endl;
|
|
|
|
|
std::cout << "2. channel_data_processed_.csv - 预处理后的数据" << std::endl;
|
|
|
|
|
std::cout << "3. calculated_metrics_detailed.csv - 详细指标数据" << std::endl;
|
|
|
|
|
std::cout << "4. 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-07-28 11:56:50 +08:00
|
|
|
int main() {
|
|
|
|
|
SetConsoleOutputCP(CP_UTF8);
|
2025-08-25 10:53:22 +08:00
|
|
|
|
|
|
|
|
// 选择要运行的测试
|
|
|
|
|
std::cout << "请选择测试模式:" << std::endl;
|
|
|
|
|
std::cout << "1. 测试MIT-BIH数据处理" << std::endl;
|
|
|
|
|
std::cout << "2. 运行完整信号数据处理流程 (推荐)" << std::endl;
|
|
|
|
|
std::cout << "请输入选择 (1 或 2): ";
|
|
|
|
|
|
|
|
|
|
int choice;
|
|
|
|
|
std::cin >> choice;
|
|
|
|
|
|
|
|
|
|
if (choice == 1) {
|
|
|
|
|
test_mit_bih(); // 测试MIT-BIH数据处理
|
|
|
|
|
} else if (choice == 2) {
|
|
|
|
|
complete_signal_processing_pipeline(); // 运行完整信号数据处理流程
|
|
|
|
|
} else {
|
|
|
|
|
std::cout << "无效选择,运行默认测试..." << std::endl;
|
|
|
|
|
test_mit_bih();
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-28 11:56:50 +08:00
|
|
|
return 0;
|
2025-08-14 11:16:24 +08:00
|
|
|
}
|