From 731e95a38aa8c4b550d3c519f99606bf8b879d98 Mon Sep 17 00:00:00 2001 From: zhaohe Date: Fri, 31 May 2024 21:29:29 +0800 Subject: [PATCH] update --- .vscode/settings.json | 3 +- CMakeLists.txt.user | 8 +- mainwindow.cpp | 36 +- mainwindow.ui | 1360 ++++++++++++----------- src/filter_algo_mgr.cpp | 24 + src/filter_algo_mgr.hpp | 6 + src/filter_group/algo/iflytop_simple_filter.cpp | 37 + src/filter_group/algo/iflytop_simple_filter.h | 11 + src/filter_group/if/if_filter_group.hpp | 15 +- src/filter_group/iir_filter_group.cpp | 7 +- src/filter_group/iir_filter_group.hpp | 1 + 11 files changed, 855 insertions(+), 653 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 6fff06c..b866fb6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -88,7 +88,8 @@ "qmessagebox": "cpp", "qgridlayout": "cpp", "qmenu": "cpp", - "qtconcurrent": "cpp" + "qtconcurrent": "cpp", + "ranges": "cpp" }, "files.autoGuessEncoding": false, } \ No newline at end of file diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user index f82a021..db0394b 100644 --- a/CMakeLists.txt.user +++ b/CMakeLists.txt.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -94,7 +94,7 @@ Desktop Qt 5.12.12 MinGW 64-bit Desktop Qt 5.12.12 MinGW 64-bit qt.qt5.51212.win64_mingw73_kit - 0 + 4 0 0 @@ -106,7 +106,7 @@ -DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX} -DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C} -DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx} - D:\workspace\nordic_wp\build-electrocardiograph_upper-Desktop_Qt_5_12_12_MinGW_64_bit-Release + D:/workspace/nordic_wp/build-electrocardiograph_upper-Desktop_Qt_5_12_12_MinGW_64_bit-Release @@ -347,7 +347,7 @@ true false true - D:/workspace/nordic_wp/build-electrocardiograph_upper-Desktop_Qt_5_12_12_MinGW_64_bit-Release + D:/workspace/nordic_wp/electrocardiograph_upper/build 1 diff --git a/mainwindow.cpp b/mainwindow.cpp index 2ea520b..f4fb25b 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -316,14 +316,38 @@ void MainWindow::constructUI() { heartrate_report_packet_t *heartrate_report = (heartrate_report_packet_t *)report_packet; static uint32_t lastpacket_index = 0; static uint32_t lostpacket = 0; - if ((lastpacket_index + 5) != (heartrate_report->sample_data_index)) { + + int packetFrameNum = (len - sizeof(heartrate_report_packet_t)) / 9; + if ((lastpacket_index + packetFrameNum) != (heartrate_report->sample_data_index)) { lostpacket++; } lastpacket_index = heartrate_report->sample_data_index; reportPreviewShow("[preview data ] lost:%d index %d", lostpacket, heartrate_report->sample_data_index); - - + { + // 解析心电数据 + + int32_t val[3]; + for (size_t i = 0; i < packetFrameNum; i++) { + uint8_t *val0p = heartrate_report->data + i * 9; + uint8_t *val1p = val0p + 3; + uint8_t *val2p = val1p + 3; + + val[0] = (int32_t)(val0p[0]) + ((int32_t)val0p[1] << 8) + ((int32_t)val0p[2] << 16); + val[1] = (int32_t)(val1p[0]) + ((int32_t)val1p[1] << 8) + ((int32_t)val1p[2] << 16); + val[2] = (int32_t)(val2p[0]) + ((int32_t)val2p[1] << 8) + ((int32_t)val2p[2] << 16); + + emit doinui_signal(QFunction([this, val, i]() { // + int32_t data0 = FilterAlgoMgr::ins()->processData("心电1", val[0]); + int32_t data1 = FilterAlgoMgr::ins()->processData("心电2", val[1]); + int32_t data2 = FilterAlgoMgr::ins()->processData("心电3", val[2]); + + wp2d->addData("心电1", data0, 0); + wp2d->addData("心电2", data1, 0); + wp2d->addData("心电3", data2, 0); + })); + } + } } else if (m_devicetype == kone_lead_ecg_v2) { if (!checkok) return; @@ -761,6 +785,9 @@ void MainWindow::on_FilterUpdateParameter_clicked() { FilterAlgoMgr::ins()->BaselineDriftRemoval_setEnable(ui->BaselineDriftRemoval_Enable->isChecked()); FilterAlgoMgr::ins()->BaselineDriftRemoval_setWindowsSize(ui->BaselineDriftRemoval_WindowsSize->text().toInt()); + FilterAlgoMgr::ins()->MedianFilter_setEnable(ui->MedianFilter_Enable->isChecked()); + FilterAlgoMgr::ins()->MedianFilter_setWindowsSize(ui->MedianFilter_WindowsSize->text().toInt()); + FilterAlgoMgr::ins()->updateParameter(); on_buttonTabWidget_currentChanged(0); @@ -790,6 +817,9 @@ void MainWindow::on_buttonTabWidget_currentChanged(int index) { ui->BaselineDriftRemoval_Enable->setChecked(FilterAlgoMgr::ins()->BaselineDriftRemoval_getEnable()); ui->BaselineDriftRemoval_WindowsSize->setText(QString::number(FilterAlgoMgr::ins()->BaselineDriftRemoval_getWindowsSize())); + + ui->MedianFilter_Enable->setChecked(FilterAlgoMgr::ins()->MedianFilter_getEnable()); + ui->MedianFilter_WindowsSize->setText(QString::number(FilterAlgoMgr::ins()->MedianFilter_getWindowsSize())); } void MainWindow::on_TestCmd_writeSubICAllReg_clicked() { diff --git a/mainwindow.ui b/mainwindow.ui index 1012a0d..f9db78a 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -869,7 +869,7 @@ p, li { white-space: pre-wrap; } - 2 + 1 @@ -1343,151 +1343,184 @@ p, li { white-space: pre-wrap; } - + - 设备测试 + 滤波器配置 - + - - - - 0 - 300 - + + + + 0 + 0 + - 测试指令 + 滤波器配置 - - - - - - 1 - 0 - - - - - 0 - 0 - - - - - 16777215 - 30 - - - - - - - - - 1 - 0 - - + + + 0 - 0 - - - - - 16777215 - 30 + 150 - - - - - 预设配置 + 通用参数 - - - - - - 16777215 - 1 - + + + + + + 1 + 0 + - - - - - 0 - 30 - + + + + + 1 + 0 + - 修改信号源为方波 + windowsSize - - - - - 16777215 - 1 - + + + + + 1 + 0 + - - - + + + + Qt::Vertical + + - 16777215 - 1 + 20 + 40 + + + + + + + 1 + 0 + + - + 数据采样周期(ms) - - - + + + + + 1 + 0 + + + + windowsType + + + + + + + + + + + + + 中值滤波 + + + + + + Qt::Vertical + + - 16777215 - 1 + 20 + 40 + + + + + + + 1 + 0 + + - - - - - 0 - 1 - + + + + + 1 + 0 + - - - 16777215 - 1 - + + 使能 + + + + + + + + 1 + 0 + + + + windowSize + + + + + + + + 1 + 0 + @@ -1497,428 +1530,130 @@ p, li { white-space: pre-wrap; } - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 1 - 0 - - - - - 0 - 30 - - - - 写ECG寄存器() + + + + 陷波滤波器(带阻) - - - - - - - 1 - 0 - - - - - 0 - 0 - - - - - 16777215 - 30 - - - - - - - - - 1 - 0 - - - - - 0 - 0 - - - - - 16777215 - 30 - - - - - - - - - 0 - 30 - - - - 读取ECG芯片寄存器 - - - - - - - - 0 - 30 - - - - 批量设置寄存器 - - - - - - - - 1 - 0 - - - - - 0 - 0 - - - - - 16777215 - 30 - - - - - - - - 基本操作 - - - - - - - 16777215 - 1 - + + + + + + 1 + 0 + - + 中心频率(HZ) - - - - - 16777215 - 1 - + + + + + 1 + 0 + - + 窗口宽度(HZ) - - - - 0 - 30 - + + + + 1 + 0 + - 停止采集 + - - - - - 0 - 1 - - - - - 16777215 - 1 - + + + + + 1 + 0 + - + 使能 - - - - - 0 - 30 - - - - 开始采集 + + + + + 1 + 0 + - - - - - 16777215 - 1 - + + + + + 1 + 0 + - - - + + + + Qt::Vertical + + - 16777215 - 1 + 20 + 40 + + + + + + + 1 + 0 + + + + + + + + + 1 + 0 + + - + 阶级 - - - - - 0 - 30 - - - - 写ECG寄存器 - - - - - - - - 1 - 0 - - - - - 0 - 0 - - - - - 16777215 - 30 - - - - - - - - - 1 - 0 - - - - - 0 - 0 - - - - - 16777215 - 30 - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 滤波器配置 - - - - - - - 0 - 0 - - - - 滤波器配置 - - - - - - - 0 - 150 - - - - 通用参数 - - - - - - - 1 - 0 - - - - - - - - - - - - 1 - 0 - - - - windowsSize - - - - - - - - 1 - 0 - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 1 - 0 - - - - 数据采样周期(ms) - - - - - - - - 1 - 0 - - - - windowsType - - - - - - - - - - - - - 高通滤波器 + + + + 高通滤波器 @@ -2109,14 +1844,40 @@ p, li { white-space: pre-wrap; } - - + + - 陷波滤波器(带阻) + 中值去基线 - - - + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 1 + 0 + + + + + + + + + 1 @@ -2124,12 +1885,12 @@ p, li { white-space: pre-wrap; } - 中心频率(HZ) + 使能 - - + + 1 @@ -2137,14 +1898,14 @@ p, li { white-space: pre-wrap; } - 窗口宽度(HZ) + windowSize - - + + - + 1 0 @@ -2154,8 +1915,17 @@ p, li { white-space: pre-wrap; } + + + + + + + 滑动均值滤波器 + + - + 1 @@ -2167,20 +1937,23 @@ p, li { white-space: pre-wrap; } - - + + - + 1 0 + + windowSize + - - + + - + 1 0 @@ -2190,8 +1963,8 @@ p, li { white-space: pre-wrap; } - - + + Qt::Vertical @@ -2203,171 +1976,441 @@ p, li { white-space: pre-wrap; } - - - - + + + + 1 0 + + + - - - - - 1 - 0 - + + + + + + + + + + + 0 + 30 + + + + + 16777215 + 16777215 + + + + 更新滤波器参数 + + + + + + + GroupBox + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 单导V2(M1003)设备测试 + + + + + + + 0 + 300 + + + + 测试指令 + + + + + + + 1 + 0 + + + + + 0 + 0 + + + + + 16777215 + 30 + + + + + + + + + 1 + 0 + + + + + 0 + 0 + + + + + 16777215 + 30 + + + + + + + + 预设配置 + + + + + + + 16777215 + 1 + - 阶级 + + + + + + + + + 0 + 30 + + + + 修改信号源为方波 + + + + + + + + 16777215 + 1 + + + + + + + + + + + + 16777215 + 1 + + + + + + + + + + + + 16777215 + 1 + + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + - - + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 1 + 0 + + + + + 0 + 30 + + + + 写ECG寄存器() + + + + + + + + 1 + 0 + + + + + 0 + 0 + + + + + 16777215 + 30 + + + + + + + + + 1 + 0 + + + + + 0 + 0 + + + + + 16777215 + 30 + + + + + + + + + 0 + 30 + + + + 读取ECG芯片寄存器 + + + + + + + + 0 + 30 + + + + 批量设置寄存器 + + + + + + + + 1 + 0 + + + + + 0 + 0 + + + + + 16777215 + 30 + + + + + + - 滑动均值滤波器 + 基本操作 - - - - - Qt::Vertical - - + + + + - 20 - 40 + 16777215 + 1 - - - - - - - 1 - 0 - - - - - - - 1 - 0 - - - - 使能 - - - - - - - - 1 - 0 - + + + + + 16777215 + 1 + - windowSize + - - - - - 1 - 0 - + + + + + 0 + 30 + - + 停止采集 - - - - - - - 中值去基线 - - - - - - Qt::Vertical - - + + + - 20 - 40 + 0 + 1 - - - - - - - 1 - 0 - + + + 16777215 + 1 + - - - - - 1 - 0 - + + + + + 0 + 30 + - 使能 + 开始采集 - - - - - 1 - 0 - + + + + + 16777215 + 1 + - windowSize + - - - - - 1 - 0 - + + + + + 16777215 + 1 + @@ -2377,37 +2420,68 @@ p, li { white-space: pre-wrap; } + + + + + 0 + 30 + + + + 写ECG寄存器 + + + + + + + + 1 + 0 + + + + + 0 + 0 + + + + + 16777215 + 30 + + + + + + + + + 1 + 0 + + + + + 0 + 0 + + + + + 16777215 + 30 + + + + - - - - 0 - 30 - - - - - 16777215 - 16777215 - - - - 更新滤波器参数 - - - - - - - GroupBox - - - - - + Qt::Vertical @@ -2588,7 +2662,7 @@ p, li { white-space: pre-wrap; } 0 0 1532 - 20 + 23 diff --git a/src/filter_algo_mgr.cpp b/src/filter_algo_mgr.cpp index 9a90c2f..a38152f 100644 --- a/src/filter_algo_mgr.cpp +++ b/src/filter_algo_mgr.cpp @@ -257,4 +257,28 @@ bool FilterAlgoMgr::BaselineDriftRemoval_getEnable() { return it.second->BaselineDriftRemoval_getEnable(); } return 0; +} + +void FilterAlgoMgr::MedianFilter_setWindowsSize(int windows_size) { + for (auto& it : m_filter_map) { + it.second->MedianFilter_setWindowsSize(windows_size); + } +} +void FilterAlgoMgr::MedianFilter_setEnable(bool enable) { + for (auto& it : m_filter_map) { + it.second->MedianFilter_setEnable(enable); + } +} + +int FilterAlgoMgr::MedianFilter_getWindowsSize() { + for (auto& it : m_filter_map) { + return it.second->MedianFilter_getWindowsSize(); + } + return 0; +} +bool FilterAlgoMgr::MedianFilter_getEnable() { + for (auto& it : m_filter_map) { + return it.second->MedianFilter_getEnable(); + } + return 0; } \ No newline at end of file diff --git a/src/filter_algo_mgr.hpp b/src/filter_algo_mgr.hpp index a05501f..3712386 100644 --- a/src/filter_algo_mgr.hpp +++ b/src/filter_algo_mgr.hpp @@ -90,6 +90,12 @@ class FilterAlgoMgr { int BaselineDriftRemoval_getWindowsSize(); bool BaselineDriftRemoval_getEnable(); + + void MedianFilter_setWindowsSize(int windows_size); + void MedianFilter_setEnable(bool enable); + + int MedianFilter_getWindowsSize(); + bool MedianFilter_getEnable(); }; } // namespace iflytop \ No newline at end of file diff --git a/src/filter_group/algo/iflytop_simple_filter.cpp b/src/filter_group/algo/iflytop_simple_filter.cpp index 72eb3ae..930e1be 100644 --- a/src/filter_group/algo/iflytop_simple_filter.cpp +++ b/src/filter_group/algo/iflytop_simple_filter.cpp @@ -205,3 +205,40 @@ float BaselineDriftRemoval_Update(BaselineDriftRemoval_t *filter, float vin) { return min_data_in_fifo - mid; } + +void MedianFilter_Init(MedianFilter_t *filter, int windows_size, bool enable) { + if (windows_size > MAX_MEDIAN_FILTER_SIZE) { + windows_size = MAX_MEDIAN_FILTER_SIZE; + } + + filter->windows_size = windows_size; + filter->datanum = 0; + filter->enable = enable; +} +float MedianFilter_Update(MedianFilter_t *filter, float vin) { + if (!filter->enable) return vin; + + memmove(filter->datawindows, filter->datawindows + 1, (filter->windows_size - 1) * sizeof(float)); + + filter->datawindows[filter->windows_size - 1] = vin; + filter->datanum++; + + float datacache[MAX_MEDIAN_FILTER_SIZE]; + memcpy(datacache, filter->datawindows, filter->windows_size * sizeof(float)); + + for (int i = 0; i < filter->windows_size; i++) { + for (int j = i + 1; j < filter->windows_size; j++) { + if (datacache[i] > datacache[j]) { + float temp = datacache[i]; + datacache[i] = datacache[j]; + datacache[j] = temp; + } + } + } + + if (filter->datanum < filter->windows_size) { + return vin; + } else { + return datacache[filter->windows_size / 2]; + } +} \ No newline at end of file diff --git a/src/filter_group/algo/iflytop_simple_filter.h b/src/filter_group/algo/iflytop_simple_filter.h index 8c226dc..f19d811 100644 --- a/src/filter_group/algo/iflytop_simple_filter.h +++ b/src/filter_group/algo/iflytop_simple_filter.h @@ -93,4 +93,15 @@ float BaselineDriftRemoval_Update(BaselineDriftRemoval_t *filter, float vin); // } // #endif +#define MAX_MEDIAN_FILTER_SIZE 100 +typedef struct { + float datawindows[MAX_MEDIAN_FILTER_SIZE]; + int windows_size; + int datanum; + bool enable; +} MedianFilter_t; + +void MedianFilter_Init(MedianFilter_t *filter, int windows_size, bool enable); +float MedianFilter_Update(MedianFilter_t *filter, float vin); + #endif \ No newline at end of file diff --git a/src/filter_group/if/if_filter_group.hpp b/src/filter_group/if/if_filter_group.hpp index 36f67d1..a4e9af1 100644 --- a/src/filter_group/if/if_filter_group.hpp +++ b/src/filter_group/if/if_filter_group.hpp @@ -17,7 +17,7 @@ using namespace std; class IF_FilterGroup { protected: - float _sampleTimeMs= 2; + float _sampleTimeMs = 2; int _windows_size = 500; string _windowType = "hamming"; @@ -40,6 +40,9 @@ class IF_FilterGroup { int _BaselineDriftRemoval_WindowsSize = 170; bool _BaselineDriftRemoval_Enable = false; + int _MedianFilter_WindowsSize = 15; + bool _MedianFilter_Enable = false; + // BaselineDriftRemoval_Enable const string kwindow_type_hamming = "hamming"; @@ -122,5 +125,15 @@ class IF_FilterGroup { virtual int BaselineDriftRemoval_getWindowsSize() { return _BaselineDriftRemoval_WindowsSize; } virtual bool BaselineDriftRemoval_getEnable() { return _BaselineDriftRemoval_Enable; } + + /*********************************************************************************************************************** + * MedianFilter * + ***********************************************************************************************************************/ + + virtual void MedianFilter_setWindowsSize(int windows_size) { _MedianFilter_WindowsSize = windows_size; } + virtual void MedianFilter_setEnable(bool enable) { _MedianFilter_Enable = enable; } + + virtual int MedianFilter_getWindowsSize() { return _MedianFilter_WindowsSize; } + virtual bool MedianFilter_getEnable() { return _MedianFilter_Enable; } }; } // namespace iflytop diff --git a/src/filter_group/iir_filter_group.cpp b/src/filter_group/iir_filter_group.cpp index 0624a94..de95f09 100644 --- a/src/filter_group/iir_filter_group.cpp +++ b/src/filter_group/iir_filter_group.cpp @@ -30,10 +30,13 @@ int32_t IIRFilterGroup::processData(int32_t data) { // v0 = BaselineDriftRemoval_Update(&baselineDriftRemoval, v0); + v0 = SmoothingFilter_Update(&smoothingFilter, v0); + + v0 = MedianFilter_Update(&medianFilter, v0); + return (int32_t)v0; } - void IIRFilterGroup::updateParameter() { std::lock_guard lock(lock_); @@ -53,4 +56,6 @@ void IIRFilterGroup::updateParameter() { SmoothingFilter_Init(&smoothingFilter, _SmoothingFilter_WindowsSize, _SmoothingFilter_Enable); BaselineDriftRemoval_Init(&baselineDriftRemoval, _BaselineDriftRemoval_WindowsSize, _BaselineDriftRemoval_Enable); + + MedianFilter_Init(&medianFilter, _MedianFilter_WindowsSize, _MedianFilter_Enable); } diff --git a/src/filter_group/iir_filter_group.hpp b/src/filter_group/iir_filter_group.hpp index f0e41bb..9aeda18 100644 --- a/src/filter_group/iir_filter_group.hpp +++ b/src/filter_group/iir_filter_group.hpp @@ -27,6 +27,7 @@ class IIRFilterGroup : public IF_FilterGroup { SmoothingFilter_t smoothingFilter; BaselineDriftRemoval_t baselineDriftRemoval; + MedianFilter_t medianFilter; int __lpfilter_order = 1; int __hpfilter_order = 1;