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