first commit

This commit is contained in:
ZhangJinLong 2025-07-28 11:56:50 +08:00
parent 498f558711
commit 3854ac2aa3
25 changed files with 2450 additions and 0 deletions

21
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -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
}

32
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,32 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch", //
"type": "cppdbg", // cppdbg
"request": "launch", // launchattach
"program": "${workspaceRoot}/${fileBasenameNoExtension}.exe",//
"args": [], //
"stopAtEntry": false, // truefalse
"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",// miDebuggerMinGw
"preLaunchTask": "C/C++: g++.exe 生成活动文件", // c++g++, cgcc
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
}

52
.vscode/settings.json vendored Normal file
View File

@ -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"
}

36
.vscode/tasks.json vendored Normal file
View File

@ -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": "调试器生成的任务。"
}
]
}

2
1.txt Normal file
View File

@ -0,0 +1,2 @@
1 2 3 4 5 6 7
sxsd

8
include/File_manage.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _FILE_MANAGE_H
#define _FILE_MANAGE_H
#include "headfile.h"
class FileManager {
public:
static std::vector<uint8_t> readBinaryFile(const std::string& filename); // 读取二进制文件
};
#endif

33
include/Generate_data.h Normal file
View File

@ -0,0 +1,33 @@
// Generate_data.h
#ifndef GENERATE_DATA_H
#define GENERATE_DATA_H
#include "headfile.h"
// 模板函数声明
template<typename T>
T random_value(T min, T max);
// 生成符合脑电设备格式的测试数据0x4230
std::vector<uint8_t> generate_eeg_test_data();
// 生成符合胸腹设备格式的测试数据0x4211
std::vector<uint8_t> generate_ecg_emg_test_data();
// 生成符合血氧设备格式的测试数据0x4302
std::vector<uint8_t> generate_ppg_test_data();
// 生成符合12导联心电设备格式的测试数据0x4402
std::vector<uint8_t> generate_12lead_ecg_test_data();
// 生成符合数字听诊设备格式的测试数据0x1102
std::vector<uint8_t> generate_stethoscope_test_data();
// 生成符合鼾声设备格式的测试数据0x4212
std::vector<uint8_t> generate_snore_test_data();
// 生成符合呼吸/姿态/环境光设备格式的测试数据0x4213
std::vector<uint8_t> generate_respiration_test_data();
void print_parsed_result(const SensorData& result);
#endif // GENERATE_DATA_H

19
include/data_mapper.h Normal file
View File

@ -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

5
include/data_output.h Normal file
View File

@ -0,0 +1,5 @@
#ifndef _DATA_OUTPUT_H_
#define _DATA_OUTPUT_H_
#include "headfile.h"
#endif

6
include/data_receiver.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef _DATA_RECEIVER_h_
#define _DATA_RECEIVER_h_
#include "headfile.h"
#endif

24
include/device_praser.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef _DEVICE_PRASER_H_
#define _DEVICE_PRASER_H_
#include <string>
#include <cstdio>
#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<SensorData> parse_device_data(const std::vector<uint8_t>& file_data);
#endif

View File

@ -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<float> 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<float>& ecg_signal,
double sample_rate,
int lead_index = -1);
// PPG特征提取
static PPGFeatures extract_ppg_features(const std::vector<float>& red_signal,
const std::vector<float>& ir_signal,
double sample_rate);
// 心率变异性(HRV)分析
static std::vector<float> analyze_hrv(const std::vector<float>& rr_intervals,
double sample_rate);
private:
// QRS波群检测
static std::vector<int> detect_qrs(const std::vector<float>& ecg_signal,
double sample_rate);
// PPG峰值检测
static std::vector<int> detect_ppg_peaks(const std::vector<float>& ppg_signal,
double sample_rate);
};
#endif

30
include/headfile.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef _HEADFILE_H
#define _HEADFILE_H
#include "test.h"
#include "data_receiver.h"
#include <iostream>
#include <cstdint>
#include <vector>
#include <variant>
#include "types.h"
#include "signal_processor.h"
#include "data_output.h"
#include <stdexcept>
#include <numeric>
#include "device_praser.h"
#include "data_mapper.h"
#include <windows.h> // 引入 Windows API 头文件
#include <cstring>
#include <random>
#include<fstream>
#include<functional>
#include<iomanip>
#include <map>
#include "Generate_data.h"
#include <iterator>
#include "File_manage.h"
#include <cmath>
#include <algorithm>
#include "feature_extractor.h"
#include <utility> // for std::pair
#endif

156
include/signal_processor.h Normal file
View File

@ -0,0 +1,156 @@
#ifndef _SIGNAL_PROCESSOR_H_
#define _SIGNAL_PROCESSOR_H_
#include "headfile.h"
#include <map>
#include <vector>
#include <string>
// 滤波类型
enum class filtertype
{
lowpass,highpass,notchpass,bandpass,bandstop
};
// 特征数据结构
struct ECGChannelFeatures {
std::vector<int> r_peaks; // R波位置
float sdnn = 0.0f; // RR间期标准差
float rmssd = 0.0f; // RR间期差值的均方根
};
struct FeatureSet {
std::vector<ECGChannelFeatures> 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<ECGIndicators> ecg_indicators;
std::vector<PPGIndicators> ppg_indicators;
std::vector<EEGIndicators> 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<std::string>& features = {});
// 计算生理指标
IndicatorSet compute_physiological_indicators(const FeatureSet& features,
const std::vector<std::string>& 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<std::string, FilterConfig> filter_configs_;
// 滤波器状态
struct FilterState {
std::vector<double> x_history;
std::vector<double> y_history;
};
std::map<std::string, FilterState> filter_states_;
// 在SignalProcessor类中添加
public:
// 带通滤波器实现
std::vector<float> bandpass_filter(const std::vector<float>& input,
double sample_rate,
double low_cutoff,
double high_cutoff);
std::vector<float> Lowpass_filter(const std::vector<float>& input,
double sample_rate,
double low_cutoff) ;
std::vector<float> filter(const std::vector<float>& input,
double sample_rate,
double low_cutoff,
double high_cutoff,
filtertype type);
std::vector<float> Highpass_filter(const std::vector<float>& input,
double sample_rate,
double high_cutoff);
std::vector<float> compensate_motion_artifact(const std::vector<float>& ppg,
const std::vector<float>& motion);
std::vector<float> compensate_eog_artifact(const std::vector<float>& eeg,
const std::vector<float>& eog1,
const std::vector<float>& eog2) ;
// 添加自适应陷波滤波器声明
std::vector<float> adaptive_notch_filter(const std::vector<float>& input,
double sample_rate,
double target_freq,
double bandwidth) ;
std::vector<float> bandstop_filter(const std::vector<float>& input,
double sample_rate,
double low_cutoff,
double high_cutoff);
// 添加通用预处理辅助函数
std::vector<float> remove_dc_offset(const std::vector<float>& signal);
std::vector<float> apply_gain(const std::vector<float>& signal, float gain);
float calculate_correlation(const std::vector<float>& x, const std::vector<float>& y);
float calculate_snr(const std::vector<float>& signal);
float calculate_PPG_sqi(const std::vector<float>& red_channel,
const std::vector<float>& ir_channel);
float calculate_ecg_sqi(const std::vector<float>& signal, double sample_rate);
};
#endif

7
include/test.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _TEST_h_
#define _TEST_H_
#include<headfile.h>
void myprint();
#endif

48
include/types.h Normal file
View File

@ -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<float>, // 单通道数据
std::vector<std::vector<float>> // 多通道数据
> channel_data;
std::vector<uint8_t> 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

61
main.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "headfile.h"
// 辅助函数:打印多通道数据
void print_multi_channel(const std::vector<std::vector<float>>& 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<float>, std::vector<std::vector<float>>>& channel_data) {
if (std::holds_alternative<std::vector<float>>(channel_data)) {
const auto& single_channel = std::get<std::vector<float>>(channel_data);
} else if (std::holds_alternative<std::vector<std::vector<float>>>(channel_data)) {
const auto& multi_channel = std::get<std::vector<std::vector<float>>>(channel_data);
print_multi_channel(multi_channel);
}
}
void test_try() {
try {
// 1. 读取原始二进制文件
std::vector<uint8_t> file_content = FileManager::readBinaryFile("C:/Users/29096/Desktop/work/data1.dat");
Mapper mapper;
// 2. 解析设备数据包 - 需要实现此函数
std::vector<SensorData> 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<int>(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<int>(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<int>(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;
}

20
src/Tool/File_manage.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "File_manage.h"
std::vector<uint8_t> 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<uint8_t> buffer(size);
if (!file.read(reinterpret_cast<char*>(buffer.data()), size)) {
throw std::runtime_error("文件读取失败: " + filename);
}
// 返回整个vector而不是裸指针
return buffer;
}

View File

View File

@ -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()<min_raw_data_length) throw std::runtime_error("Raw data length is insufficient");
const uint16_t* p = reinterpret_cast<const uint16_t*>(processed.raw_data.data());
const int16_t (*read_channels)[14] = reinterpret_cast<const int16_t(*)[14]>(p+4);
std::vector<std::vector<float>> 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<std::vector<std::vector<float>>>(data.channel_data);
// 创建7通道输出结构
std::vector<std::vector<float>> 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<const int16_t*>(raw + 8);
// 创建12导联数据结构
std::vector<std::vector<float>> channels(12, std::vector<float>(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<std::vector<std::vector<float>>>(data.channel_data)) {
throw std::runtime_error("Invalid channel data format for PPG");
}
// 获取输入通道数据
auto& input_channels = std::get<std::vector<std::vector<float>>>(data.channel_data);
// 确保有足够的通道
if (input_channels.size() < 2) {
throw std::runtime_error("Input channel data for PPG has less than 2 channels");
}
// 创建输出通道数据
std::vector<std::vector<float>> output(2);
// 通道0: 红光数据 (57个采样点)
if (input_channels[0].size() >= 57) {
output[0] = std::vector<float>(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<float>(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()<min_data_length) throw std::runtime_error("Raw data length is insufficient");
auto& input_channels = std::get<std::vector<std::vector<float>>>(data.channel_data);
std::vector<std::vector<float>> 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<std::vector<float>>(data.channel_data)) {
throw std::runtime_error("Invalid channel data format for SNORE");
}
// 获取原始通道数据
auto& raw_samples = std::get<std::vector<float>>(data.channel_data);
// 应用校准系数 (0.146 mV/unit)
std::vector<float> 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()<min_data_length) throw std::runtime_error("Raw data length is insufficient");
auto& input_channels = std::get<std::vector<std::vector<float>>>(data.channel_data);
std::vector<std::vector<float>> 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;
}

View File

@ -0,0 +1,357 @@
#include "headfile.h"
#include <cstring> // 添加 memcpy 头文件
// 辅助函数:从字节数组读取小端整数
template <typename T>
T read_le(const uint8_t* data) {
T value = 0;
for (size_t i = 0; i < sizeof(T); ++i) {
value |= static_cast<T>(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<uint16_t>(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<std::vector<std::vector<float>>>();
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<int16_t>(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<int16_t>(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<uint16_t>(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<std::vector<std::vector<float>>>();
// ECG1 (25采样点)
channels.push_back({});
for (int i = 0; i < 25; ++i) {
int16_t adc_value = read_le<int16_t>(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<int16_t>(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<int16_t>(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<int16_t>(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<int16_t>(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<int16_t>(payload);
payload += 2;
channels.back().push_back(static_cast<float>(imp_value)); // 原始值
}
// 呼吸阻抗2 (5采样点)
channels.push_back({});
for (int i = 0; i < 5; ++i) {
int16_t imp_value = read_le<int16_t>(payload);
payload += 2;
channels.back().push_back(static_cast<float>(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<uint16_t>(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<int16_t>(payload);
result.additional.temperature = static_cast<float>(temp_raw) / 100.0f;
payload += 2;
// 解析红光数据 (57采样点)
auto& channels = result.channel_data.emplace<std::vector<std::vector<float>>>();
channels.push_back({});
for (int i = 0; i < 57; ++i) {
int16_t adc_value = read_le<int16_t>(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<int16_t>(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<uint16_t>(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<std::vector<std::vector<float>>>();
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<int16_t>(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<uint16_t>(data);
// 跳过 DataType(2) 和 data_len(2)
const uint8_t* payload = data + 6;
// 解析双通道音频数据
auto& channels = result.channel_data.emplace<std::vector<std::vector<float>>>();
channels.resize(2);
// 通道1数据 (116采样点)
for (int i = 0; i < 116; ++i) {
int8_t sample = static_cast<int8_t>(*payload++);
channels[0].push_back(sample * 0.146f); // mV
}
// 通道2数据 (116采样点)
for (int i = 0; i < 116; ++i) {
int8_t sample = static_cast<int8_t>(*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<uint16_t>(data);
// 跳过 DataType(2) + data_len(2)
const uint8_t* payload = data + 6;
// 解析鼾声数据 (232字节)
auto& channels = result.channel_data.emplace<std::vector<float>>();
// 高效转换: 直接使用 reinterpret_cast
const int8_t* snore_data = reinterpret_cast<const int8_t*>(payload);
for (int i = 0; i < 232; ++i) {
channels.push_back(static_cast<float>(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<uint16_t>(data);
// 跳过 DataType(2) 和 data_len(2)
const uint8_t* payload = data + 6;
// 解析呼吸气流数据 (114采样点)
auto& channels = result.channel_data.emplace<std::vector<std::vector<float>>>();
channels.push_back({});
for (int i = 0; i < 114; ++i) {
int16_t adc_value = read_le<int16_t>(payload);
payload += 2;
channels.back().push_back(adc_value * 0.1f); // 实际单位
}
// 解析附加数据
result.additional.movement = read_le<uint16_t>(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<SensorData> parse_device_data(const std::vector<uint8_t>& 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<SensorData> 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<uint16_t>(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;
}

View File

@ -0,0 +1,456 @@
#include "Generate_data.h"
template<typename T>
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<T>(dis(gen));
}
// 生成符合脑电设备格式的测试数据0x4230
std::vector<uint8_t> generate_eeg_test_data() {
std::vector<uint8_t> data;
// 包头6字节
uint16_t sn = random_value<uint16_t>(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<uint8_t>(0, 255));
data.push_back(random_value<uint8_t>(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<int16_t>(-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<int16_t>(-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<uint8_t>(0, 255));
}
return data;
}
// 生成符合胸腹设备格式的测试数据0x4211
std::vector<uint8_t> generate_ecg_emg_test_data() {
std::vector<uint8_t> data;
// 包头6字节
uint16_t sn = random_value<uint16_t>(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<uint8_t>(0, 255));
data.push_back(random_value<uint8_t>(0, 255));
// ECG1 (25采样点)
for (int i = 0; i < 25; ++i) {
int16_t adc_value = random_value<int16_t>(-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<int16_t>(-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<int16_t>(-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<int16_t>(-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<int16_t>(-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<uint8_t>(0, 255));
}
return data;
}
// 生成符合血氧设备格式的测试数据0x4302
std::vector<uint8_t> generate_ppg_test_data() {
std::vector<uint8_t> data;
// 包头6字节
uint16_t sn = random_value<uint16_t>(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<uint8_t>(40, 200)); // 心率
data.push_back(random_value<uint8_t>(70, 100)); // 血氧
int16_t temp = random_value<int16_t>(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<int16_t>(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<int16_t>(0, 1000);
data.push_back(val & 0xFF);
data.push_back((val >> 8) & 0xFF);
}
return data;
}
// 生成符合12导联心电设备格式的测试数据0x4402
std::vector<uint8_t> generate_12lead_ecg_test_data() {
std::vector<uint8_t> data;
// 包头6字节
uint16_t sn = random_value<uint16_t>(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<uint8_t>(0, 255);
uint8_t stat_dm = random_value<uint8_t>(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<int16_t>(-32768, 32767);
data.push_back(adc_value & 0xFF);
data.push_back((adc_value >> 8) & 0xFF);
}
}
// GPIO状态 (1字节)
data.push_back(random_value<uint8_t>(0, 15));
// 预留区 (5字节)
for (int i = 0; i < 5; ++i) {
data.push_back(random_value<uint8_t>(0, 255));
}
return data;
}
// 生成符合数字听诊设备格式的测试数据0x1102
std::vector<uint8_t> generate_stethoscope_test_data() {
std::vector<uint8_t> data;
// 包头6字节
uint16_t sn = random_value<uint16_t>(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<uint8_t>(-128, 127));
}
// 通道2数据 (116采样点)
for (int i = 0; i < 116; ++i) {
data.push_back(random_value<uint8_t>(-128, 127));
}
return data;
}
// 生成符合鼾声设备格式的测试数据0x4212
std::vector<uint8_t> generate_snore_test_data() {
std::vector<uint8_t> data;
// 包头6字节
uint16_t sn = random_value<uint16_t>(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<uint8_t>(-128, 127));
}
return data;
}
// 生成符合呼吸/姿态/环境光设备格式的测试数据0x4213
std::vector<uint8_t> generate_respiration_test_data() {
std::vector<uint8_t> data;
// 包头6字节
uint16_t sn = random_value<uint16_t>(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<int16_t>(-32768, 32767);
data.push_back(adc_value & 0xFF);
data.push_back((adc_value >> 8) & 0xFF);
}
// 解析附加数据
uint16_t movement = random_value<uint16_t>(0, 1000);
data.push_back(movement & 0xFF);
data.push_back((movement >> 8) & 0xFF);
data.push_back(random_value<uint8_t>(0, 5)); // 姿态数据
data.push_back(random_value<uint8_t>(0, 255)); // 环境光数据
return data;
}
// 生成随机数的辅助函数
#include <iomanip> // 添加用于格式化输出的头文件
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<int>(result.lead_status.status[0])
<< std::setw(2) << static_cast<int>(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<int>(result.additional.hr) << " bpm\n";
std::cout << "血氧饱和度 (SpO2): " << static_cast<int>(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<int>(result.additional.gpio_state)
<< std::dec << "\n";
break;
case DataType::RESPIRATION:
std::cout << "运动强度 (Movement): " << result.additional.movement << "\n";
std::cout << "姿态 (Posture): " << static_cast<int>(result.additional.posture) << "\n";
std::cout << "环境光 (Ambient Light): " << static_cast<int>(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<size_t>(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<std::vector<float>>(&result.channel_data)) {
// 单通道设备
std::vector<std::vector<float>> 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<std::vector<std::vector<float>>>(&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";
}

View File

@ -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<float>& ecg_signal,
double sample_rate,
int lead_index) {
ECGFeatures features;
if (ecg_signal.empty() || sample_rate <= 0) return features;
// 1. 检测QRS波群
std::vector<int> qrs_locations = detect_qrs(ecg_signal, sample_rate);
if (qrs_locations.size() < 2) {
std::cerr << "QRS检测失败未检测到足够的心跳" << std::endl;
return features;
}
// 2. 计算心率
std::vector<float> 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<int>(0.08 * sample_rate);
int t_end = r_pos + static_cast<int>(0.20 * sample_rate);
t_end = std::min(t_end, static_cast<int>(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<int>(0.04 * sample_rate); // J点QRS结束点
int st_point = j_point + static_cast<int>(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<int> FeatureExtractor::detect_qrs(const std::vector<float>& ecg_signal,
double sample_rate) {
std::vector<int> qrs_locations;
if (ecg_signal.empty()) return qrs_locations;
// 1. 计算信号梯度增强QRS特征
std::vector<float> 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<int>(0.15 * sample_rate);
std::vector<float> 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<float>& red_signal,
const std::vector<float>& ir_signal,
double sample_rate) {
PPGFeatures features;
if (red_signal.empty() || ir_signal.empty() || sample_rate <= 0)
return features;
// 1. 检测红光信号峰值
std::vector<int> red_peaks = detect_ppg_peaks(red_signal, sample_rate);
if (red_peaks.size() < 2) {
std::cerr << "PPG峰值检测失败未检测到足够的脉搏波" << std::endl;
return features;
}
// 2. 计算心率
std::vector<float> 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<int> FeatureExtractor::detect_ppg_peaks(const std::vector<float>& ppg_signal,
double sample_rate) {
std::vector<int> peaks;
if (ppg_signal.empty()) return peaks;
// 1. 计算移动平均(窗宽=200ms
int window_size = static_cast<int>(0.2 * sample_rate);
std::vector<float> 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<float> FeatureExtractor::analyze_hrv(const std::vector<float>& rr_intervals,
double sample_rate) {
std::vector<float> 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;
}

View File

@ -0,0 +1,442 @@
#include "signal_processor.h"
SensorData SignalProcessor::preprocess_generic(const SensorData& data) {
SensorData processed = data;
// 通用预处理:带通滤波
if (auto* channels = std::get_if<std::vector<std::vector<float>>>(&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<std::vector<std::vector<float>>>(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<std::vector<std::vector<float>>>(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<float> SignalProcessor::remove_dc_offset(const std::vector<float>& signal) {
if (signal.empty()) return {}; // 处理空输入
std::vector<float> 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<float> SignalProcessor::apply_gain(const std::vector<float>& signal, float gain) {
std::vector<float> result = signal;
return result;
}
// 实现眼电伪迹补偿
std::vector<float> SignalProcessor::compensate_eog_artifact(const std::vector<float>& eeg,
const std::vector<float>& eog1,
const std::vector<float>& eog2) {
std::vector<float> result = eeg;
return result;
}
// 实现自适应陷波滤波器(成员函数)
std::vector<float> SignalProcessor::adaptive_notch_filter(const std::vector<float>& input,
double sample_rate,
double target_freq,
double bandwidth) {
std::vector<float> 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<float> SignalProcessor::filter(const std::vector<float>& 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<float> SignalProcessor::Lowpass_filter(const std::vector<float>& input,
double sample_rate,
double low_cutoff){
if (input.empty()) return input;
std::vector<float> 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<float> SignalProcessor::Highpass_filter(const std::vector<float>& input,
double sample_rate,
double high_cutoff){
if (input.empty()) return input;
std::vector<float> 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<float> SignalProcessor::bandpass_filter(const std::vector<float>& input,
double sample_rate,
double low_cutoff,
double high_cutoff) {
std::vector<float> 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<float> SignalProcessor::bandstop_filter(const std::vector<float>& 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<float> 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<float>(y);
// 更新状态
x2 = x1;
x1 = x0;
y2 = y1;
y1 = y;
}
return output;
}
// 运动补偿
std::vector<float> SignalProcessor::compensate_motion_artifact(const std::vector<float>& ppg,
const std::vector<float>& motion) {
std::vector<float> output = ppg;
return ppg;
}
// 辅助函数计算PPG信号质量指数
float SignalProcessor::calculate_PPG_sqi(const std::vector<float>& red_channel,
const std::vector<float>& ir_channel) {
return 0.0f;
}
// 辅助函数计算信号的信噪比SNR
float SignalProcessor::calculate_snr(const std::vector<float>& signal) {
return 0.0f;
}
// 辅助函数:计算两个信号的相关系数
float SignalProcessor::calculate_correlation(const std::vector<float>& x,
const std::vector<float>& y) {
return 0.0f;
}
// 在 signal_processor.cpp 文件中添加以下代码
float SignalProcessor::calculate_ecg_sqi(const std::vector<float>& 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<size_t>(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<float> 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);
}

9
src/test.cpp Normal file
View File

@ -0,0 +1,9 @@
//test.cpp
#include <test.h>
#include "iostream"
using namespace std;
void myprint()
{
cout<<"myprint.\n";
}