Compare commits

...

7 Commits

5 changed files with 94 additions and 52 deletions

View File

@ -7,12 +7,11 @@ from PySide6.QtWidgets import QMessageBox, QMainWindow, QApplication
from matplotlib.backends.backend_qt import NavigationToolbar2QT from matplotlib.backends.backend_qt import NavigationToolbar2QT
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure from matplotlib.figure import Figure
from numba import prange, njit
from numpy import repeat, convolve, ones, mean, std, empty, int64, sum as np_sum, pad, zeros, array, argmax, linspace, \ from numpy import repeat, convolve, ones, mean, std, empty, int64, sum as np_sum, pad, zeros, array, argmax, linspace, \
diff diff
from overrides import overrides from overrides import overrides
from pandas import read_csv, DataFrame from pandas import read_csv, DataFrame
from scipy.signal import find_peaks, resample, butter, sosfiltfilt from scipy.signal import find_peaks, resample, butter, sosfiltfilt, correlate
from yaml import dump, load, FullLoader from yaml import dump, load, FullLoader
from func.utils.PublicFunc import PublicFunc from func.utils.PublicFunc import PublicFunc
@ -856,10 +855,19 @@ class Data:
self.processed_Abd = None self.processed_Abd = None
def open_file(self): def open_file(self):
if ((not Path(Config["Path"]["Input_orgBcg"]).exists())
or (not Path(Config["Path"]["Input_Tho"]).exists()) if not Path(Config["Path"]["Input_orgBcg"]).exists():
or (not Path(Config["Path"]["Input_Abd"]).exists())): return Result().failure(
return Result().failure(info=Constants.INPUT_FAILURE + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON["Data_Path_Not_Exist"]) info=Constants.INPUT_FAILURE + "orgBcg: " + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON[
"Data_Path_Not_Exist"])
if not Path(Config["Path"]["Input_Tho"]).exists():
return Result().failure(
info=Constants.INPUT_FAILURE + "Tho: " + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON[
"Data_Path_Not_Exist"])
if not Path(Config["Path"]["Input_Abd"]).exists():
return Result().failure(
info=Constants.INPUT_FAILURE + "Abd: " + Constants.APPROXIMATELY_ALIGN_FAILURE_REASON[
"Data_Path_Not_Exist"])
try: try:
self.raw_orgBcg = read_csv(Config["Path"]["Input_orgBcg"], self.raw_orgBcg = read_csv(Config["Path"]["Input_orgBcg"],
@ -1008,20 +1016,16 @@ class Data:
def calculate_correlation1(self): def calculate_correlation1(self):
# 计算互相关1/2 # 计算互相关1/2
try: try:
# 计算因子
MULTIPLE_FACTOER = ConfigParams.APPROXIMATELY_ALIGN_CONFIG_NEW_CONTENT["Multiple_Factor"]
a = self.processed_Tho[Config["PSGConfig"]["PreCut"]:len(self.processed_Tho) - Config["PSGConfig"]["PostCut"]].copy() a = self.processed_Tho[Config["PSGConfig"]["PreCut"]:len(self.processed_Tho) - Config["PSGConfig"]["PostCut"]].copy()
v = self.processed_orgBcg[Config["orgBcgConfig"]["PreCut"]:len(self.processed_orgBcg) - Config["orgBcgConfig"]["PostCut"]].copy() v = self.processed_orgBcg[Config["orgBcgConfig"]["PreCut"]:len(self.processed_orgBcg) - Config["orgBcgConfig"]["PostCut"]].copy()
a *= 100 a *= MULTIPLE_FACTOER
v *= 100 v *= MULTIPLE_FACTOER
a = a.astype(int64) a = a.astype(int64)
v = v.astype(int64) v = v.astype(int64)
a = pad(a, (len(v) - 1, len(v) - 1), mode='constant') tho_relate = correlate(a, v, mode='full')
tho_relate = zeros(len(a) - len(v) - 1, dtype=int64) tho_relate = tho_relate / (MULTIPLE_FACTOER ** 2)
len_calc = len(a) - len(v) - 1
# 将序列分成一百份来计算
for i in range(100):
tho_relate[i * len_calc // 100:(i + 1) * len_calc // 100] = Data.get_Correlate(a, v, array(
[i * len_calc // 100, (i + 1) * len_calc // 100], dtype=int64))
tho_relate = tho_relate / 10000
tho_relate2 = - tho_relate tho_relate2 = - tho_relate
result = {"tho_relate": tho_relate, "tho_relate2": tho_relate2} result = {"tho_relate": tho_relate, "tho_relate2": tho_relate2}
@ -1039,14 +1043,7 @@ class Data:
v *= 100 v *= 100
a = a.astype(int64) a = a.astype(int64)
v = v.astype(int64) v = v.astype(int64)
a = pad(a, (len(v) - 1, len(v) - 1), mode='constant') abd_relate = correlate(a, v, mode='full')
abd_relate = zeros(len(a) - len(v) - 1, dtype=int64)
len_calc = len(a) - len(v) - 1
# 将序列分成一百份来计算
for i in range(100):
abd_relate[i * len_calc // 100:(i + 1) * len_calc // 100] = Data.get_Correlate(a, v, array(
[i * len_calc // 100, (i + 1) * len_calc // 100], dtype=int64))
abd_relate = abd_relate / 10000 abd_relate = abd_relate / 10000
abd_relate2 = - abd_relate abd_relate2 = - abd_relate
@ -1086,13 +1083,3 @@ class Data:
return Result().success(info=Constants.APPROXIMATELY_EPOCH_GET_FINISHED, data=result) return Result().success(info=Constants.APPROXIMATELY_EPOCH_GET_FINISHED, data=result)
@staticmethod
@njit("int64[:](int64[:],int64[:], int64[:])", nogil=True, parallel=True)
def get_Correlate(a, v, between):
begin, end = between
if end == 0:
end = len(a) - len(v) - 1
result = empty(end - begin, dtype=int64)
for i in prange(end - begin):
result[i] = np_sum(a[begin + i: begin + i + len(v)] * v)
return result

View File

@ -66,6 +66,7 @@ class MainWindow(QMainWindow, Ui_Signal_Label):
@staticmethod @staticmethod
def __read_config__(): def __read_config__():
if not Path(ConfigParams.PUBLIC_CONFIG_FILE_PATH).exists(): if not Path(ConfigParams.PUBLIC_CONFIG_FILE_PATH).exists():
Path(ConfigParams.PUBLIC_CONFIG_FILE_PATH).parent.mkdir(parents=True, exist_ok=True)
with open(ConfigParams.PUBLIC_CONFIG_FILE_PATH, "w") as f: with open(ConfigParams.PUBLIC_CONFIG_FILE_PATH, "w") as f:
dump(ConfigParams.PUBLIC_CONFIG_NEW_CONTENT, f) dump(ConfigParams.PUBLIC_CONFIG_NEW_CONTENT, f)
@ -95,60 +96,90 @@ class MainWindow(QMainWindow, Ui_Signal_Label):
def __slot_btn_approximately_align__(self): def __slot_btn_approximately_align__(self):
self.approximately_align = MainWindow_approximately_align() self.approximately_align = MainWindow_approximately_align()
root_path = self.ui.plainTextEdit_root_path.toPlainText() root_path = self.ui.plainTextEdit_root_path.toPlainText()
sampID = int(self.ui.comboBox_sampID.currentText()) sampID = self.ui.comboBox_sampID.currentText()
self.approximately_align.show(root_path, sampID) if not self.check_root_path():
return
if not self.check_sampID():
return
self.approximately_align.show(root_path, int(sampID))
def __slot_btn_preprocess__(self): def __slot_btn_preprocess__(self):
self.preprocess = MainWindow_preprocess() self.preprocess = MainWindow_preprocess()
sender = self.sender() sender = self.sender()
root_path = self.ui.plainTextEdit_root_path.toPlainText() root_path = self.ui.plainTextEdit_root_path.toPlainText()
sampID = int(self.ui.comboBox_sampID.currentText()) sampID = self.ui.comboBox_sampID.currentText()
if sender == self.ui.pushButton_preprocess_BCG: if sender == self.ui.pushButton_preprocess_BCG:
mode = "BCG" mode = "BCG"
elif sender == self.ui.pushButton_preprocess_ECG: elif sender == self.ui.pushButton_preprocess_ECG:
mode = "ECG" mode = "ECG"
else: else:
raise ValueError("模式不存在") raise ValueError("模式不存在")
self.preprocess.show(mode, root_path, sampID) if not self.check_root_path():
return
if not self.check_sampID():
return
self.preprocess.show(mode, root_path, int(sampID))
def __slot_btn_detect_Jpeak__(self): def __slot_btn_detect_Jpeak__(self):
self.detect_Jpeak = MainWindow_detect_Jpeak() self.detect_Jpeak = MainWindow_detect_Jpeak()
root_path = self.ui.plainTextEdit_root_path.toPlainText() root_path = self.ui.plainTextEdit_root_path.toPlainText()
sampID = int(self.ui.comboBox_sampID.currentText()) sampID = self.ui.comboBox_sampID.currentText()
self.detect_Jpeak.show(root_path, sampID) if not self.check_root_path():
return
if not self.check_sampID():
return
self.detect_Jpeak.show(root_path, int(sampID))
def __slot_btn_detect_Rpeak__(self): def __slot_btn_detect_Rpeak__(self):
self.detect_Rpeak = MainWindow_detect_Rpeak() self.detect_Rpeak = MainWindow_detect_Rpeak()
root_path = self.ui.plainTextEdit_root_path.toPlainText() root_path = self.ui.plainTextEdit_root_path.toPlainText()
sampID = int(self.ui.comboBox_sampID.currentText()) sampID = self.ui.comboBox_sampID.currentText()
self.detect_Rpeak.show(root_path, sampID) if not self.check_root_path():
return
if not self.check_sampID():
return
self.detect_Rpeak.show(root_path, int(sampID))
def __slot_btn_label_check__(self): def __slot_btn_label_check__(self):
self.label_check = MainWindow_label_check() self.label_check = MainWindow_label_check()
sender = self.sender() sender = self.sender()
root_path = self.ui.plainTextEdit_root_path.toPlainText() root_path = self.ui.plainTextEdit_root_path.toPlainText()
sampID = int(self.ui.comboBox_sampID.currentText()) sampID = self.ui.comboBox_sampID.currentText()
if not self.check_root_path():
return
if not self.check_sampID():
return
if sender == self.ui.pushButton_label_check_BCG: if sender == self.ui.pushButton_label_check_BCG:
mode = "BCG" mode = "BCG"
elif sender == self.ui.pushButton_label_check_ECG: elif sender == self.ui.pushButton_label_check_ECG:
mode = "ECG" mode = "ECG"
else: else:
raise ValueError("模式不存在") raise ValueError("模式不存在")
self.label_check.show(mode, root_path, sampID) self.label_check.show(mode, root_path, int(sampID))
def __slot_btn_precisely_align__(self): def __slot_btn_precisely_align__(self):
self.precisely_align = MainWindow_precisely_align() self.precisely_align = MainWindow_precisely_align()
root_path = self.ui.plainTextEdit_root_path.toPlainText() root_path = self.ui.plainTextEdit_root_path.toPlainText()
sampID = int(self.ui.comboBox_sampID.currentText()) sampID = self.ui.comboBox_sampID.currentText()
self.precisely_align.show(root_path, sampID) if not self.check_root_path():
return
if not self.check_sampID():
return
self.precisely_align.show(root_path, int(sampID))
def __slot_btn_cut_PSG__(self): def __slot_btn_cut_PSG__(self):
self.cut_PSG = MainWindow_cut_PSG() self.cut_PSG = MainWindow_cut_PSG()
root_path = self.ui.plainTextEdit_root_path.toPlainText() root_path = self.ui.plainTextEdit_root_path.toPlainText()
sampID = int(self.ui.comboBox_sampID.currentText()) sampID = self.ui.comboBox_sampID.currentText()
self.cut_PSG.show(root_path, sampID) if not self.check_root_path():
return
if not self.check_sampID():
return
self.cut_PSG.show(root_path, int(sampID))
def seek_sampID(self, path): def seek_sampID(self, path):
if not Path(path).exists(): if not Path(path).exists():
@ -157,3 +188,15 @@ class MainWindow(QMainWindow, Ui_Signal_Label):
sub_folders = [item.name for item in Path(path).iterdir() if item.is_dir()] sub_folders = [item.name for item in Path(path).iterdir() if item.is_dir()]
self.ui.comboBox_sampID.addItems(sub_folders) self.ui.comboBox_sampID.addItems(sub_folders)
def check_root_path(self):
if self.ui.plainTextEdit_root_path.toPlainText() == Constants.STRING_IS_EMPTY:
PublicFunc.msgbox_output(self, Constants.MAINWINDOW_ROOT_PATH_NOT_EXIST, Constants.MSGBOX_TYPE_ERROR)
return False
return True
def check_sampID(self):
if self.ui.comboBox_sampID.currentText() == Constants.STRING_IS_EMPTY:
PublicFunc.msgbox_output(self, Constants.MAINWINDOW_SAMPID_EMPTY, Constants.MSGBOX_TYPE_ERROR)
return False
return True

View File

@ -42,7 +42,8 @@ class ConfigParams:
"BandPassOrder": 4, "BandPassOrder": 4,
"BandPassLow": 0.01, "BandPassLow": 0.01,
"BandPassHigh": 0.7 "BandPassHigh": 0.7
} },
"Multiple_Factor":100
} }
APPROXIMATELY_ALIGN_INPUT_ORGBCG_FILENAME: str = "orgBcg_Raw_" APPROXIMATELY_ALIGN_INPUT_ORGBCG_FILENAME: str = "orgBcg_Raw_"
APPROXIMATELY_ALIGN_INPUT_THO_FILENAME: str = "Effort Tho_Raw_" APPROXIMATELY_ALIGN_INPUT_THO_FILENAME: str = "Effort Tho_Raw_"

View File

@ -12,6 +12,7 @@ class Constants:
MSGBOX_TYPE_QUESTION: str = "Question" MSGBOX_TYPE_QUESTION: str = "Question"
MAINWINDOW_ROOT_PATH_NOT_EXIST: str = "根目录路径输入错误" MAINWINDOW_ROOT_PATH_NOT_EXIST: str = "根目录路径输入错误"
MAINWINDOW_SAMPID_EMPTY: str = "样本ID为空"
MAINWINDOW_MSGBOX_TITLE: str = "消息" MAINWINDOW_MSGBOX_TITLE: str = "消息"
INPUTTING_DATA: str = "正在导入数据" INPUTTING_DATA: str = "正在导入数据"

16
run.py
View File

@ -2,12 +2,11 @@ from logging import getLogger, NOTSET, FileHandler, Formatter, StreamHandler, in
from pathlib import Path from pathlib import Path
from sys import argv from sys import argv
from time import strftime, localtime, time from time import strftime, localtime, time
import os
from PySide6.QtCore import Qt from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication from PySide6.QtWidgets import QApplication
from func.Module_mainwindow import MainWindow from func.Module_mainwindow import MainWindow
import importlib.util
if __name__ == '__main__': if __name__ == '__main__':
# 设置日志 # 设置日志
@ -28,6 +27,17 @@ if __name__ == '__main__':
getLogger('matplotlib.font_manager').disabled = True getLogger('matplotlib.font_manager').disabled = True
info("程序启动") info("程序启动")
# 解决 Could not find the Qt platform plugin "windows"
spec = importlib.util.find_spec("PySide6")
if spec and spec.origin:
dirname = Path(spec.origin).parent
plugin_path = dirname / 'plugins' / 'platforms'
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path.__str__()
# 解决 Error #15: Initializing libiomp5md.dll
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
app = QApplication(argv) app = QApplication(argv)
app.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough) app.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
app.styleHints().setColorScheme(Qt.ColorScheme.Light) # 强制使用浅色模式 app.styleHints().setColorScheme(Qt.ColorScheme.Light) # 强制使用浅色模式