From c46916a4ef31bfe0b421a0c6bbb43a6b5b107c14 Mon Sep 17 00:00:00 2001
From: marques <20172333133@m.scnu.edu.cn>
Date: Wed, 4 Jun 2025 22:26:32 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0ECG=E8=87=AA=E5=8A=A8?=
=?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=8C=BA=E9=97=B4=E5=8A=9F=E8=83=BD=EF=BC=8C?=
=?UTF-8?q?=E4=BC=98=E5=8C=96=E7=9B=B8=E5=85=B3=E6=8F=90=E7=A4=BA=E4=BF=A1?=
=?UTF-8?q?=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
func/Module_precisely_align.py | 115 +++++++++++++++++---
func/utils/Constants.py | 6 +
ui/MainWindow/MainWindow_precisely_align.py | 52 ++++++++-
ui/MainWindow/MainWindow_precisely_align.ui | 65 ++++++++++-
4 files changed, 216 insertions(+), 22 deletions(-)
diff --git a/func/Module_precisely_align.py b/func/Module_precisely_align.py
index e674d4b..8444608 100644
--- a/func/Module_precisely_align.py
+++ b/func/Module_precisely_align.py
@@ -9,7 +9,8 @@ from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication, QButtonGro
from matplotlib import gridspec, patches
from matplotlib.backends.backend_qt import NavigationToolbar2QT
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
-from numpy import (diff, where, correlate, corrcoef, sum as np_sum, max as np_max, min as np_min, arange, array,
+from numpy import (diff, where, correlate, corrcoef, searchsorted, sum as np_sum, max as np_max, min as np_min, arange,
+ array,
append, delete, abs as np_abs, argmin as np_argmin, argmax as np_argmax, asarray)
from overrides import overrides
from pandas import read_csv, DataFrame
@@ -989,13 +990,31 @@ class MainWindow_precisely_align(QMainWindow):
Config["IV_Coordinate"]["BCG_front_2"] = self.ui.spinBox_BCG_front_JJIV_2.value()
Config["Coordinate"]["BCG_front_2"] = self.data.Jpeak[:-2][self.ui.spinBox_BCG_front_JJIV_2.value()]
self.ui.spinBox_BCG_front_Signal_2.setValue(Config["Coordinate"]["BCG_front_2"])
+ estimate_ECG_front_1 = self.data.get_corresponding_interval(Config["Coordinate"]["BCG_front_1"]).data[
+ "new_point"]
+ estimate_ECG_front_2 = self.data.get_corresponding_interval(Config["Coordinate"]["BCG_front_2"]).data[
+ "new_point"]
PublicFunc.text_output(self.ui, Constants.CORRESPONDING_INTERVAL_PROMOTE_TEMPLATE.format(
Config["Coordinate"]["BCG_front_1"],
Config["Coordinate"]["BCG_front_2"],
- self.data.get_corresponding_interval(Config["Coordinate"]["BCG_front_1"]).data["new_point"],
- self.data.get_corresponding_interval(Config["Coordinate"]["BCG_front_2"]).data["new_point"],
+ estimate_ECG_front_1, estimate_ECG_front_2
), Constants.TIPS_TYPE_INFO)
+ if self.ui.checkBox_ECG_autoset.isChecked():
+ extend_second = int(self.ui.spinBox_ECG_expend_second.value())
+
+ reponse = self.data.get_rriv_from_ecg_point(
+ estimate_ECG_front_1, extend_second, "right").data
+ Config["IV_Coordinate"]["ECG_front_1"] = reponse["estimate_RRIV"]
+ Config["Coordinate"]["ECG_front_1"] = reponse["extend_point"]
+
+ reponse = self.data.get_rriv_from_ecg_point(
+ estimate_ECG_front_2, extend_second, "left").data
+
+ Config["IV_Coordinate"]["ECG_front_2"] = reponse["estimate_RRIV"]
+ Config["Coordinate"]["ECG_front_2"] = reponse["extend_point"]
+
+
elif sender == self.ui.spinBox_BCG_back_JJIV_1:
if self.ui.spinBox_BCG_back_JJIV_1.value() >= len(self.data.Jpeak[:-2]):
self.ui.spinBox_BCG_back_JJIV_1.setValue(len(self.data.Jpeak[:-2]) - 1)
@@ -1008,13 +1027,30 @@ class MainWindow_precisely_align(QMainWindow):
Config["IV_Coordinate"]["BCG_back_2"] = self.ui.spinBox_BCG_back_JJIV_2.value()
Config["Coordinate"]["BCG_back_2"] = self.data.Jpeak[:-2][self.ui.spinBox_BCG_back_JJIV_2.value()]
self.ui.spinBox_BCG_back_Signal_2.setValue(Config["Coordinate"]["BCG_back_2"])
+ estimate_ECG_back_1 = self.data.get_corresponding_interval(
+ Config["Coordinate"]["BCG_back_1"]).data["new_point"]
+ estimate_ECG_back_2 = self.data.get_corresponding_interval(
+ Config["Coordinate"]["BCG_back_2"]).data["new_point"]
PublicFunc.text_output(self.ui, Constants.CORRESPONDING_INTERVAL_PROMOTE_TEMPLATE.format(
Config["Coordinate"]["BCG_back_1"],
Config["Coordinate"]["BCG_back_2"],
- self.data.get_corresponding_interval(Config["Coordinate"]["BCG_back_1"]).data["new_point"],
- self.data.get_corresponding_interval(Config["Coordinate"]["BCG_back_2"]).data["new_point"],
+ estimate_ECG_back_1, estimate_ECG_back_2
), Constants.TIPS_TYPE_INFO)
+ if self.ui.checkBox_ECG_autoset.isChecked():
+ extend_second = int(self.ui.spinBox_ECG_expend_second.value())
+
+ reponse = self.data.get_rriv_from_ecg_point(
+ estimate_ECG_back_1, extend_second, "right").data
+ Config["IV_Coordinate"]["ECG_back_1"] = reponse["estimate_RRIV"]
+ Config["Coordinate"]["ECG_back_1"] = reponse["extend_point"]
+
+ reponse = self.data.get_rriv_from_ecg_point(
+ estimate_ECG_back_2, extend_second, "left").data
+
+ Config["IV_Coordinate"]["ECG_back_2"] = reponse["estimate_RRIV"]
+ Config["Coordinate"]["ECG_back_2"] = reponse["extend_point"]
+
elif sender == self.ui.spinBox_ECG_front_RRIV_1:
if self.ui.spinBox_ECG_front_RRIV_1.value() >= len(self.data.Rpeak[:-2]):
self.ui.spinBox_ECG_front_RRIV_1.setValue(len(self.data.Rpeak[:-2]) - 1)
@@ -1312,30 +1348,64 @@ class MainWindow_precisely_align(QMainWindow):
Config["IV_Coordinate"]["BCG_front_2"] = indices[-1]
Config["Coordinate"]["BCG_front_1"] = self.data.Jpeak[:-2][indices[0]]
Config["Coordinate"]["BCG_front_2"] = self.data.Jpeak[:-2][indices[-1]]
+ estimate_ECG_front_1 = self.data.get_corresponding_interval(
+ Config["Coordinate"]["BCG_front_1"]).data["new_point"]
+ estimate_ECG_front_2 = self.data.get_corresponding_interval(
+ Config["Coordinate"]["BCG_front_2"]).data["new_point"]
PublicFunc.text_output(
self.ui,
Constants.CORRESPONDING_INTERVAL_PROMOTE_TEMPLATE.format(
Config["Coordinate"]["BCG_front_1"],
Config["Coordinate"]["BCG_front_2"],
- self.data.get_corresponding_interval(
- Config["Coordinate"]["BCG_front_1"]).data["new_point"],
- self.data.get_corresponding_interval(
- Config["Coordinate"]["BCG_front_2"]).data["new_point"],
+ estimate_ECG_front_1, estimate_ECG_front_2
), Constants.TIPS_TYPE_INFO)
+
+ if self.ui.checkBox_ECG_autoset.isChecked():
+ extend_second = int(self.ui.spinBox_ECG_expend_second.value())
+
+ reponse = self.data.get_rriv_from_ecg_point(
+ estimate_ECG_front_1, extend_second, "right").data
+ Config["IV_Coordinate"]["ECG_front_1"] = reponse["estimate_RRIV"]
+ Config["Coordinate"]["ECG_front_1"] = reponse["extend_point"]
+
+ reponse = self.data.get_rriv_from_ecg_point(
+ estimate_ECG_front_2, extend_second, "left").data
+
+ Config["IV_Coordinate"]["ECG_front_2"] = reponse["estimate_RRIV"]
+ Config["Coordinate"]["ECG_front_2"] = reponse["extend_point"]
+
+
+
elif self.ui.radioButton_BCG_back.isChecked():
Config["IV_Coordinate"]["BCG_back_1"] = indices[0]
Config["IV_Coordinate"]["BCG_back_2"] = indices[-1]
Config["Coordinate"]["BCG_back_1"] = self.data.Jpeak[:-2][indices[0]]
Config["Coordinate"]["BCG_back_2"] = self.data.Jpeak[:-2][indices[-1]]
+ estimate_ECG_back_1 = self.data.get_corresponding_interval(
+ Config["Coordinate"]["BCG_back_1"]).data["new_point"]
+ estimate_ECG_back_2 = self.data.get_corresponding_interval(
+ Config["Coordinate"]["BCG_back_2"]).data["new_point"]
PublicFunc.text_output(
self.ui, Constants.CORRESPONDING_INTERVAL_PROMOTE_TEMPLATE.format(
Config["Coordinate"]["BCG_back_1"],
Config["Coordinate"]["BCG_back_2"],
- self.data.get_corresponding_interval(
- Config["Coordinate"]["BCG_back_1"]).data["new_point"],
- self.data.get_corresponding_interval(
- Config["Coordinate"]["BCG_back_2"]).data["new_point"],
+ estimate_ECG_back_1, estimate_ECG_back_2
), Constants.TIPS_TYPE_INFO)
+
+ if self.ui.checkBox_ECG_autoset.isChecked():
+ extend_second = int(self.ui.spinBox_ECG_expend_second.value())
+
+ reponse = self.data.get_rriv_from_ecg_point(
+ estimate_ECG_back_1, extend_second, "right").data
+ Config["IV_Coordinate"]["ECG_back_1"] = reponse["estimate_RRIV"]
+ Config["Coordinate"]["ECG_back_1"] = reponse["extend_point"]
+
+ reponse = self.data.get_rriv_from_ecg_point(
+ estimate_ECG_back_2, extend_second, "left").data
+
+ Config["IV_Coordinate"]["ECG_back_2"] = reponse["estimate_RRIV"]
+ Config["Coordinate"]["ECG_back_2"] = reponse["extend_point"]
+
elif self.ui.radioButton_ECG_front.isChecked() or self.ui.radioButton_ECG_back.isChecked():
if rect_left < 0:
rect_left = 0
@@ -1374,7 +1444,6 @@ class MainWindow_precisely_align(QMainWindow):
Config["Coordinate"]["ECG_back_1"] = self.data.Rpeak[:-2][indices[0]]
Config["Coordinate"]["ECG_back_2"] = self.data.Rpeak[:-2][indices[-1]]
-
self.figToolbar.rect_start_x = None
self.figToolbar.rect_end_x = None
@@ -2138,6 +2207,24 @@ class Data:
return Result().success(info=Constants.PRECISELY_ALIGN_GET_CORRESPONDING_INTERVAL_FINISHED, data=result)
+ def get_rriv_from_ecg_point(self, point:int, expend_second:int, side="left"):
+ extend_point = expend_second * Config["InputConfig"]["UseFreq"]
+
+ if side == "left":
+ extend_point = max(point + extend_point, 0)
+ elif side == "right":
+ extend_point = min(point - extend_point, max(self.Rpeak))
+
+ else:
+ return Result().failure(info=Constants.PRECISELY_ALIGN_GET_RRIV_FROM_ECG_POINT_FAILURE +
+ Constants.FAILURE_REASON["Invalid_Side_Parameter"])
+
+ extend_estimate_RRIV = searchsorted(self.Rpeak[:-2], extend_point, side)
+ result = {
+ "estimate_RRIV": extend_estimate_RRIV,
+ "extend_point": extend_point
+ }
+ return Result().success(info=Constants.PRECISELY_ALIGN_GET_RRIV_FROM_ECG_POINT_FINISHED, data=result)
class CustomNavigationToolbar(NavigationToolbar2QT):
diff --git a/func/utils/Constants.py b/func/utils/Constants.py
index 0b7f2cd..e28b358 100644
--- a/func/utils/Constants.py
+++ b/func/utils/Constants.py
@@ -126,6 +126,7 @@ class Constants:
"Calculate_Correlation1_Exception": "(计算互相关1/2异常)",
"Calculate_Correlation2_Exception": "(计算互相关2/2异常)",
"Calculate_Maxvalue_Pos_Exception": "(计算最大值位置异常)",
+ "Invalid_Side_Parameter": "(无效的方向参数)",
"Get_Epoch_Exception": "(获取epoch异常)",
"Get_Corr_By_Epoch_Exception": "(通过epoch获取相关性异常)",
"Predict_Exception": "(预测异常)",
@@ -258,6 +259,11 @@ class Constants:
PRECISELY_ALIGN_PROCESS_FINISHED: str = "处理完成"
PRECISELY_ALIGN_PROCESS_FAILURE: str = "处理失败"
+ #
+ PRECISELY_ALIGN_GET_RRIV_FROM_ECG_POINT_FAILURE: str = "从ECG点获取RRIV失败"
+ PRECISELY_ALIGN_GET_RRIV_FROM_ECG_POINT_FINISHED: str = "从ECG点获取RRIV完成"
+
+
PRECISELY_ALIGN_CALCULATING_CORRELATION_FRONT: str = "正在计算前段相关性"
PRECISELY_ALIGN_CALCULATE_FINISHED_FRONT: str = "计算前段相关性完成"
PRECISELY_ALIGN_CALCULATE_FAILURE_FRONT: str = "计算前段相关性失败"
diff --git a/ui/MainWindow/MainWindow_precisely_align.py b/ui/MainWindow/MainWindow_precisely_align.py
index 7a51e76..89617f2 100644
--- a/ui/MainWindow/MainWindow_precisely_align.py
+++ b/ui/MainWindow/MainWindow_precisely_align.py
@@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'MainWindow_precisely_align.ui'
##
-## Created by: Qt User Interface Compiler version 6.8.2
+## Created by: Qt User Interface Compiler version 6.7.0
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@@ -16,10 +16,11 @@ from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient,
QIcon, QImage, QKeySequence, QLinearGradient,
QPainter, QPalette, QPixmap, QRadialGradient,
QTransform)
-from PySide6.QtWidgets import (QAbstractSpinBox, QApplication, QGridLayout, QGroupBox,
- QHBoxLayout, QLabel, QMainWindow, QPushButton,
- QRadioButton, QSizePolicy, QSpacerItem, QSpinBox,
- QStatusBar, QTextBrowser, QVBoxLayout, QWidget)
+from PySide6.QtWidgets import (QAbstractSpinBox, QApplication, QCheckBox, QGridLayout,
+ QGroupBox, QHBoxLayout, QLabel, QMainWindow,
+ QPushButton, QRadioButton, QSizePolicy, QSpacerItem,
+ QSpinBox, QStatusBar, QTextBrowser, QVBoxLayout,
+ QWidget)
class Ui_MainWindow_precisely_align(object):
def setupUi(self, MainWindow_precisely_align):
@@ -96,6 +97,38 @@ class Ui_MainWindow_precisely_align(object):
self.groupBox_args.setObjectName(u"groupBox_args")
self.verticalLayout_5 = QVBoxLayout(self.groupBox_args)
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
+ self.groupBox_6 = QGroupBox(self.groupBox_args)
+ self.groupBox_6.setObjectName(u"groupBox_6")
+ self.horizontalLayout = QHBoxLayout(self.groupBox_6)
+ self.horizontalLayout.setObjectName(u"horizontalLayout")
+ self.checkBox_ECG_autoset = QCheckBox(self.groupBox_6)
+ self.checkBox_ECG_autoset.setObjectName(u"checkBox_ECG_autoset")
+ self.checkBox_ECG_autoset.setChecked(True)
+
+ self.horizontalLayout.addWidget(self.checkBox_ECG_autoset)
+
+ self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Minimum)
+
+ self.horizontalLayout.addItem(self.horizontalSpacer)
+
+ self.label_17 = QLabel(self.groupBox_6)
+ self.label_17.setObjectName(u"label_17")
+ self.label_17.setAlignment(Qt.AlignmentFlag.AlignRight|Qt.AlignmentFlag.AlignTrailing|Qt.AlignmentFlag.AlignVCenter)
+
+ self.horizontalLayout.addWidget(self.label_17)
+
+ self.spinBox_ECG_expend_second = QSpinBox(self.groupBox_6)
+ self.spinBox_ECG_expend_second.setObjectName(u"spinBox_ECG_expend_second")
+ self.spinBox_ECG_expend_second.setAlignment(Qt.AlignmentFlag.AlignRight|Qt.AlignmentFlag.AlignTrailing|Qt.AlignmentFlag.AlignVCenter)
+ self.spinBox_ECG_expend_second.setButtonSymbols(QAbstractSpinBox.ButtonSymbols.NoButtons)
+ self.spinBox_ECG_expend_second.setMaximum(1000000)
+ self.spinBox_ECG_expend_second.setValue(30)
+
+ self.horizontalLayout.addWidget(self.spinBox_ECG_expend_second)
+
+
+ self.verticalLayout_5.addWidget(self.groupBox_6)
+
self.groupBox_2 = QGroupBox(self.groupBox_args)
self.groupBox_2.setObjectName(u"groupBox_2")
self.verticalLayout_2 = QVBoxLayout(self.groupBox_2)
@@ -426,6 +459,11 @@ class Ui_MainWindow_precisely_align(object):
self.verticalLayout_5.addWidget(self.groupBox_5)
+ self.verticalLayout_5.setStretch(0, 2)
+ self.verticalLayout_5.setStretch(1, 2)
+ self.verticalLayout_5.setStretch(2, 2)
+ self.verticalLayout_5.setStretch(3, 2)
+ self.verticalLayout_5.setStretch(4, 2)
self.verticalLayout.addWidget(self.groupBox_args)
@@ -489,7 +527,6 @@ class Ui_MainWindow_precisely_align(object):
self.verticalLayout.setStretch(0, 1)
self.verticalLayout.setStretch(1, 7)
- self.verticalLayout.setStretch(2, 2)
self.verticalLayout.setStretch(3, 1)
self.verticalLayout.setStretch(4, 1)
self.verticalLayout.setStretch(5, 5)
@@ -517,6 +554,9 @@ class Ui_MainWindow_precisely_align(object):
self.pushButton_input_setting.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u5bfc\u5165\u8bbe\u7f6e", None))
self.pushButton_input.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u5f00\u59cb\u5bfc\u5165", None))
self.groupBox_args.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u53c2\u6570\u8f93\u5165", None))
+ self.groupBox_6.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"ECG\u81ea\u52a8\u83b7\u53d6\u533a\u95f4", None))
+ self.checkBox_ECG_autoset.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u81ea\u52a8\u83b7\u53d6ECG\u533a\u95f4", None))
+ self.label_17.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u62d3\u5c55\u79d2\u6570\uff1a", None))
self.groupBox_2.setTitle(QCoreApplication.translate("MainWindow_precisely_align", u"\u524d\u6bb5BCG\u533a\u95f4\u5750\u6807\u53d6\u503c", None))
self.radioButton_BCG_front.setText(QCoreApplication.translate("MainWindow_precisely_align", u"\u524d\u6bb5BCG", None))
self.label_4.setText(QCoreApplication.translate("MainWindow_precisely_align", u"~", None))
diff --git a/ui/MainWindow/MainWindow_precisely_align.ui b/ui/MainWindow/MainWindow_precisely_align.ui
index 566269e..f4e7095 100644
--- a/ui/MainWindow/MainWindow_precisely_align.ui
+++ b/ui/MainWindow/MainWindow_precisely_align.ui
@@ -56,7 +56,7 @@
数据精同步
-
+
-
-
@@ -102,7 +102,68 @@
参数输入
-
+
+
-
+
+
+ ECG自动获取区间
+
+
+
-
+
+
+ 自动获取ECG区间
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+ QSizePolicy::Policy::Preferred
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ 拓展秒数:
+
+
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
+
+
+
+ -
+
+
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
+
+
+ QAbstractSpinBox::ButtonSymbols::NoButtons
+
+
+ 1000000
+
+
+ 30
+
+
+
+
+
+
-