From 3854ac2aa32c68cf9c5b21bab1aa4d54fd882110 Mon Sep 17 00:00:00 2001 From: ZhangJinLong <19357383190@163.com> Date: Mon, 28 Jul 2025 11:56:50 +0800 Subject: [PATCH] first commit --- .vscode/c_cpp_properties.json | 21 + .vscode/launch.json | 32 ++ .vscode/settings.json | 52 ++ .vscode/tasks.json | 36 ++ 1.txt | 2 + include/File_manage.h | 8 + include/Generate_data.h | 33 ++ include/data_mapper.h | 19 + include/data_output.h | 5 + include/data_receiver.h | 6 + include/device_praser.h | 24 + include/feature_extractor.h | 51 ++ include/headfile.h | 30 ++ include/signal_processor.h | 156 ++++++ include/test.h | 7 + include/types.h | 48 ++ main.cpp | 61 +++ src/Tool/File_manage.cpp | 20 + src/data_output/rest_api_output.cpp | 0 src/data_receiver/data_mapper.cpp | 232 +++++++++ .../protocol_adapter/device_praser.cpp | 357 ++++++++++++++ src/data_test/Generate_data.cpp | 456 ++++++++++++++++++ src/signal_processor/feature_extractor.cpp | 343 +++++++++++++ src/signal_processor/signal_processor.cpp | 442 +++++++++++++++++ src/test.cpp | 9 + 25 files changed, 2450 insertions(+) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 1.txt create mode 100644 include/File_manage.h create mode 100644 include/Generate_data.h create mode 100644 include/data_mapper.h create mode 100644 include/data_output.h create mode 100644 include/data_receiver.h create mode 100644 include/device_praser.h create mode 100644 include/feature_extractor.h create mode 100644 include/headfile.h create mode 100644 include/signal_processor.h create mode 100644 include/test.h create mode 100644 include/types.h create mode 100644 main.cpp create mode 100644 src/Tool/File_manage.cpp create mode 100644 src/data_output/rest_api_output.cpp create mode 100644 src/data_receiver/data_mapper.cpp create mode 100644 src/data_receiver/protocol_adapter/device_praser.cpp create mode 100644 src/data_test/Generate_data.cpp create mode 100644 src/signal_processor/feature_extractor.cpp create mode 100644 src/signal_processor/signal_processor.cpp create mode 100644 src/test.cpp diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..8a517c7 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,21 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/include", + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "compilerPath": "C:\\Users\\29096\\Downloads\\x86_64-8.1.0-release-posix-seh-rt_v6-rev0\\mingw64\\bin\\gcc.exe", + "cStandard": "c17", + "cppStandard": "gnu++17", + "intelliSenseMode": "windows-gcc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..2cce4e7 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Launch", // 配置名称,将会在启动配置的下拉菜单中显示 + "type": "cppdbg", // 配置类型,这里只能为cppdbg + "request": "launch", // 请求配置类型,可以为launch(启动)或attach(附加) + "program": "${workspaceRoot}/${fileBasenameNoExtension}.exe",// 将要进行调试的程序的路径 + "args": [], // 程序调试时传递给程序的命令行参数,一般设为空即可 + "stopAtEntry": false, // 设为true时程序将暂停在程序入口处,一般设置为false + "cwd": "${workspaceRoot}",// 调试程序时的工作目录,一般为${workspaceRoot}即代码所在目录 + "environment": [], + "externalConsole": true,// 调试时是否显示控制台窗口,一般设置为true显示控制台 + "MIMode": "gdb", + "miDebuggerPath": "C:/Users/29096/Downloads/x86_64-8.1.0-release-posix-seh-rt_v6-rev0/mingw64/bin/gdb.exe",// miDebugger的路径,注意这里要与MinGw的路径对应 + "preLaunchTask": "C/C++: g++.exe 生成活动文件", // 调试会话开始前执行的任务,一般为编译程序,c++为g++, c为gcc + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + + ] + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..60291ae --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,52 @@ +{ + "files.associations": { + "ostream": "cpp", + "iostream": "cpp", + "vector": "cpp", + "variant": "cpp", + "array": "cpp", + "atomic": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "unordered_map": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "optional": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "typeinfo": "cpp", + "functional": "cpp", + "iterator": "cpp", + "numeric": "cpp", + "random": "cpp", + "ctime": "cpp", + "iomanip": "cpp", + "map": "cpp" + }, + "C_Cpp.errorSquiggles": "disabled" +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..c67f460 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,36 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: g++.exe 生成活动文件", + "command": "C:\\Users\\29096\\Downloads\\x86_64-8.1.0-release-posix-seh-rt_v6-rev0\\mingw64\\bin\\g++.exe", + "args": [ + "-fdiagnostics-color=always", + "-g", + "-mconsole", + "-std=gnu++17", // 添加这一行,使用 C++17 标准 + "${workspaceFolder}/main.cpp", + "${workspaceFolder}/src/*.cpp", + "${workspaceFolder}/src/Tool/*.cpp", + "${workspaceFolder}/src/data_test/*.cpp", + "${workspaceFolder}/src/data_output/*.cpp", + "${workspaceFolder}/src/data_receiver/*.cpp", + "${workspaceFolder}/src/data_receiver/protocol_adapter/*.cpp", + "${workspaceFolder}/src/signal_processor/*.cpp", + "-I", "${workspaceFolder}/include", + "-o", + "${fileDirname}\\${fileBasenameNoExtension}.exe" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": ["$gcc"], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "调试器生成的任务。" + } + ] +} \ No newline at end of file diff --git a/1.txt b/1.txt new file mode 100644 index 0000000..ff03742 --- /dev/null +++ b/1.txt @@ -0,0 +1,2 @@ +1 2 3 4 5 6 7 +sxsd \ No newline at end of file diff --git a/include/File_manage.h b/include/File_manage.h new file mode 100644 index 0000000..45131bb --- /dev/null +++ b/include/File_manage.h @@ -0,0 +1,8 @@ +#ifndef _FILE_MANAGE_H +#define _FILE_MANAGE_H +#include "headfile.h" +class FileManager { +public: + static std::vector readBinaryFile(const std::string& filename); // 读取二进制文件 +}; +#endif \ No newline at end of file diff --git a/include/Generate_data.h b/include/Generate_data.h new file mode 100644 index 0000000..004b3a1 --- /dev/null +++ b/include/Generate_data.h @@ -0,0 +1,33 @@ +// Generate_data.h +#ifndef GENERATE_DATA_H +#define GENERATE_DATA_H + +#include "headfile.h" + +// 模板函数声明 +template +T random_value(T min, T max); + +// 生成符合脑电设备格式的测试数据(0x4230) +std::vector generate_eeg_test_data(); + +// 生成符合胸腹设备格式的测试数据(0x4211) +std::vector generate_ecg_emg_test_data(); + +// 生成符合血氧设备格式的测试数据(0x4302) +std::vector generate_ppg_test_data(); + +// 生成符合12导联心电设备格式的测试数据(0x4402) +std::vector generate_12lead_ecg_test_data(); + +// 生成符合数字听诊设备格式的测试数据(0x1102) +std::vector generate_stethoscope_test_data(); + +// 生成符合鼾声设备格式的测试数据(0x4212) +std::vector generate_snore_test_data(); + +// 生成符合呼吸/姿态/环境光设备格式的测试数据(0x4213) +std::vector generate_respiration_test_data(); + +void print_parsed_result(const SensorData& result); +#endif // GENERATE_DATA_H \ No newline at end of file diff --git a/include/data_mapper.h b/include/data_mapper.h new file mode 100644 index 0000000..1f73399 --- /dev/null +++ b/include/data_mapper.h @@ -0,0 +1,19 @@ +#ifndef _DATA_MAPPER_H +#define _DATA_MAPPER_H +#include "headfile.h" +class Mapper +{ +private: + +public: +SensorData DataMapper(SensorData& data); +SensorData EEG_Data_Mapper(SensorData& data); +SensorData ECG_2LEAD_Data_Mapper(SensorData& data); +SensorData ECG_12LEAD_Data_Mapper(SensorData& data); +SensorData PPG_Data_Mapper(SensorData& data); +SensorData Respiration_Data_Mapper(SensorData& data); +SensorData Snore_Data_Mapper(SensorData& data); +SensorData Stethoscope_Data_Mapper(SensorData& data); + +}; +#endif \ No newline at end of file diff --git a/include/data_output.h b/include/data_output.h new file mode 100644 index 0000000..3e0c7a9 --- /dev/null +++ b/include/data_output.h @@ -0,0 +1,5 @@ +#ifndef _DATA_OUTPUT_H_ +#define _DATA_OUTPUT_H_ +#include "headfile.h" +#endif + \ No newline at end of file diff --git a/include/data_receiver.h b/include/data_receiver.h new file mode 100644 index 0000000..1d1ba68 --- /dev/null +++ b/include/data_receiver.h @@ -0,0 +1,6 @@ +#ifndef _DATA_RECEIVER_h_ +#define _DATA_RECEIVER_h_ +#include "headfile.h" + +#endif + \ No newline at end of file diff --git a/include/device_praser.h b/include/device_praser.h new file mode 100644 index 0000000..9ea998b --- /dev/null +++ b/include/device_praser.h @@ -0,0 +1,24 @@ +#ifndef _DEVICE_PRASER_H_ +#define _DEVICE_PRASER_H_ + +#include +#include +#include "headfile.h" + +// 辅助函数:将数值转换为十六进制字符串 +inline std::string to_hex_string(uint16_t value) { + char buffer[5]; + snprintf(buffer, sizeof(buffer), "%04X", value); + return std::string(buffer); +} + +SensorData parse_ppg(const uint8_t* data); +SensorData parse_eeg(const uint8_t* data); +SensorData parse_ecg_emg(const uint8_t* data); +SensorData parse_12lead_ecg(const uint8_t* data); +SensorData parse_stethoscope(const uint8_t* data); +SensorData parse_snore(const uint8_t* data); +SensorData parse_respiration(const uint8_t* data); +std::vector parse_device_data(const std::vector& file_data); + +#endif \ No newline at end of file diff --git a/include/feature_extractor.h b/include/feature_extractor.h new file mode 100644 index 0000000..817b0fc --- /dev/null +++ b/include/feature_extractor.h @@ -0,0 +1,51 @@ +#ifndef _FEATURE_EXTRACTOR_H +#define _FEATURE_EXTRACTOR_H +#include "headfile.h" + +// ECG特征结构体 +struct ECGFeatures { + float heart_rate = 0.0f; // 心率 (bpm) + float qrs_duration = 0.0f; // QRS波群时长 (ms) + float qt_interval = 0.0f; // QT间期 (ms) + float qtc_interval = 0.0f; // 校正的QT间期 (ms) + std::vector st_segment; // ST段偏移值 (mV) + float p_wave_amplitude = 0.0f; // P波振幅 (mV) + float t_wave_amplitude = 0.0f; // T波振幅 (mV) +}; + +// PPG特征结构体 +struct PPGFeatures { + float heart_rate = 0.0f; // 心率 (bpm) + float perfusion_index = 0.0f; // 灌注指数 (PI) + float pulse_width = 0.0f; // 脉搏波宽度 (ms) + float amplitude_ratio = 0.0f; // 红光/红外光振幅比 + float spo2 = 0.0f; // 血氧饱和度 (%) +}; + +// 特征提取器类 +class FeatureExtractor { +public: + // ECG特征提取 + static ECGFeatures extract_ecg_features(const std::vector& ecg_signal, + double sample_rate, + int lead_index = -1); + + // PPG特征提取 + static PPGFeatures extract_ppg_features(const std::vector& red_signal, + const std::vector& ir_signal, + double sample_rate); + + // 心率变异性(HRV)分析 + static std::vector analyze_hrv(const std::vector& rr_intervals, + double sample_rate); + +private: + // QRS波群检测 + static std::vector detect_qrs(const std::vector& ecg_signal, + double sample_rate); + + // PPG峰值检测 + static std::vector detect_ppg_peaks(const std::vector& ppg_signal, + double sample_rate); +}; +#endif \ No newline at end of file diff --git a/include/headfile.h b/include/headfile.h new file mode 100644 index 0000000..5118307 --- /dev/null +++ b/include/headfile.h @@ -0,0 +1,30 @@ +#ifndef _HEADFILE_H +#define _HEADFILE_H +#include "test.h" +#include "data_receiver.h" +#include +#include +#include +#include +#include "types.h" +#include "signal_processor.h" +#include "data_output.h" +#include +#include +#include "device_praser.h" +#include "data_mapper.h" +#include // 引入 Windows API 头文件 +#include +#include +#include +#include +#include +#include +#include "Generate_data.h" +#include +#include "File_manage.h" +#include +#include +#include "feature_extractor.h" +#include // for std::pair +#endif \ No newline at end of file diff --git a/include/signal_processor.h b/include/signal_processor.h new file mode 100644 index 0000000..f2ba6fe --- /dev/null +++ b/include/signal_processor.h @@ -0,0 +1,156 @@ +#ifndef _SIGNAL_PROCESSOR_H_ +#define _SIGNAL_PROCESSOR_H_ + +#include "headfile.h" +#include +#include +#include +// 滤波类型 +enum class filtertype +{ + lowpass,highpass,notchpass,bandpass,bandstop +}; +// 特征数据结构 +struct ECGChannelFeatures { + std::vector r_peaks; // R波位置 + float sdnn = 0.0f; // RR间期标准差 + float rmssd = 0.0f; // RR间期差值的均方根 +}; + +struct FeatureSet { + std::vector ecg_features; + // 其他设备的特征结构... +}; + +// 生理指标数据结构 +struct ECGIndicators { + float heart_rate = 0.0f; // 心率 (bpm) + float sdnn = 0.0f; // 心率变异性指标 + float rmssd = 0.0f; // 心率变异性指标 + float st_elevation = 0.0f; // ST段抬高 (mV) + float st_depression = 0.0f; // ST段压低 (mV) +}; + +struct PPGIndicators { + float spo2 = 0.0f; // 血氧饱和度 + float pi = 0.0f; // 灌注指数 + float pulse_rate = 0.0f; // 脉率 +}; + +struct EEGIndicators { + float alpha_power = 0.0f; // Alpha波功率 + float beta_power = 0.0f; // Beta波功率 + float attention = 0.0f; // 注意力指数 +}; + +struct IndicatorSet { + float sqi = 0.0f; // 信号质量指数 (0.0-1.0) + std::vector ecg_indicators; + std::vector ppg_indicators; + std::vector eeg_indicators; +}; + +// 滤波器配置 +struct FilterConfig { + std::string type; + double cutoff_frequency = 0.0; + double Q_factor = 0.0; + double low_cutoff = 0.0; + double high_cutoff = 0.0; +}; + +class SignalProcessor { +public: + // 预处理信号 + SensorData preprocess_signals(const SensorData& raw_data); // 使用DataType枚举 + SensorData preprocess_generic(const SensorData& data); + // 特征提取 + FeatureSet extract_signal_features(const SensorData& processed_data, + const std::vector& features = {}); + + // 计算生理指标 + IndicatorSet compute_physiological_indicators(const FeatureSet& features, + const std::vector& indicators = {}); + + // 获取处理流水线配置 + std::string getProcessingPipeline(DataType device_type); // 使用DataType枚举 + + // 设置滤波器参数 + void setFilterParams(const std::string& filter_type, const FilterConfig& params); + + + // 修改为public访问权限 + public: + SensorData preprocess_ecg_12lead(const SensorData& data); + SensorData preprocess_eeg(const SensorData& data); + SensorData preprocess_ecg_2lead(const SensorData& data); + SensorData preprocess_ppg(const SensorData& data); + SensorData preprocess_respiration(const SensorData& data); + SensorData preprocess_snore(const SensorData& data); + SensorData preprocess_stethoscope(const SensorData& data); + + // 设备特定的特征提取 + FeatureSet extract_eeg_features(const SensorData& data); + FeatureSet extract_ecg_features(const SensorData& data); + FeatureSet extract_ppg_features(const SensorData& data); + FeatureSet extract_respiration_features(const SensorData& data); + FeatureSet extract_snore_features(const SensorData& data); + FeatureSet extract_stethoscope_features(const SensorData& data); + + // 滤波器配置 + std::map filter_configs_; + + // 滤波器状态 + struct FilterState { + std::vector x_history; + std::vector y_history; + }; + std::map filter_states_; + + // 在SignalProcessor类中添加 +public: +// 带通滤波器实现 + std::vector bandpass_filter(const std::vector& input, + double sample_rate, + double low_cutoff, + double high_cutoff); + std::vector Lowpass_filter(const std::vector& input, + double sample_rate, + double low_cutoff) ; + + std::vector filter(const std::vector& input, + double sample_rate, + double low_cutoff, + double high_cutoff, + filtertype type); + std::vector Highpass_filter(const std::vector& input, + double sample_rate, + double high_cutoff); + std::vector compensate_motion_artifact(const std::vector& ppg, + const std::vector& motion); + std::vector compensate_eog_artifact(const std::vector& eeg, + const std::vector& eog1, + const std::vector& eog2) ; + // 添加自适应陷波滤波器声明 + std::vector adaptive_notch_filter(const std::vector& input, + double sample_rate, + double target_freq, + double bandwidth) ; + std::vector bandstop_filter(const std::vector& input, + double sample_rate, + double low_cutoff, + double high_cutoff); + + // 添加通用预处理辅助函数 + std::vector remove_dc_offset(const std::vector& signal); + std::vector apply_gain(const std::vector& signal, float gain); + float calculate_correlation(const std::vector& x, const std::vector& y); + float calculate_snr(const std::vector& signal); + float calculate_PPG_sqi(const std::vector& red_channel, + const std::vector& ir_channel); + float calculate_ecg_sqi(const std::vector& signal, double sample_rate); +}; + + +#endif + \ No newline at end of file diff --git a/include/test.h b/include/test.h new file mode 100644 index 0000000..2a0c25b --- /dev/null +++ b/include/test.h @@ -0,0 +1,7 @@ +#ifndef _TEST_h_ +#define _TEST_H_ + +#include +void myprint(); + +#endif diff --git a/include/types.h b/include/types.h new file mode 100644 index 0000000..7201996 --- /dev/null +++ b/include/types.h @@ -0,0 +1,48 @@ +#ifndef _TYPES_h_ +#define _TYPES_h_ + +#include "headfile.h" +#pragma once + +// 设备类型枚举 +enum class DataType { + EEG, // 脑电 + ECG_2LEAD, // 胸腹心电/肌电 + ECG_12LEAD, // 12导联心电 + PPG, // 血氧 + RESPIRATION, // 呼吸/姿态 + SNORE, // 鼾声 + STETHOSCOPE // 数字听诊 +}; + +// 导联脱落状态 +struct LeadOffStatus { + uint8_t status[2]; // 导联状态字节 +}; + +// 统一传感器数据结构 +struct SensorData { + DataType data_type; + uint16_t packet_sn; // 数据包序列号 + LeadOffStatus lead_status; // 导联状态 + int64_t timestamp; // 系统时间戳(微秒) + float sqi; //信号质量 + + // 通道数据 + std::variant< + std::vector, // 单通道数据 + std::vector> // 多通道数据 + > channel_data; + std::vector raw_data; // 原始二进制数据 + // 附加数据 + struct { + uint16_t movement; // 运动强度 (呼吸设备) + uint8_t posture; // 姿态 (呼吸设备) + uint8_t ambient_light; // 环境光 (呼吸设备) + uint8_t hr; // 心率 (血氧) + uint8_t spo2; // 血氧饱和度 (血氧) + float temperature; // 温度 (修正为浮点类型) + uint8_t gpio_state; // GPIO状态 (12导联心电) + } additional; +}; +#endif \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..2040092 --- /dev/null +++ b/main.cpp @@ -0,0 +1,61 @@ +#include "headfile.h" +// 辅助函数:打印多通道数据 +void print_multi_channel(const std::vector>& channels) { + for (size_t ch = 0; ch < channels.size(); ++ch) { + std::cout << " Channel " << ch << ": "; + for (size_t i = 0; i < channels[ch].size(); ++i) { + std::cout << std::fixed << std::setprecision(2) << channels[ch][i] << " "; + } + std::cout << std::endl; + } +} + +// 辅助函数:打印通道数据 +void print_channel_data(const std::variant, std::vector>>& channel_data) { + if (std::holds_alternative>(channel_data)) { + const auto& single_channel = std::get>(channel_data); + } else if (std::holds_alternative>>(channel_data)) { + const auto& multi_channel = std::get>>(channel_data); + print_multi_channel(multi_channel); + } +} +void test_try() { + try { + // 1. 读取原始二进制文件 + std::vector file_content = FileManager::readBinaryFile("C:/Users/29096/Desktop/work/data1.dat"); + Mapper mapper; + // 2. 解析设备数据包 - 需要实现此函数 + std::vector all_data = parse_device_data(file_content); + // 3. 创建信号处理器实例 + SignalProcessor processor; + // 4. 遍历所有数据包 + for (auto& data : all_data) { + // 打印原始数据信息 + // print_parsed_result(data); // 需要实现此函数 + std::cout << "Before mapping (ECG-12):" << std::endl; + std::cout << "Packet SN: " << data.packet_sn << ", Data Type: " << static_cast(data.data_type) << std::endl; + + SensorData mapped_ecg_12lead = mapper.DataMapper(data); + SensorData processed_ecg_12_lead = processor.preprocess_signals(mapped_ecg_12lead); + std::cout << "After mapping (ECG-12):" << std::endl; + std::cout << "Packet SN: " << mapped_ecg_12lead.packet_sn << ", Data Type: " << static_cast(mapped_ecg_12lead.data_type) << std::endl; + print_channel_data(mapped_ecg_12lead.channel_data); + std::cout << "After processed (ECG-12):" << std::endl; + std::cout << "Packet SN: " << mapped_ecg_12lead.packet_sn << ", Data Type: " << static_cast(mapped_ecg_12lead.data_type) << std::endl; + print_channel_data(processed_ecg_12_lead.channel_data); + } + + }catch (const std::exception& e) { + std::cerr << "解析错误: " << e.what() << std::endl; + std::cout << "Press Enter to exit..." << std::endl; + std::cin.get(); + return ; + } + std::cout << "Press Enter to exit..." << std::endl; + std::cin.get(); +} +int main() { + SetConsoleOutputCP(CP_UTF8); + test_try(); + return 0; +} diff --git a/src/Tool/File_manage.cpp b/src/Tool/File_manage.cpp new file mode 100644 index 0000000..de6f2f6 --- /dev/null +++ b/src/Tool/File_manage.cpp @@ -0,0 +1,20 @@ +#include "File_manage.h" +std::vector FileManager::readBinaryFile(const std::string& filename) { + std::ifstream file(filename, std::ios::binary | std::ios::ate); + if (!file) { + throw std::runtime_error("文件打开失败: " + filename); + } + + // 获取文件大小 + std::streamsize size = file.tellg(); + file.seekg(0, std::ios::beg); + + // 读取二进制数据到vector + std::vector buffer(size); + if (!file.read(reinterpret_cast(buffer.data()), size)) { + throw std::runtime_error("文件读取失败: " + filename); + } + + // 返回整个vector而不是裸指针 + return buffer; +} diff --git a/src/data_output/rest_api_output.cpp b/src/data_output/rest_api_output.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/data_receiver/data_mapper.cpp b/src/data_receiver/data_mapper.cpp new file mode 100644 index 0000000..324e42b --- /dev/null +++ b/src/data_receiver/data_mapper.cpp @@ -0,0 +1,232 @@ +#include "data_mapper.h" +SensorData Mapper::DataMapper(SensorData& data) +{ + SensorData data_mapped; + data_mapped = data; + switch(data_mapped.data_type){ + case DataType::EEG : + data_mapped = EEG_Data_Mapper(data_mapped);break; + case DataType::ECG_2LEAD: + data_mapped = ECG_2LEAD_Data_Mapper(data_mapped);break; + case DataType::ECG_12LEAD: + data_mapped = ECG_12LEAD_Data_Mapper(data_mapped);break; + case DataType::PPG: + data_mapped = PPG_Data_Mapper(data_mapped);break; + case DataType::RESPIRATION: + data_mapped = Respiration_Data_Mapper(data_mapped);break; + case DataType::SNORE: + data_mapped = Snore_Data_Mapper(data_mapped);break; + case DataType::STETHOSCOPE: + data_mapped = Stethoscope_Data_Mapper(data_mapped);break; + default: + break; + } + return data_mapped; + +}; +SensorData Mapper::EEG_Data_Mapper(SensorData& data) +{ + SensorData processed; + processed = data; + const size_t min_raw_data_length = 4*sizeof(uint16_t) + 8*14*sizeof(int16_t); + if(processed.raw_data.size()(processed.raw_data.data()); + const int16_t (*read_channels)[14] = reinterpret_cast(p+4); + std::vector> channels(8); + for(auto& ch:channels) ch.resize(14); + for(int i = 0;i<8 ;i++) + { + for(int j = 0;j<14;j++) channels[i][j] = read_channels[i][j]*0.318;//0-5 eeg ,6-7 eog. + } + + processed.channel_data = channels; + return data; +} +// 胸腹设备数据映射器 +SensorData Mapper::ECG_2LEAD_Data_Mapper(SensorData& data) { + // 创建处理后的数据结构 + SensorData processed = data; + + // 检查原始数据长度 + const size_t min_raw_data_length = 238; + if (processed.raw_data.size() < min_raw_data_length) { + throw std::runtime_error("Raw data length is insufficient for ECG_2LEAD mapping"); + } + + // 获取原始通道数据 + auto& input_channels = std::get>>(data.channel_data); + + // 创建7通道输出结构 + std::vector> output_channels; + output_channels.resize(7); + + // 前4个通道直接映射 (ECG1, ECG2, EMG1, EMG2) + for (int i = 0; i < 4; ++i) { + if (i < input_channels.size()) { + output_channels[i] = input_channels[i]; + } + } + + // 第5通道: 呼吸温度 (取完整5个采样点) + if (input_channels.size() > 4) { + output_channels[4] = input_channels[4]; + } + + // 第6通道: 呼吸阻抗1 (取完整5个采样点) + if (input_channels.size() > 5) { + output_channels[5] = input_channels[5]; + } + + // 第7通道: 呼吸阻抗2 (取完整5个采样点) + if (input_channels.size() > 6) { + output_channels[6] = input_channels[6]; + } + + // 更新处理后的通道数据 + processed.channel_data = output_channels; + + return processed; +} +SensorData Mapper::ECG_12LEAD_Data_Mapper(SensorData& data) +{ + // 直接使用原始数据指针操作 + const uint8_t* raw = data.raw_data.data(); + if (data.raw_data.size() < 232) { + throw std::runtime_error("Raw data length is insufficient"); + } + + // 跳过头部信息 (packet_sn + data_type + data_len + lead_status) + const int16_t* ecg_data = reinterpret_cast(raw + 8); + + // 创建12导联数据结构 + std::vector> channels(12, std::vector(14)); + + // 处理前8个通道 + for (int ch = 0; ch < 8; ++ch) { + for (int sample = 0; sample < 14; ++sample) { + channels[ch][sample] = ecg_data[ch * 14 + sample] * 0.318f; + } + } + + // 计算标准导联 + for (int sample = 0; sample < 14; ++sample) { + float RA = channels[0][sample]; // 右臂 + float LA = channels[1][sample]; // 左臂 + float LL = channels[2][sample]; // 左腿 + + channels[0][sample] = LA - RA; // I导联 + channels[1][sample] = LL - RA; // II导联 + channels[2][sample] = LL - LA; // III导联 + } + + // 计算加压肢体导联 + for (int sample = 0; sample < 14; ++sample) { + float lead_I = channels[0][sample]; + float lead_II = channels[1][sample]; + + channels[9][sample] = -0.5f * (lead_I + lead_II); // aVR + channels[10][sample] = lead_I - 0.5f * lead_II; // aVL + channels[11][sample] = lead_II - 0.5f * lead_I; // aVF + } + + // 更新处理后的数据 + SensorData processed = data; + processed.channel_data = channels; + return processed; +} + +SensorData Mapper::PPG_Data_Mapper(SensorData& data) +{ + SensorData processed = data; // 复制原始数据 + + // 检查原始数据长度(根据文档总长度238字节) + const size_t min_raw_data_length = 238; + if (processed.raw_data.size() < min_raw_data_length) { + throw std::runtime_error("Raw data length is insufficient for PPG mapping"); + } + + // 检查通道数据类型 + if (!std::holds_alternative>>(data.channel_data)) { + throw std::runtime_error("Invalid channel data format for PPG"); + } + + // 获取输入通道数据 + auto& input_channels = std::get>>(data.channel_data); + + // 确保有足够的通道 + if (input_channels.size() < 2) { + throw std::runtime_error("Input channel data for PPG has less than 2 channels"); + } + + // 创建输出通道数据 + std::vector> output(2); + + // 通道0: 红光数据 (57个采样点) + if (input_channels[0].size() >= 57) { + output[0] = std::vector(input_channels[0].begin(), input_channels[0].begin() + 57); + } else { + throw std::runtime_error("Red channel data length is insufficient"); + } + + // 通道1: 红外光数据 (57个采样点) + if (input_channels[1].size() >= 57) { + output[1] = std::vector(input_channels[1].begin(), input_channels[1].begin() + 57); + } else { + throw std::runtime_error("IR channel data length is insufficient"); + } + + // 更新处理后的通道数据 + processed.channel_data = output; + + return processed; +} +SensorData Mapper::Respiration_Data_Mapper(SensorData& data) +{ + SensorData processed = data; + size_t min_data_length = 238; + if(processed.raw_data.size()>>(data.channel_data); + std::vector> output(1); + output[0].resize(114); + output[0] = input_channels[0]; + processed.channel_data = output; + return processed; +} +SensorData Mapper::Snore_Data_Mapper(SensorData& data) +{ + // 检查数据类型 + if (!std::holds_alternative>(data.channel_data)) { + throw std::runtime_error("Invalid channel data format for SNORE"); + } + + // 获取原始通道数据 + auto& raw_samples = std::get>(data.channel_data); + + // 应用校准系数 (0.146 mV/unit) + std::vector calibrated; + calibrated.reserve(raw_samples.size()); + + for (float sample : raw_samples) { + calibrated.push_back(sample * 0.146f); + } + + // 更新处理后的数据 + SensorData processed = data; + processed.channel_data = calibrated; + return processed; +} +SensorData Mapper::Stethoscope_Data_Mapper(SensorData& data) +{ + SensorData processed = data; + size_t min_data_length = 238; + if(processed.raw_data.size()>>(data.channel_data); + std::vector> output(2); + output[0].resize(116); + output[1].resize(116); + output[0] = input_channels[0]; + output[1] = input_channels[1]; + processed.channel_data = output; + return processed; +} + diff --git a/src/data_receiver/protocol_adapter/device_praser.cpp b/src/data_receiver/protocol_adapter/device_praser.cpp new file mode 100644 index 0000000..12f9c2f --- /dev/null +++ b/src/data_receiver/protocol_adapter/device_praser.cpp @@ -0,0 +1,357 @@ +#include "headfile.h" +#include // 添加 memcpy 头文件 + +// 辅助函数:从字节数组读取小端整数 +template +T read_le(const uint8_t* data) { + T value = 0; + for (size_t i = 0; i < sizeof(T); ++i) { + value |= static_cast(data[i]) << (i * 8); + } + return value; +} + +// 脑电设备解析 (0x4230) +SensorData parse_eeg(const uint8_t* data) { + SensorData result; + result.data_type = DataType::EEG; + result.packet_sn = read_le(data); + + // 跳过 DataType(2) 和 data_len(2) + const uint8_t* payload = data + 6; + + // 导联状态 + std::memcpy(result.lead_status.status, payload, 2); + payload += 2; + + // 解析EEG数据 (6通道 × 14采样点) + auto& eeg_data = result.channel_data.emplace>>(); + eeg_data.resize(6); + + for (int ch = 0; ch < 6; ++ch) { + eeg_data[ch].reserve(14); + for (int i = 0; i < 14; ++i) { + int16_t adc_value = read_le(payload); + payload += 2; + eeg_data[ch].push_back(adc_value * 0.318f); // 转换为μV + } + } + + // 解析EOG数据 (2通道 × 14采样点) + for (int ch = 0; ch < 2; ++ch) { + eeg_data.push_back({}); // 添加新通道 + for (int i = 0; i < 14; ++i) { + int16_t adc_value = read_le(payload); + payload += 2; + eeg_data.back().push_back(adc_value * 0.318f); // 转换为μV + } + } + + // 跳过预留区 (6字节) + payload += 6; + + // 赋值原始二进制数据 + result.raw_data.assign(data, data + 6 + 2 + 6 * 14 * 2 + 2 * 14 * 2 + 6); + + return result; +} + +// 胸腹设备解析 (0x4211) +SensorData parse_ecg_emg(const uint8_t* data) { + SensorData result; + result.data_type = DataType::ECG_2LEAD; + result.packet_sn = read_le(data); + + // 跳过 data_type(2) 和 data_len(2) + const uint8_t* payload = data + 6; + + // 导联状态 + std::memcpy(result.lead_status.status, payload, 2); + payload += 2; + + // 解析数据 (多通道混合) + auto& channels = result.channel_data.emplace>>(); + + // ECG1 (25采样点) + channels.push_back({}); + for (int i = 0; i < 25; ++i) { + int16_t adc_value = read_le(payload); + payload += 2; + channels.back().push_back(adc_value * 0.318f); // μV + } + + // ECG2 (25采样点) + channels.push_back({}); + for (int i = 0; i < 25; ++i) { + int16_t adc_value = read_le(payload); + payload += 2; + channels.back().push_back(adc_value * 0.318f); // μV + } + + // EMG1 (25采样点) + channels.push_back({}); + for (int i = 0; i < 25; ++i) { + int16_t adc_value = read_le(payload); + payload += 2; + channels.back().push_back(adc_value * 0.318f); // μV + } + + // EMG2 (25采样点) + channels.push_back({}); + for (int i = 0; i < 25; ++i) { + int16_t adc_value = read_le(payload); + payload += 2; + channels.back().push_back(adc_value * 0.318f); // μV + } + + // 呼吸温度 (5采样点) + channels.push_back({}); + for (int i = 0; i < 5; ++i) { + int16_t temp_value = read_le(payload); + payload += 2; + channels.back().push_back(temp_value * 0.477f); // 存储所有采样点 + } + + // 呼吸阻抗1 (5采样点) + channels.push_back({}); + for (int i = 0; i < 5; ++i) { + int16_t imp_value = read_le(payload); + payload += 2; + channels.back().push_back(static_cast(imp_value)); // 原始值 + } + + // 呼吸阻抗2 (5采样点) + channels.push_back({}); + for (int i = 0; i < 5; ++i) { + int16_t imp_value = read_le(payload); + payload += 2; + channels.back().push_back(static_cast(imp_value)); // 原始值 + } + + // 赋值原始二进制数据 + result.raw_data.assign(data, data + 238); // 完整238字节 + + return result; +} + +// 血氧设备解析 (0x4302) +SensorData parse_ppg(const uint8_t* data) { + SensorData result; + result.data_type = DataType::PPG; + result.packet_sn = read_le(data); + + // 跳过 DataType(2) 和 data_len(2) + const uint8_t* payload = data + 6; + + // 读取生命体征 + result.additional.hr = *payload++; + result.additional.spo2 = *payload++; + + // 修正:温度值扩大100倍存储,需要除以100 + int16_t temp_raw = read_le(payload); + result.additional.temperature = static_cast(temp_raw) / 100.0f; + payload += 2; + + // 解析红光数据 (57采样点) + auto& channels = result.channel_data.emplace>>(); + channels.push_back({}); + for (int i = 0; i < 57; ++i) { + int16_t adc_value = read_le(payload); + payload += 2; + channels.back().push_back(adc_value * 0.879f); // mV + } + + // 解析红外光数据 (57采样点) + channels.push_back({}); + for (int i = 0; i < 57; ++i) { + int16_t adc_value = read_le(payload); + payload += 2; + channels.back().push_back(adc_value * 0.879f); // mV + } + + // 赋值原始二进制数据 + result.raw_data.assign(data, data + 6 + 4 + 57 * 2 * 2); + + return result; +} + +// 12导联心电解析 (0x4402) +SensorData parse_12lead_ecg(const uint8_t* data) { + SensorData result; + result.data_type = DataType::ECG_12LEAD; + result.packet_sn = read_le(data); + + // 跳过 DataType(2) 和 data_len(2) + const uint8_t* payload = data + 6; + + // 导联状态 (按文档说明处理STAT寄存器) + uint8_t stat_dh = payload[0]; // STAT.DH + uint8_t stat_dm = payload[1]; // STAT.DM + + // 正确拼接方式: (STAT.DH << 4) | (STAT.DM >> 4) + result.lead_status.status[0] = (stat_dh << 4) | (stat_dm >> 4) ; + + result.lead_status.status[1] = 0; // 第二个字节未使用 + payload += 2; + + // 解析8通道ECG数据 + auto& channels = result.channel_data.emplace>>(); + channels.resize(8); + + for (int ch = 0; ch < 8; ++ch) { + channels[ch].reserve(14); + for (int i = 0; i < 14; ++i) { + int16_t adc_value = read_le(payload); + payload += 2; + channels[ch].push_back(adc_value); // raw_data + } + } + + // GPIO状态 (取低4位) + result.additional.gpio_state = *payload & 0x0F; + payload += 1; + + // 跳过预留区 (5字节) + payload += 5; + + // 赋值原始二进制数据 + result.raw_data.assign(data, data + 6 + 2 + 8 * 14 * 2 + 1 + 5); + + return result; +} + +// 数字听诊解析 (0x1102) +SensorData parse_stethoscope(const uint8_t* data) { + SensorData result; + result.data_type = DataType::STETHOSCOPE; + result.packet_sn = read_le(data); + + // 跳过 DataType(2) 和 data_len(2) + const uint8_t* payload = data + 6; + + // 解析双通道音频数据 + auto& channels = result.channel_data.emplace>>(); + channels.resize(2); + + // 通道1数据 (116采样点) + for (int i = 0; i < 116; ++i) { + int8_t sample = static_cast(*payload++); + channels[0].push_back(sample * 0.146f); // mV + } + + // 通道2数据 (116采样点) + for (int i = 0; i < 116; ++i) { + int8_t sample = static_cast(*payload++); + channels[1].push_back(sample * 0.146f); // mV + } + + // 赋值原始二进制数据 + result.raw_data.assign(data, data + 6 + 116 * 2); + + return result; +} + +// 鼾声解析 (0x4212) +SensorData parse_snore(const uint8_t* data) { + SensorData result; + result.data_type = DataType::SNORE; + result.packet_sn = read_le(data); + + // 跳过 DataType(2) + data_len(2) + const uint8_t* payload = data + 6; + + // 解析鼾声数据 (232字节) + auto& channels = result.channel_data.emplace>(); + + // 高效转换: 直接使用 reinterpret_cast + const int8_t* snore_data = reinterpret_cast(payload); + for (int i = 0; i < 232; ++i) { + channels.push_back(static_cast(snore_data[i])); + } + + // 赋值原始二进制数据 + result.raw_data.assign(data, data + 6 + 232); + + return result; +} + +// 呼吸/姿态/环境光解析 (0x4213) +SensorData parse_respiration(const uint8_t* data) { + SensorData result; + result.data_type = DataType::RESPIRATION; + result.packet_sn = read_le(data); + + // 跳过 DataType(2) 和 data_len(2) + const uint8_t* payload = data + 6; + + // 解析呼吸气流数据 (114采样点) + auto& channels = result.channel_data.emplace>>(); + channels.push_back({}); + + for (int i = 0; i < 114; ++i) { + int16_t adc_value = read_le(payload); + payload += 2; + channels.back().push_back(adc_value * 0.1f); // 实际单位 + } + + // 解析附加数据 + result.additional.movement = read_le(payload); // 运动强度 + payload += 2; + + result.additional.posture = *payload++; // 姿态数据 + result.additional.ambient_light = *payload++; // 环境光数据 + + // 赋值原始二进制数据 + result.raw_data.assign(data, data + 6 + 114 * 2 + 2 + 1 + 1); + + return result; +} + +// 统一解析入口函数 - 修改为处理多个数据包 +std::vector parse_device_data(const std::vector& file_data) { + const size_t PACKET_SIZE = 238; // 每个数据包固定大小 + const size_t file_size = file_data.size(); + + if (file_size % PACKET_SIZE != 0) { + throw std::runtime_error("文件大小不是238字节的整数倍,可能已损坏"); + } + + const size_t packet_count = file_size / PACKET_SIZE; + std::vector results; + results.reserve(packet_count); + + const uint8_t* ptr = file_data.data(); + for (size_t i = 0; i < packet_count; i++) { + // 读取数据类型标识 + const uint16_t data_type = read_le(ptr + 2); + + switch (data_type) { + case 0x4230: + results.push_back(parse_eeg(ptr)); + break; + case 0x4211: + results.push_back(parse_ecg_emg(ptr)); + break; + case 0x4212: + results.push_back(parse_snore(ptr)); + break; + case 0x4213: + results.push_back(parse_respiration(ptr)); + break; + case 0x4402: + results.push_back(parse_12lead_ecg(ptr)); + break; + case 0x4302: + results.push_back(parse_ppg(ptr)); + break; + case 0x1102: + results.push_back(parse_stethoscope(ptr)); + // 其他设备类型可以继续添加 + default: + throw std::runtime_error("未知设备类型"); + } + ptr += PACKET_SIZE; + } + + return results; +} \ No newline at end of file diff --git a/src/data_test/Generate_data.cpp b/src/data_test/Generate_data.cpp new file mode 100644 index 0000000..1b75e12 --- /dev/null +++ b/src/data_test/Generate_data.cpp @@ -0,0 +1,456 @@ +#include "Generate_data.h" +template +T random_value(T min, T max) { + static std::random_device rd; + static std::mt19937 gen(rd()); + std::uniform_int_distribution<> dis(min, max); + return static_cast(dis(gen)); +} + +// 生成符合脑电设备格式的测试数据(0x4230) +std::vector generate_eeg_test_data() { + std::vector data; + + // 包头(6字节) + uint16_t sn = random_value(1, 1000); + uint16_t data_type = 0x4230; + uint16_t data_len = 6 * 14 * 2 + 2 * 14 * 2 + 2 + 6; + + // 小端序写入包头 + data.push_back(sn & 0xFF); + data.push_back((sn >> 8) & 0xFF); + data.push_back(data_type & 0xFF); + data.push_back((data_type >> 8) & 0xFF); + data.push_back(data_len & 0xFF); + data.push_back((data_len >> 8) & 0xFF); + + // 导联状态(2字节) + data.push_back(random_value(0, 255)); + data.push_back(random_value(0, 255)); + + // EEG数据 (6通道 × 14采样点) + for (int ch = 0; ch < 6; ++ch) { + for (int i = 0; i < 14; ++i) { + int16_t adc_value = random_value(-32768, 32767); + data.push_back(adc_value & 0xFF); + data.push_back((adc_value >> 8) & 0xFF); + } + } + + // EOG数据 (2通道 × 14采样点) + for (int ch = 0; ch < 2; ++ch) { + for (int i = 0; i < 14; ++i) { + int16_t adc_value = random_value(-32768, 32767); + data.push_back(adc_value & 0xFF); + data.push_back((adc_value >> 8) & 0xFF); + } + } + + // 预留区 (6字节) + for (int i = 0; i < 6; ++i) { + data.push_back(random_value(0, 255)); + } + + return data; +} + +// 生成符合胸腹设备格式的测试数据(0x4211) +std::vector generate_ecg_emg_test_data() { + std::vector data; + + // 包头(6字节) + uint16_t sn = random_value(1, 1000); + uint16_t data_type = 0x4211; + uint16_t data_len = 4 * 25 * 2 + 5 * 2 + 20 + 2; + + // 小端序写入包头 + data.push_back(sn & 0xFF); + data.push_back((sn >> 8) & 0xFF); + data.push_back(data_type & 0xFF); + data.push_back((data_type >> 8) & 0xFF); + data.push_back(data_len & 0xFF); + data.push_back((data_len >> 8) & 0xFF); + + // 导联状态(2字节) + data.push_back(random_value(0, 255)); + data.push_back(random_value(0, 255)); + + // ECG1 (25采样点) + for (int i = 0; i < 25; ++i) { + int16_t adc_value = random_value(-32768, 32767); + data.push_back(adc_value & 0xFF); + data.push_back((adc_value >> 8) & 0xFF); + } + + // ECG2 (25采样点) + for (int i = 0; i < 25; ++i) { + int16_t adc_value = random_value(-32768, 32767); + data.push_back(adc_value & 0xFF); + data.push_back((adc_value >> 8) & 0xFF); + } + + // EMG1 (25采样点) + for (int i = 0; i < 25; ++i) { + int16_t adc_value = random_value(-32768, 32767); + data.push_back(adc_value & 0xFF); + data.push_back((adc_value >> 8) & 0xFF); + } + + // EMG2 (25采样点) + for (int i = 0; i < 25; ++i) { + int16_t adc_value = random_value(-32768, 32767); + data.push_back(adc_value & 0xFF); + data.push_back((adc_value >> 8) & 0xFF); + } + + // 呼吸温度 (5采样点) + for (int i = 0; i < 5; ++i) { + int16_t temp_value = random_value(-32768, 32767); + data.push_back(temp_value & 0xFF); + data.push_back((temp_value >> 8) & 0xFF); + } + + // 呼吸阻抗数据 (2×5×2=20字节) + for (int i = 0; i < 20; ++i) { + data.push_back(random_value(0, 255)); + } + + return data; +} + +// 生成符合血氧设备格式的测试数据(0x4302) +std::vector generate_ppg_test_data() { + std::vector data; + + // 包头(6字节) + uint16_t sn = random_value(1, 1000); + uint16_t data_type = 0x4302; + uint16_t data_len = 4 + 57 * 2 * 2; + + // 小端序写入包头 + data.push_back(sn & 0xFF); + data.push_back((sn >> 8) & 0xFF); + data.push_back(data_type & 0xFF); + data.push_back((data_type >> 8) & 0xFF); + data.push_back(data_len & 0xFF); + data.push_back((data_len >> 8) & 0xFF); + + // 生命体征(4字节) + data.push_back(random_value(40, 200)); // 心率 + data.push_back(random_value(70, 100)); // 血氧 + int16_t temp = random_value(2000, 4000); // 温度 + data.push_back(temp & 0xFF); + data.push_back((temp >> 8) & 0xFF); + + // 红光数据(57采样点) + for (int i = 0; i < 57; ++i) { + int16_t val = random_value(0, 1000); + data.push_back(val & 0xFF); + data.push_back((val >> 8) & 0xFF); + } + + // 红外光数据(57采样点) + for (int i = 0; i < 57; ++i) { + int16_t val = random_value(0, 1000); + data.push_back(val & 0xFF); + data.push_back((val >> 8) & 0xFF); + } + + return data; +} + +// 生成符合12导联心电设备格式的测试数据(0x4402) +std::vector generate_12lead_ecg_test_data() { + std::vector data; + + // 包头(6字节) + uint16_t sn = random_value(1, 1000); + uint16_t data_type = 0x4402; + uint16_t data_len = 8 * 14 * 2 + 2 + 1 + 5; + + // 小端序写入包头 + data.push_back(sn & 0xFF); + data.push_back((sn >> 8) & 0xFF); + data.push_back(data_type & 0xFF); + data.push_back((data_type >> 8) & 0xFF); + data.push_back(data_len & 0xFF); + data.push_back((data_len >> 8) & 0xFF); + + // 导联状态 (2字节) + uint8_t stat_dh = random_value(0, 255); + uint8_t stat_dm = random_value(0, 255); + data.push_back(stat_dh); + data.push_back(stat_dm); + + // 解析8通道ECG数据 + for (int ch = 0; ch < 8; ++ch) { + for (int i = 0; i < 14; ++i) { + int16_t adc_value = random_value(-32768, 32767); + data.push_back(adc_value & 0xFF); + data.push_back((adc_value >> 8) & 0xFF); + } + } + + // GPIO状态 (1字节) + data.push_back(random_value(0, 15)); + + // 预留区 (5字节) + for (int i = 0; i < 5; ++i) { + data.push_back(random_value(0, 255)); + } + + return data; +} + +// 生成符合数字听诊设备格式的测试数据(0x1102) +std::vector generate_stethoscope_test_data() { + std::vector data; + + // 包头(6字节) + uint16_t sn = random_value(1, 1000); + uint16_t data_type = 0x1102; + uint16_t data_len = 116 * 2 * 1; + + // 小端序写入包头 + data.push_back(sn & 0xFF); + data.push_back((sn >> 8) & 0xFF); + data.push_back(data_type & 0xFF); + data.push_back((data_type >> 8) & 0xFF); + data.push_back(data_len & 0xFF); + data.push_back((data_len >> 8) & 0xFF); + + // 通道1数据 (116采样点) + for (int i = 0; i < 116; ++i) { + data.push_back(random_value(-128, 127)); + } + + // 通道2数据 (116采样点) + for (int i = 0; i < 116; ++i) { + data.push_back(random_value(-128, 127)); + } + + return data; +} + +// 生成符合鼾声设备格式的测试数据(0x4212) +std::vector generate_snore_test_data() { + std::vector data; + + // 包头(6字节) + uint16_t sn = random_value(1, 1000); + uint16_t data_type = 0x4212; + uint16_t data_len = 232; + + // 小端序写入包头 + data.push_back(sn & 0xFF); + data.push_back((sn >> 8) & 0xFF); + data.push_back(data_type & 0xFF); + data.push_back((data_type >> 8) & 0xFF); + data.push_back(data_len & 0xFF); + data.push_back((data_len >> 8) & 0xFF); + + // 鼾声数据 (232字节) + for (int i = 0; i < 232; ++i) { + data.push_back(random_value(-128, 127)); + } + + return data; +} + +// 生成符合呼吸/姿态/环境光设备格式的测试数据(0x4213) +std::vector generate_respiration_test_data() { + std::vector data; + + // 包头(6字节) + uint16_t sn = random_value(1, 1000); + uint16_t data_type = 0x4213; + uint16_t data_len = 114 * 2 + 2 + 1 + 1; + + // 小端序写入包头 + data.push_back(sn & 0xFF); + data.push_back((sn >> 8) & 0xFF); + data.push_back(data_type & 0xFF); + data.push_back((data_type >> 8) & 0xFF); + data.push_back(data_len & 0xFF); + data.push_back((data_len >> 8) & 0xFF); + + // 解析呼吸气流数据 (114采样点) + for (int i = 0; i < 114; ++i) { + int16_t adc_value = random_value(-32768, 32767); + data.push_back(adc_value & 0xFF); + data.push_back((adc_value >> 8) & 0xFF); + } + + // 解析附加数据 + uint16_t movement = random_value(0, 1000); + data.push_back(movement & 0xFF); + data.push_back((movement >> 8) & 0xFF); + + data.push_back(random_value(0, 5)); // 姿态数据 + data.push_back(random_value(0, 255)); // 环境光数据 + + return data; +} +// 生成随机数的辅助函数 + + +#include // 添加用于格式化输出的头文件 + +void print_parsed_result(const SensorData& result) { + std::cout << "\n===== 设备数据解析结果 =====\n"; + + // 设备类型信息 + std::cout << "设备类型: "; + switch (result.data_type) { + case DataType::EEG: std::cout << "脑电 (EEG)"; break; + case DataType::ECG_2LEAD: std::cout << "胸腹心电/肌电 (ECG/EMG)"; break; + case DataType::ECG_12LEAD: std::cout << "12导联心电 (ECG-12)"; break; + case DataType::PPG: std::cout << "血氧 (PPG)"; break; + case DataType::RESPIRATION: std::cout << "呼吸/姿态 (RESPIRATION)"; break; + case DataType::SNORE: std::cout << "鼾声 (SNORE)"; break; + case DataType::STETHOSCOPE: std::cout << "数字听诊 (STETHOSCOPE)"; break; + } + std::cout << "\n"; + + // 公共字段 + std::cout << "数据包序列号 (SN): " << result.packet_sn << "\n"; + //std::cout << "系统时间戳: " << result.timestamp << " μs\n"; + + // 导联状态 + std::ios_base::fmtflags f(std::cout.flags()); // 保存格式状态 + + std::cout << "导联状态: 0x" + << std::hex << std::setfill('0') + << std::setw(2) << static_cast(result.lead_status.status[0]) + << std::setw(2) << static_cast(result.lead_status.status[1]) + << std::setfill(' ') << std::dec << "\n"; + + std::cout.flags(f); // 恢复格式状态 + + // 解析具体导联状态 + const uint8_t* status = result.lead_status.status; + std::cout << "导联详情:\n"; + std::cout << " RA: " << ((status[0] & 0x01) ? "脱落" : "正常") << "\n"; + std::cout << " LA: " << ((status[0] & 0x02) ? "脱落" : "正常") << "\n"; + std::cout << " LL: " << ((status[0] & 0x04) ? "脱落" : "正常") << "\n"; + std::cout << " V1: " << ((status[1] & 0x01) ? "脱落" : "正常") << "\n"; + std::cout << " V2: " << ((status[1] & 0x02) ? "脱落" : "正常") << "\n"; + + // 设备特定数据 + switch (result.data_type) { + case DataType::PPG: + std::cout << "心率 (HR): " << static_cast(result.additional.hr) << " bpm\n"; + std::cout << "血氧饱和度 (SpO2): " << static_cast(result.additional.spo2) << "%\n"; + std::cout << "温度 (Temperature): " << result.additional.temperature << " °C\n"; + break; + + case DataType::ECG_2LEAD: + std::cout << "呼吸温度 (Respiration Temp): " << result.additional.temperature << " μV\n"; + break; + + case DataType::ECG_12LEAD: + std::cout << "GPIO状态: 0x" << std::hex + << static_cast(result.additional.gpio_state) + << std::dec << "\n"; + break; + + case DataType::RESPIRATION: + std::cout << "运动强度 (Movement): " << result.additional.movement << "\n"; + std::cout << "姿态 (Posture): " << static_cast(result.additional.posture) << "\n"; + std::cout << "环境光 (Ambient Light): " << static_cast(result.additional.ambient_light) << "\n"; + break; + + default: + // 其他设备没有额外字段 + break; + } + + // 通道数据打印 + auto print_channel_data = [](const auto& channels, const std::string& unit) { + for (size_t ch_idx = 0; ch_idx < channels.size(); ++ch_idx) { + std::cout << "\n通道 " << ch_idx + 1 << " (" << channels[ch_idx].size() << " 采样点):\n"; + + // 打印前10个和后5个采样点 + const size_t print_count = std::min(15, channels[ch_idx].size()); + for (size_t i = 0; i < print_count; ++i) { + if (i == 10 && channels[ch_idx].size() > 15) { + std::cout << "... "; + continue; + } + + // 只打印前10和后5个点 + if (i < 10 || i >= channels[ch_idx].size() - 5) { + std::cout << std::fixed << std::setprecision(2) << channels[ch_idx][i]; + if (i < channels[ch_idx].size() - 1) std::cout << ", "; + + // 每5个点换行 + if ((i + 1) % 5 == 0) std::cout << "\n"; + } + } + + // 单位信息 + if (!channels[ch_idx].empty()) { + std::cout << "\n<< 单位: " << unit << " >>"; + } + std::cout << "\n"; + } + }; + + // 根据设备类型打印通道数据 + std::cout << "\n===== 通道数据 =====\n"; + if (auto single = std::get_if>(&result.channel_data)) { + // 单通道设备 + std::vector> wrapper = {*single}; + + switch (result.data_type) { + case DataType::SNORE: + print_channel_data(wrapper, "原始值"); + break; + default: + print_channel_data(wrapper, "mV"); + } + } + else if (auto multi = std::get_if>>(&result.channel_data)) { + // 多通道设备 + switch (result.data_type) { + case DataType::EEG: + for (size_t i = 0; i < 6; ++i) { + std::cout << "EEG通道" << i + 1 << " "; + } + for (size_t i = 0; i < 2; ++i) { + std::cout << "EOG通道" << i + 1 << " "; + } + std::cout << "\n"; + print_channel_data(*multi, "μV"); + break; + + case DataType::ECG_2LEAD: + std::cout << "ECG1, ECG2, EMG1, EMG2\n"; + print_channel_data(*multi, "μV"); + break; + + case DataType::ECG_12LEAD: + std::cout << "8个心电通道 (I, II, V1-V6)\n"; + print_channel_data(*multi, "μV"); + break; + + case DataType::PPG: + std::cout << "红光通道, 红外光通道\n"; + print_channel_data(*multi, "mV"); + break; + + case DataType::STETHOSCOPE: + std::cout << "听诊通道1, 听诊通道2\n"; + print_channel_data(*multi, "mV"); + break; + case DataType::RESPIRATION: + print_channel_data(*multi, "原始值"); + break; + + default: + print_channel_data(*multi, "原始值"); + } + } + + std::cout << "================================\n\n"; +} \ No newline at end of file diff --git a/src/signal_processor/feature_extractor.cpp b/src/signal_processor/feature_extractor.cpp new file mode 100644 index 0000000..3dd13c4 --- /dev/null +++ b/src/signal_processor/feature_extractor.cpp @@ -0,0 +1,343 @@ +#include "feature_extractor.h" +const float QRS_DETECTION_THRESHOLD = 0.5f; // QRS检测阈值 +const int MIN_RR_INTERVAL = 200; // 最小RR间期(ms) - 对应300bpm +const int MAX_RR_INTERVAL = 2000; // 最大RR间期(ms) - 对应30bpm + +// ECG特征提取实现 +ECGFeatures FeatureExtractor::extract_ecg_features(const std::vector& ecg_signal, + double sample_rate, + int lead_index) { + ECGFeatures features; + if (ecg_signal.empty() || sample_rate <= 0) return features; + + // 1. 检测QRS波群 + std::vector qrs_locations = detect_qrs(ecg_signal, sample_rate); + if (qrs_locations.size() < 2) { + std::cerr << "QRS检测失败:未检测到足够的心跳" << std::endl; + return features; + } + + // 2. 计算心率 + std::vector rr_intervals; + for (size_t i = 1; i < qrs_locations.size(); i++) { + float interval = (qrs_locations[i] - qrs_locations[i-1]) * 1000.0f / sample_rate; + if (interval > MIN_RR_INTERVAL && interval < MAX_RR_INTERVAL) { + rr_intervals.push_back(interval); + } + } + + if (!rr_intervals.empty()) { + float avg_rr = std::accumulate(rr_intervals.begin(), rr_intervals.end(), 0.0f) / rr_intervals.size(); + features.heart_rate = 60000.0f / avg_rr; // bpm + } + + // 3. 分析QRS复合波 + for (int r_pos : qrs_locations) { + // 查找Q波起点(R波前下降点) + int q_start = r_pos; + for (int i = r_pos; i > 0 && i > r_pos - 0.1*sample_rate; i--) { + if (ecg_signal[i] < ecg_signal[i-1]) { + q_start = i; + } else { + break; + } + } + + // 查找S波终点(R波后上升点) + int s_end = r_pos; + for (int i = r_pos; i < ecg_signal.size()-1 && i < r_pos + 0.1*sample_rate; i++) { + if (ecg_signal[i] < ecg_signal[i+1]) { + s_end = i; + } else { + break; + } + } + + // 计算QRS持续时间 + float duration = (s_end - q_start) * 1000.0f / sample_rate; + features.qrs_duration += duration; + + // 查找T波峰值(R波后80-200ms) + int t_start = r_pos + static_cast(0.08 * sample_rate); + int t_end = r_pos + static_cast(0.20 * sample_rate); + t_end = std::min(t_end, static_cast(ecg_signal.size()-1)); + + if (t_start < ecg_signal.size()) { + auto t_max = std::max_element(ecg_signal.begin() + t_start, + ecg_signal.begin() + t_end); + features.t_wave_amplitude += *t_max; + } + } + + // 平均特征值 + if (!qrs_locations.empty()) { + features.qrs_duration /= qrs_locations.size(); + features.t_wave_amplitude /= qrs_locations.size(); + } + + // 4. ST段分析(J点后60-80ms) + for (int r_pos : qrs_locations) { + int j_point = r_pos + static_cast(0.04 * sample_rate); // J点(QRS结束点) + int st_point = j_point + static_cast(0.06 * sample_rate); // ST段测量点 + + if (st_point < ecg_signal.size()) { + features.st_segment.push_back(ecg_signal[st_point]); + } + } + + return features; +} + +// QRS波群检测实现 +std::vector FeatureExtractor::detect_qrs(const std::vector& ecg_signal, + double sample_rate) { + std::vector qrs_locations; + if (ecg_signal.empty()) return qrs_locations; + + // 1. 计算信号梯度(增强QRS特征) + std::vector gradient(ecg_signal.size(), 0.0f); + for (size_t i = 1; i < ecg_signal.size(); i++) { + gradient[i] = ecg_signal[i] - ecg_signal[i-1]; + } + + // 2. 平方信号(突出高幅值特征) + for (float& val : gradient) { + val = val * val; + } + + // 3. 移动平均滤波(窗宽=150ms) + int window_size = static_cast(0.15 * sample_rate); + std::vector integrated(gradient.size(), 0.0f); + + float sum = 0.0f; + for (int i = 0; i < window_size && i < integrated.size(); i++) { + sum += gradient[i]; + } + + for (int i = 0; i < integrated.size(); i++) { + integrated[i] = sum / window_size; + if (i + window_size < gradient.size()) { + sum += gradient[i+window_size] - gradient[i]; + } + } + + // 4. 自适应阈值检测 + float threshold = *std::max_element(integrated.begin(), integrated.end()) * QRS_DETECTION_THRESHOLD; + bool in_peak = false; + int peak_start = 0; + + for (int i = 1; i < integrated.size(); i++) { + if (!in_peak && integrated[i] > threshold) { + in_peak = true; + peak_start = i; + } else if (in_peak && integrated[i] < threshold) { + in_peak = false; + + // 在峰值区域内找到最大值位置 + auto max_it = std::max_element(ecg_signal.begin() + peak_start, + ecg_signal.begin() + i); + int r_peak = std::distance(ecg_signal.begin(), max_it); + + // 确保峰值间隔有效 + if (qrs_locations.empty() || + (r_peak - qrs_locations.back()) * 1000.0 / sample_rate > MIN_RR_INTERVAL) { + qrs_locations.push_back(r_peak); + } + } + } + + return qrs_locations; +} + +// PPG特征提取实现 +PPGFeatures FeatureExtractor::extract_ppg_features(const std::vector& red_signal, + const std::vector& ir_signal, + double sample_rate) { + PPGFeatures features; + if (red_signal.empty() || ir_signal.empty() || sample_rate <= 0) + return features; + + // 1. 检测红光信号峰值 + std::vector red_peaks = detect_ppg_peaks(red_signal, sample_rate); + if (red_peaks.size() < 2) { + std::cerr << "PPG峰值检测失败:未检测到足够的脉搏波" << std::endl; + return features; + } + + // 2. 计算心率 + std::vector pulse_intervals; + for (size_t i = 1; i < red_peaks.size(); i++) { + float interval = (red_peaks[i] - red_peaks[i-1]) * 1000.0f / sample_rate; + if (interval > MIN_RR_INTERVAL && interval < MAX_RR_INTERVAL) { + pulse_intervals.push_back(interval); + } + } + + if (!pulse_intervals.empty()) { + float avg_interval = std::accumulate(pulse_intervals.begin(), pulse_intervals.end(), 0.0f) + / pulse_intervals.size(); + features.heart_rate = 60000.0f / avg_interval; + } + + // 3. 计算灌注指数(PI) - 交流分量/直流分量 + float red_ac = 0.0f, red_dc = 0.0f; + for (int peak : red_peaks) { + if (peak > 0 && peak < red_signal.size() - 1) { + // 峰峰值作为交流分量 + float min_val = *std::min_element(red_signal.begin() + red_peaks[0], + red_signal.begin() + peak); + red_ac += (red_signal[peak] - min_val); + + // 谷值平均作为直流分量 + red_dc += min_val; + } + } + + if (red_dc > 0.0f && !red_peaks.empty()) { + features.perfusion_index = (red_ac / red_peaks.size()) / (red_dc / red_peaks.size()); + } + + // 4. 计算振幅比(红光/红外光) + float red_amplitude = 0.0f, ir_amplitude = 0.0f; + for (int peak : red_peaks) { + if (peak < ir_signal.size()) { + // 获取对应红外光信号值 + red_amplitude += red_signal[peak]; + ir_amplitude += ir_signal[peak]; + } + } + + if (ir_amplitude > 0.0f && !red_peaks.empty()) { + features.amplitude_ratio = (red_amplitude / red_peaks.size()) / + (ir_amplitude / red_peaks.size()); + + // 5. 经验公式估算血氧值(实际设备需要校准) + features.spo2 = 110.0f - 25.0f * features.amplitude_ratio; + features.spo2 = std::max(70.0f, std::min(100.0f, features.spo2)); + } + + // 6. 计算脉搏波宽度(10%-90%上升时间) + for (int peak : red_peaks) { + if (peak > 0) { + float peak_val = red_signal[peak]; + float min_val = *std::min_element(red_signal.begin(), + red_signal.begin() + peak); + + float threshold_low = min_val + 0.1 * (peak_val - min_val); + float threshold_high = min_val + 0.9 * (peak_val - min_val); + + int start_idx = peak; + int end_idx = peak; + + // 向后查找10%点 + for (int i = peak; i >= 0; i--) { + if (red_signal[i] <= threshold_low) { + start_idx = i; + break; + } + } + + // 向前查找90%点 + for (int i = peak; i < red_signal.size(); i++) { + if (red_signal[i] >= threshold_high) { + end_idx = i; + break; + } + } + + features.pulse_width += (end_idx - start_idx) * 1000.0f / sample_rate; + } + } + + if (!red_peaks.empty()) { + features.pulse_width /= red_peaks.size(); + } + + return features; +} + +// PPG峰值检测实现 +std::vector FeatureExtractor::detect_ppg_peaks(const std::vector& ppg_signal, + double sample_rate) { + std::vector peaks; + if (ppg_signal.empty()) return peaks; + + // 1. 计算移动平均(窗宽=200ms) + int window_size = static_cast(0.2 * sample_rate); + std::vector avg_signal(ppg_signal.size(), 0.0f); + + float sum = 0.0f; + for (int i = 0; i < window_size && i < avg_signal.size(); i++) { + sum += ppg_signal[i]; + } + + for (int i = 0; i < avg_signal.size(); i++) { + avg_signal[i] = sum / window_size; + if (i + window_size < ppg_signal.size()) { + sum += ppg_signal[i+window_size] - ppg_signal[i]; + } + } + + // 2. 自适应阈值检测 + float threshold = *std::max_element(ppg_signal.begin(), ppg_signal.end()) * 0.7f; + bool in_peak = false; + int peak_start = 0; + + for (int i = 1; i < ppg_signal.size(); i++) { + // 进入峰值区域 + if (!in_peak && ppg_signal[i] > threshold && ppg_signal[i] > avg_signal[i] * 1.3f) { + in_peak = true; + peak_start = i; + } + // 离开峰值区域 + else if (in_peak && ppg_signal[i] < threshold) { + in_peak = false; + + // 在峰值区域内找到最大值位置 + auto max_it = std::max_element(ppg_signal.begin() + peak_start, + ppg_signal.begin() + i); + int peak_idx = std::distance(ppg_signal.begin(), max_it); + + // 确保峰值间隔有效 + if (peaks.empty() || + (peak_idx - peaks.back()) * 1000.0 / sample_rate > MIN_RR_INTERVAL) { + peaks.push_back(peak_idx); + } + } + } + + return peaks; +} + +// 心率变异性分析实现 +std::vector FeatureExtractor::analyze_hrv(const std::vector& rr_intervals, + double sample_rate) { + std::vector hrv_features; + if (rr_intervals.size() < 10) return hrv_features; // 需要足够的数据点 + + // 1. 时域特征 + float mean_rr = std::accumulate(rr_intervals.begin(), rr_intervals.end(), 0.0f) + / rr_intervals.size(); + + // SDNN - RR间期的标准差 + float variance = 0.0f; + for (float rr : rr_intervals) { + variance += (rr - mean_rr) * (rr - mean_rr); + } + float sdnn = std::sqrt(variance / (rr_intervals.size() - 1)); + hrv_features.push_back(sdnn); + + // RMSSD - 相邻RR间期差值的均方根 + float rmssd = 0.0f; + for (size_t i = 1; i < rr_intervals.size(); i++) { + float diff = rr_intervals[i] - rr_intervals[i-1]; + rmssd += diff * diff; + } + rmssd = std::sqrt(rmssd / (rr_intervals.size() - 1)); + hrv_features.push_back(rmssd); + + // 2. 频域特征(需要5分钟以上数据) + // 这里简化为示例,实际需要FFT实现 + + return hrv_features; +} \ No newline at end of file diff --git a/src/signal_processor/signal_processor.cpp b/src/signal_processor/signal_processor.cpp new file mode 100644 index 0000000..b54f6b8 --- /dev/null +++ b/src/signal_processor/signal_processor.cpp @@ -0,0 +1,442 @@ +#include "signal_processor.h" +SensorData SignalProcessor::preprocess_generic(const SensorData& data) { + SensorData processed = data; + + // 通用预处理:带通滤波 + if (auto* channels = std::get_if>>(&processed.channel_data)) { + for (auto& channel : *channels) { + channel = bandpass_filter(channel, 100.0, 0.5, 45.0); + } + } + return processed; +} +SensorData SignalProcessor::preprocess_signals(const SensorData& raw_data ) { + // 1. 创建处理后的数据结构 + SensorData processed = raw_data; + + // 2. 设备特定预处理 + switch (processed.data_type) { + case DataType::EEG: + processed = preprocess_eeg(raw_data); + break; + case DataType::ECG_2LEAD: + processed = preprocess_ecg_2lead(raw_data); + break; + case DataType::ECG_12LEAD: + processed = preprocess_ecg_12lead(raw_data); + break; + case DataType::PPG: + processed = preprocess_ppg(raw_data); + break; + case DataType::RESPIRATION: + processed = preprocess_respiration(raw_data); + break; + case DataType::SNORE: + processed = preprocess_snore(raw_data); + break; + case DataType::STETHOSCOPE: + processed = preprocess_stethoscope(raw_data); + break; + default: + processed = preprocess_generic(raw_data); + break; + } + + // 3. 通用后处 + return processed; +} + +SensorData SignalProcessor::preprocess_eeg(const SensorData& data) { + SensorData processed = data; + return processed; +} +SensorData SignalProcessor::preprocess_ecg_2lead(const SensorData& data) +{ + SensorData processed = data; + return processed; + +} +// 12导联心电预处理函数 +SensorData SignalProcessor::preprocess_ecg_12lead(const SensorData& data) { + const double SAMPLE_RATE = 250.0; // 12导联心电标准采样率500Hz + + // 创建处理后的数据结构 + SensorData processed = data; + + // 获取通道数据 + auto& channels = std::get>>(processed.channel_data); + if (channels.size() != 12) { + throw std::runtime_error("Invalid channel count for 12-lead ECG"); + } + + // 对每个导联独立进行信号处理 + for (auto& channel : channels) { + // 1. 0.5Hz高通滤波 (去除基线漂移) + channel = filter(channel, SAMPLE_RATE, 0.5, 0.0, filtertype::highpass); + + // 2. 50Hz自适应陷波滤波 (去除工频干扰) + channel = filter(channel, SAMPLE_RATE, 50.0, 60,filtertype::notchpass); + + // 3. 25-40Hz带阻滤波 (去除肌电干扰) + channel = filter(channel, SAMPLE_RATE, 25.0, 40.0, filtertype::bandstop); + } + + // 计算并存储信号质量指数 + float avg_sqi = 0.0f; + for (const auto& channel : channels) { + avg_sqi += calculate_ecg_sqi(channel, SAMPLE_RATE); + } + processed.sqi = avg_sqi / channels.size(); + + return processed; +} +SensorData SignalProcessor::preprocess_ppg(const SensorData& data) { + // 1. 创建处理后的数据结构 + SensorData processed = data; + + // 2. 获取通道数据(红光和红外光) + auto& channels = std::get>>(processed.channel_data); + if (channels.size() < 2) { + throw std::runtime_error("PPG数据需要至少两个通道(红光和红外光)"); + } + + channels[0] = remove_dc_offset(channels[0]); + + + // c. 带通滤波 (0.5-10Hz) + channels[0] = bandpass_filter(channels[0], 50.0, 0.5, 10.0); + + + // 4. 预处理红外光通道(通道1) + + // b. 移除直流分量(DC) + channels[1] = remove_dc_offset(channels[1]); + + // c. 带通滤波 (0.5-10Hz) + channels[1] = bandpass_filter(channels[1], 50.0, 0.5, 10.0); + + + // 5. 计算信号质量指数(SQI) + processed.sqi = calculate_PPG_sqi(channels[0], channels[1]); + + // 6. 更新附加数据(心率和血氧) + // 文档中已经提供了hr和spo2值,但我们可以根据信号质量进行修正 + if (processed.sqi > 0.8) { + // 高质量信号,使用设备提供的值 + } else { + // 低质量信号,可能需要重新计算或标记为不可靠 + processed.additional.hr = 0; // 设置为0表示不可靠 + processed.additional.spo2 = 0; + } + + return processed; +} +SensorData SignalProcessor::preprocess_respiration(const SensorData& data) +{ + SensorData processed = data; + return processed; +} +SensorData SignalProcessor::preprocess_snore(const SensorData& data) +{ + SensorData processed = data; + return processed; +} +SensorData SignalProcessor::preprocess_stethoscope(const SensorData& data) +{ + SensorData processed = data; + return processed; +} +// 添加预处理辅助函数 +std::vector SignalProcessor::remove_dc_offset(const std::vector& signal) { + if (signal.empty()) return {}; // 处理空输入 + std::vector result = signal; + float dc_remove = 0; + for(auto& val:signal) dc_remove += val; + dc_remove /= result.size(); + for(auto& value:result) value -= dc_remove; + return result; +} +std::vector SignalProcessor::apply_gain(const std::vector& signal, float gain) { + std::vector result = signal; + return result; +} +// 实现眼电伪迹补偿 +std::vector SignalProcessor::compensate_eog_artifact(const std::vector& eeg, + const std::vector& eog1, + const std::vector& eog2) { + std::vector result = eeg; + return result; +} +// 实现自适应陷波滤波器(成员函数) +std::vector SignalProcessor::adaptive_notch_filter(const std::vector& input, + double sample_rate, + double target_freq, + double bandwidth) { + std::vector output(input.size(), 0.0f); + + // 计算滤波器系数 + double omega0 = 2 * M_PI * target_freq / sample_rate; + double alpha = sin(omega0) * sinh(log(2) / 2 * bandwidth * omega0 / sin(omega0)); + + double b0 = 1; + double b1 = -2 * cos(omega0); + double b2 = 1; + double a0 = 1 + alpha; + double a1 = -2 * cos(omega0); + double a2 = 1 - alpha; + + // 归一化系数 + b0 /= a0; + b1 /= a0; + b2 /= a0; + a1 /= a0; + a2 /= a0; + + // 初始化滤波器状态 + double x1 = 0, x2 = 0; + double y1 = 0, y2 = 0; + + // 应用滤波器 + for (size_t n = 0; n < input.size(); ++n) { + double x0 = input[n]; + output[n] = b0 * x0 + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2; + + // 更新状态 + x2 = x1; + x1 = x0; + y2 = y1; + y1 = output[n]; + } + + return output; +} + +std::vector SignalProcessor::filter(const std::vector& input, + double sample_rate, + double low_cutoff, + double high_cutoff, + filtertype type){ + + switch(type) + { + case filtertype::lowpass: + return Lowpass_filter(input,sample_rate,low_cutoff); + case filtertype::highpass: + return Highpass_filter(input,sample_rate,high_cutoff); + case filtertype::notchpass: + return adaptive_notch_filter(input,sample_rate,0.5*(high_cutoff+low_cutoff),high_cutoff-low_cutoff); + case filtertype::bandpass: + return bandpass_filter(input,sample_rate,low_cutoff,high_cutoff); + case filtertype::bandstop: + return bandstop_filter(input,sample_rate,low_cutoff,high_cutoff); + default: + return input; + } +} +std::vector SignalProcessor::Lowpass_filter(const std::vector& input, + double sample_rate, + double low_cutoff){ + if (input.empty()) return input; + std::vector output(input.size()); + double A,f; + f = 1/sample_rate; + A = 1.0f/(1+(1/(2*M_PI*f*low_cutoff))); + output[0] = input[0]; + if (input.size() > 1) output[1] = input[1]; + for (size_t n = 2; n < input.size(); n++) + { + output[n] = A*input[n] + (1-A)*output[n-1]; + } + return output; +} +std::vector SignalProcessor::Highpass_filter(const std::vector& input, + double sample_rate, + double high_cutoff){ + if (input.empty()) return input; + std::vector output(input.size()); + double A,f; + f = 1/sample_rate; + A = 1.0f/(1+(1/(2*M_PI*f*high_cutoff))); + output[0] = input[0]; + if (input.size() > 1) output[1] = input[1]; + for (size_t n = 2; n < input.size(); n++) + { + output[n] = A*output[n-1] + A*(input[n]-input[n-1]); + } + return output; +} +// 带通滤波器 +std::vector SignalProcessor::bandpass_filter(const std::vector& input, + double sample_rate, + double low_cutoff, + double high_cutoff) { + std::vector output(input.size(), 0.0f); + + // 计算滤波器系数 + double omega0 = 2 * M_PI * (low_cutoff + high_cutoff) / (2 * sample_rate); + double BW = (high_cutoff - low_cutoff) / sample_rate; + double Q = (low_cutoff + high_cutoff) / (2 * (high_cutoff - low_cutoff)); + + double alpha = sin(omega0) / (2 * Q); + double b0 = alpha; + double b1 = 0; + double b2 = -alpha; + double a0 = 1 + alpha; + double a1 = -2 * cos(omega0); + double a2 = 1 - alpha; + + // 归一化系数 + b0 /= a0; + b1 /= a0; + b2 /= a0; + a1 /= a0; + a2 /= a0; + + // 初始化滤波器状态 + double x1 = 0, x2 = 0; + double y1 = 0, y2 = 0; + + // 应用滤波器 + for (size_t n = 0; n < input.size(); ++n) { + double x0 = input[n]; + output[n] = b0 * x0 + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2; + + // 更新状态 + x2 = x1; + x1 = x0; + y2 = y1; + y1 = output[n]; + } + + return output; +} +//带阻滤波器 +std::vector SignalProcessor::bandstop_filter(const std::vector& input, + double sample_rate, + double low_cutoff, + double high_cutoff) { + if (input.empty()) return {}; + if (low_cutoff >= high_cutoff) { + throw std::invalid_argument("Low cutoff must be less than high cutoff"); + } + + std::vector output(input.size(), 0.0f); + const double f0 = (low_cutoff + high_cutoff) / 2.0; // 中心频率 + const double BW = high_cutoff - low_cutoff; // 带宽 + const double Q = f0 / BW; // 品质因数 + const double omega0 = 2 * M_PI * f0 / sample_rate; + const double alpha = sin(omega0) / (2 * Q); + + // 计算滤波器系数 + const double b0 = 1.0; + const double b1 = -2 * cos(omega0); + const double b2 = 1.0; + const double a0 = 1.0 + alpha; + const double a1 = -2 * cos(omega0); + const double a2 = 1.0 - alpha; + + // 归一化系数 + const double inv_a0 = 1.0 / a0; + const double nb0 = b0 * inv_a0; + const double nb1 = b1 * inv_a0; + const double nb2 = b2 * inv_a0; + const double na1 = a1 * inv_a0; + const double na2 = a2 * inv_a0; + + // 滤波器状态 + double x1 = 0.0, x2 = 0.0; + double y1 = 0.0, y2 = 0.0; + + // 应用滤波器 + for (size_t n = 0; n < input.size(); ++n) { + const double x0 = input[n]; + const double y = nb0 * x0 + nb1 * x1 + nb2 * x2 - na1 * y1 - na2 * y2; + + output[n] = static_cast(y); + + // 更新状态 + x2 = x1; + x1 = x0; + y2 = y1; + y1 = y; + } + + return output; +} + +// 运动补偿 +std::vector SignalProcessor::compensate_motion_artifact(const std::vector& ppg, + const std::vector& motion) { + std::vector output = ppg; + return ppg; +} +// 辅助函数:计算PPG信号质量指数 +float SignalProcessor::calculate_PPG_sqi(const std::vector& red_channel, + const std::vector& ir_channel) { + return 0.0f; +} + +// 辅助函数:计算信号的信噪比(SNR) +float SignalProcessor::calculate_snr(const std::vector& signal) { + return 0.0f; +} +// 辅助函数:计算两个信号的相关系数 +float SignalProcessor::calculate_correlation(const std::vector& x, + const std::vector& y) { + return 0.0f; +} +// 在 signal_processor.cpp 文件中添加以下代码 +float SignalProcessor::calculate_ecg_sqi(const std::vector& signal, double sample_rate) { + // 1. 检查输入有效性 + if (signal.empty()) return 0.0f; + if (sample_rate <= 0) return 0.0f; + const size_t min_samples = static_cast(0.5 * sample_rate); // 至少0.5秒数据 + if (signal.size() < min_samples) return 0.0f; + + // 3. 幅度检测(检测导联脱落或信号丢失) + float max_val = *std::max_element(signal.begin(), signal.end()); + float min_val = *std::min_element(signal.begin(), signal.end()); + float pp_amp = max_val - min_val; // 峰峰值幅度 + if (pp_amp < 0.1f) return 0.0f; // 幅度过低(假设单位是mV) + + // 4. 噪声水平评估 + float noise_level = 0.0f; + for (size_t i = 1; i < signal.size(); ++i) { + float diff = signal[i] - signal[i-1]; + noise_level += diff * diff; + } + noise_level = std::sqrt(noise_level / signal.size()); + + // 5. 功率谱分析(QRS频带能量比) + float total_power = 0.0f; + float qrs_power = 0.0f; + for (float s : signal) { + total_power += s * s; + } + + // 5-20Hz带通滤波(QRS主要能量带) + std::vector qrs_band = bandpass_filter(signal, sample_rate, 5.0, 20.0); + for (float s : qrs_band) { + qrs_power += s * s; + } + + float qrs_ratio = (total_power > 0) ? qrs_power / total_power : 0.0f; + + // 6. 基于特征的SQI计算 + float sqi = 0.0f; + + // 幅度因子(0.5-5mV为理想范围) + float amp_factor = std::clamp((pp_amp - 0.5f) / 4.5f, 0.0f, 1.0f); + + // 噪声因子(经验阈值) + float noise_factor = std::exp(-noise_level * 50.0f); + + // QRS能量因子 + float qrs_factor = std::clamp((qrs_ratio - 0.3f) * 2.5f, 0.0f, 1.0f); + + // 综合评分(加权平均) + sqi = 0.4f * amp_factor + 0.4f * qrs_factor + 0.2f * noise_factor; + + // 确保在[0,1]范围内 + return std::clamp(sqi, 0.0f, 1.0f); +} \ No newline at end of file diff --git a/src/test.cpp b/src/test.cpp new file mode 100644 index 0000000..c0934ca --- /dev/null +++ b/src/test.cpp @@ -0,0 +1,9 @@ + +//test.cpp +#include +#include "iostream" +using namespace std; +void myprint() +{ + cout<<"myprint.\n"; +}