forth commit
This commit is contained in:
parent
e161dd7319
commit
08e3f2cede
|
|
@ -0,0 +1,82 @@
|
|||
# 通道级滤波重构说明
|
||||
|
||||
## 问题描述
|
||||
|
||||
原来的滤波逻辑存在严重问题:
|
||||
- **错误做法**:对单个数据包内的短时间序列进行滤波
|
||||
- **问题**:滤波器无法获得足够的上下文信息,导致滤波效果差
|
||||
- **后果**:信号质量下降,可能引入伪影
|
||||
|
||||
## 解决方案
|
||||
|
||||
新的通道级滤波逻辑:
|
||||
1. **收集数据**:收集所有数据包中相同通道的完整数据
|
||||
2. **整体滤波**:对完整通道数据进行滤波处理
|
||||
3. **重新分配**:将滤波后的数据重新分配回数据包结构
|
||||
|
||||
## 核心方法
|
||||
|
||||
### `process_channel_based_filtering()`
|
||||
- 输入:多个数据包的向量
|
||||
- 输出:处理后的数据包向量
|
||||
- 功能:实现通道级滤波的核心逻辑
|
||||
|
||||
### `apply_channel_filters()`
|
||||
- 根据设备类型选择合适的滤波策略
|
||||
- 支持EEG、ECG、PPG、呼吸、打鼾、听诊器等设备
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 原来的错误用法
|
||||
```cpp
|
||||
// ❌ 错误:对单个数据包滤波
|
||||
std::vector<SensorData> raw_packets = get_raw_data_packets();
|
||||
for (auto& packet : raw_packets) {
|
||||
packet = signal_processor.preprocess_signals(packet); // 错误!
|
||||
}
|
||||
```
|
||||
|
||||
### 新的正确用法
|
||||
```cpp
|
||||
// ✅ 正确:通道级滤波
|
||||
std::vector<SensorData> raw_packets = get_raw_data_packets();
|
||||
std::vector<SensorData> processed_packets =
|
||||
signal_processor.process_channel_based_filtering(raw_packets);
|
||||
```
|
||||
|
||||
## 滤波流程
|
||||
|
||||
```
|
||||
原始数据包 → 按通道收集 → 完整通道滤波 → 重新分配 → 处理后数据包
|
||||
↓ ↓ ↓ ↓ ↓
|
||||
[包1,包2,包3] → [通道1数据] → [滤波后] → [新包1,新包2,新包3]
|
||||
[通道2数据] → [滤波后]
|
||||
[通道3数据] → [滤波后]
|
||||
```
|
||||
|
||||
## 优势
|
||||
|
||||
1. **滤波质量提升**:滤波器获得完整的时间序列信息
|
||||
2. **边界效应减少**:避免数据包边界处的滤波伪影
|
||||
3. **计算效率**:批量处理,减少重复计算
|
||||
4. **信号连续性**:保持通道数据的连续性
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **内存使用**:需要临时存储完整通道数据
|
||||
2. **数据包重构**:滤波后需要重新构建数据包结构
|
||||
3. **时序保持**:确保数据包的时间顺序正确
|
||||
|
||||
## 测试
|
||||
|
||||
运行测试文件验证功能:
|
||||
```bash
|
||||
g++ -o test_channel_filtering test_channel_filtering.cpp src/signal_processor/signal_processor.cpp -I./include
|
||||
./test_channel_filtering
|
||||
```
|
||||
|
||||
## 兼容性
|
||||
|
||||
- 保持原有API不变
|
||||
- 新增方法不影响现有代码
|
||||
- 可以逐步迁移到新的滤波逻辑
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -4,7 +4,7 @@
|
|||
class FileManager {
|
||||
public:
|
||||
static std::vector<uint8_t> readBinaryFile(const std::string& filename); // 读取二进制文件
|
||||
|
||||
bool is_mit_bih_file(const std::vector<uint8_t>& data);
|
||||
};
|
||||
void save_to_csv(const std::vector<SensorData>& all_data, const std::string& filename);//将数据写入csv
|
||||
#endif
|
||||
|
|
@ -20,6 +20,7 @@ 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);
|
||||
SensorData parse_mit_bih(const uint8_t* data, size_t size, int num_channels, int samples_per_channel);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef _HEADFILE_H
|
||||
#define _HEADFILE_H
|
||||
|
||||
#include "test.h"
|
||||
#include "data_receiver.h"
|
||||
#include <iostream>
|
||||
|
|
@ -24,7 +25,9 @@
|
|||
#include <iterator>
|
||||
#include "File_manage.h"
|
||||
#include <cmath>
|
||||
#include "indicator_cal.h"
|
||||
#include <algorithm>
|
||||
#include "feature_extractor.h"
|
||||
#include <utility> // for std::pair
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef _INDICATOR_CAL_H
|
||||
#define _INDICATOR_CAL_H
|
||||
#include "headfile.h"
|
||||
class MetricsCalculator
|
||||
{
|
||||
public:
|
||||
float calculate_heart_rate_ecg(const SensorData& ecg_signal, float sample_rate);
|
||||
float calculate_t_wave_amplitude(const std::vector<float>& ecg_signal);
|
||||
float calculate_heart_rate_ppg(const std::vector<float>& ppg_signal, float sample_rate);
|
||||
float calculate_spo2(const SensorData& ppg_data);
|
||||
float calculate_pulse_width(const std::vector<float>& ppg_signal);
|
||||
float calculate_amplitude_ratio(const SensorData& ppg_data);
|
||||
float calculate_sdnn(const std::vector<float>& rr_intervals);
|
||||
float calculate_rmssd(const std::vector<float>& rr_intervals) ;
|
||||
std::vector<float> detect_r_peaks(const std::vector<float>& ecg_signal, float sample_rate) ;
|
||||
std::vector<float> detect_pulse_peaks(const std::vector<float>& ppg_signal, float sample_rate);
|
||||
};
|
||||
#endif
|
||||
|
|
@ -64,6 +64,11 @@ public:
|
|||
// 预处理信号
|
||||
SensorData preprocess_signals(const SensorData& raw_data); // 使用DataType枚举
|
||||
SensorData preprocess_generic(const SensorData& data);
|
||||
|
||||
// 新增:通道级滤波处理
|
||||
std::vector<SensorData> process_channel_based_filtering(
|
||||
const std::vector<SensorData>& data_packets);
|
||||
|
||||
// 特征提取
|
||||
FeatureSet extract_signal_features(const SensorData& processed_data,
|
||||
const std::vector<std::string>& features = {});
|
||||
|
|
@ -150,6 +155,23 @@ public:
|
|||
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);
|
||||
|
||||
// 新增:通道级滤波辅助方法
|
||||
private:
|
||||
std::vector<std::vector<float>> apply_channel_filters(
|
||||
const std::vector<std::vector<float>>& channels, DataType data_type);
|
||||
std::vector<std::vector<float>> apply_eeg_filters(
|
||||
const std::vector<std::vector<float>>& channels);
|
||||
std::vector<std::vector<float>> apply_ecg_filters(
|
||||
const std::vector<std::vector<float>>& channels);
|
||||
std::vector<std::vector<float>> apply_ppg_filters(
|
||||
const std::vector<std::vector<float>>& channels);
|
||||
std::vector<std::vector<float>> apply_respiration_filters(
|
||||
const std::vector<std::vector<float>>& channels);
|
||||
std::vector<std::vector<float>> apply_snore_filters(
|
||||
const std::vector<std::vector<float>>& channels);
|
||||
std::vector<std::vector<float>> apply_stethoscope_filters(
|
||||
const std::vector<std::vector<float>>& channels);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ enum class DataType {
|
|||
PPG, // 血氧
|
||||
RESPIRATION, // 呼吸/姿态
|
||||
SNORE, // 鼾声
|
||||
STETHOSCOPE // 数字听诊
|
||||
STETHOSCOPE, // 数字听诊
|
||||
MIT_BIH // 添加MIT-BIH心律失常数据集类型
|
||||
};
|
||||
|
||||
// 导联脱落状态
|
||||
|
|
|
|||
61
main.cpp
61
main.cpp
|
|
@ -1,4 +1,5 @@
|
|||
#include "headfile.h"
|
||||
std::vector<float> heart_rate;
|
||||
// 辅助函数:打印多通道数据
|
||||
void print_multi_channel(const std::vector<std::vector<float>>& channels) {
|
||||
for (size_t ch = 0; ch < channels.size(); ++ch) {
|
||||
|
|
@ -19,32 +20,51 @@ void print_channel_data(const std::variant<std::vector<float>, std::vector<std::
|
|||
print_multi_channel(multi_channel);
|
||||
}
|
||||
}
|
||||
|
||||
void test_mit_bih() {
|
||||
try {
|
||||
// 读取MIT-BIH数据文件
|
||||
std::vector<uint8_t> file_content = FileManager::readBinaryFile("C:/Users/29096/Desktop/work/mit-bih-arrhythmia-database-1.0.0/222.dat");
|
||||
|
||||
// 解析数据
|
||||
std::vector<SensorData> all_data = parse_device_data(file_content);
|
||||
|
||||
// 保存结果
|
||||
save_to_csv(all_data, "mit_bih_output.csv");
|
||||
|
||||
std::cout << "MIT-BIH数据处理完成" << std::endl;
|
||||
std::cout << "Press Enter to exit..." << std::endl;
|
||||
std::cin.get();
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "处理错误: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void test_try() {
|
||||
try {
|
||||
// 1. 读取原始二进制文件
|
||||
std::vector<uint8_t> file_content = FileManager::readBinaryFile("C:/Users/29096/Documents/WeChat Files/wxid_sh93l5lycr8b22/FileStorage/File/2025-07/ecg_data_raw.dat");
|
||||
Mapper mapper;
|
||||
SignalProcessor processor;
|
||||
MetricsCalculator calculator;
|
||||
// 2. 解析设备数据包 - 需要实现此函数
|
||||
std::vector<SensorData> all_data = parse_device_data(file_content);
|
||||
save_to_csv(all_data, "channel_data_transered_.csv");
|
||||
// 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;*/
|
||||
// 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<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);
|
||||
}*/
|
||||
std::cout<<"1"<<std::endl;
|
||||
for(auto& mapped_data:all_data)
|
||||
{
|
||||
mapped_data = mapper.DataMapper(mapped_data);//通道映射
|
||||
}
|
||||
save_to_csv(all_data, "channel_data_mapped_.csv");
|
||||
for(auto& processed_data:all_data)
|
||||
{
|
||||
processed_data = processor.preprocess_signals(processed_data); //十二导联心电
|
||||
}
|
||||
for(auto& calculated_data:all_data)
|
||||
{
|
||||
heart_rate.push_back(calculator.calculate_heart_rate_ecg(calculated_data,250)); //十二导联心电
|
||||
}
|
||||
for(uint16_t i;i<heart_rate.size();i++) std::cout<<heart_rate[i]<<std::endl;
|
||||
save_to_csv(all_data, "channel_data_processed_.csv");
|
||||
|
||||
}catch (const std::exception& e) {
|
||||
std::cerr << "解析错误: " << e.what() << std::endl;
|
||||
|
|
@ -57,7 +77,6 @@ void test_try() {
|
|||
}
|
||||
int main() {
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
test_try();
|
||||
test_try(); // 测试MIT-BIH数据处理
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -84,3 +84,11 @@ void save_to_csv(const std::vector<SensorData>& all_data, const std::string& fil
|
|||
outfile.close();
|
||||
std::cout << "数据已保存至: " << filename << std::endl;
|
||||
}
|
||||
// 检测是否为MIT-BIH文件
|
||||
bool FileManager::is_mit_bih_file(const std::vector<uint8_t>& data) {
|
||||
// 简单启发式检测:检查文件大小是否匹配典型MIT-BIH格式
|
||||
// 实际应用中应该解析头文件(.hea)获取确切信息
|
||||
const size_t size = data.size();
|
||||
std::cout<<size<<std::endl;
|
||||
return (size > 1024 && size % (2 * sizeof(int16_t)) == 0);
|
||||
}
|
||||
|
|
@ -0,0 +1,313 @@
|
|||
// metrics_calculator.cpp
|
||||
#include "indicator_cal.h"
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
// 辅助函数:从SensorData获取单通道数据
|
||||
static const std::vector<float>& get_single_channel(const SensorData& data) {
|
||||
if (std::holds_alternative<std::vector<float>>(data.channel_data)) {
|
||||
return std::get<std::vector<float>>(data.channel_data);
|
||||
} else {
|
||||
const auto& channels = std::get<std::vector<std::vector<float>>>(data.channel_data);
|
||||
if (!channels.empty()) {
|
||||
return channels[0]; // 返回第一通道
|
||||
}
|
||||
static const std::vector<float> empty;
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
// ECG心率计算
|
||||
float MetricsCalculator::calculate_heart_rate_ecg(const SensorData& ecg_signal, float sample_rate) {
|
||||
const auto& signal = get_single_channel(ecg_signal);
|
||||
if (signal.size() < 3 || sample_rate <= 0) return 0.0f;
|
||||
|
||||
// 检测R峰
|
||||
auto r_peaks = detect_r_peaks(signal, sample_rate);
|
||||
if (r_peaks.size() < 2) return 0.0f; // 至少需要2个R峰计算心率
|
||||
|
||||
// 计算平均RR间期
|
||||
float total_rr = 0.0f;
|
||||
for (size_t i = 1; i < r_peaks.size(); i++) {
|
||||
total_rr += r_peaks[i] - r_peaks[i-1];
|
||||
}
|
||||
float avg_rr = total_rr / (r_peaks.size() - 1);
|
||||
|
||||
// 转换为心率 (次/分钟)
|
||||
return 60.0f / (avg_rr / sample_rate);
|
||||
}
|
||||
|
||||
|
||||
// T波振幅计算
|
||||
float MetricsCalculator::calculate_t_wave_amplitude(const std::vector<float>& ecg_signal) {
|
||||
if (ecg_signal.empty()) return 0.0f;
|
||||
|
||||
// 计算QRS波群后的平均振幅(代表T波)
|
||||
const size_t window_start = static_cast<size_t>(ecg_signal.size() * 0.3); // QRS后约30%位置
|
||||
const size_t window_end = static_cast<size_t>(ecg_signal.size() * 0.5); // 50%位置
|
||||
|
||||
float max_amplitude = 0.0f;
|
||||
for (size_t i = window_start; i < window_end && i < ecg_signal.size(); i++) {
|
||||
if (std::abs(ecg_signal[i]) > max_amplitude) {
|
||||
max_amplitude = std::abs(ecg_signal[i]);
|
||||
}
|
||||
}
|
||||
return max_amplitude;
|
||||
}
|
||||
|
||||
// PPG心率计算
|
||||
float MetricsCalculator::calculate_heart_rate_ppg(const std::vector<float>& ppg_signal, float sample_rate) {
|
||||
if (ppg_signal.size() < 3 || sample_rate <= 0) return 0.0f;
|
||||
|
||||
// 检测脉搏波峰
|
||||
auto pulse_peaks = detect_pulse_peaks(ppg_signal, sample_rate);
|
||||
if (pulse_peaks.size() < 2) return 0.0f;
|
||||
|
||||
// 计算平均脉搏间期
|
||||
float total_intervals = 0.0f;
|
||||
for (size_t i = 1; i < pulse_peaks.size(); i++) {
|
||||
total_intervals += pulse_peaks[i] - pulse_peaks[i-1];
|
||||
}
|
||||
float avg_interval = total_intervals / (pulse_peaks.size() - 1);
|
||||
|
||||
// 转换为心率 (次/分钟)
|
||||
return 60.0f / (avg_interval / sample_rate);
|
||||
}
|
||||
|
||||
// 血氧饱和度计算
|
||||
float MetricsCalculator::calculate_spo2(const SensorData& ppg_data) {
|
||||
if (!std::holds_alternative<std::vector<std::vector<float>>>(ppg_data.channel_data) ||
|
||||
std::get<std::vector<std::vector<float>>>(ppg_data.channel_data).size() < 2) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
const auto& channels = std::get<std::vector<std::vector<float>>>(ppg_data.channel_data);
|
||||
const auto& red_channel = channels[0];
|
||||
const auto& ir_channel = channels[1];
|
||||
|
||||
// 计算红光和红外光的AC/DC分量
|
||||
auto calc_ac_dc = [](const std::vector<float>& signal) -> std::pair<float, float> {
|
||||
float max_val = *std::max_element(signal.begin(), signal.end());
|
||||
float min_val = *std::min_element(signal.begin(), signal.end());
|
||||
float dc = (max_val + min_val) / 2.0f;
|
||||
float ac = (max_val - min_val) / 2.0f;
|
||||
return {ac, dc};
|
||||
};
|
||||
|
||||
auto [red_ac, red_dc] = calc_ac_dc(red_channel);
|
||||
auto [ir_ac, ir_dc] = calc_ac_dc(ir_channel);
|
||||
|
||||
// 计算R值 (红光AC/DC与红外光AC/DC的比值)
|
||||
float r_value = (red_ac / red_dc) / (ir_ac / ir_dc);
|
||||
|
||||
// 经验公式计算SpO2 (需要根据设备校准)
|
||||
return 110.0f - 25.0f * r_value;
|
||||
}
|
||||
|
||||
// 脉搏波宽度计算
|
||||
float MetricsCalculator::calculate_pulse_width(const std::vector<float>& ppg_signal) {
|
||||
if (ppg_signal.empty()) return 0.0f;
|
||||
|
||||
// 找到最大峰值位置
|
||||
auto max_it = std::max_element(ppg_signal.begin(), ppg_signal.end());
|
||||
size_t peak_idx = std::distance(ppg_signal.begin(), max_it);
|
||||
|
||||
// 找到上升沿起点 (信号值小于峰值的10%)
|
||||
size_t start_idx = peak_idx;
|
||||
while (start_idx > 0 && ppg_signal[start_idx] > 0.1f * *max_it) {
|
||||
start_idx--;
|
||||
}
|
||||
|
||||
// 找到下降沿终点 (信号值小于峰值的10%)
|
||||
size_t end_idx = peak_idx;
|
||||
while (end_idx < ppg_signal.size() - 1 && ppg_signal[end_idx] > 0.1f * *max_it) {
|
||||
end_idx++;
|
||||
}
|
||||
|
||||
return static_cast<float>(end_idx - start_idx);
|
||||
}
|
||||
|
||||
// 红光/红外光振幅比
|
||||
float MetricsCalculator::calculate_amplitude_ratio(const SensorData& ppg_data) {
|
||||
if (!std::holds_alternative<std::vector<std::vector<float>>>(ppg_data.channel_data) ||
|
||||
std::get<std::vector<std::vector<float>>>(ppg_data.channel_data).size() < 2) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
const auto& channels = std::get<std::vector<std::vector<float>>>(ppg_data.channel_data);
|
||||
const auto& red_channel = channels[0];
|
||||
const auto& ir_channel = channels[1];
|
||||
|
||||
float red_amp = *std::max_element(red_channel.begin(), red_channel.end()) -
|
||||
*std::min_element(red_channel.begin(), red_channel.end());
|
||||
|
||||
float ir_amp = *std::max_element(ir_channel.begin(), ir_channel.end()) -
|
||||
*std::min_element(ir_channel.begin(), ir_channel.end());
|
||||
|
||||
return (ir_amp > 0.0001f) ? red_amp / ir_amp : 0.0f;
|
||||
}
|
||||
|
||||
// HRV指标 - SDNN (RR间期的标准差)
|
||||
float MetricsCalculator::calculate_sdnn(const std::vector<float>& rr_intervals) {
|
||||
if (rr_intervals.size() < 2) return 0.0f;
|
||||
|
||||
float mean = std::accumulate(rr_intervals.begin(), rr_intervals.end(), 0.0f) / rr_intervals.size();
|
||||
|
||||
float variance = 0.0f;
|
||||
for (float rr : rr_intervals) {
|
||||
variance += (rr - mean) * (rr - mean);
|
||||
}
|
||||
variance /= rr_intervals.size();
|
||||
|
||||
return std::sqrt(variance);
|
||||
}
|
||||
|
||||
// HRV指标 - RMSSD (相邻RR间期差值的均方根)
|
||||
float MetricsCalculator::calculate_rmssd(const std::vector<float>& rr_intervals) {
|
||||
if (rr_intervals.size() < 2) return 0.0f;
|
||||
|
||||
float sum_sq_diff = 0.0f;
|
||||
for (size_t i = 1; i < rr_intervals.size(); i++) {
|
||||
float diff = rr_intervals[i] - rr_intervals[i-1];
|
||||
sum_sq_diff += diff * diff;
|
||||
}
|
||||
|
||||
return std::sqrt(sum_sq_diff / (rr_intervals.size() - 1));
|
||||
}
|
||||
|
||||
// 改进的R峰检测算法 (基于Pan-Tompkins算法)
|
||||
std::vector<float> MetricsCalculator::detect_r_peaks(const std::vector<float>& ecg_signal, float sample_rate) {
|
||||
std::vector<float> r_peaks;
|
||||
if (ecg_signal.size() < 5 || sample_rate <= 0) return r_peaks;
|
||||
|
||||
const size_t n = ecg_signal.size();
|
||||
|
||||
// 1. 计算积分窗口大小 (150ms窗口)
|
||||
const int win_integ = static_cast<int>(0.15f * sample_rate + 0.5f); // 四舍五入
|
||||
if (win_integ < 1) return r_peaks;
|
||||
|
||||
// 有效数据起始位置 (滤波+积分导致的延迟)
|
||||
const size_t start_index = 5 + win_integ - 1;
|
||||
|
||||
// 2. 带通滤波 (通过移动平均近似)
|
||||
std::vector<float> filtered(n, 0.0f);
|
||||
// 低通滤波 (5点移动平均)
|
||||
for (size_t i = 4; i < n; i++) {
|
||||
filtered[i] = (ecg_signal[i-4] + ecg_signal[i-3] +
|
||||
ecg_signal[i-2] + ecg_signal[i-1] +
|
||||
ecg_signal[i]) / 5.0f;
|
||||
}
|
||||
|
||||
// 3. 微分 (增强QRS斜率)
|
||||
std::vector<float> diff(n, 0.0f);
|
||||
for (size_t i = 5; i < n; i++) {
|
||||
diff[i] = filtered[i] - filtered[i-1];
|
||||
}
|
||||
|
||||
// 4. 平方 (放大高频分量)
|
||||
std::vector<float> sqrd(n, 0.0f);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
sqrd[i] = diff[i] * diff[i];
|
||||
}
|
||||
|
||||
// 5. 移动平均积分 (突出QRS复合波)
|
||||
std::vector<float> integrated(n, 0.0f);
|
||||
for (size_t i = start_index; i < n; i++) {
|
||||
float sum = 0.0f;
|
||||
for (int j = 0; j < win_integ; j++) {
|
||||
sum += sqrd[i - j];
|
||||
}
|
||||
integrated[i] = sum / win_integ;
|
||||
}
|
||||
|
||||
// 6. 自适应阈值检测
|
||||
float threshold = 0.0f;
|
||||
float peak_value = 0.0f;
|
||||
const size_t min_interval = static_cast<size_t>(0.2f * sample_rate); // 200ms最小间隔
|
||||
|
||||
// 初始阈值设置 (使用前2秒数据)
|
||||
const size_t init_win = std::min(static_cast<size_t>(2 * sample_rate), n - start_index);
|
||||
if (init_win > 10) {
|
||||
auto max_it = std::max_element(integrated.begin() + start_index,
|
||||
integrated.begin() + start_index + init_win);
|
||||
threshold = 0.5f * (*max_it);
|
||||
} else {
|
||||
threshold = 0.5f * (*std::max_element(integrated.begin(), integrated.end()));
|
||||
}
|
||||
|
||||
// 噪声和信号峰值跟踪
|
||||
float noise_peak = 0.25f * threshold;
|
||||
float signal_peak = threshold;
|
||||
const float decay_rate = 0.125f; // 阈值衰减率
|
||||
|
||||
size_t last_peak = 0;
|
||||
bool found_peak = false;
|
||||
|
||||
for (size_t i = start_index + 1; i < n - 1; i++) {
|
||||
// 检测峰值 (大于前后两点)
|
||||
if (integrated[i] > integrated[i-1] &&
|
||||
integrated[i] > integrated[i+1] &&
|
||||
integrated[i] > threshold) {
|
||||
|
||||
// 检查最小间隔
|
||||
if (last_peak == 0 || i - last_peak > min_interval) {
|
||||
r_peaks.push_back(static_cast<float>(i));
|
||||
last_peak = i;
|
||||
found_peak = true;
|
||||
peak_value = integrated[i];
|
||||
}
|
||||
}
|
||||
|
||||
// 自适应阈值更新
|
||||
if (found_peak) {
|
||||
// 检测到峰值后更新信号阈值
|
||||
signal_peak = decay_rate * peak_value + (1 - decay_rate) * signal_peak;
|
||||
found_peak = false;
|
||||
} else {
|
||||
// 未检测到峰值时更新噪声阈值
|
||||
if (integrated[i] > noise_peak) {
|
||||
noise_peak = decay_rate * integrated[i] + (1 - decay_rate) * noise_peak;
|
||||
}
|
||||
}
|
||||
|
||||
// 组合阈值 (信号和噪声阈值的加权平均)
|
||||
threshold = 0.25f * signal_peak + 0.75f * noise_peak;
|
||||
}
|
||||
|
||||
return r_peaks;
|
||||
}
|
||||
|
||||
// 脉搏波峰检测
|
||||
std::vector<float> MetricsCalculator::detect_pulse_peaks(const std::vector<float>& ppg_signal, float sample_rate) {
|
||||
std::vector<float> pulse_peaks;
|
||||
if (ppg_signal.empty()) return pulse_peaks;
|
||||
|
||||
// 自适应阈值
|
||||
float threshold = 0.6f * (*std::max_element(ppg_signal.begin(), ppg_signal.end()));
|
||||
|
||||
// 最小脉搏间隔 (300ms ≈ 200bpm)
|
||||
const size_t min_interval = static_cast<size_t>(0.3f * sample_rate);
|
||||
|
||||
bool in_peak = false;
|
||||
size_t last_peak = 0;
|
||||
|
||||
for (size_t i = 1; i < ppg_signal.size() - 1; i++) {
|
||||
// 检测上升沿
|
||||
if (!in_peak && ppg_signal[i] > threshold &&
|
||||
ppg_signal[i] > ppg_signal[i-1] && ppg_signal[i] > ppg_signal[i+1]) {
|
||||
|
||||
if (i - last_peak > min_interval || last_peak == 0) {
|
||||
pulse_peaks.push_back(static_cast<float>(i));
|
||||
last_peak = i;
|
||||
in_peak = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 检测下降沿
|
||||
if (in_peak && ppg_signal[i] < 0.7f * threshold) {
|
||||
in_peak = false;
|
||||
}
|
||||
}
|
||||
|
||||
return pulse_peaks;
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ SensorData Mapper::ECG_12LEAD_Data_Mapper(SensorData& data)
|
|||
// 处理前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;
|
||||
channels[ch][sample] = ecg_data[ch * 14 + sample]*0.318;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -220,6 +220,52 @@ SensorData parse_12lead_ecg(const uint8_t* data) {
|
|||
return result;
|
||||
}
|
||||
|
||||
// MIT-BIH 212格式解析器
|
||||
SensorData parse_mit_bih_212(const uint8_t* data, size_t size) {
|
||||
SensorData result;
|
||||
result.data_type = DataType::MIT_BIH;
|
||||
result.packet_sn = 0; // 单文件数据,SN设为0
|
||||
result.lead_status = {{0}}; // 无导联状态
|
||||
result.timestamp = 0; // 无时间戳
|
||||
|
||||
// 检查文件大小是否合理
|
||||
if (size < 1024 || size % 2 != 0) {
|
||||
throw std::runtime_error("无效的MIT-BIH文件大小");
|
||||
}
|
||||
|
||||
// 解析212格式数据
|
||||
auto& channels = result.channel_data.emplace<std::vector<std::vector<float>>>();
|
||||
channels.resize(2); // 两个导联
|
||||
|
||||
// 212格式: 每2字节包含两个12位样本
|
||||
for (size_t i = 0; i < size; i += 2) {
|
||||
uint8_t byte1 = data[i];
|
||||
uint8_t byte2 = data[i+1];
|
||||
|
||||
// 解析第一个通道 (低12位)
|
||||
int16_t sample1 = ((byte1 & 0x0F) << 8) | byte2;
|
||||
// 符号扩展 (12位有符号 -> 16位有符号)
|
||||
if (sample1 & 0x0800) sample1 |= 0xF000;
|
||||
|
||||
// 解析第二个通道 (高12位)
|
||||
int16_t sample2 = ((byte1 & 0xF0) << 4) | (byte2 >> 4);
|
||||
// 符号扩展 (12位有符号 -> 16位有符号)
|
||||
if (sample2 & 0x0800) sample2 |= 0xF000;
|
||||
|
||||
// 转换为毫伏 (MIT-BIH ADC范围: ±5mV = ±2048)
|
||||
float mv1 = sample1 * (5.0f / 2048.0f);
|
||||
float mv2 = sample2 * (5.0f / 2048.0f);
|
||||
|
||||
channels[0].push_back(mv1);
|
||||
channels[1].push_back(mv2);
|
||||
}
|
||||
|
||||
// 存储原始数据
|
||||
result.raw_data.assign(data, data + size);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 数字听诊解析 (0x1102)
|
||||
SensorData parse_stethoscope(const uint8_t* data) {
|
||||
SensorData result;
|
||||
|
|
@ -309,6 +355,7 @@ SensorData parse_respiration(const uint8_t* data) {
|
|||
|
||||
// 统一解析入口函数 - 支持多个帧头和数据包组
|
||||
std::vector<SensorData> parse_device_data(const std::vector<uint8_t>& file_data) {
|
||||
FileManager manager_;
|
||||
const size_t PACKET_SIZE = 238; // 每个数据包固定大小
|
||||
const size_t RESPONSE_HEADER_SIZE = 10; // 响应帧头大小 (2功能码 + 2数据长度 + 4实际采集点数+crc校验)
|
||||
const uint16_t FUNCTION_CODE = 0x0010; // 获取数据功能码
|
||||
|
|
@ -316,9 +363,8 @@ std::vector<SensorData> parse_device_data(const std::vector<uint8_t>& file_data)
|
|||
const size_t file_size = file_data.size();
|
||||
const uint8_t* ptr = file_data.data();
|
||||
const uint8_t* end_ptr = ptr + file_size;
|
||||
|
||||
std::map<DataType, std::vector<SensorData>> grouped_data;
|
||||
std::vector<SensorData> results;
|
||||
|
||||
while (ptr < end_ptr) {
|
||||
// 检查是否有响应帧头
|
||||
bool has_response_header = false;
|
||||
|
|
@ -440,6 +486,39 @@ std::vector<SensorData> parse_device_data(const std::vector<uint8_t>& file_data)
|
|||
}
|
||||
}
|
||||
}
|
||||
// 将解析的结果按数据类型分组
|
||||
for (const auto& result : results) {
|
||||
grouped_data[result.data_type].push_back(result);
|
||||
}
|
||||
for (auto& [data_type, packets] : grouped_data) {
|
||||
if (packets.empty()) continue;
|
||||
|
||||
// 创建新的SensorData对象,包含完整通道数据
|
||||
SensorData full_data = packets[0];
|
||||
full_data.channel_data = std::vector<std::vector<float>>();
|
||||
|
||||
// 获取通道数量
|
||||
size_t num_channels = 0;
|
||||
if (auto* channels = std::get_if<std::vector<std::vector<float>>>(&packets[0].channel_data)) {
|
||||
num_channels = channels->size();
|
||||
full_data.channel_data.emplace<std::vector<std::vector<float>>>(num_channels);
|
||||
}
|
||||
|
||||
// 合并所有数据包中的通道数据
|
||||
auto& full_channels = std::get<std::vector<std::vector<float>>>(full_data.channel_data);
|
||||
for (size_t ch = 0; ch < num_channels; ch++) {
|
||||
for (auto& packet : packets) {
|
||||
if (auto* channels = std::get_if<std::vector<std::vector<float>>>(&packet.channel_data)) {
|
||||
if (ch < channels->size()) {
|
||||
full_channels[ch].insert(full_channels[ch].end(),
|
||||
(*channels)[ch].begin(),
|
||||
(*channels)[ch].end());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results.push_back(full_data);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
|
@ -1,4 +1,264 @@
|
|||
#include "signal_processor.h"
|
||||
|
||||
// 新增:处理多个数据包的通道级滤波
|
||||
std::vector<SensorData> SignalProcessor::process_channel_based_filtering(
|
||||
const std::vector<SensorData>& data_packets) {
|
||||
|
||||
if (data_packets.empty()) return {};
|
||||
|
||||
// 按数据类型分组
|
||||
std::map<DataType, std::vector<SensorData>> grouped_data;
|
||||
for (const auto& packet : data_packets) {
|
||||
grouped_data[packet.data_type].push_back(packet);
|
||||
}
|
||||
|
||||
std::vector<SensorData> processed_packets;
|
||||
|
||||
// 对每种数据类型分别处理
|
||||
for (auto& [data_type, packets] : grouped_data) {
|
||||
if (packets.empty()) continue;
|
||||
|
||||
// 获取第一个数据包作为模板
|
||||
SensorData template_packet = packets[0];
|
||||
|
||||
// 收集所有通道的完整数据
|
||||
std::vector<std::vector<float>> all_channels;
|
||||
size_t num_channels = 0;
|
||||
|
||||
// 确定通道数量
|
||||
if (auto* channels = std::get_if<std::vector<std::vector<float>>>(&packets[0].channel_data)) {
|
||||
num_channels = channels->size();
|
||||
all_channels.resize(num_channels);
|
||||
}
|
||||
|
||||
// 收集所有数据包中相同通道的数据
|
||||
for (size_t ch = 0; ch < num_channels; ch++) {
|
||||
for (const auto& packet : packets) {
|
||||
if (auto* channels = std::get_if<std::vector<std::vector<float>>>(&packet.channel_data)) {
|
||||
if (ch < channels->size()) {
|
||||
all_channels[ch].insert(all_channels[ch].end(),
|
||||
(*channels)[ch].begin(),
|
||||
(*channels)[ch].end());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 对完整通道数据进行滤波处理
|
||||
std::vector<std::vector<float>> filtered_channels =
|
||||
apply_channel_filters(all_channels, data_type);
|
||||
|
||||
// 将滤波后的数据重新分配回数据包结构
|
||||
size_t samples_per_packet = 0;
|
||||
if (auto* channels = std::get_if<std::vector<std::vector<float>>>(&packets[0].channel_data)) {
|
||||
if (!channels->empty()) {
|
||||
samples_per_packet = (*channels)[0].size();
|
||||
}
|
||||
}
|
||||
|
||||
// 重新构建数据包
|
||||
size_t total_samples = filtered_channels[0].size();
|
||||
size_t num_packets = (total_samples + samples_per_packet - 1) / samples_per_packet;
|
||||
|
||||
for (size_t p = 0; p < num_packets; p++) {
|
||||
SensorData new_packet = template_packet;
|
||||
new_packet.packet_sn = p; // 重新分配包序号
|
||||
|
||||
// 创建新的通道数据结构
|
||||
auto& new_channels = new_packet.channel_data.emplace<std::vector<std::vector<float>>>();
|
||||
new_channels.resize(num_channels);
|
||||
|
||||
// 分配数据到各个通道
|
||||
for (size_t ch = 0; ch < num_channels; ch++) {
|
||||
size_t start_idx = p * samples_per_packet;
|
||||
size_t end_idx = std::min(start_idx + samples_per_packet, filtered_channels[ch].size());
|
||||
|
||||
if (start_idx < filtered_channels[ch].size()) {
|
||||
new_channels[ch].assign(filtered_channels[ch].begin() + start_idx,
|
||||
filtered_channels[ch].begin() + end_idx);
|
||||
}
|
||||
}
|
||||
|
||||
processed_packets.push_back(new_packet);
|
||||
}
|
||||
}
|
||||
|
||||
return processed_packets;
|
||||
}
|
||||
|
||||
// 新增:对完整通道数据应用滤波器
|
||||
std::vector<std::vector<float>> SignalProcessor::apply_channel_filters(
|
||||
const std::vector<std::vector<float>>& channels, DataType data_type) {
|
||||
|
||||
std::vector<std::vector<float>> filtered_channels = channels;
|
||||
|
||||
switch (data_type) {
|
||||
case DataType::EEG:
|
||||
filtered_channels = apply_eeg_filters(channels);
|
||||
break;
|
||||
case DataType::ECG_2LEAD:
|
||||
case DataType::ECG_12LEAD:
|
||||
filtered_channels = apply_ecg_filters(channels);
|
||||
break;
|
||||
case DataType::PPG:
|
||||
filtered_channels = apply_ppg_filters(channels);
|
||||
break;
|
||||
case DataType::RESPIRATION:
|
||||
filtered_channels = apply_respiration_filters(channels);
|
||||
break;
|
||||
case DataType::SNORE:
|
||||
filtered_channels = apply_snore_filters(channels);
|
||||
break;
|
||||
case DataType::STETHOSCOPE:
|
||||
filtered_channels = apply_stethoscope_filters(channels);
|
||||
break;
|
||||
default:
|
||||
// 通用滤波
|
||||
for (auto& channel : filtered_channels) {
|
||||
channel = bandpass_filter(channel, 250.0, 0.5, 45.0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return filtered_channels;
|
||||
}
|
||||
|
||||
// 新增:EEG通道滤波
|
||||
std::vector<std::vector<float>> SignalProcessor::apply_eeg_filters(
|
||||
const std::vector<std::vector<float>>& channels) {
|
||||
|
||||
const double SAMPLE_RATE = 250.0;
|
||||
std::vector<std::vector<float>> filtered_channels = channels;
|
||||
|
||||
if (channels.size() < 8) return filtered_channels;
|
||||
|
||||
// 分离EEG和EOG通道
|
||||
std::vector<std::vector<float>> eeg_channels(channels.begin(), channels.begin() + 6);
|
||||
std::vector<std::vector<float>> eog_channels(channels.begin() + 6, channels.end());
|
||||
|
||||
// 处理EEG通道
|
||||
for (auto& channel : eeg_channels) {
|
||||
// 眼电伪迹补偿
|
||||
if (eog_channels.size() >= 2) {
|
||||
channel = compensate_eog_artifact(channel, eog_channels[0], eog_channels[1]);
|
||||
}
|
||||
|
||||
// 50Hz自适应陷波滤波
|
||||
channel = adaptive_notch_filter(channel, SAMPLE_RATE, 50.0, 5.0);
|
||||
|
||||
// 0.5-45Hz带通滤波
|
||||
channel = bandpass_filter(channel, SAMPLE_RATE, 0.5, 45.0);
|
||||
}
|
||||
|
||||
// 处理EOG通道
|
||||
for (auto& channel : eog_channels) {
|
||||
channel = bandpass_filter(channel, SAMPLE_RATE, 0.5, 30.0);
|
||||
}
|
||||
|
||||
// 合并处理后的通道
|
||||
filtered_channels.clear();
|
||||
filtered_channels.insert(filtered_channels.end(), eeg_channels.begin(), eeg_channels.end());
|
||||
filtered_channels.insert(filtered_channels.end(), eog_channels.begin(), eog_channels.end());
|
||||
|
||||
return filtered_channels;
|
||||
}
|
||||
|
||||
// 新增:ECG通道滤波
|
||||
std::vector<std::vector<float>> SignalProcessor::apply_ecg_filters(
|
||||
const std::vector<std::vector<float>>& channels) {
|
||||
|
||||
const double SAMPLE_RATE = 250.0;
|
||||
std::vector<std::vector<float>> filtered_channels = channels;
|
||||
|
||||
for (auto& channel : filtered_channels) {
|
||||
// 0.5Hz高通滤波
|
||||
channel = Highpass_filter(channel, SAMPLE_RATE, 0.5);
|
||||
|
||||
// 50Hz自适应陷波滤波
|
||||
channel = adaptive_notch_filter(channel, SAMPLE_RATE, 50.0, 5.0);
|
||||
|
||||
// 25-40Hz带阻滤波
|
||||
channel = bandstop_filter(channel, SAMPLE_RATE, 25.0, 40.0);
|
||||
}
|
||||
|
||||
return filtered_channels;
|
||||
}
|
||||
|
||||
// 新增:PPG通道滤波
|
||||
std::vector<std::vector<float>> SignalProcessor::apply_ppg_filters(
|
||||
const std::vector<std::vector<float>>& channels) {
|
||||
|
||||
const double SAMPLE_RATE = 50.0;
|
||||
std::vector<std::vector<float>> filtered_channels = channels;
|
||||
|
||||
for (auto& channel : filtered_channels) {
|
||||
// 移除直流分量
|
||||
channel = remove_dc_offset(channel);
|
||||
|
||||
// 0.5-10Hz带通滤波
|
||||
channel = bandpass_filter(channel, SAMPLE_RATE, 0.5, 10.0);
|
||||
}
|
||||
|
||||
return filtered_channels;
|
||||
}
|
||||
|
||||
// 新增:呼吸通道滤波
|
||||
std::vector<std::vector<float>> SignalProcessor::apply_respiration_filters(
|
||||
const std::vector<std::vector<float>>& channels) {
|
||||
|
||||
const double SAMPLE_RATE = 100.0;
|
||||
std::vector<std::vector<float>> filtered_channels = channels;
|
||||
|
||||
for (auto& channel : filtered_channels) {
|
||||
// 0.1Hz高通滤波
|
||||
channel = filter(channel, SAMPLE_RATE, 0, 0.1, filtertype::highpass);
|
||||
|
||||
// 50Hz陷波滤波
|
||||
channel = adaptive_notch_filter(channel, SAMPLE_RATE, 50.0, 5.0);
|
||||
|
||||
// 振幅归一化
|
||||
normalize_amplitude(channel);
|
||||
}
|
||||
|
||||
return filtered_channels;
|
||||
}
|
||||
|
||||
// 新增:打鼾通道滤波
|
||||
std::vector<std::vector<float>> SignalProcessor::apply_snore_filters(
|
||||
const std::vector<std::vector<float>>& channels) {
|
||||
|
||||
const double SAMPLE_RATE = 2000.0;
|
||||
std::vector<std::vector<float>> filtered_channels = channels;
|
||||
|
||||
for (auto& channel : filtered_channels) {
|
||||
// 50-2000Hz带通滤波
|
||||
channel = bandpass_filter(channel, SAMPLE_RATE, 50.0, 2000.0);
|
||||
|
||||
// 振幅归一化
|
||||
normalize_amplitude(channel);
|
||||
}
|
||||
|
||||
return filtered_channels;
|
||||
}
|
||||
|
||||
// 新增:听诊器通道滤波
|
||||
std::vector<std::vector<float>> SignalProcessor::apply_stethoscope_filters(
|
||||
const std::vector<std::vector<float>>& channels) {
|
||||
|
||||
const double SAMPLE_RATE = 4000.0;
|
||||
std::vector<std::vector<float>> filtered_channels = channels;
|
||||
|
||||
for (auto& channel : filtered_channels) {
|
||||
// 20-2000Hz带通滤波
|
||||
channel = bandpass_filter(channel, SAMPLE_RATE, 20.0, 2000.0);
|
||||
|
||||
// 振幅归一化
|
||||
normalize_amplitude(channel);
|
||||
}
|
||||
|
||||
return filtered_channels;
|
||||
}
|
||||
|
||||
SensorData SignalProcessor::preprocess_generic(const SensorData& data) {
|
||||
SensorData processed = data;
|
||||
|
||||
|
|
@ -142,16 +402,18 @@ SensorData SignalProcessor::preprocess_ecg_12lead(const SensorData& data) {
|
|||
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);
|
||||
//channel = remove_dc_offset(channel);
|
||||
channel = filter(channel, SAMPLE_RATE,0,0.5, filtertype::highpass);
|
||||
|
||||
// 2. 50Hz自适应陷波滤波 (去除工频干扰)
|
||||
channel = filter(channel, SAMPLE_RATE, 50.0, 60,filtertype::notchpass);
|
||||
channel = filter(channel, SAMPLE_RATE, 49.5, 51.5, filtertype::notchpass);
|
||||
|
||||
// 3. 25-40Hz带阻滤波 (去除肌电干扰)
|
||||
channel = filter(channel, SAMPLE_RATE, 25.0, 40.0, filtertype::bandstop);
|
||||
channel = filter(channel, SAMPLE_RATE, 0.5, 0.6, filtertype::bandstop);
|
||||
}
|
||||
|
||||
// 计算并存储信号质量指数
|
||||
|
|
@ -291,8 +553,7 @@ std::vector<float> SignalProcessor::remove_dc_offset(const std::vector<float>& s
|
|||
float dc_remove = 0;
|
||||
for(auto& val:signal) dc_remove += val;
|
||||
dc_remove /= result.size();
|
||||
for(auto& value:result) value -= dc_remove;
|
||||
return result;
|
||||
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;
|
||||
|
|
@ -310,45 +571,53 @@ std::vector<float> SignalProcessor::adaptive_notch_filter(const std::vector<floa
|
|||
double sample_rate,
|
||||
double target_freq,
|
||||
double bandwidth) {
|
||||
std::vector<float> output(input.size(), 0.0f);
|
||||
if (input.empty()) return {};
|
||||
|
||||
// 计算滤波器系数
|
||||
double omega0 = 2 * M_PI * target_freq / sample_rate;
|
||||
double alpha = sin(omega0) * sinh(log(2) / 2 * bandwidth * omega0 / sin(omega0));
|
||||
// 使用更稳定的实现
|
||||
const double omega0 = 2 * M_PI * target_freq / sample_rate;
|
||||
const 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;
|
||||
// 系数计算
|
||||
const double b0 = 1.0;
|
||||
const double b1 = -2 * cos(omega0);
|
||||
const double b2 = 1.0;
|
||||
const double a0 = 1 + alpha;
|
||||
const double a1 = -2 * cos(omega0);
|
||||
const double a2 = 1 - alpha;
|
||||
|
||||
// 归一化系数
|
||||
b0 /= a0;
|
||||
b1 /= a0;
|
||||
b2 /= a0;
|
||||
a1 /= a0;
|
||||
a2 /= a0;
|
||||
|
||||
// 初始化滤波器状态
|
||||
double x1 = 0, x2 = 0;
|
||||
double y1 = 0, y2 = 0;
|
||||
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;
|
||||
|
||||
// 应用滤波器
|
||||
std::vector<float> output(input.size());
|
||||
double x1 = 0.0, x2 = 0.0;
|
||||
double y1 = 0.0, y2 = 0.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;
|
||||
double y = nb0 * x0 + nb1 * x1 + nb2 * x2 - na1 * y1 - na2 * y2;
|
||||
|
||||
// 防止不稳定
|
||||
if (!std::isfinite(y)) y = 0.0;
|
||||
|
||||
output[n] = static_cast<float>(y);
|
||||
|
||||
// 更新状态
|
||||
x2 = x1;
|
||||
x1 = x0;
|
||||
y2 = y1;
|
||||
y1 = output[n];
|
||||
y1 = y;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
std::vector<float> SignalProcessor::filter(const std::vector<float>& input,
|
||||
double sample_rate,
|
||||
double low_cutoff,
|
||||
|
|
@ -375,34 +644,106 @@ std::vector<float> SignalProcessor::filter(const std::vector<float>& 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;
|
||||
if (input.empty() || low_cutoff <= 0 || low_cutoff >= sample_rate/2) {
|
||||
return input;
|
||||
}
|
||||
|
||||
const double nyquist = sample_rate / 2.0;
|
||||
const double omega = 2.0 * M_PI * low_cutoff / sample_rate;
|
||||
const double k = 1.0 / tan(omega / 2.0); // 双线性变换预矫正
|
||||
const double k2 = k * k;
|
||||
const double sqrt2 = std::sqrt(2.0);
|
||||
|
||||
// 计算归一化系数
|
||||
const double a0 = k2 + sqrt2 * k + 1;
|
||||
const double b0 = 1.0 / a0;
|
||||
const double b1 = 2 * b0;
|
||||
const double b2 = b0;
|
||||
const double a1 = 2 * (1 - k2) * b0;
|
||||
const double a2 = (k2 - sqrt2 * k + 1) * b0;
|
||||
|
||||
// 应用滤波器
|
||||
std::vector<float> output(input.size());
|
||||
double x1 = 0.0, x2 = 0.0; // 输入延迟
|
||||
double y1 = 0.0, y2 = 0.0; // 输出延迟
|
||||
|
||||
for (size_t i = 0; i < input.size(); ++i) {
|
||||
const double x0 = input[i];
|
||||
const double y0 = b0 * x0 + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2;
|
||||
|
||||
output[i] = static_cast<float>(y0);
|
||||
|
||||
// 更新延迟
|
||||
x2 = x1;
|
||||
x1 = x0;
|
||||
y2 = y1;
|
||||
y1 = y0;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
//高通滤波器
|
||||
//改进后的高通滤波实现
|
||||
std::vector<float> SignalProcessor::Highpass_filter(const std::vector<float>& input,
|
||||
double sample_rate,
|
||||
double high_cutoff){
|
||||
double cutoff) {
|
||||
if (input.empty()) return input;
|
||||
int a = input[0];
|
||||
// 1. 计算滤波器系数(二阶巴特沃斯)
|
||||
const double omega = 2.0 * M_PI * cutoff / sample_rate;
|
||||
const double sn = sin(omega);
|
||||
const double cs = cos(omega);
|
||||
const double alpha = sn / (2.0 * 0.707); // Q=0.707 (Butterworth)
|
||||
|
||||
const double b0 = (1 + cs) / 2.0;
|
||||
const double b1 = -(1 + cs);
|
||||
const double b2 = b0;
|
||||
const double a0 = 1 + alpha;
|
||||
const double a1 = -2 * cs;
|
||||
const double a2 = 1 - alpha;
|
||||
|
||||
// 2. 归一化系数
|
||||
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;
|
||||
|
||||
// 3. 初始化状态(使用前两个样本值)
|
||||
double x1 = input.size() > 0 ? input[0] : 0;
|
||||
double x2 = x1;
|
||||
double y1 = 0;
|
||||
double y2 = 0;
|
||||
|
||||
// 4. 应用滤波器(处理边界条件)
|
||||
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]);
|
||||
for (size_t n = 0; n < input.size(); ++n) {
|
||||
const double x0 = input[n];
|
||||
|
||||
// 计算当前输出
|
||||
double y = nb0 * x0 + nb1 * x1 + nb2 * x2 - na1 * y1 - na2 * y2;
|
||||
|
||||
// 5. 稳定化处理(防止NaN/Inf)
|
||||
if (!std::isfinite(y)) y = 0.0;
|
||||
|
||||
output[n] = static_cast<float>(y);
|
||||
|
||||
// 6. 更新状态变量
|
||||
x2 = x1;
|
||||
x1 = x0;
|
||||
y2 = y1;
|
||||
y1 = y;
|
||||
}
|
||||
|
||||
// 7. 可选:去除初始瞬态(前100ms数据)
|
||||
/*const size_t transient_samples = static_cast<size_t>(0.1 * sample_rate);
|
||||
if (output.size() > transient_samples) {
|
||||
const float initial_value = output[transient_samples];
|
||||
for (size_t i = 0; i < transient_samples; ++i) {
|
||||
output[i] = initial_value;
|
||||
}
|
||||
}*/
|
||||
|
||||
return output;
|
||||
}
|
||||
// 带通滤波器
|
||||
|
|
@ -454,43 +795,68 @@ std::vector<float> SignalProcessor::bandpass_filter(const std::vector<float>& in
|
|||
std::vector<float> SignalProcessor::bandstop_filter(const std::vector<float>& input,
|
||||
double sample_rate,
|
||||
double low_cutoff,
|
||||
double high_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");
|
||||
}
|
||||
if (input.size() < 4) return input; // 太短的信号无法有效滤波
|
||||
|
||||
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 f0 = (low_cutoff + high_cutoff) / 2.0;
|
||||
const double bw = high_cutoff - low_cutoff;
|
||||
|
||||
// 1. 使用双线性变换进行频率预矫正
|
||||
const double T = 1.0 / sample_rate;
|
||||
const double w0 = 2.0 * M_PI * f0;
|
||||
const double wd = 2.0 * M_PI * bw;
|
||||
|
||||
// 预矫正模拟频率
|
||||
const double wa = 2.0 / T * tan(w0 * T / 2.0);
|
||||
const double Ba = 2.0 / T * tan(wd * T / 2.0);
|
||||
|
||||
// 2. 计算Butterworth滤波器系数
|
||||
const double Q = wa / Ba; // 更精确的Q值计算
|
||||
const double alpha = sin(w0 * T) / (2 * Q);
|
||||
|
||||
// 计算滤波器系数
|
||||
const double b0 = 1.0;
|
||||
const double b1 = -2 * cos(omega0);
|
||||
const double b1 = -2.0 * cos(w0 * T);
|
||||
const double b2 = 1.0;
|
||||
const double a0 = 1.0 + alpha;
|
||||
const double a1 = -2 * cos(omega0);
|
||||
const double a1 = -2.0 * cos(w0 * T);
|
||||
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;
|
||||
// 3. 更精确的系数归一化
|
||||
const double gain = 1.0 / a0; // 保证通带增益为1
|
||||
const double nb0 = b0 * gain;
|
||||
const double nb1 = b1 * gain;
|
||||
const double nb2 = b2 * gain;
|
||||
const double na1 = a1 * gain;
|
||||
const double na2 = a2 * gain;
|
||||
|
||||
// 滤波器状态
|
||||
double x1 = 0.0, x2 = 0.0;
|
||||
double y1 = 0.0, y2 = 0.0;
|
||||
// 4. 应用滤波器(带合理状态初始化)
|
||||
std::vector<float> output(input.size());
|
||||
double x1 = input[0], x2 = input[0]; // 输入状态初始化
|
||||
double y1 = 0.0, y2 = 0.0; // 输出状态初始化
|
||||
|
||||
// 使用前两个样本计算初始输出状态
|
||||
if (input.size() >= 2) {
|
||||
const double x0 = input[0];
|
||||
y1 = nb0 * x0 + nb1 * x1 + nb2 * x2;
|
||||
x2 = x1;
|
||||
x1 = x0;
|
||||
}
|
||||
|
||||
// 应用滤波器
|
||||
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;
|
||||
double y = nb0 * x0 + nb1 * x1 + nb2 * x2 - na1 * y1 - na2 * y2;
|
||||
|
||||
// 5. 添加输出限幅保护
|
||||
const double input_max = *std::max_element(input.begin(), input.end());
|
||||
const double safety_margin = 2.0 * input_max;
|
||||
if (std::abs(y) > safety_margin) {
|
||||
y = std::copysign(safety_margin, y);
|
||||
}
|
||||
|
||||
output[n] = static_cast<float>(y);
|
||||
|
||||
|
|
@ -500,17 +866,15 @@ std::vector<float> SignalProcessor::bandstop_filter(const std::vector<float>& in
|
|||
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信号质量指数
|
||||
// 辅助函数:计算PPG信号质量指 数
|
||||
float SignalProcessor::calculate_PPG_sqi(const std::vector<float>& red_channel,
|
||||
const std::vector<float>& ir_channel) {
|
||||
return 0.0f;
|
||||
|
|
@ -622,3 +986,26 @@ void SignalProcessor::normalize_amplitude(std::vector<float>& signal) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用示例:如何正确使用通道级滤波
|
||||
/*
|
||||
// 原来的错误用法(对单个数据包滤波):
|
||||
std::vector<SensorData> raw_packets = get_raw_data_packets();
|
||||
for (auto& packet : raw_packets) {
|
||||
packet = signal_processor.preprocess_signals(packet); // 错误!对单个包滤波
|
||||
}
|
||||
|
||||
// 新的正确用法(通道级滤波):
|
||||
std::vector<SensorData> raw_packets = get_raw_data_packets();
|
||||
std::vector<SensorData> processed_packets =
|
||||
signal_processor.process_channel_based_filtering(raw_packets);
|
||||
|
||||
// 或者,如果你想保持原有的数据包结构,可以这样:
|
||||
std::vector<SensorData> raw_packets = get_raw_data_packets();
|
||||
std::vector<SensorData> processed_packets =
|
||||
signal_processor.process_channel_based_filtering(raw_packets);
|
||||
|
||||
// 关键区别:
|
||||
// 1. 原来:对每个数据包内的短时间序列进行滤波(错误)
|
||||
// 2. 现在:收集所有数据包中相同通道的完整数据,进行滤波,然后重新分配
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue