已完成<重采样>和<R峰提取>的功能

This commit is contained in:
Yorusora 2025-02-19 21:08:27 +08:00
parent 80a555007f
commit b8773a158d
8 changed files with 2583 additions and 0 deletions

5
.gitignore vendored
View File

@ -174,6 +174,11 @@ ipython_config.py
# Remove previous ipynb_checkpoints
# git rm -r .ipynb_checkpoints/
heartbeat_annotation/
logs/*
.idea/*
!./logs
# ---> JetBrains
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

View File

@ -0,0 +1,271 @@
# encoding:utf-8
import os
import numpy as np
import pandas as pd
import warnings
import matplotlib.pyplot as plt
import matplotlib.colors as colors
from scipy import signal
from glob import glob
from torch.utils.data import Dataset, DataLoader, TensorDataset
warnings.filterwarnings("ignore")
class BCGDataset(Dataset):
def __init__(self, train=True):
if train:
self.data = np.array(pd.read_csv("./in_data/train.txt").iloc[:,np.arange(1000)])
self.label = np.array(pd.read_csv("./in_data/train.txt").iloc[:,np.arange(1000,2000)])
else:
self.data = np.array(pd.read_csv("./in_data/test.txt").iloc[:, np.arange(1000)])
self.label = np.array(pd.read_csv("./in_data/test.txt").iloc[:, np.arange(1000, 2000)])
def __getitem__(self, index):
return self.data[index], self.label[index]
def __len__(self):
return len(self.label)
class BCG_Operation():
def __init__(self, sample_rate=1000):
self.sample_rate = sample_rate
def down_sample(self,data=None, down_radio=10):
if data is None:
raise ValueError("data is None, please given an real value!")
length_before = len(data)
length_after = length_before//down_radio
data = data[:length_after*down_radio]
data = data.reshape(-1,down_radio)
data = data[:,0]
self.sample_rate = self.sample_rate/down_radio
return data
def Splitwin(self, data=None, len_win=None, coverage=1.0,calculate_to_end=False):
"""
分窗
:param len_win: length of window
:return: signal windows
"""
if ( len_win is None) or (data is None):
raise ValueError("length of window or data is None, please given an real value!")
else:
length = len_win * self.sample_rate # number point of a window
# step of split windows
step = length*coverage
start = 0
Splitdata = []
while (len(data)-start>=length):
Splitdata.append( data[int(start):int(start+length)] )
start += step
if calculate_to_end and (len(data)-start>2000):
remain = len(data)-start
start = start - step
step = int(remain/2000)
start = start + step*2000
Splitdata.append(data[int(start):int(start+length)])
return np.array(Splitdata), step
elif calculate_to_end :
return np.array(Splitdata), 0
else:
return np.array(Splitdata)
def Butterworth(self,data, type, low_cut = 0.0, high_cut = 0.0, order = 10):
"""
:param type: Type of Butter. filter, lowpass, bandpass, ...
:param lowcut: Low cutoff frequency
:param highcut: High cutoff frequency
:param order: Order of filter
:return: Signal after filtering
"""
if type == "lowpass": # 低通滤波处理
b, a = signal.butter(order, low_cut / (self.sample_rate * 0.5), btype='lowpass')
return signal.filtfilt(b, a, np.array(data))
elif type == "bandpass": # 带通滤波处理
low = low_cut / (self.sample_rate * 0.5)
high = high_cut / (self.sample_rate * 0.5)
b, a = signal.butter(order, [low, high], btype='bandpass')
return signal.filtfilt(b, a, np.array(data))
elif type == "highpass": # 高通滤波处理
b, a = signal.butter(order, high_cut / (self.sample_rate * 0.5), btype='highpass')
return signal.filtfilt(b, a, np.array(data))
else: # 警告,滤波器类型必须有
raise ValueError("Please choose a type of fliter")
def AmpMovement(self, data, win_size, threshold=20, get_judge_line=False):
"""
基于幅值方法检测体动
1.将输入信号按win_size切分
2.将每个win_size信号片段分窗每个窗2s步长为2s
3.计算一分钟所有信号窗的最大峰谷值差获取中位数和均值
4.所有2s时间窗内大于中位数/均值的2.2倍视为体动
5.体动间间隔过短的信号同样标记为体动
:param data: Input signal
:param win_size: Size of the win(Must be a multiple of 2)
:return: State of signal
"""
Dataframe, cover_num = self.Splitwin(data, len_win=win_size, coverage=1.0, calculate_to_end=True)
state_all = np.array([])
Amp_list = np.array([])
for win in range(Dataframe.shape[0]):
state = np.array([])
# two seconds window
data_win = self.Splitwin(Dataframe[win], len_win=2, coverage=1.0)
Amp = np.zeros(data_win.shape[0])
for i in range(data_win.shape[0]):
Amp[i] = np.max(data_win[i]) - np.min(data_win[i]) # max - min
# 取..位数
Median_Amp = np.percentile(Amp, 20) # 20%
if get_judge_line:
Amp_list = np.append(Amp_list, np.full(win_size * self.sample_rate, 2.3 * Median_Amp))
for i in range(len(Amp)):
if (Amp[i] > 2.1 * Median_Amp):
state = np.append(state, "Movement")
elif Amp[i] < threshold:
state = np.append(state, "Nobody")
else:
state = np.append(state, "Sleep")
if win == Dataframe.shape[0] - 1 and cover_num > 0:
state = state[-int(cover_num):]
state_all = np.append(state_all, state)
if get_judge_line:
return state_all, Amp_list
else:
return state_all
def preprocess1(self):
# ----------------------------------------------------------
data_dir = "../in_data/"
dir_list = os.listdir(data_dir)
data_list = [data_dir + dir + "/orgData.txt" for dir in dir_list]
label_list = [data_dir + dir + "/label.txt" for dir in dir_list]
print(data_list)
print(label_list)
for i in range(len(data_list)):
orgBCG = np.array(pd.read_csv(data_list[i], header=None)).reshape(-1)
orgLabel = np.array(pd.read_csv(label_list[i])).reshape(-1)
# ---------------------Movement Detection-------------------------
operation = BCG_Operation()
BCG = operation.Butterworth(data=orgBCG, type="bandpass", low_cut=2.5, high_cut=10, order=2)
state_win60 = operation.AmpMovement(orgBCG, win_size=60)
visual_state = np.array([])
for num in range(state_win60.shape[0]):
print("state_num/all_state: ", num, '/', state_win60.shape[0])
if state_win60[num] == "Movement":
visual_state = np.append(visual_state, np.full(2000, 1))
else:
visual_state = np.append(visual_state, np.full(2000, 0))
# ------------------------------------------------------------------
downBCG = operation.down_sample(data=orgBCG, down_radio=10)
downLabel = operation.down_sample(data=orgLabel, down_radio=10)
downState = operation.down_sample(data=visual_state, down_radio=10)
length_before = len(downState)
length_after = length_before // 1000
downBCG = downBCG[:length_after * 1000]
downLabel = downLabel[:length_after * 1000]
downState = downState[:length_after * 1000]
downBCG = downBCG.reshape(-1, 1000)
downLabel = downLabel.reshape(-1, 1000)
downState = downState.reshape(-1, 1000)
downState = np.max(downState, axis=1)
df_BCG = pd.DataFrame(downBCG)
df_label = pd.DataFrame(downLabel)
df_state = pd.DataFrame(downState, columns=["state"])
df_BCG.to_csv()
df_all = pd.concat([df_BCG, df_label, df_state], axis=1)
df_all.to_csv(data_dir + "/data" + str(i + 1) + ".txt", index=False)
def read_all_data(data_dir):
df_all = pd.read_csv(data_dir)
df_clean = df_all[ df_all["state"]==0.0 ]
df_artifact = df_all[ df_all["state"]==1.0 ]
data_clean = df_clean.iloc[:,np.arange(1000)]
label_clean = df_clean.iloc[:,np.arange(1000,2000)]
data_artifact = df_artifact.iloc[:,np.arange(1000)]
label_artifact = df_artifact.iloc[:,np.arange(1000,2000)]
return np.array(data_clean),np.array(label_clean),np.array(data_artifact),np.array(label_artifact)
#orgBCG = np.array(pd.read_csv("../in_data/data1zuo/orgData.txt", header=None)).reshape(-1)
#orgLabel = np.array(pd.read_csv("../in_data/data1zuo/label.txt")).reshape(-1)
## ---------------------Movement Detection-------------------------
#operation = BCG_Operation()
#BCG = operation.Butterworth(data=orgBCG, type="bandpass", low_cut=2.5, high_cut=10, order=2)
#state_win60 = operation.AmpMovement(orgBCG, win_size=60)
#visual_state = np.array([])
#for num in range(state_win60.shape[0]):
# print("state_num/all_state: ", num, '/', state_win60.shape[0])
# if state_win60[num] == "Movement":
# visual_state = np.append(visual_state, np.full(2000, 1))
# else:
# visual_state = np.append(visual_state, np.full(2000, 0))
## ------------------------------------------------------------------
#downBCG = operation.down_sample(data=orgBCG, down_radio=10)
#downLabel = operation.down_sample(data=orgLabel, down_radio=10)
#downState = operation.down_sample(data=visual_state, down_radio=10)
#length_before = len(downState)
#length_after = length_before // 1000
#downBCG = downBCG[:length_after * 1000]
#downLabel = downLabel[:length_after * 1000]
#downState = downState[:length_after * 1000]
#downBCG = downBCG.reshape(-1, 1000)
#downLabel = downLabel.reshape(-1, 1000)
#downState = downState.reshape(-1, 1000)
#downState = np.max(downState, axis=1)
#df_BCG = pd.DataFrame(downBCG)
#df_label = pd.DataFrame(downLabel)
#df_state = pd.DataFrame(downState, columns=["state"])
#df_BCG.to_csv()
#df_all = pd.concat([df_BCG, df_label, df_state], axis=1)
#df_all.to_csv("../in_data/data1zuo.txt", index=False)
#data_dir = glob("../in_data/*.txt")
#print(data_dir)
#for num in range(len(data_dir)):
# if num==0 :
# all_data = pd.read_csv(data_dir[num])
# else:
# all_data = pd.concat([all_data,pd.read_csv(data_dir[num])],ignore_index=True,axis=0)
#
#all_data.to_csv("../in_data/all_data.txt",index=False)
#data = pd.read_csv("../in_data/all_data.txt")
#clean_data = data[data["state"]==0]
#Movement_data = data[data["state"]==1]
#print(data.shape)
#print(clean_data.shape)
#
## -------------------- 划分训练集和测试集73 ----------------------------
#sample = clean_data.sample(int(0.3*len(clean_data)))
#sample_index = sample.index
#print(sample.shape)
#print(sample_index)
## 剩余数据
#all_index = clean_data.index
## 去除sample之后剩余的数据
#residue_index = all_index.difference(sample_index)
#print(residue_index.shape)
#print(residue_index)
#residue = clean_data.loc[residue_index]
## 保存
#test = pd.concat([sample,Movement_data],ignore_index=True)
#test.to_csv("../in_data/test.txt",index=False)
#residue.to_csv("../in_data/train.txt",index=False)

1
BCGDataset/__init__.py Normal file
View File

@ -0,0 +1 @@
from .Dataset_operation import BCGDataset,BCG_Operation,read_all_data

699
MainWindow.py Normal file
View File

@ -0,0 +1,699 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'MainWindow.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1920, 1187)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.gridLayout_left = QtWidgets.QGridLayout()
self.gridLayout_left.setObjectName("gridLayout_left")
self.groupBox_func_select = QtWidgets.QGroupBox(self.centralwidget)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.groupBox_func_select.setFont(font)
self.groupBox_func_select.setObjectName("groupBox_func_select")
self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox_func_select)
self.gridLayout_2.setObjectName("gridLayout_2")
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_2.addItem(spacerItem, 6, 1, 1, 2)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout_2.addItem(spacerItem1, 0, 3, 9, 1)
self.pushButton_detect_Rpeaks = QtWidgets.QPushButton(self.groupBox_func_select)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_detect_Rpeaks.sizePolicy().hasHeightForWidth())
self.pushButton_detect_Rpeaks.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(24)
self.pushButton_detect_Rpeaks.setFont(font)
self.pushButton_detect_Rpeaks.setObjectName("pushButton_detect_Rpeaks")
self.gridLayout_2.addWidget(self.pushButton_detect_Rpeaks, 5, 1, 1, 2)
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_2.addItem(spacerItem2, 2, 1, 1, 2)
spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_2.addItem(spacerItem3, 4, 1, 1, 2)
spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_2.addItem(spacerItem4, 0, 1, 1, 2)
self.pushButton_detect_Jpeaks = QtWidgets.QPushButton(self.groupBox_func_select)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_detect_Jpeaks.sizePolicy().hasHeightForWidth())
self.pushButton_detect_Jpeaks.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(24)
self.pushButton_detect_Jpeaks.setFont(font)
self.pushButton_detect_Jpeaks.setObjectName("pushButton_detect_Jpeaks")
self.gridLayout_2.addWidget(self.pushButton_detect_Jpeaks, 7, 1, 1, 2)
self.pushButton_rootpath_open = QtWidgets.QPushButton(self.groupBox_func_select)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.pushButton_rootpath_open.setFont(font)
self.pushButton_rootpath_open.setObjectName("pushButton_rootpath_open")
self.gridLayout_2.addWidget(self.pushButton_rootpath_open, 1, 2, 1, 1)
self.pushButton_resample1000Hz = QtWidgets.QPushButton(self.groupBox_func_select)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_resample1000Hz.sizePolicy().hasHeightForWidth())
self.pushButton_resample1000Hz.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(24)
self.pushButton_resample1000Hz.setFont(font)
self.pushButton_resample1000Hz.setObjectName("pushButton_resample1000Hz")
self.gridLayout_2.addWidget(self.pushButton_resample1000Hz, 3, 1, 1, 2)
self.lineEdit_rootpath = QtWidgets.QLineEdit(self.groupBox_func_select)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(14)
self.lineEdit_rootpath.setFont(font)
self.lineEdit_rootpath.setObjectName("lineEdit_rootpath")
self.gridLayout_2.addWidget(self.lineEdit_rootpath, 1, 1, 1, 1)
spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout_2.addItem(spacerItem5, 0, 0, 9, 1)
spacerItem6 = QtWidgets.QSpacerItem(518, 57, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_2.addItem(spacerItem6, 8, 1, 1, 2)
self.gridLayout_2.setColumnStretch(0, 2)
self.gridLayout_2.setRowStretch(0, 2)
self.gridLayout_2.setRowStretch(1, 2)
self.gridLayout_2.setRowStretch(2, 2)
self.gridLayout_2.setRowStretch(3, 3)
self.gridLayout_2.setRowStretch(4, 2)
self.gridLayout_2.setRowStretch(5, 3)
self.gridLayout_2.setRowStretch(6, 2)
self.gridLayout_2.setRowStretch(7, 3)
self.gridLayout_2.setRowStretch(8, 2)
self.gridLayout_left.addWidget(self.groupBox_func_select, 0, 1, 1, 1)
self.gridLayout.addLayout(self.gridLayout_left, 0, 0, 1, 1)
self.verticalLayout_right = QtWidgets.QVBoxLayout()
self.verticalLayout_right.setObjectName("verticalLayout_right")
self.groupBox_plot = QtWidgets.QGroupBox(self.centralwidget)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.groupBox_plot.setFont(font)
self.groupBox_plot.setObjectName("groupBox_plot")
self.gridLayout_3 = QtWidgets.QGridLayout(self.groupBox_plot)
self.gridLayout_3.setObjectName("gridLayout_3")
self.verticalLayout_canvas = QtWidgets.QVBoxLayout()
self.verticalLayout_canvas.setObjectName("verticalLayout_canvas")
self.gridLayout_3.addLayout(self.verticalLayout_canvas, 0, 0, 1, 1)
self.verticalLayout_right.addWidget(self.groupBox_plot)
self.gridLayout.addLayout(self.verticalLayout_right, 0, 3, 1, 1)
self.verticalLayout_middle = QtWidgets.QVBoxLayout()
self.verticalLayout_middle.setObjectName("verticalLayout_middle")
self.groupBox_resample1000Hz = QtWidgets.QGroupBox(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.groupBox_resample1000Hz.sizePolicy().hasHeightForWidth())
self.groupBox_resample1000Hz.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.groupBox_resample1000Hz.setFont(font)
self.groupBox_resample1000Hz.setObjectName("groupBox_resample1000Hz")
self.gridLayout_64 = QtWidgets.QGridLayout(self.groupBox_resample1000Hz)
self.gridLayout_64.setObjectName("gridLayout_64")
self.pushButton_resample1000Hz_view = QtWidgets.QPushButton(self.groupBox_resample1000Hz)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_resample1000Hz_view.sizePolicy().hasHeightForWidth())
self.pushButton_resample1000Hz_view.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.pushButton_resample1000Hz_view.setFont(font)
self.pushButton_resample1000Hz_view.setObjectName("pushButton_resample1000Hz_view")
self.gridLayout_64.addWidget(self.pushButton_resample1000Hz_view, 3, 0, 1, 1)
self.groupBox_resample1000Hz_inputFile_check = QtWidgets.QGroupBox(self.groupBox_resample1000Hz)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.groupBox_resample1000Hz_inputFile_check.sizePolicy().hasHeightForWidth())
self.groupBox_resample1000Hz_inputFile_check.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.groupBox_resample1000Hz_inputFile_check.setFont(font)
self.groupBox_resample1000Hz_inputFile_check.setObjectName("groupBox_resample1000Hz_inputFile_check")
self.gridLayout_70 = QtWidgets.QGridLayout(self.groupBox_resample1000Hz_inputFile_check)
self.gridLayout_70.setObjectName("gridLayout_70")
self.lineEdit_resample1000Hz_DSbcg_sig_path = QtWidgets.QLineEdit(self.groupBox_resample1000Hz_inputFile_check)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.lineEdit_resample1000Hz_DSbcg_sig_path.setFont(font)
self.lineEdit_resample1000Hz_DSbcg_sig_path.setObjectName("lineEdit_resample1000Hz_DSbcg_sig_path")
self.gridLayout_70.addWidget(self.lineEdit_resample1000Hz_DSbcg_sig_path, 3, 0, 1, 1)
self.label_4 = QtWidgets.QLabel(self.groupBox_resample1000Hz_inputFile_check)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label_4.setFont(font)
self.label_4.setObjectName("label_4")
self.gridLayout_70.addWidget(self.label_4, 0, 0, 1, 1)
self.label_6 = QtWidgets.QLabel(self.groupBox_resample1000Hz_inputFile_check)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label_6.setFont(font)
self.label_6.setObjectName("label_6")
self.gridLayout_70.addWidget(self.label_6, 4, 0, 1, 1)
self.lineEdit_resample1000Hz_raw_org_path = QtWidgets.QLineEdit(self.groupBox_resample1000Hz_inputFile_check)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.lineEdit_resample1000Hz_raw_org_path.setFont(font)
self.lineEdit_resample1000Hz_raw_org_path.setObjectName("lineEdit_resample1000Hz_raw_org_path")
self.gridLayout_70.addWidget(self.lineEdit_resample1000Hz_raw_org_path, 1, 0, 1, 1)
self.label_5 = QtWidgets.QLabel(self.groupBox_resample1000Hz_inputFile_check)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
self.gridLayout_70.addWidget(self.label_5, 2, 0, 1, 1)
self.lineEdit_resample1000Hz_save_path = QtWidgets.QLineEdit(self.groupBox_resample1000Hz_inputFile_check)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.lineEdit_resample1000Hz_save_path.setFont(font)
self.lineEdit_resample1000Hz_save_path.setObjectName("lineEdit_resample1000Hz_save_path")
self.gridLayout_70.addWidget(self.lineEdit_resample1000Hz_save_path, 5, 0, 1, 1)
self.gridLayout_64.addWidget(self.groupBox_resample1000Hz_inputFile_check, 0, 0, 1, 2)
self.pushButton_resample1000Hz_save = QtWidgets.QPushButton(self.groupBox_resample1000Hz)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_resample1000Hz_save.sizePolicy().hasHeightForWidth())
self.pushButton_resample1000Hz_save.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.pushButton_resample1000Hz_save.setFont(font)
self.pushButton_resample1000Hz_save.setObjectName("pushButton_resample1000Hz_save")
self.gridLayout_64.addWidget(self.pushButton_resample1000Hz_save, 3, 1, 1, 1)
self.groupBox_resample1000Hz_input_args = QtWidgets.QGroupBox(self.groupBox_resample1000Hz)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.groupBox_resample1000Hz_input_args.sizePolicy().hasHeightForWidth())
self.groupBox_resample1000Hz_input_args.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.groupBox_resample1000Hz_input_args.setFont(font)
self.groupBox_resample1000Hz_input_args.setObjectName("groupBox_resample1000Hz_input_args")
self.gridLayout_71 = QtWidgets.QGridLayout(self.groupBox_resample1000Hz_input_args)
self.gridLayout_71.setObjectName("gridLayout_71")
self.lineEdit_resample1000Hz_original_sampling_rate = QtWidgets.QLineEdit(self.groupBox_resample1000Hz_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.lineEdit_resample1000Hz_original_sampling_rate.setFont(font)
self.lineEdit_resample1000Hz_original_sampling_rate.setPlaceholderText("")
self.lineEdit_resample1000Hz_original_sampling_rate.setObjectName("lineEdit_resample1000Hz_original_sampling_rate")
self.gridLayout_71.addWidget(self.lineEdit_resample1000Hz_original_sampling_rate, 0, 1, 1, 1)
self.label_3 = QtWidgets.QLabel(self.groupBox_resample1000Hz_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label_3.setFont(font)
self.label_3.setObjectName("label_3")
self.gridLayout_71.addWidget(self.label_3, 1, 0, 1, 1)
self.lineEdit_resample1000Hz_target_sampling_rate = QtWidgets.QLineEdit(self.groupBox_resample1000Hz_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.lineEdit_resample1000Hz_target_sampling_rate.setFont(font)
self.lineEdit_resample1000Hz_target_sampling_rate.setPlaceholderText("")
self.lineEdit_resample1000Hz_target_sampling_rate.setObjectName("lineEdit_resample1000Hz_target_sampling_rate")
self.gridLayout_71.addWidget(self.lineEdit_resample1000Hz_target_sampling_rate, 1, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(self.groupBox_resample1000Hz_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label_2.setFont(font)
self.label_2.setObjectName("label_2")
self.gridLayout_71.addWidget(self.label_2, 0, 0, 1, 1)
self.label = QtWidgets.QLabel(self.groupBox_resample1000Hz_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label.setFont(font)
self.label.setObjectName("label")
self.gridLayout_71.addWidget(self.label, 2, 0, 1, 1)
self.lineEdit_resample1000Hz_cut_second = QtWidgets.QLineEdit(self.groupBox_resample1000Hz_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.lineEdit_resample1000Hz_cut_second.setFont(font)
self.lineEdit_resample1000Hz_cut_second.setPlaceholderText("")
self.lineEdit_resample1000Hz_cut_second.setObjectName("lineEdit_resample1000Hz_cut_second")
self.gridLayout_71.addWidget(self.lineEdit_resample1000Hz_cut_second, 2, 1, 1, 1)
self.gridLayout_64.addWidget(self.groupBox_resample1000Hz_input_args, 1, 0, 1, 2)
self.gridLayout_64.setColumnStretch(0, 1)
self.gridLayout_64.setColumnStretch(1, 1)
self.gridLayout_64.setRowStretch(0, 5)
self.gridLayout_64.setRowStretch(1, 4)
self.gridLayout_64.setRowStretch(2, 5)
self.gridLayout_64.setRowStretch(3, 2)
self.pushButton_resample1000Hz_view.raise_()
self.pushButton_resample1000Hz_save.raise_()
self.groupBox_resample1000Hz_input_args.raise_()
self.groupBox_resample1000Hz_inputFile_check.raise_()
self.verticalLayout_middle.addWidget(self.groupBox_resample1000Hz)
self.groupBox_detect_Rpeaks = QtWidgets.QGroupBox(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.groupBox_detect_Rpeaks.sizePolicy().hasHeightForWidth())
self.groupBox_detect_Rpeaks.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.groupBox_detect_Rpeaks.setFont(font)
self.groupBox_detect_Rpeaks.setObjectName("groupBox_detect_Rpeaks")
self.gridLayout_67 = QtWidgets.QGridLayout(self.groupBox_detect_Rpeaks)
self.gridLayout_67.setObjectName("gridLayout_67")
self.groupBox_detect_Rpeaks_inputFile_check = QtWidgets.QGroupBox(self.groupBox_detect_Rpeaks)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.groupBox_detect_Rpeaks_inputFile_check.sizePolicy().hasHeightForWidth())
self.groupBox_detect_Rpeaks_inputFile_check.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.groupBox_detect_Rpeaks_inputFile_check.setFont(font)
self.groupBox_detect_Rpeaks_inputFile_check.setObjectName("groupBox_detect_Rpeaks_inputFile_check")
self.gridLayout_72 = QtWidgets.QGridLayout(self.groupBox_detect_Rpeaks_inputFile_check)
self.gridLayout_72.setObjectName("gridLayout_72")
self.lineEdit_detect_Rpeaks_filter_ecg_path = QtWidgets.QLineEdit(self.groupBox_detect_Rpeaks_inputFile_check)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.lineEdit_detect_Rpeaks_filter_ecg_path.setFont(font)
self.lineEdit_detect_Rpeaks_filter_ecg_path.setObjectName("lineEdit_detect_Rpeaks_filter_ecg_path")
self.gridLayout_72.addWidget(self.lineEdit_detect_Rpeaks_filter_ecg_path, 1, 0, 1, 1)
self.label_7 = QtWidgets.QLabel(self.groupBox_detect_Rpeaks_inputFile_check)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label_7.setFont(font)
self.label_7.setObjectName("label_7")
self.gridLayout_72.addWidget(self.label_7, 0, 0, 1, 1)
self.textBrowser = QtWidgets.QTextBrowser(self.groupBox_detect_Rpeaks_inputFile_check)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.textBrowser.sizePolicy().hasHeightForWidth())
self.textBrowser.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(12)
self.textBrowser.setFont(font)
self.textBrowser.setStyleSheet("background-color: rgb(85, 255, 255);")
self.textBrowser.setObjectName("textBrowser")
self.gridLayout_72.addWidget(self.textBrowser, 4, 0, 1, 1)
self.label_8 = QtWidgets.QLabel(self.groupBox_detect_Rpeaks_inputFile_check)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label_8.setFont(font)
self.label_8.setObjectName("label_8")
self.gridLayout_72.addWidget(self.label_8, 2, 0, 1, 1)
self.lineEdit_detect_Rpeaks_save_path = QtWidgets.QLineEdit(self.groupBox_detect_Rpeaks_inputFile_check)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.lineEdit_detect_Rpeaks_save_path.setFont(font)
self.lineEdit_detect_Rpeaks_save_path.setObjectName("lineEdit_detect_Rpeaks_save_path")
self.gridLayout_72.addWidget(self.lineEdit_detect_Rpeaks_save_path, 3, 0, 1, 1)
self.gridLayout_72.setRowStretch(0, 1)
self.gridLayout_72.setRowStretch(1, 1)
self.gridLayout_72.setRowStretch(2, 1)
self.gridLayout_72.setRowStretch(3, 1)
self.gridLayout_72.setRowStretch(4, 2)
self.gridLayout_67.addWidget(self.groupBox_detect_Rpeaks_inputFile_check, 0, 0, 1, 2)
self.pushButton_detect_Rpeaks_save = QtWidgets.QPushButton(self.groupBox_detect_Rpeaks)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_detect_Rpeaks_save.sizePolicy().hasHeightForWidth())
self.pushButton_detect_Rpeaks_save.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.pushButton_detect_Rpeaks_save.setFont(font)
self.pushButton_detect_Rpeaks_save.setObjectName("pushButton_detect_Rpeaks_save")
self.gridLayout_67.addWidget(self.pushButton_detect_Rpeaks_save, 3, 1, 1, 1)
self.pushButton_detect_Rpeaks_view = QtWidgets.QPushButton(self.groupBox_detect_Rpeaks)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_detect_Rpeaks_view.sizePolicy().hasHeightForWidth())
self.pushButton_detect_Rpeaks_view.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.pushButton_detect_Rpeaks_view.setFont(font)
self.pushButton_detect_Rpeaks_view.setObjectName("pushButton_detect_Rpeaks_view")
self.gridLayout_67.addWidget(self.pushButton_detect_Rpeaks_view, 3, 0, 1, 1)
self.groupBox_detect_Rpeaks_input_args = QtWidgets.QGroupBox(self.groupBox_detect_Rpeaks)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.groupBox_detect_Rpeaks_input_args.sizePolicy().hasHeightForWidth())
self.groupBox_detect_Rpeaks_input_args.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.groupBox_detect_Rpeaks_input_args.setFont(font)
self.groupBox_detect_Rpeaks_input_args.setObjectName("groupBox_detect_Rpeaks_input_args")
self.gridLayout_73 = QtWidgets.QGridLayout(self.groupBox_detect_Rpeaks_input_args)
self.gridLayout_73.setObjectName("gridLayout_73")
self.radioButton_detector_method_Wt = QtWidgets.QRadioButton(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.radioButton_detector_method_Wt.setFont(font)
self.radioButton_detector_method_Wt.setObjectName("radioButton_detector_method_Wt")
self.gridLayout_73.addWidget(self.radioButton_detector_method_Wt, 6, 0, 1, 1)
self.label_9 = QtWidgets.QLabel(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label_9.setFont(font)
self.label_9.setObjectName("label_9")
self.gridLayout_73.addWidget(self.label_9, 0, 0, 1, 1)
self.lineEdit_detect_Rpeaks_bandpass_low = QtWidgets.QLineEdit(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.lineEdit_detect_Rpeaks_bandpass_low.setFont(font)
self.lineEdit_detect_Rpeaks_bandpass_low.setPlaceholderText("")
self.lineEdit_detect_Rpeaks_bandpass_low.setObjectName("lineEdit_detect_Rpeaks_bandpass_low")
self.gridLayout_73.addWidget(self.lineEdit_detect_Rpeaks_bandpass_low, 2, 1, 1, 1)
self.radioButton_detector_method_ta = QtWidgets.QRadioButton(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.radioButton_detector_method_ta.setFont(font)
self.radioButton_detector_method_ta.setObjectName("radioButton_detector_method_ta")
self.gridLayout_73.addWidget(self.radioButton_detector_method_ta, 4, 1, 1, 3)
self.label_11 = QtWidgets.QLabel(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label_11.setFont(font)
self.label_11.setObjectName("label_11")
self.gridLayout_73.addWidget(self.label_11, 1, 0, 1, 1)
self.radioButton_detector_method_Hamilton = QtWidgets.QRadioButton(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.radioButton_detector_method_Hamilton.setFont(font)
self.radioButton_detector_method_Hamilton.setObjectName("radioButton_detector_method_Hamilton")
self.gridLayout_73.addWidget(self.radioButton_detector_method_Hamilton, 6, 1, 1, 3)
self.lineEdit_detect_Rpeaks_sampling_rate = QtWidgets.QLineEdit(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.lineEdit_detect_Rpeaks_sampling_rate.setFont(font)
self.lineEdit_detect_Rpeaks_sampling_rate.setPlaceholderText("")
self.lineEdit_detect_Rpeaks_sampling_rate.setObjectName("lineEdit_detect_Rpeaks_sampling_rate")
self.gridLayout_73.addWidget(self.lineEdit_detect_Rpeaks_sampling_rate, 0, 1, 1, 3)
self.label_12 = QtWidgets.QLabel(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label_12.setFont(font)
self.label_12.setObjectName("label_12")
self.gridLayout_73.addWidget(self.label_12, 2, 0, 1, 1)
self.radioButton_detector_method_pt = QtWidgets.QRadioButton(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.radioButton_detector_method_pt.setFont(font)
self.radioButton_detector_method_pt.setObjectName("radioButton_detector_method_pt")
self.gridLayout_73.addWidget(self.radioButton_detector_method_pt, 4, 0, 1, 1)
self.radioButton_detector_method_Engzee = QtWidgets.QRadioButton(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.radioButton_detector_method_Engzee.setFont(font)
self.radioButton_detector_method_Engzee.setObjectName("radioButton_detector_method_Engzee")
self.gridLayout_73.addWidget(self.radioButton_detector_method_Engzee, 8, 0, 1, 1)
self.lineEdit_detect_Rpeaks_bandpass_high = QtWidgets.QLineEdit(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.lineEdit_detect_Rpeaks_bandpass_high.setFont(font)
self.lineEdit_detect_Rpeaks_bandpass_high.setPlaceholderText("")
self.lineEdit_detect_Rpeaks_bandpass_high.setObjectName("lineEdit_detect_Rpeaks_bandpass_high")
self.gridLayout_73.addWidget(self.lineEdit_detect_Rpeaks_bandpass_high, 2, 3, 1, 1)
self.lineEdit_detect_Rpeaks_peaks_value = QtWidgets.QLineEdit(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.lineEdit_detect_Rpeaks_peaks_value.setFont(font)
self.lineEdit_detect_Rpeaks_peaks_value.setPlaceholderText("")
self.lineEdit_detect_Rpeaks_peaks_value.setObjectName("lineEdit_detect_Rpeaks_peaks_value")
self.gridLayout_73.addWidget(self.lineEdit_detect_Rpeaks_peaks_value, 1, 1, 1, 3)
self.label_13 = QtWidgets.QLabel(self.groupBox_detect_Rpeaks_input_args)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label_13.setFont(font)
self.label_13.setObjectName("label_13")
self.gridLayout_73.addWidget(self.label_13, 2, 2, 1, 1)
self.label_10 = QtWidgets.QLabel(self.groupBox_detect_Rpeaks_input_args)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label_10.sizePolicy().hasHeightForWidth())
self.label_10.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.label_10.setFont(font)
self.label_10.setObjectName("label_10")
self.gridLayout_73.addWidget(self.label_10, 3, 0, 1, 4)
self.gridLayout_67.addWidget(self.groupBox_detect_Rpeaks_input_args, 1, 0, 1, 2)
self.groupBox_detect_Rpeaks_signal_parts_list = QtWidgets.QGroupBox(self.groupBox_detect_Rpeaks)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.groupBox_detect_Rpeaks_signal_parts_list.sizePolicy().hasHeightForWidth())
self.groupBox_detect_Rpeaks_signal_parts_list.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.groupBox_detect_Rpeaks_signal_parts_list.setFont(font)
self.groupBox_detect_Rpeaks_signal_parts_list.setObjectName("groupBox_detect_Rpeaks_signal_parts_list")
self.gridLayout_74 = QtWidgets.QGridLayout(self.groupBox_detect_Rpeaks_signal_parts_list)
self.gridLayout_74.setObjectName("gridLayout_74")
self.pushButton_detect_Rpeaks_left = QtWidgets.QPushButton(self.groupBox_detect_Rpeaks_signal_parts_list)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_detect_Rpeaks_left.sizePolicy().hasHeightForWidth())
self.pushButton_detect_Rpeaks_left.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.pushButton_detect_Rpeaks_left.setFont(font)
self.pushButton_detect_Rpeaks_left.setObjectName("pushButton_detect_Rpeaks_left")
self.gridLayout_74.addWidget(self.pushButton_detect_Rpeaks_left, 0, 2, 1, 1)
self.pushButton_detect_Rpeaks_right = QtWidgets.QPushButton(self.groupBox_detect_Rpeaks_signal_parts_list)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_detect_Rpeaks_right.sizePolicy().hasHeightForWidth())
self.pushButton_detect_Rpeaks_right.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.pushButton_detect_Rpeaks_right.setFont(font)
self.pushButton_detect_Rpeaks_right.setObjectName("pushButton_detect_Rpeaks_right")
self.gridLayout_74.addWidget(self.pushButton_detect_Rpeaks_right, 1, 2, 1, 1)
self.tableWidget_detect_Rpeaks_signal_parts_list = QtWidgets.QTableWidget(self.groupBox_detect_Rpeaks_signal_parts_list)
self.tableWidget_detect_Rpeaks_signal_parts_list.setColumnCount(1)
self.tableWidget_detect_Rpeaks_signal_parts_list.setObjectName("tableWidget_detect_Rpeaks_signal_parts_list")
self.tableWidget_detect_Rpeaks_signal_parts_list.setRowCount(0)
self.tableWidget_detect_Rpeaks_signal_parts_list.verticalHeader().setVisible(False)
self.gridLayout_74.addWidget(self.tableWidget_detect_Rpeaks_signal_parts_list, 0, 0, 2, 2)
self.gridLayout_74.setColumnStretch(0, 1)
self.gridLayout_74.setColumnStretch(1, 1)
self.gridLayout_74.setColumnStretch(2, 1)
self.gridLayout_67.addWidget(self.groupBox_detect_Rpeaks_signal_parts_list, 2, 0, 1, 2)
self.gridLayout_67.setRowStretch(0, 4)
self.gridLayout_67.setRowStretch(1, 4)
self.gridLayout_67.setRowStretch(2, 4)
self.gridLayout_67.setRowStretch(3, 1)
self.verticalLayout_middle.addWidget(self.groupBox_detect_Rpeaks)
self.groupBox_detect_Jpeaks = QtWidgets.QGroupBox(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.groupBox_detect_Jpeaks.sizePolicy().hasHeightForWidth())
self.groupBox_detect_Jpeaks.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.groupBox_detect_Jpeaks.setFont(font)
self.groupBox_detect_Jpeaks.setObjectName("groupBox_detect_Jpeaks")
self.gridLayout_69 = QtWidgets.QGridLayout(self.groupBox_detect_Jpeaks)
self.gridLayout_69.setObjectName("gridLayout_69")
self.pushButton_5 = QtWidgets.QPushButton(self.groupBox_detect_Jpeaks)
self.pushButton_5.setObjectName("pushButton_5")
self.gridLayout_69.addWidget(self.pushButton_5, 0, 0, 1, 1)
self.gridLayout_69.setColumnStretch(0, 1)
self.verticalLayout_middle.addWidget(self.groupBox_detect_Jpeaks)
self.groupBox_info = QtWidgets.QGroupBox(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.groupBox_info.sizePolicy().hasHeightForWidth())
self.groupBox_info.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.groupBox_info.setFont(font)
self.groupBox_info.setObjectName("groupBox_info")
self.gridLayout_66 = QtWidgets.QGridLayout(self.groupBox_info)
self.gridLayout_66.setObjectName("gridLayout_66")
self.textBrowser_infoOutput = QtWidgets.QTextBrowser(self.groupBox_info)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(10)
self.textBrowser_infoOutput.setFont(font)
self.textBrowser_infoOutput.setObjectName("textBrowser_infoOutput")
self.gridLayout_66.addWidget(self.textBrowser_infoOutput, 0, 0, 1, 2)
self.pushButton_backToMenu = QtWidgets.QPushButton(self.groupBox_info)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_backToMenu.sizePolicy().hasHeightForWidth())
self.pushButton_backToMenu.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.pushButton_backToMenu.setFont(font)
self.pushButton_backToMenu.setObjectName("pushButton_backToMenu")
self.gridLayout_66.addWidget(self.pushButton_backToMenu, 1, 0, 1, 1)
self.gridLayout_66.setColumnStretch(0, 1)
self.gridLayout_66.setRowStretch(0, 4)
self.gridLayout_66.setRowStretch(1, 1)
self.verticalLayout_middle.addWidget(self.groupBox_info)
self.verticalLayout_middle.setStretch(0, 8)
self.verticalLayout_middle.setStretch(1, 5)
self.verticalLayout_middle.setStretch(2, 8)
self.verticalLayout_middle.setStretch(3, 3)
self.gridLayout.addLayout(self.verticalLayout_middle, 0, 2, 1, 1)
self.gridLayout.setColumnStretch(0, 5)
self.gridLayout.setColumnStretch(2, 3)
self.gridLayout.setColumnStretch(3, 15)
MainWindow.setCentralWidget(self.centralwidget)
self.action_selectPath = QtWidgets.QAction(MainWindow)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.action_selectPath.setFont(font)
self.action_selectPath.setObjectName("action_selectPath")
self.action = QtWidgets.QAction(MainWindow)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(14)
self.action.setFont(font)
self.action.setObjectName("action")
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Heartbeat_Annotation"))
self.groupBox_func_select.setTitle(_translate("MainWindow", "功能选择"))
self.pushButton_detect_Rpeaks.setText(_translate("MainWindow", "ECG的R峰提取"))
self.pushButton_detect_Jpeaks.setText(_translate("MainWindow", "BCG的J峰提取"))
self.pushButton_rootpath_open.setText(_translate("MainWindow", "浏览"))
self.pushButton_resample1000Hz.setText(_translate("MainWindow", "重采样至1000Hz"))
self.lineEdit_rootpath.setPlaceholderText(_translate("MainWindow", "数据根目录"))
self.groupBox_plot.setTitle(_translate("MainWindow", "绘图区"))
self.groupBox_resample1000Hz.setTitle(_translate("MainWindow", "重采样至1000Hz"))
self.pushButton_resample1000Hz_view.setText(_translate("MainWindow", "查看结果"))
self.groupBox_resample1000Hz_inputFile_check.setTitle(_translate("MainWindow", "程序识别到的文件路径"))
self.lineEdit_resample1000Hz_DSbcg_sig_path.setPlaceholderText(_translate("MainWindow", "DSbcg_sig.txt文件路径"))
self.label_4.setText(_translate("MainWindow", "raw_org.txt"))
self.label_6.setText(_translate("MainWindow", "保存路径"))
self.lineEdit_resample1000Hz_raw_org_path.setPlaceholderText(_translate("MainWindow", "raw_org.txt文件路径"))
self.label_5.setText(_translate("MainWindow", "DSbcg_sig.txt"))
self.lineEdit_resample1000Hz_save_path.setPlaceholderText(_translate("MainWindow", "文件保存路径"))
self.pushButton_resample1000Hz_save.setText(_translate("MainWindow", "保存结果"))
self.groupBox_resample1000Hz_input_args.setTitle(_translate("MainWindow", "<重采样>参数输入"))
self.lineEdit_resample1000Hz_original_sampling_rate.setText(_translate("MainWindow", "100"))
self.label_3.setText(_translate("MainWindow", "目标采样率(Hz)"))
self.lineEdit_resample1000Hz_target_sampling_rate.setText(_translate("MainWindow", "1000"))
self.label_2.setText(_translate("MainWindow", "原始采样率(Hz)"))
self.label.setText(_translate("MainWindow", "裁剪的时间(秒)"))
self.groupBox_detect_Rpeaks.setTitle(_translate("MainWindow", "ECG的R峰提取"))
self.groupBox_detect_Rpeaks_inputFile_check.setTitle(_translate("MainWindow", "程序识别到的文件路径"))
self.lineEdit_detect_Rpeaks_filter_ecg_path.setPlaceholderText(_translate("MainWindow", "filter_ecg.txt文件路径"))
self.label_7.setText(_translate("MainWindow", "filter_ecg.txt"))
self.textBrowser.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'黑体\',\'黑体\',\'黑体\'; font-size:12pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'黑体\',\'黑体\';\">将在此目录的文件夹下生成一一对应的hecg.txt和hRpeak.txt若干个</span></p></body></html>"))
self.label_8.setText(_translate("MainWindow", "保存路径"))
self.lineEdit_detect_Rpeaks_save_path.setPlaceholderText(_translate("MainWindow", "文件保存路径"))
self.pushButton_detect_Rpeaks_save.setText(_translate("MainWindow", "保存结果"))
self.pushButton_detect_Rpeaks_view.setText(_translate("MainWindow", "查看结果"))
self.groupBox_detect_Rpeaks_input_args.setTitle(_translate("MainWindow", "<R峰提取>参数输入"))
self.radioButton_detector_method_Wt.setText(_translate("MainWindow", "Wt"))
self.label_9.setText(_translate("MainWindow", "信号采样率(Hz)"))
self.lineEdit_detect_Rpeaks_bandpass_low.setText(_translate("MainWindow", "2"))
self.radioButton_detector_method_ta.setText(_translate("MainWindow", "ta"))
self.label_11.setText(_translate("MainWindow", "寻峰阈值(个)"))
self.radioButton_detector_method_Hamilton.setText(_translate("MainWindow", "Hamilton"))
self.lineEdit_detect_Rpeaks_sampling_rate.setText(_translate("MainWindow", "1000"))
self.label_12.setText(_translate("MainWindow", "带通滤波截止频率(Hz)"))
self.radioButton_detector_method_pt.setText(_translate("MainWindow", "pt"))
self.radioButton_detector_method_Engzee.setText(_translate("MainWindow", "Engzee"))
self.lineEdit_detect_Rpeaks_bandpass_high.setText(_translate("MainWindow", "15"))
self.lineEdit_detect_Rpeaks_peaks_value.setText(_translate("MainWindow", "200"))
self.label_13.setText(_translate("MainWindow", "~"))
self.label_10.setText(_translate("MainWindow", "R峰检测方法选择(一般选pt)"))
self.groupBox_detect_Rpeaks_signal_parts_list.setTitle(_translate("MainWindow", "信号片段列表"))
self.pushButton_detect_Rpeaks_left.setText(_translate("MainWindow", "上一个"))
self.pushButton_detect_Rpeaks_right.setText(_translate("MainWindow", "下一个"))
self.groupBox_detect_Jpeaks.setTitle(_translate("MainWindow", "BCG的J峰提取"))
self.pushButton_5.setText(_translate("MainWindow", "PushButton"))
self.groupBox_info.setTitle(_translate("MainWindow", "信息"))
self.pushButton_backToMenu.setText(_translate("MainWindow", "返回主菜单"))
self.action_selectPath.setText(_translate("MainWindow", "数据路径选择"))
self.action.setText(_translate("MainWindow", "加载存档"))

1058
MainWindow.ui Normal file

File diff suppressed because it is too large Load Diff

102
detect_Rpeak2.py Normal file
View File

@ -0,0 +1,102 @@
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import ecgdetectors
from ecgdetectors import Detectors
from scipy import fftpack
import os
from BCGDataset import BCGDataset,BCG_Operation,read_all_data
import math
def Normalize(data):
return (data - np.min(data))/(np.max(data) - np.min(data))
def refinement( data, peak):
if len(data) == 0 or len(peak) <=2 : return None
firstPeak = peak[0]
lastPeak = peak[-1]
meanPeak = np.quantile( data[peak[1:-1]], 0.2 )
if data[firstPeak] < meanPeak * 0.6 :
peak = np.delete(peak, 0)
if data[lastPeak] < meanPeak * 0.6 :
peak = np.delete(peak, -1)
return np.array(peak)
def find_TPeak(data,peaks,th=50):
"""
找出真实的J峰或R峰
:param data: BCG或ECG数据
:param peaks: 初步峰值从label中导出的location_R
:param th: 范围阈值
:return: 真实峰值
"""
return_peak = []
for peak in peaks:
if peak>len(data):continue
min_win,max_win = max(0,int(peak-th)),min(len(data),int(peak+th))
return_peak.append(np.argmax(data[min_win:max_win])+min_win)
return np.array(return_peak)
def Rpeak_Detection(raw_ecg,fs,low_cut,high_cut,th1,detector_method):
detectors = Detectors(sampling_frequency=fs)
method_dic = {'pt': detectors.pan_tompkins_detector,
'ta': detectors.two_average_detector,
"Engzee": detectors.engzee_detector,
"Wt": detectors.swt_detector,
"Christov": detectors.christov_detector,
"Hamilton": detectors.hamilton_detector
}
detectormethods = method_dic[detector_method]
# raw_ecg = raw_ecg[200*sample_rate:]
preprocessing = BCG_Operation(sample_rate=fs) # 对ECG做了降采样处理
raw_ecg = preprocessing.Butterworth(raw_ecg, "bandpass", low_cut=low_cut, high_cut=high_cut, order=3) * 4
#######################限制幅值处理############################################
# for i in range(len(raw_ecg)):
# if raw_ecg[i] > 300 or raw_ecg[i] < -300:
# raw_ecg[i] = 0
##############################################################################
##############################切割处理##########################################
all_file_num = math.ceil((len(raw_ecg) / fs / 60 / 60))
ecg_seq = np.array(np.arange(all_file_num))
ecg_seq = ecg_seq.astype(np.ndarray)
R_peak_seq = np.array(np.arange(all_file_num))
R_peak_seq = R_peak_seq.astype(np.ndarray)
Interval_seq = np.array(np.arange(all_file_num))
Interval_seq = Interval_seq.astype(np.ndarray)
RRIV_seq = np.array(np.arange(all_file_num))
RRIV_seq = RRIV_seq.astype(np.ndarray)
for file_num in range(1,all_file_num+1):
if file_num != all_file_num:
new_ecg = raw_ecg[fs*3600*(file_num - 1) : fs*3600*file_num]
else:
new_ecg = raw_ecg[fs*3600*(file_num - 1):]
##############################################################################
R_peak = np.array(detectormethods(new_ecg)) - 100
# R_peak = np.array(detectors.pan_tompkins_detector(raw_ecg))-100
R_peak = find_TPeak(new_ecg, R_peak, th=int(th1 * fs / 1000))
R_peak = refinement(new_ecg, R_peak)
RR_Interval = np.full(len(R_peak) - 1, np.nan)
for i in range(len(R_peak) - 1):
RR_Interval[i] = R_peak[i + 1] - R_peak[i]
RRIV = np.full(len(RR_Interval) - 1, np.nan)
for i in range(len(RR_Interval) - 1):
RRIV[i] = RR_Interval[i + 1] - RR_Interval[i]
Interval = np.full(len(new_ecg), np.nan)
for i in range(len(R_peak) - 1):
Interval[R_peak[i]: R_peak[i + 1]] = R_peak[i + 1] - R_peak[i]
ecg_seq[file_num - 1] = new_ecg
R_peak_seq[file_num - 1] = R_peak
Interval_seq[file_num - 1] = Interval
RRIV_seq[file_num - 1] = RRIV
return ecg_seq, R_peak_seq, Interval_seq, RRIV_seq

428
heartbeat_annotation.py Normal file
View File

@ -0,0 +1,428 @@
"""
@author:Yosa
@file:heartbeat_annotation.py
@email:2023025086@m.scnu.edu.cn
@time:2025/2/18
"""
import sys
from logging import NOTSET, getLogger, FileHandler, Formatter, StreamHandler, info, error, debug
from time import time, strftime, localtime
import numpy as np
from PyQt5.QtGui import QFont, QDoubleValidator, QIntValidator
from matplotlib.pyplot import title
from pandas import DataFrame, read_csv, read_excel, Series, concat
from matplotlib.ticker import FuncFormatter
from numpy import load, nan, zeros, append, linspace, place
from matplotlib import use
from matplotlib import pyplot as plt, gridspec
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT
from datetime import datetime
from pathlib import Path
from PyQt5.QtCore import QCoreApplication, QTimer
from PyQt5.QtWidgets import QFileDialog, QMainWindow, QMessageBox, QButtonGroup, QApplication, QTableWidgetItem, \
QLineEdit, QAction, QTableWidget
from scipy import signal
from scipy.signal import butter, filtfilt, find_peaks
import detect_Rpeak2
import resample_1000hz
from MainWindow import Ui_MainWindow
use("Qt5Agg") # 声明使用 QT5
# 设置日志
logger = getLogger()
logger.setLevel(NOTSET)
realtime = strftime('%Y%m%d', localtime(time()))
if not Path("logs").exists():
Path("logs").mkdir(exist_ok=True)
fh = FileHandler(Path("logs") / (realtime + ".log"), mode='a')
fh.setLevel(NOTSET)
fh.setFormatter(Formatter("%(asctime)s: %(message)s"))
logger.addHandler(fh)
ch = StreamHandler()
ch.setLevel(NOTSET)
ch.setFormatter(Formatter("%(asctime)s: %(message)s"))
logger.addHandler(ch)
getLogger('matplotlib.font_manager').disabled = True
info("------------------------------------")
info("------heartbeat_annotation.py-------")
class MainWindow(QMainWindow, Ui_MainWindow):
root_path = Path("")
data1 = None
data2 = None
data3 = None
ecg_seq = None
R_peak_seq = None
Interval_seq = None
RRIV_seq = None
temp = None
# 程序初始化操作
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
# 设置画框
self.figure = plt.figure(figsize=(12, 6), dpi=150)
self.canvas = FigureCanvasQTAgg(self.figure)
self.figToolbar = NavigationToolbar2QT(self.canvas)
self.verticalLayout_canvas.addWidget(self.canvas)
self.verticalLayout_canvas.addWidget(self.figToolbar)
# 界面状态初始化
self.groupBox_func_select.setVisible(True)
self.groupBox_resample1000Hz.setVisible(False)
self.groupBox_detect_Rpeaks.setVisible(False)
self.groupBox_detect_Jpeaks.setVisible(False)
self.groupBox_info.setVisible(False)
self.groupBox_plot.setVisible(False)
self.lineEdit_resample1000Hz_raw_org_path.setEnabled(False)
self.lineEdit_resample1000Hz_DSbcg_sig_path.setEnabled(False)
self.lineEdit_detect_Rpeaks_filter_ecg_path.setEnabled(False)
self.groupBox_detect_Rpeaks_signal_parts_list.setEnabled(False)
# 设置表格属性
self.tableWidget_detect_Rpeaks_signal_parts_list.setHorizontalHeaderLabels(['信号片段'])
self.tableWidget_detect_Rpeaks_signal_parts_list.setEditTriggers(QTableWidget.NoEditTriggers)
self.tableWidget_detect_Rpeaks_signal_parts_list.horizontalHeader().setStretchLastSection(True)
self.tableWidget_detect_Rpeaks_signal_parts_list.horizontalHeader().setSectionResizeMode(1)
# 槽函数连接初始化
self.pushButton_rootpath_open.clicked.connect(self.slot_btn_rootpath_open)
self.pushButton_resample1000Hz.clicked.connect(self.slot_btn_resample1000Hz)
self.pushButton_detect_Rpeaks.clicked.connect(self.slot_btn_detect_Rpeaks)
self.pushButton_detect_Jpeaks.clicked.connect(self.slot_btn_detect_Jpeaks)
self.pushButton_backToMenu.clicked.connect(self.slot_btn_backToMenu)
self.pushButton_resample1000Hz_view.clicked.connect(self.slot_btn_resample1000Hz_view)
self.pushButton_resample1000Hz_save.clicked.connect(self.slot_btn_resample1000Hz_save)
self.pushButton_detect_Rpeaks_view.clicked.connect(self.slot_btn_detect_Rpeaks_view)
self.pushButton_detect_Rpeaks_save.clicked.connect(self.slot_btn_detect_Rpeaks_save)
self.pushButton_detect_Rpeaks_left.clicked.connect(self.slot_btn_detect_Rpeaks_left)
self.pushButton_detect_Rpeaks_right.clicked.connect(self.slot_btn_detect_Rpeaks_right)
self.tableWidget_detect_Rpeaks_signal_parts_list.cellDoubleClicked.connect(self.slot_tableWidget_detect_Rpeaks_signal_parts_list_on_cell_double_clicked)
# 消息弹窗初始化
self.msgBox = QMessageBox()
self.msgBox.setWindowTitle("消息")
def slot_btn_rootpath_open(self):
fileDialog = QFileDialog()
if self.sender() == self.pushButton_rootpath_open:
fileDialog.setFileMode(QFileDialog.Directory)
fileDialog.setOption(QFileDialog.ShowDirsOnly, True)
if fileDialog.exec_() == QFileDialog.Accepted:
self.root_path = fileDialog.selectedFiles()[0]
if not self.root_path:
error("Root Path not Exist...")
self.textBrowser_update("操作:根目录路径输入错误")
self.msgBox.setText("根目录路径输入错误")
self.msgBox.setIcon(QMessageBox.Critical)
self.msgBox.exec()
return
self.lineEdit_rootpath.setText(self.root_path)
self.root_path = Path(self.root_path)
info("Loading Root Path...")
else:
info("Canceled Loading Root Path.")
self.textBrowser_update("提示:根目录路径选择取消")
self.msgBox.setText("根目录路径选择取消")
self.msgBox.setIcon(QMessageBox.Warning)
self.msgBox.exec()
def slot_btn_resample1000Hz(self):
raw_org_path = self.root_path / "raw_org.txt"
DSbcg_sig_path = self.root_path / "bcg_test" / "DSbcg_sig.txt"
if not raw_org_path.exists() or not DSbcg_sig_path.exists():
error("Can't Find raw_org.txt or DSbcg_sig.txt.")
self.textBrowser_update("错误无法找到raw_org.txt或DSbcg_sig.txt无法执行<重采样>,请检查文件是否存在")
self.msgBox.setText("无法找到raw_org.txt或DSbcg_sig.txt无法执行<重采样>,请检查文件是否存在")
self.msgBox.setIcon(QMessageBox.Critical)
self.msgBox.exec()
return
info("Found raw_org.txt and DSbcg_sig.txt.")
# 画框子图初始化
self.gs = gridspec.GridSpec(1, 1, height_ratios=[1])
self.figure.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
plt.margins(0, 0)
plt.tight_layout()
plt.xticks([])
plt.yticks([])
self.ax0 = self.figure.add_subplot(self.gs[0])
self.ax0 = plt.gca()
self.ax0.grid(True)
self.ax0.xaxis.set_major_formatter(FuncFormatter(lambda x, p: f"{x:.0f}"))
self.lineEdit_resample1000Hz_raw_org_path.setText(str(raw_org_path))
self.lineEdit_resample1000Hz_DSbcg_sig_path.setText(str(DSbcg_sig_path))
self.lineEdit_resample1000Hz_save_path.setText(str(self.root_path / "DSbcg_sig_1000hz3.txt"))
self.textBrowser_update("提示找到raw_org.txt和DSbcg_sig.txt")
self.data1 = read_csv(raw_org_path, encoding="utf-8").to_numpy()
self.data2 = read_csv(DSbcg_sig_path, encoding="utf-8", sep="\t")
self.groupBox_func_select.setVisible(False)
self.groupBox_resample1000Hz.setVisible(True)
self.groupBox_info.setVisible(True)
self.groupBox_plot.setVisible(True)
def slot_btn_resample1000Hz_view(self):
if self.lineEdit_resample1000Hz_original_sampling_rate.text() != "" and self.lineEdit_resample1000Hz_target_sampling_rate.text() != "" and self.lineEdit_resample1000Hz_cut_second.text() != "":
self.ax0.remove()
self.ax0 = self.figure.add_subplot(self.gs[0])
self.ax0 = plt.gca()
self.ax0.grid(True)
self.ax0.xaxis.set_major_formatter(FuncFormatter(lambda x, p: f"{x:.0f}"))
data_before = self.data1
data_test = resample_1000hz.upsample(self.data2.iloc[:, 2], float(self.lineEdit_resample1000Hz_original_sampling_rate.text()), float(self.lineEdit_resample1000Hz_target_sampling_rate.text()))
data_new = resample_1000hz.upsample(self.data2.iloc[int(float(self.lineEdit_resample1000Hz_original_sampling_rate.text()) * float(self.lineEdit_resample1000Hz_cut_second.text())):, 2], float(self.lineEdit_resample1000Hz_original_sampling_rate.text()), float(self.lineEdit_resample1000Hz_target_sampling_rate.text()))
self.ax0.plot(data_before, 'r', label="Original Data")
self.ax0.plot(data_test + 200, 'g', label="Filtered Data")
self.ax0.plot(data_new, 'b', label="Data After Cut")
self.ax0.legend(loc='upper right')
self.canvas.draw()
self.data3 = data_new
info("Finished Data Plot.")
self.textBrowser_update("提示:完成绘图")
else:
error(f"Miss Args for Resample1000Hz.")
self.textBrowser_update("错误:参数输入存在空值")
self.msgBox.setText("参数输入存在空值")
self.msgBox.setIcon(QMessageBox.Critical)
self.msgBox.exec()
def slot_btn_resample1000Hz_save(self):
if self.data3 is not None:
if self.lineEdit_resample1000Hz_save_path.text() != "" and self.lineEdit_resample1000Hz_save_path.text().endswith(".txt"):
reply = QMessageBox.question(self, "警告:确认操作", f"你确定要将裁剪结果保存到{self.lineEdit_resample1000Hz_save_path.text()}", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
np.savetxt(self.lineEdit_resample1000Hz_save_path.text(), self.data3, fmt='%.4f')
info(f"Saved Data After Cut to {self.lineEdit_resample1000Hz_save_path.text()}.")
self.textBrowser_update(f"提示:保存成功至{self.lineEdit_resample1000Hz_save_path.text()}")
self.msgBox.setText(f"保存成功至{self.lineEdit_resample1000Hz_save_path.text()}")
self.msgBox.setIcon(QMessageBox.Information)
self.msgBox.exec()
else:
self.textBrowser_update("错误:保存路径输入有误,请检查后重新执行保存")
self.msgBox.setText("保存路径输入有误,请检查后重新执行保存")
self.msgBox.setIcon(QMessageBox.Information)
self.msgBox.exec()
else:
error(f"data new is None.")
self.textBrowser_update("错误:裁切后的数据不存在")
self.msgBox.setText("裁切后的数据不存在")
self.msgBox.setIcon(QMessageBox.Critical)
self.msgBox.exec()
def slot_btn_detect_Rpeaks(self):
filter_ecg_path = self.root_path / "filter_ecg.txt"
if not filter_ecg_path.exists():
error("Can't Find filter_ecg.txt.")
self.textBrowser_update("错误无法找到filter_ecg.txt无法执行<R峰提取>,请检查文件是否存在")
self.msgBox.setText("无法找到filter_ecg.txt无法执行<R峰提取>,请检查文件是否存在")
self.msgBox.setIcon(QMessageBox.Critical)
self.msgBox.exec()
return
info("Found filter_ecg.txt.")
# 画框子图初始化
self.gs = gridspec.GridSpec(2, 1, height_ratios=[1, 1])
self.figure.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
plt.margins(0, 0)
plt.tight_layout()
plt.xticks([])
plt.yticks([])
self.ax0 = self.figure.add_subplot(self.gs[0])
self.ax0 = plt.gca()
self.ax0.grid(True)
self.ax0.tick_params(axis='x', colors='white')
self.ax0.xaxis.set_major_formatter(FuncFormatter(lambda x, p: f"{x:.0f}"))
self.ax1 = self.figure.add_subplot(self.gs[1], sharex=self.ax0)
self.ax1 = plt.gca()
self.ax1.grid(True)
self.ax1.xaxis.set_major_formatter(FuncFormatter(lambda x, p: f"{x:.0f}"))
self.lineEdit_detect_Rpeaks_filter_ecg_path.setText(str(filter_ecg_path))
self.lineEdit_detect_Rpeaks_save_path.setText(str(self.root_path / "label"))
self.textBrowser_update("提示找到filter_ecg.txt")
self.data1 = read_csv(filter_ecg_path, encoding="utf-8").to_numpy().reshape(-1)
self.groupBox_func_select.setVisible(False)
self.groupBox_detect_Rpeaks.setVisible(True)
self.groupBox_info.setVisible(True)
self.groupBox_plot.setVisible(True)
self.radioButton_detector_method_pt.setChecked(True)
def slot_btn_detect_Rpeaks_view(self):
if self.lineEdit_detect_Rpeaks_sampling_rate.text() != "" and self.lineEdit_detect_Rpeaks_peaks_value.text() != "" and self.lineEdit_detect_Rpeaks_bandpass_low.text() != "" and self.lineEdit_detect_Rpeaks_bandpass_high.text() != "":
if self.lineEdit_detect_Rpeaks_save_path.text() != "":
self.ax0.remove()
self.ax0 = self.figure.add_subplot(self.gs[0])
self.ax0 = plt.gca()
self.ax0.grid(True)
self.ax0.tick_params(axis='x', colors='white')
self.ax0.xaxis.set_major_formatter(FuncFormatter(lambda x, p: f"{x:.0f}"))
self.ax1.remove()
self.ax1 = self.figure.add_subplot(self.gs[1], sharex=self.ax0)
self.ax1 = plt.gca()
self.ax1.grid(True)
self.ax1.xaxis.set_major_formatter(FuncFormatter(lambda x, p: f"{x:.0f}"))
ecg_data = self.data1
if self.radioButton_detector_method_pt.isChecked():
detector_method = 'pt'
elif self.radioButton_detector_method_ta.isChecked():
detector_method = 'ta'
elif self.radioButton_detector_method_Wt.isChecked():
detector_method = 'Wt'
elif self.radioButton_detector_method_Hamilton.isChecked():
detector_method = 'Hamilton'
elif self.radioButton_detector_method_Engzee.isChecked():
detector_method = 'Engzee'
self.ecg_seq, self.R_peak_seq, self.Interval_seq, self.RRIV_seq = detect_Rpeak2.Rpeak_Detection(ecg_data, int(self.lineEdit_detect_Rpeaks_sampling_rate.text()), int(self.lineEdit_detect_Rpeaks_bandpass_low.text()), int(self.lineEdit_detect_Rpeaks_bandpass_high.text()), int(self.lineEdit_detect_Rpeaks_peaks_value.text()), detector_method)
if len(self.ecg_seq) != len(self.R_peak_seq) != len(self.Interval_seq) != len(self.RRIV_seq):
error("len(self.ecg_seq) and len(self.R_peak_seq) and len(self.Interval_seq) and len(self.RRIV_seq) are not equal.")
self.textBrowser_update("错误ecg_seq和R_peak_seq和Interval_seq和RRIV_seq的长度不相等")
return
info(f"Data Length:{len(ecg_data)}")
self.textBrowser_update(f"数据长度:{len(ecg_data)}")
info(f"Data Duration:{len(ecg_data) / int(self.lineEdit_detect_Rpeaks_sampling_rate.text()) / 60}分钟")
self.textBrowser_update(f"数据时长:{len(ecg_data) / int(self.lineEdit_detect_Rpeaks_sampling_rate.text()) / 60}分钟")
info(f"Data Parts:{len(self.ecg_seq)}小时")
self.textBrowser_update(f"数据总时长:{len(self.ecg_seq)}小时")
self.tableWidget_detect_Rpeaks_signal_parts_list.setRowCount(len(self.ecg_seq))
for row in range(len(self.ecg_seq)):
item = QTableWidgetItem(str(row + 1))
self.tableWidget_detect_Rpeaks_signal_parts_list.setItem(row, 0, item)
self.groupBox_detect_Rpeaks_signal_parts_list.setEnabled(True)
self.ax0.plot(self.R_peak_seq[0][2: ], self.RRIV_seq[0], 'r.', label="RRIV")
self.ax0.legend(loc='upper right')
self.ax1.plot(self.ecg_seq[0], 'r', label="ECG")
self.ax1.plot(self.R_peak_seq[0], self.ecg_seq[0][self.R_peak_seq[0]], 'b*', label="R_peaks")
self.ax1.plot(self.Interval_seq[0], 'g', label="Interval")
self.ax1.legend(loc='upper right')
self.canvas.draw()
self.temp = 0
info("Finished R peaks Detect and Data Part 1 Plot.")
self.textBrowser_update("提示完成R峰提取并绘制信号第1段")
else:
error(f"Miss Args for detect_Rpeaks.")
self.textBrowser_update("错误:参数输入存在空值")
self.msgBox.setText("参数输入存在空值")
self.msgBox.setIcon(QMessageBox.Critical)
self.msgBox.exec()
def slot_btn_detect_Rpeaks_save(self):
if self.ecg_seq is not None and self.R_peak_seq is not None:
if self.lineEdit_detect_Rpeaks_save_path.text() != "":
if Path(self.lineEdit_detect_Rpeaks_save_path.text()).is_dir() == False:
Path(self.lineEdit_detect_Rpeaks_save_path.text()).mkdir(parents=True, exist_ok=True)
info("Save Path is not Exist, Made it as a New Directory.")
self.textBrowser_update("提示:检测到保存路径所指向的文件夹不存在,已创建相应文件夹")
reply = QMessageBox.question(self, "警告:确认操作", f"你确定要将裁剪结果保存到{self.lineEdit_resample1000Hz_save_path.text()}", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
for idx in range(len(self.ecg_seq)):
DataFrame(self.ecg_seq[idx].reshape(-1)).to_csv(str(Path(self.lineEdit_detect_Rpeaks_save_path.text()) / f"{idx + 1}ecg.txt"), index=False, header=None)
DataFrame(self.R_peak_seq[idx].reshape(-1)).to_csv(str(Path(self.lineEdit_detect_Rpeaks_save_path.text()) / f"{idx + 1}Rpeak.txt"), index=False, header=None)
info(f"Saved Data {idx + 1} to Directory {self.lineEdit_detect_Rpeaks_save_path.text()}.")
self.textBrowser_update(f"提示:保存片段{idx + 1}成功至文件夹{self.lineEdit_detect_Rpeaks_save_path.text()}")
self.msgBox.setText(f"保存成功至{self.lineEdit_detect_Rpeaks_save_path.text()}")
self.msgBox.setIcon(QMessageBox.Information)
self.msgBox.exec()
else:
self.textBrowser_update("错误:保存路径输入有误,请检查后重新执行保存")
self.msgBox.setText("保存路径输入有误,请检查后重新执行保存")
self.msgBox.setIcon(QMessageBox.Information)
self.msgBox.exec()
else:
error(f"data is None.")
self.textBrowser_update("错误:需要保存的数据不存在")
self.msgBox.setText("需要保存的数据不存在")
self.msgBox.setIcon(QMessageBox.Critical)
self.msgBox.exec()
def slot_tableWidget_detect_Rpeaks_signal_parts_list_on_cell_double_clicked(self, row, column):
self.temp = int(self.tableWidget_detect_Rpeaks_signal_parts_list.item(row, column).text()) - 1
self.detect_Rpeaks_update_plot(self.temp)
info(f"Finished Data Part {self.temp + 1} Plot.")
self.textBrowser_update(f"提示:完成绘制信号第{self.temp + 1}")
def slot_btn_detect_Rpeaks_left(self):
if self.temp <= 0:
self.msgBox.setText("你正在查看第1段信号")
self.msgBox.setIcon(QMessageBox.Warning)
self.msgBox.exec()
else:
self.temp -= 1
self.detect_Rpeaks_update_plot(self.temp)
info(f"Finished Data Part {self.temp + 1} Plot.")
self.textBrowser_update(f"提示:完成绘制信号第{self.temp + 1}")
def slot_btn_detect_Rpeaks_right(self):
if self.temp >= int(self.tableWidget_detect_Rpeaks_signal_parts_list.item(self.tableWidget_detect_Rpeaks_signal_parts_list.rowCount() - 1, 0).text()) - 1:
self.msgBox.setText("你正在查看最后1段信号")
self.msgBox.setIcon(QMessageBox.Warning)
self.msgBox.exec()
else:
self.temp += 1
self.detect_Rpeaks_update_plot(self.temp)
info(f"Finished Data Part {self.temp + 1} Plot.")
self.textBrowser_update(f"提示:完成绘制信号第{self.temp + 1}")
def detect_Rpeaks_update_plot(self, part_index):
self.ax0.remove()
self.ax0 = self.figure.add_subplot(self.gs[0])
self.ax0 = plt.gca()
self.ax0.grid(True)
self.ax0.tick_params(axis='x', colors='white')
self.ax0.xaxis.set_major_formatter(FuncFormatter(lambda x, p: f"{x:.0f}"))
self.ax1.remove()
self.ax1 = self.figure.add_subplot(self.gs[1], sharex=self.ax0)
self.ax1 = plt.gca()
self.ax1.grid(True)
self.ax1.xaxis.set_major_formatter(FuncFormatter(lambda x, p: f"{x:.0f}"))
self.ax0.plot(self.R_peak_seq[part_index][2:], self.RRIV_seq[part_index], 'r.', label="RRIV")
self.ax0.legend(loc='upper right')
self.ax1.plot(self.ecg_seq[part_index], 'r', label="ECG")
self.ax1.plot(self.R_peak_seq[part_index], self.ecg_seq[part_index][self.R_peak_seq[part_index]], 'b*', label="R_peaks")
self.ax1.plot(self.Interval_seq[part_index], 'g', label="Interval")
self.ax1.legend(loc='upper right')
self.canvas.draw()
def slot_btn_detect_Jpeaks(self):
pass
def slot_btn_backToMenu(self):
self.data1 = None
self.data2 = None
self.data3 = None
self.ecg_seq = None
self.R_peak_seq = None
self.Interval_seq = None
self.RRIV_seq = None
self.temp = None
self.tableWidget_detect_Rpeaks_signal_parts_list.clearContents()
self.groupBox_func_select.setVisible(True)
self.groupBox_resample1000Hz.setVisible(False)
self.groupBox_detect_Rpeaks.setVisible(False)
self.groupBox_detect_Jpeaks.setVisible(False)
self.groupBox_info.setVisible(False)
self.groupBox_plot.setVisible(False)
self.groupBox_detect_Rpeaks_signal_parts_list.setEnabled(False)
self.figure.clf()
def textBrowser_update(self, message):
self.textBrowser_infoOutput.append(str(datetime.now().strftime("%H:%M:%S")) + ": " + message)
# 主函数
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())

19
resample_1000hz.py Normal file
View File

@ -0,0 +1,19 @@
"""
@Author: cys
@Email: 2022024904@m.scnu.edu.cn
@FileName: resample_1000hz.py
@Function: 将预处理后的数据100Hz重采样至1000Hz
@DateTime: 2023/11/27 9:59
@SoftWare: PyCharm
"""
from scipy.signal import resample
def upsample(original_signal, original_sampling_rate, target_sampling_rate):
""""""
# 计算重采样后的数据点数量
num_samples_target = int(len(original_signal) * (target_sampling_rate / original_sampling_rate))
# 使用 scipy 的 resample 函数进行重采样
resampled_signal = resample(original_signal, num_samples_target)
return resampled_signal