diff --git a/1.txt b/1.txt deleted file mode 100644 index ff03742..0000000 --- a/1.txt +++ /dev/null @@ -1,2 +0,0 @@ -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 index 45131bb..689ed1a 100644 --- a/include/File_manage.h +++ b/include/File_manage.h @@ -4,5 +4,7 @@ class FileManager { public: static std::vector readBinaryFile(const std::string& filename); // 读取二进制文件 + }; +void save_to_csv(const std::vector& all_data, const std::string& filename);//将数据写入csv #endif \ No newline at end of file diff --git a/include/device_praser.h b/include/device_praser.h index 9ea998b..71cde57 100644 --- a/include/device_praser.h +++ b/include/device_praser.h @@ -21,4 +21,5 @@ 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/signal_processor.h b/include/signal_processor.h index f2ba6fe..929b3e3 100644 --- a/include/signal_processor.h +++ b/include/signal_processor.h @@ -140,6 +140,7 @@ public: double sample_rate, double low_cutoff, double high_cutoff); + void normalize_amplitude(std::vector& signal) ; // 添加通用预处理辅助函数 std::vector remove_dc_offset(const std::vector& signal); diff --git a/main.cpp b/main.cpp index 2040092..41fe45b 100644 --- a/main.cpp +++ b/main.cpp @@ -22,20 +22,21 @@ void print_channel_data(const std::variant, std::vector file_content = FileManager::readBinaryFile("C:/Users/29096/Desktop/work/data1.dat"); + std::vector file_content = FileManager::readBinaryFile("C:/Users/29096/Documents/WeChat Files/wxid_sh93l5lycr8b22/FileStorage/File/2025-07/ecg_data_raw.dat"); Mapper mapper; // 2. 解析设备数据包 - 需要实现此函数 std::vector all_data = parse_device_data(file_content); + save_to_csv(all_data, "channel_data_transered_.csv"); // 3. 创建信号处理器实例 - SignalProcessor processor; + /* 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); + std::cout << "Packet SN: " << data.packet_sn << ", Data Type: " << static_cast(data.data_type) << std::endl;*/ + // print_channel_data(data.channel_data); + /* 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; @@ -43,7 +44,7 @@ void test_try() { 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; @@ -59,3 +60,4 @@ int main() { test_try(); return 0; } + \ No newline at end of file diff --git a/src/Tool/File_manage.cpp b/src/Tool/File_manage.cpp index de6f2f6..3b59ed8 100644 --- a/src/Tool/File_manage.cpp +++ b/src/Tool/File_manage.cpp @@ -18,3 +18,69 @@ std::vector FileManager::readBinaryFile(const std::string& filename) { // 返回整个vector而不是裸指针 return buffer; } +// 保存通道数据到CSV文件 +void save_to_csv(const std::vector& all_data, const std::string& filename) { + std::ofstream outfile(filename); + if (!outfile.is_open()) { + std::cerr << "无法打开文件: " << filename << std::endl; + return; + } + + // 查找最大通道数 + size_t max_channels = 0; + for (const auto& data : all_data) { + if (std::holds_alternative>>(data.channel_data)) { + const auto& channels = std::get>>(data.channel_data); + if (channels.size() > max_channels) { + max_channels = channels.size(); + } + } else if (std::holds_alternative>(data.channel_data)) { + if (1 > max_channels) { // 单通道设备 + max_channels = 1; + } + } + } + + // 写入表头 + outfile << "SN"; + for (size_t ch = 1; ch <= max_channels; ++ch) { + outfile << ",Channel" << ch; + } + outfile << "\n"; + + // 写入数据 + for (const auto& data : all_data) { + // 处理单通道设备 (如SNORE) + if (std::holds_alternative>(data.channel_data)) { + const auto& samples = std::get>(data.channel_data); + for (const auto& sample : samples) { + outfile << data.packet_sn << "," << std::fixed << std::setprecision(4) << sample; + // 补充空值使列数一致 + for (size_t i = 1; i < max_channels; ++i) { + outfile << ","; + } + outfile << "\n"; + } + } + // 处理多通道设备 (如EEG, ECG) + else if (std::holds_alternative>>(data.channel_data)) { + const auto& channels = std::get>>(data.channel_data); + const size_t num_samples = channels.empty() ? 0 : channels[0].size(); + + // 按采样点写入数据 + for (size_t sample_idx = 0; sample_idx < num_samples; sample_idx++) { + outfile << data.packet_sn; + for (size_t ch_idx = 0; ch_idx < max_channels; ch_idx++) { + outfile << ","; + if (ch_idx < channels.size() && sample_idx < channels[ch_idx].size()) { + outfile << std::fixed << std::setprecision(4) << channels[ch_idx][sample_idx]; + } + } + outfile << "\n"; + } + } + } + + outfile.close(); + std::cout << "数据已保存至: " << filename << std::endl; +} \ No newline at end of file diff --git a/src/data_receiver/protocol_adapter/device_praser.cpp b/src/data_receiver/protocol_adapter/device_praser.cpp index 12f9c2f..1f6b7b1 100644 --- a/src/data_receiver/protocol_adapter/device_praser.cpp +++ b/src/data_receiver/protocol_adapter/device_praser.cpp @@ -1,4 +1,4 @@ -#include "headfile.h" +#include "device_praser.h" #include // 添加 memcpy 头文件 // 辅助函数:从字节数组读取小端整数 @@ -203,7 +203,7 @@ SensorData parse_12lead_ecg(const uint8_t* data) { for (int i = 0; i < 14; ++i) { int16_t adc_value = read_le(payload); payload += 2; - channels[ch].push_back(adc_value); // raw_data + channels[ch].push_back(adc_value * 0.318f); //原始数据进行量纲转换 } } @@ -307,51 +307,139 @@ SensorData parse_respiration(const uint8_t* data) { 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(); + const size_t RESPONSE_HEADER_SIZE = 10; // 响应帧头大小 (2功能码 + 2数据长度 + 4实际采集点数+crc校验) + const uint16_t FUNCTION_CODE = 0x0010; // 获取数据功能码 - 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 size_t file_size = file_data.size(); 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); + const uint8_t* end_ptr = ptr + file_size; + + std::vector results; + + while (ptr < end_ptr) { + // 检查是否有响应帧头 + bool has_response_header = false; + size_t remaining = end_ptr - ptr; - 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("未知设备类型"); + // 确保有足够的空间检查帧头 + if (remaining >= RESPONSE_HEADER_SIZE) { + // 读取功能码 (小端) + uint16_t func_code = read_le(ptr); + // 读取数据长度 (小端) + uint16_t data_len = read_le(ptr + 2); + + // 检查是否符合0x0010响应帧特征 + if (func_code == FUNCTION_CODE && data_len == 0x0004) { + has_response_header = true; + + // 读取实际数据点数 (小端) + uint32_t actual_points = read_le(ptr + 4); + + // 计算期望的数据长度 (实际点数 * 包大小) + size_t expected_data_size = actual_points * PACKET_SIZE; + size_t remaining_after_header = remaining - RESPONSE_HEADER_SIZE; + + // 验证数据长度是否匹配 + if (remaining_after_header < expected_data_size) { + std::string error = "帧头数据不足: 预期 " + + std::to_string(expected_data_size) + + " 字节, 实际 " + + std::to_string(remaining_after_header) + + " 字节"; + throw std::runtime_error(error); + } + + // 跳过帧头 + ptr += RESPONSE_HEADER_SIZE; + + // 处理帧头后的数据包 + for (uint32_t i = 0; i < actual_points; i++) { + if (end_ptr - ptr < static_cast(PACKET_SIZE)) { + throw std::runtime_error("数据包不完整"); + } + + // 读取数据类型标识 + 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)); + break; + default: + throw std::runtime_error("未知设备类型: 0x" + + to_hex_string(data_type)); + } + ptr += PACKET_SIZE; + } + } + } + + // 如果没有检测到响应帧头,尝试按纯数据包处理 + if (!has_response_header) { + // 检查是否有完整的数据包 + if (remaining >= PACKET_SIZE) { + // 读取数据类型标识 + 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)); + break; + default: + // 如果不是已知类型,跳过这个包继续处理 + ptr += PACKET_SIZE; + continue; + } + ptr += PACKET_SIZE; + } else { + // 剩余数据不足一个包,但大于0,发出警告 + if (remaining > 0) { + std::cerr << "警告: 文件包含 " << remaining + << " 字节额外数据,已忽略" << std::endl; + } + break; // 结束处理 + } } - ptr += PACKET_SIZE; } - + return results; } \ No newline at end of file diff --git a/src/signal_processor/signal_processor.cpp b/src/signal_processor/signal_processor.cpp index b54f6b8..348290f 100644 --- a/src/signal_processor/signal_processor.cpp +++ b/src/signal_processor/signal_processor.cpp @@ -47,18 +47,91 @@ SensorData SignalProcessor::preprocess_signals(const SensorData& raw_data ) { } SensorData SignalProcessor::preprocess_eeg(const SensorData& data) { +const double SAMPLE_RATE = 250.0; // 脑电标准采样率250Hz + SensorData processed = data; + + // 获取通道数据 + auto& channels = std::get>>(processed.channel_data); + if (channels.size() < 8) { + throw std::runtime_error("Invalid channel count for EEG"); + } + + // 分离EEG和EOG通道 + std::vector> eeg_channels(channels.begin(), channels.begin() + 6); + std::vector> eog_channels(channels.begin() + 6, channels.end()); + + // 处理EEG通道 + for (auto& channel : eeg_channels) { + // 1. 眼电伪迹补偿(使用EOG通道) + if (eog_channels.size() >= 2) { + channel = compensate_eog_artifact(channel, eog_channels[0], eog_channels[1]); + } + + // 2. 50Hz自适应陷波滤波 (去除工频干扰) + channel = adaptive_notch_filter(channel, SAMPLE_RATE, 50.0, 5.0); + + // 3. 0.5-45Hz带通滤波 (保留有效频段) + channel = bandpass_filter(channel, SAMPLE_RATE, 0.5, 45.0); + } + + // 处理EOG通道 + for (auto& channel : eog_channels) { + // 0.5-30Hz带通滤波 + channel = bandpass_filter(channel, SAMPLE_RATE, 0.5, 30.0); + } + + // 合并处理后的通道 + channels.clear(); + channels.insert(channels.end(), eeg_channels.begin(), eeg_channels.end()); + channels.insert(channels.end(), eog_channels.begin(), eog_channels.end()); + + // 计算并存储信号质量指数 + float avg_sqi = 0.0f; + for (const auto& channel : eeg_channels) { + avg_sqi += calculate_snr(channel); + } + processed.sqi = avg_sqi / eeg_channels.size(); + return processed; } SensorData SignalProcessor::preprocess_ecg_2lead(const SensorData& data) { + const double SAMPLE_RATE = 250.0; // 2导联心电标准采样率500Hz + SensorData processed = data; + + // 获取通道数据 + auto& channels = std::get>>(processed.channel_data); + if (channels.size() < 2) { + throw std::runtime_error("Invalid channel count for 2-lead ECG"); + } + + // 对每个导联独立进行信号处理 + for (auto& channel : channels) { + // 1. 0.5Hz高通滤波 (去除基线漂移) + channel = Highpass_filter(channel, SAMPLE_RATE, 0.5); + + // 2. 50Hz自适应陷波滤波 (去除工频干扰) + channel = adaptive_notch_filter(channel, SAMPLE_RATE, 50.0, 5.0); + + // 3. 25-40Hz带阻滤波 (去除肌电干扰) + channel = bandstop_filter(channel, SAMPLE_RATE, 25.0, 40.0); + } + + // 计算并存储信号质量指数 + 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; } // 12导联心电预处理函数 SensorData SignalProcessor::preprocess_ecg_12lead(const SensorData& data) { - const double SAMPLE_RATE = 250.0; // 12导联心电标准采样率500Hz + const double SAMPLE_RATE = 250.0; // 12导联心电标准采样率250.0Hz // 创建处理后的数据结构 SensorData processed = data; @@ -92,6 +165,7 @@ SensorData SignalProcessor::preprocess_ecg_12lead(const SensorData& data) { } SensorData SignalProcessor::preprocess_ppg(const SensorData& data) { // 1. 创建处理后的数据结构 + double SAMPLE_RATE = 50; SensorData processed = data; // 2. 获取通道数据(红光和红外光) @@ -133,17 +207,81 @@ SensorData SignalProcessor::preprocess_ppg(const SensorData& data) { } SensorData SignalProcessor::preprocess_respiration(const SensorData& data) { + const double SAMPLE_RATE = 100.0; // 呼吸信号标准采样率100Hz + SensorData processed = data; + + // 获取通道数据 + auto& channels = std::get>>(processed.channel_data); + if (channels.empty()) { + throw std::runtime_error("No channel data for respiration"); + } + + // 对每个通道进行处理 + for (auto& channel : channels) { + // 1. 0.1Hz高通滤波 (去除基线漂移) + channel = filter(channel, SAMPLE_RATE,0, 0.1,filtertype::highpass); + + // 2. 50Hz陷波滤波 (去除工频干扰) + channel = adaptive_notch_filter(channel, SAMPLE_RATE, 50.0, 5.0); + + // 3. 振幅归一化 (归一化到-1到1之间) + normalize_amplitude(channel); + } + + // 计算并存储信号质量指数 + processed.sqi = calculate_snr(channels[0]); + return processed; } SensorData SignalProcessor::preprocess_snore(const SensorData& data) { + const double SAMPLE_RATE = 2000.0; // 鼾声信号标准采样率2000Hz + SensorData processed = data; + + // 获取通道数据 + auto& channel = std::get>(processed.channel_data); + + // 1. 50-2000Hz带通滤波 (保留有效频段) + std::vector filtered = bandpass_filter(channel, SAMPLE_RATE, 50.0, 2000.0); + + // 2. 振幅归一化 + normalize_amplitude(filtered); + + processed.channel_data = filtered; + processed.sqi = calculate_snr(filtered); + return processed; } SensorData SignalProcessor::preprocess_stethoscope(const SensorData& data) { +const double SAMPLE_RATE = 4000.0; // 听诊信号标准采样率4000Hz + SensorData processed = data; + + // 获取通道数据 + auto& channels = std::get>>(processed.channel_data); + if (channels.size() < 2) { + throw std::runtime_error("Invalid channel count for stethoscope"); + } + + // 对每个通道进行处理 + for (auto& channel : channels) { + // 1. 20-2000Hz带通滤波 (保留有效频段) + channel = bandpass_filter(channel, SAMPLE_RATE, 20.0, 2000.0); + + // 2. 振幅归一化 + normalize_amplitude(channel); + } + + // 计算并存储信号质量指数 + float avg_sqi = 0.0f; + for (const auto& channel : channels) { + avg_sqi += calculate_snr(channel); + } + processed.sqi = avg_sqi / channels.size(); + return processed; } // 添加预处理辅助函数 @@ -233,6 +371,7 @@ std::vector SignalProcessor::filter(const std::vector& input, return input; } } +//低通滤波器 std::vector SignalProcessor::Lowpass_filter(const std::vector& input, double sample_rate, double low_cutoff){ @@ -249,6 +388,7 @@ std::vector SignalProcessor::Lowpass_filter(const std::vector& inp } return output; } +//高通滤波器 std::vector SignalProcessor::Highpass_filter(const std::vector& input, double sample_rate, double high_cutoff){ @@ -378,14 +518,36 @@ float SignalProcessor::calculate_PPG_sqi(const std::vector& red_channel, // 辅助函数:计算信号的信噪比(SNR) float SignalProcessor::calculate_snr(const std::vector& signal) { - return 0.0f; + if (signal.size() < 2) return 0.0f; + + // 计算信号功率 + float signal_power = 0.0f; + for (float s : signal) { + signal_power += s * s; + } + signal_power /= signal.size(); + + // 计算噪声功率(通过差分近似) + float noise_power = 0.0f; + for (size_t i = 1; i < signal.size(); ++i) { + float diff = signal[i] - signal[i-1]; + noise_power += diff * diff; + } + noise_power /= (signal.size() - 1); + + // 计算SNR (dB) + if (noise_power < 1e-6f) return 1.0f; // 避免除以零 + float snr_db = 10.0f * std::log10(signal_power / noise_power); + + // 将SNR转换为0-1的质量指数 + return std::clamp(snr_db / 40.0f, 0.0f, 1.0f); // 假设40dB为最大质量 } // 辅助函数:计算两个信号的相关系数 float SignalProcessor::calculate_correlation(const std::vector& x, const std::vector& y) { return 0.0f; } -// 在 signal_processor.cpp 文件中添加以下代码 +//ecg sqi float SignalProcessor::calculate_ecg_sqi(const std::vector& signal, double sample_rate) { // 1. 检查输入有效性 if (signal.empty()) return 0.0f; @@ -439,4 +601,24 @@ float SignalProcessor::calculate_ecg_sqi(const std::vector& signal, doubl // 确保在[0,1]范围内 return std::clamp(sqi, 0.0f, 1.0f); -} \ No newline at end of file +} +void SignalProcessor::normalize_amplitude(std::vector& signal) { + if (signal.empty()) return; + + // 找到最大绝对值 + float max_val = 0.0f; + for (float value : signal) { + float abs_val = std::abs(value); + if (abs_val > max_val) { + max_val = abs_val; + } + } + + // 归一化处理 + if (max_val > 0.0f) { + float scale = 1.0f / max_val; + for (float& value : signal) { + value *= scale; + } + } +}