Compare commits

...

2 Commits

5 changed files with 253 additions and 91 deletions

View File

@ -1,3 +1,4 @@
import traceback
from gc import collect
from pathlib import Path
from traceback import format_exc
@ -211,19 +212,22 @@ class SettingWindow(QMainWindow):
if result.status:
Config["InputConfig"]["orgBcgFreq"] = result.data["freq"]
else:
PublicFunc.msgbox_output(self, Filename.ORGBCG_RAW + Constants.FAILURE_REASON["Get_Freq_Not_Correct"], Constants.MSGBOX_TYPE_ERROR)
PublicFunc.msgbox_output(self, Filename.ORGBCG_RAW + Constants.FAILURE_REASON["Get_Freq_Not_Correct"],
Constants.MSGBOX_TYPE_ERROR)
result = PublicFunc.examine_file(Config["Path"]["Input_Tho"], Filename.THO_RAW, Params.ENDSWITH_TXT)
if result.status:
Config["InputConfig"]["ThoFreq"] = result.data["freq"]
else:
PublicFunc.msgbox_output(self, Filename.THO_RAW + Constants.FAILURE_REASON["Get_Freq_Not_Correct"], Constants.MSGBOX_TYPE_ERROR)
PublicFunc.msgbox_output(self, Filename.THO_RAW + Constants.FAILURE_REASON["Get_Freq_Not_Correct"],
Constants.MSGBOX_TYPE_ERROR)
result = PublicFunc.examine_file(Config["Path"]["Input_Abd"], Filename.ABD_RAW, Params.ENDSWITH_TXT)
if result.status:
Config["InputConfig"]["AbdFreq"] = result.data["freq"]
else:
PublicFunc.msgbox_output(self, Filename.ABD_RAW + Constants.FAILURE_REASON["Get_Freq_Not_Correct"], Constants.MSGBOX_TYPE_ERROR)
PublicFunc.msgbox_output(self, Filename.ABD_RAW + Constants.FAILURE_REASON["Get_Freq_Not_Correct"],
Constants.MSGBOX_TYPE_ERROR)
# 数据回显
self.ui.spinBox_input_orgBcg_freq.setValue(Config["InputConfig"]["orgBcgFreq"])
@ -352,7 +356,6 @@ class MainWindow_approximately_align(QMainWindow):
self.ui.radioButton_freqTHO.setText("备选1")
self.ui.radioButton_freqABD.setText("备选2")
def __plot__(self, *args, **kwargs):
sender = self.sender()
self.fig.clf()
@ -398,6 +401,19 @@ class MainWindow_approximately_align(QMainWindow):
else:
return result
def __preload_PreCut__(self):
time_bias_seconds = Config.get("TimeBiasSecond", None)
if time_bias_seconds is not None:
if time_bias_seconds > 0:
self.ui.spinBox_orgBcgPreCut.setValue(int(time_bias_seconds))
self.ui.spinBox_PSGPreCut.setValue(0)
self.ui.spinBox_PSGPreA.setValue(int(time_bias_seconds))
else:
self.ui.spinBox_orgBcgPreCut.setValue(0)
self.ui.spinBox_PSGPreCut.setValue(int(-time_bias_seconds))
self.ui.spinBox_orgBcgPreA.setValue(int(-time_bias_seconds))
def __slot_btn_input__(self):
PublicFunc.__disableAllButton__(self, ButtonState)
@ -423,6 +439,7 @@ class MainWindow_approximately_align(QMainWindow):
self.ui.label_orgBcg_length.setText(str(orgBcg_seconds))
self.ui.label_PSG_length.setText(str(PSG_seconds))
self.__reset__()
self.__preload_PreCut__()
self.setting.close()
PublicFunc.finish_operation(self, ButtonState)
@ -459,7 +476,6 @@ class MainWindow_approximately_align(QMainWindow):
"PSGZScoreLimit": self.ui.checkBox_PSGZScoreLimit.isChecked(),
})
if Config["RawSignal"]:
# 仅重采样
PublicFunc.progressbar_update(self, 1, 1, Constants.APPROXIMATELY_ONLY_ALIGN_RESAMPLING, 0)
@ -525,6 +541,7 @@ class MainWindow_approximately_align(QMainWindow):
PublicFunc.finish_operation(self, ButtonState)
return
else:
PublicFunc.text_output(self.ui, f"(5/5) {result.data}", Constants.TIPS_TYPE_INFO)
PublicFunc.text_output(self.ui, "(5/5)" + result.info, Constants.TIPS_TYPE_INFO)
self.__plot__()
@ -534,19 +551,30 @@ class MainWindow_approximately_align(QMainWindow):
def __slot_btn_CutOff__(self):
PublicFunc.__disableAllButton__(self, ButtonState)
if self.ui.spinBox_orgBcgPreA.value() + self.ui.spinBox_orgBcgPostCut.value() >= len(self.data.processed_downsample_orgBcg):
if self.ui.spinBox_orgBcgPreA.value() + self.ui.spinBox_orgBcgPostCut.value() >= len(
self.data.processed_downsample_orgBcg):
result = Result().failure(
info=Constants.OPERATION_FAILURE + Constants.FAILURE_REASON["OrgBCG_Cut_Length_Not_Correct"])
elif self.ui.spinBox_PSGPreCut.value() + self.ui.spinBox_PSGPostCut.value() >= len(self.data.processed_downsample_Tho):
elif self.ui.spinBox_PSGPreCut.value() + self.ui.spinBox_PSGPostCut.value() >= len(
self.data.processed_downsample_Tho):
result = Result().failure(
info=Constants.OPERATION_FAILURE + Constants.FAILURE_REASON["PSG_Cut_Length_Not_Correct"])
else:
Config["orgBcgConfig"].update({"PreA": self.ui.spinBox_orgBcgPreA.value(),
"PreCut": self.ui.spinBox_orgBcgPreCut.value(),
"PostCut": self.ui.spinBox_orgBcgPostCut.value()})
Config["PSGConfig"].update({"PreA": self.ui.spinBox_PSGPreA.value(),
"PreCut": self.ui.spinBox_PSGPreCut.value(),
"PostCut": self.ui.spinBox_PSGPostCut.value()})
ApplyFrequency = Config["ApplyFrequency"]
Config["orgBcgConfig"].update({"PreA": self.ui.spinBox_orgBcgPreA.value() * ApplyFrequency,
"PreCut": self.ui.spinBox_orgBcgPreCut.value() * ApplyFrequency,
"PostCut": self.ui.spinBox_orgBcgPostCut.value() * ApplyFrequency,
"PreA_seconds": self.ui.spinBox_orgBcgPreA.value(),
"PreCut_seconds": self.ui.spinBox_orgBcgPreCut.value(),
"PostCut_seconds": self.ui.spinBox_orgBcgPostCut.value()
})
Config["PSGConfig"].update({"PreA": self.ui.spinBox_PSGPreA.value() * ApplyFrequency,
"PreCut": self.ui.spinBox_PSGPreCut.value() * ApplyFrequency,
"PostCut": self.ui.spinBox_PSGPostCut.value() * ApplyFrequency,
"PreA_seconds": self.ui.spinBox_PSGPreA.value(),
"PreCut_seconds": self.ui.spinBox_PSGPreCut.value(),
"PostCut_seconds": self.ui.spinBox_PSGPostCut.value()
})
PublicFunc.progressbar_update(self, 1, 1, Constants.DRAWING_DATA, 0)
result = self.__plot__()
@ -611,10 +639,10 @@ class MainWindow_approximately_align(QMainWindow):
else:
PublicFunc.text_output(self.ui, "(4/4)" + result.info, Constants.TIPS_TYPE_INFO)
self.ui.radioButton_PABD.setText(str(result.data["abd_max"] + result.data["bias"]))
self.ui.radioButton_PTHO.setText(str(result.data["tho_max"] + result.data["bias"]))
self.ui.radioButton_NABD.setText(str(result.data["abd_max2"] + result.data["bias"]))
self.ui.radioButton_NTHO.setText(str(result.data["tho_max2"] + result.data["bias"]))
self.ui.radioButton_PABD.setText(str((result.data["abd_max"] + result.data["bias"]) / Config["ApplyFrequency"]))
self.ui.radioButton_PTHO.setText(str((result.data["tho_max"] + result.data["bias"]) / Config["ApplyFrequency"]))
self.ui.radioButton_NABD.setText(str((result.data["abd_max2"] + result.data["bias"]) / Config["ApplyFrequency"]))
self.ui.radioButton_NTHO.setText(str((result.data["tho_max2"] + result.data["bias"]) / Config["ApplyFrequency"]))
ButtonState["Current"]["radioButton_PTHO"] = True
ButtonState["Current"]["radioButton_PABD"] = True
ButtonState["Current"]["radioButton_NTHO"] = True
@ -655,12 +683,11 @@ class MainWindow_approximately_align(QMainWindow):
Config["estimate"]["abd_slope"] = abd_slope
Config["estimate"]["abd_intercept"] = abd_intercept
self.ui.radioButton_freqTHO.setText(str(Config["estimate"]["tho_frequency"]))
self.ui.radioButton_freqABD.setText(str(Config["estimate"]["abd_frequency"]))
self.ui.radioButton_freqTHO.setText(str(Config["estimate"]["tho_frequency"] * Config["InputConfig"]["orgBcgFreq"]))
self.ui.radioButton_freqABD.setText(str(Config["estimate"]["abd_frequency"] * Config["InputConfig"]["orgBcgFreq"]))
ButtonState["Current"]["radioButton_freqTHO"] = True
ButtonState["Current"]["radioButton_freqABD"] = True
if not result.status:
PublicFunc.text_output(self.ui, "(1/1)" + result.info, Constants.TIPS_TYPE_ERROR)
PublicFunc.msgbox_output(self, result.info, Constants.MSGBOX_TYPE_ERROR)
@ -707,7 +734,6 @@ class MainWindow_approximately_align(QMainWindow):
ButtonState["Current"]["pushButton_save"] = True
PublicFunc.finish_operation(self, ButtonState)
def __EpochChange__(self):
# 获取当前值
value = self.ui.spinBox_SelectEpoch.value()
@ -734,24 +760,24 @@ class MainWindow_approximately_align(QMainWindow):
PublicFunc.__disableAllButton__(self, ButtonState)
if self.ui.radioButton_NTHO.isChecked():
relate = int(self.ui.radioButton_NTHO.text())
relate = float(self.ui.radioButton_NTHO.text())
reverse = -1
elif self.ui.radioButton_PTHO.isChecked():
relate = int(self.ui.radioButton_PTHO.text())
relate = float(self.ui.radioButton_PTHO.text())
reverse = 1
elif self.ui.radioButton_PABD.isChecked():
relate = int(self.ui.radioButton_PABD.text())
relate = float(self.ui.radioButton_PABD.text())
reverse = 1
elif self.ui.radioButton_NABD.isChecked():
relate = int(self.ui.radioButton_NABD.text())
relate = float(self.ui.radioButton_NABD.text())
reverse = -1
elif self.ui.radioButton_custom.isChecked():
relate = int(self.ui.spinBox_custom.value())
relate = float(self.ui.spinBox_custom.value())
reverse = 1
else:
return
# 最大相关系数值相对于PSG的位置
Config.update({"pos": relate})
Config.update({"pos": int(relate * Config["ApplyFrequency"])})
# 设置epoch上下限
Config.update({"orgBcg_reverse": reverse})
PublicFunc.text_output(self.ui, "相对位置:{}".format(Config["pos"]), Constants.TIPS_TYPE_INFO)
@ -796,76 +822,81 @@ class MainWindow_approximately_align(QMainWindow):
def DrawPicRawOverview(self):
try:
max_x = max(self.data.processed_downsample_Tho.shape[0], self.data.processed_downsample_Abd.shape[0],
self.data.processed_downsample_orgBcg.shape[0])
ApplyFrequency = Config["ApplyFrequency"]
orgBcg_seconds = Config["orgBcg_seconds"]
PSG_seconds = Config["PSG_seconds"]
max_x = max(PSG_seconds, orgBcg_seconds)
ax1 = self.fig.add_subplot(311)
ax1.plot(self.data.processed_downsample_Tho, color='blue')
ax1.plot(linspace(0, PSG_seconds, PSG_seconds * ApplyFrequency), self.data.processed_downsample_Tho, color='blue')
ax1.set_xlim(0, max_x)
ax1.set_title("THO")
ax2 = self.fig.add_subplot(312, sharex=ax1, sharey=ax1)
ax2.plot(self.data.processed_downsample_orgBcg, color='blue')
ax2.plot(linspace(0, orgBcg_seconds, orgBcg_seconds * ApplyFrequency), self.data.processed_downsample_orgBcg,
color='blue')
ax2.set_xlim(0, max_x)
ax2.set_title("orgBcg")
ax3 = self.fig.add_subplot(313, sharex=ax1, sharey=ax1)
ax3.plot(self.data.processed_downsample_Abd, color='blue')
ax3.plot(linspace(0, PSG_seconds, PSG_seconds * ApplyFrequency), self.data.processed_downsample_Abd, color='blue')
ax3.set_xlim(0, max_x)
ax3.set_title("ABD")
self.fig.canvas.draw()
except Exception as e:
traceback.print_exc()
return Result().failure(info=Constants.DRAW_FAILURE + "\n" + format_exc())
# 返回图片以便存到QPixImage
return Result().success(info=Constants.DRAW_FINISHED)
def DrawPicOverviewWithCutOff(self):
try:
max_x = max(self.data.processed_downsample_Tho.shape[0] + Config["PSGConfig"]["PreA"],
self.data.processed_downsample_orgBcg.shape[0] + Config["orgBcgConfig"]["PreA"])
min_x = min(Config["PSGConfig"]["PreA"], Config["orgBcgConfig"]["PreA"], 0)
ApplyFrequency = Config["ApplyFrequency"]
orgBcg_seconds = Config["orgBcg_seconds"]
PSG_seconds = Config["PSG_seconds"]
PSG_PreA_seconds = Config["PSGConfig"]["PreA_seconds"]
orgBcg_PreA_seconds = Config["orgBcgConfig"]["PreA_seconds"]
PSG_PreCut_seconds = Config["PSGConfig"]["PreCut_seconds"]
orgBcg_PreCut_seconds = Config["orgBcgConfig"]["PreCut_seconds"]
PSG_PostCut_seconds = Config["PSGConfig"]["PostCut_seconds"]
orgBcg_PostCut_seconds = Config["orgBcgConfig"]["PostCut_seconds"]
max_x = max(PSG_seconds + PSG_PreA_seconds,
orgBcg_seconds + orgBcg_PreA_seconds)
min_x = min(PSG_PreA_seconds, orgBcg_PreA_seconds, 0)
ax1 = self.fig.add_subplot(311)
ax1.plot(
linspace(Config["PSGConfig"]["PreA"],
len(self.data.processed_downsample_Tho) + Config["PSGConfig"]["PreA"],
len(self.data.processed_downsample_Tho)), self.data.processed_downsample_Tho, color='blue')
linspace(PSG_PreA_seconds, (PSG_seconds + PSG_PreA_seconds), len(self.data.processed_downsample_Tho)),
self.data.processed_downsample_Tho,
color='blue'
)
# 绘制x = PreCut的线 和 x = PostCut的虚线
ax1.axvline(x=Config["PSGConfig"]["PreCut"] + Config["PSGConfig"]["PreA"], color='red',
linestyle='--')
ax1.axvline(
x=len(self.data.processed_downsample_Tho) - Config["PSGConfig"]["PostCut"] + Config["PSGConfig"][
"PreA"],
color='red', linestyle='--')
ax1.axvline(x=(PSG_PreCut_seconds + PSG_PreA_seconds), color='red', linestyle='--')
ax1.axvline(x=(PSG_seconds - PSG_PostCut_seconds + PSG_PreA_seconds), color='red', linestyle='--')
ax1.set_xlim(min_x, max_x)
ax1.set_title("THO")
ax2 = self.fig.add_subplot(312, sharex=ax1, sharey=ax1)
ax2.plot(
linspace(Config["orgBcgConfig"]["PreA"],
len(self.data.processed_downsample_orgBcg) + Config["orgBcgConfig"]["PreA"],
linspace(orgBcg_PreA_seconds, (orgBcg_seconds + orgBcg_PreA_seconds),
len(self.data.processed_downsample_orgBcg)), self.data.processed_downsample_orgBcg,
color='blue')
ax2.axvline(x=Config["orgBcgConfig"]["PreCut"] + Config["orgBcgConfig"]["PreA"], color='red',
ax2.axvline(x=(orgBcg_PreCut_seconds + orgBcg_PreA_seconds), color='red',
linestyle='--')
ax2.axvline(
x=len(self.data.processed_downsample_orgBcg) - Config["orgBcgConfig"]["PostCut"] +
Config["orgBcgConfig"]["PreA"],
color='red', linestyle='--')
ax2.axvline(x=orgBcg_seconds - orgBcg_PostCut_seconds + orgBcg_PreA_seconds, color='red', linestyle='--')
ax2.set_xlim(min_x, max_x)
ax2.set_title("orgBcg")
ax3 = self.fig.add_subplot(313, sharex=ax1, sharey=ax1)
ax3.plot(
linspace(Config["PSGConfig"]["PreA"],
len(self.data.processed_downsample_Abd) + Config["PSGConfig"]["PreA"],
len(self.data.processed_downsample_Abd)), self.data.processed_downsample_Abd, color='blue')
ax3.axvline(x=Config["PSGConfig"]["PreCut"] + Config["PSGConfig"]["PreA"], color='red',
linestyle='--')
ax3.axvline(
x=len(self.data.processed_downsample_Tho) - Config["PSGConfig"]["PostCut"] + Config["PSGConfig"][
"PreA"],
color='red', linestyle='--')
linspace(PSG_PreA_seconds, (PSG_seconds + PSG_PreA_seconds), len(self.data.processed_downsample_Abd)),
self.data.processed_downsample_Abd, color='blue')
ax3.axvline(x=(PSG_PreCut_seconds + PSG_PreA_seconds), color='red', linestyle='--')
ax3.axvline(x=(PSG_seconds - PSG_PostCut_seconds + PSG_PreA_seconds), color='red', linestyle='--')
ax3.set_xlim(min_x, max_x)
ax3.set_title("ABD")
@ -895,27 +926,35 @@ class MainWindow_approximately_align(QMainWindow):
self.fig.canvas.draw()
except Exception as e:
traceback.print_exc(e)
return Result().failure(info=Constants.DRAW_FAILURE + "\n" + format_exc())
# 返回图片以便存到QPixImage
return Result().success(info=Constants.DRAW_FINISHED)
def DrawPicTryAlign(self):
try:
max_x = max(self.data.processed_downsample_Tho.shape[0],
self.data.processed_downsample_orgBcg.shape[0] + Config["pos"])
min_x = min(Config["PSGConfig"]["PreA"], Config["orgBcgConfig"]["PreA"] + Config["pos"], 0)
ApplyFrequency = Config["ApplyFrequency"]
orgBcg_seconds = Config["orgBcg_seconds"]
PSG_seconds = Config["PSG_seconds"]
PSG_PreA_seconds = Config["PSGConfig"]["PreA_seconds"]
orgBcg_PreA_seconds = Config["orgBcgConfig"]["PreA_seconds"]
pos_seconds = Config["pos"] / ApplyFrequency
max_x = max(PSG_seconds,
orgBcg_seconds + pos_seconds)
min_x = min(PSG_PreA_seconds, orgBcg_PreA_seconds + pos_seconds, 0)
ax1 = self.fig.add_subplot(311)
ax1.plot(
linspace(0, len(self.data.processed_downsample_Tho),
linspace(0, PSG_seconds,
len(self.data.processed_downsample_Tho)), self.data.processed_downsample_Tho, color='blue')
# 绘制x = PreCut的线 和 x = PostCut的虚线
ax1.set_xlim(min_x, max_x)
ax1.set_title("THO")
ax2 = self.fig.add_subplot(312, sharex=ax1, sharey=ax1)
ax2.plot(linspace(Config["pos"],
len(self.data.processed_downsample_orgBcg) + Config["pos"],
ax2.plot(linspace(pos_seconds,
orgBcg_seconds + pos_seconds,
len(self.data.processed_downsample_orgBcg)), self.data.processed_downsample_orgBcg,
color='blue')
ax2.set_xlim(min_x, max_x)
@ -923,7 +962,7 @@ class MainWindow_approximately_align(QMainWindow):
ax3 = self.fig.add_subplot(313, sharex=ax1, sharey=ax1)
ax3.plot(
linspace(0, len(self.data.processed_downsample_Abd),
linspace(0, PSG_seconds,
len(self.data.processed_downsample_Abd)), self.data.processed_downsample_Abd, color='blue')
ax3.set_xlim(min_x, max_x)
ax3.set_title("ABD")
@ -936,8 +975,18 @@ class MainWindow_approximately_align(QMainWindow):
def DrawPicByEpoch(self, epoch):
try:
PSG_SP = epoch * 30 * Config["ApplyFrequency"]
PSG_EP = (epoch + 6) * 30 * Config["ApplyFrequency"]
ApplyFrequency = Config["ApplyFrequency"]
pos_seconds = Config["pos"] / ApplyFrequency
PSG_SP_seconds = epoch * 30
PSG_EP_seconds = (epoch + 6) * 30
PSG_SP = epoch * 30 * ApplyFrequency
PSG_EP = (epoch + 6) * 30 * ApplyFrequency
orgBcg_SP_seconds = PSG_SP_seconds - pos_seconds
orgBcg_EP_seconds = PSG_EP_seconds - pos_seconds
orgBcg_SP = PSG_SP - Config["pos"]
orgBcg_EP = PSG_EP - Config["pos"]
@ -948,43 +997,43 @@ class MainWindow_approximately_align(QMainWindow):
# 根据PSG来和绘制
ax1 = self.fig.add_subplot(321)
ax1.plot(linspace(PSG_SP, PSG_EP, len(tho_seg)), tho_seg)
ax1.plot(linspace(PSG_SP_seconds, PSG_EP_seconds, len(tho_seg)), tho_seg)
tho_peaks, _ = find_peaks(tho_seg, prominence=0, distance=3 * Config["ApplyFrequency"])
ax1.plot(linspace(PSG_SP, PSG_EP, len(tho_seg))[tho_peaks], tho_seg[tho_peaks], "x")
ax1.plot(linspace(PSG_SP_seconds, PSG_EP_seconds, len(tho_seg))[tho_peaks], tho_seg[tho_peaks], "x")
ax3 = self.fig.add_subplot(323)
ax3.plot(linspace(orgBcg_SP, orgBcg_EP, len(orgBcg_seg)), orgBcg_seg)
ax3.plot(linspace(orgBcg_SP_seconds, orgBcg_EP_seconds, len(orgBcg_seg)), orgBcg_seg)
orgBcg_peaks, _ = find_peaks(orgBcg_seg, prominence=0, distance=3 * Config["ApplyFrequency"])
ax3.plot(linspace(orgBcg_SP, orgBcg_EP, len(orgBcg_seg))[orgBcg_peaks], orgBcg_seg[orgBcg_peaks], "x")
ax3.plot(linspace(orgBcg_SP_seconds, orgBcg_EP_seconds, len(orgBcg_seg))[orgBcg_peaks], orgBcg_seg[orgBcg_peaks], "x")
ax2 = self.fig.add_subplot(325)
ax2.plot(linspace(PSG_SP, PSG_EP, len(abd_seg)), abd_seg)
ax2.plot(linspace(PSG_SP_seconds, PSG_EP_seconds, len(abd_seg)), abd_seg)
abd_peaks, _ = find_peaks(abd_seg, prominence=0, distance=3 * Config["ApplyFrequency"])
ax2.plot(linspace(PSG_SP, PSG_EP, len(abd_seg))[abd_peaks], abd_seg[abd_peaks], "x")
ax2.plot(linspace(PSG_SP_seconds, PSG_EP_seconds, len(abd_seg))[abd_peaks], abd_seg[abd_peaks], "x")
# 绘制间期
ax4 = self.fig.add_subplot(322)
ax4.plot(linspace(PSG_SP, PSG_EP, len(diff(tho_peaks).repeat(Config["ApplyFrequency"]))),
ax4.plot(linspace(PSG_SP_seconds, PSG_EP_seconds, len(diff(tho_peaks).repeat(Config["ApplyFrequency"]))),
diff(tho_peaks).repeat(Config["ApplyFrequency"]), label="tho")
ax4.plot(linspace(PSG_SP, PSG_EP, len(diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]))),
ax4.plot(linspace(PSG_SP_seconds, PSG_EP_seconds, len(diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]))),
diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]), label="resp")
ax4.set_title("tho_interval")
ax4.legend()
ax4.set_ylim((10, 50))
ax5 = self.fig.add_subplot(324)
ax5.plot(linspace(orgBcg_SP, orgBcg_EP, len(diff(tho_peaks).repeat(Config["ApplyFrequency"]))),
ax5.plot(linspace(orgBcg_SP_seconds, orgBcg_EP_seconds, len(diff(tho_peaks).repeat(Config["ApplyFrequency"]))),
diff(tho_peaks).repeat(Config["ApplyFrequency"]), label="tho")
ax5.plot(linspace(orgBcg_SP, orgBcg_EP, len(diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]))),
ax5.plot(linspace(orgBcg_SP_seconds, orgBcg_EP_seconds, len(diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]))),
diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]), label="resp")
ax5.set_title("resp_interval")
ax5.legend()
ax5.set_ylim((10, 50))
ax6 = self.fig.add_subplot(326)
ax6.plot(linspace(PSG_SP, PSG_EP, len(diff(abd_peaks).repeat(Config["ApplyFrequency"]))),
ax6.plot(linspace(PSG_SP_seconds, PSG_EP_seconds, len(diff(abd_peaks).repeat(Config["ApplyFrequency"]))),
diff(abd_peaks).repeat(Config["ApplyFrequency"]), label="abd")
ax6.plot(linspace(PSG_SP, PSG_EP, len(diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]))),
ax6.plot(linspace(PSG_SP_seconds, PSG_EP_seconds, len(diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]))),
diff(orgBcg_peaks).repeat(Config["ApplyFrequency"]), label="resp")
ax6.set_title("abd_interval")
ax6.legend()
@ -997,11 +1046,12 @@ class MainWindow_approximately_align(QMainWindow):
return Result().success(info=Constants.DRAW_FINISHED)
def DrawAlignScatter(self, epoch_min, epoch_max, tho_bias_list, abd_bias_list, tho_y, abd_y,
tho_frequency, abd_frequency):
tho_frequency, abd_frequency):
try:
ax1 = self.fig.add_subplot(211)
ax1.scatter(linspace(epoch_min, epoch_max, len(tho_bias_list)), tho_bias_list, alpha=0.2)
ax1.plot(linspace(epoch_min, epoch_max, len(tho_bias_list)), tho_y, color='orange', label=f"THO Frequency: {tho_frequency} Hz")
ax1.scatter(linspace(epoch_min, epoch_max, len(tho_bias_list)), tho_bias_list, alpha=0.2)
ax1.plot(linspace(epoch_min, epoch_max, len(tho_bias_list)), tho_y, color='orange',
label=f"THO Frequency: {tho_frequency} Hz")
ax1.axhline(y=0, color='red', linestyle='--', alpha=0.3)
ax1.set_xlabel("Epoch")
ax1.set_ylabel("Tho Bias / s")
@ -1010,7 +1060,8 @@ class MainWindow_approximately_align(QMainWindow):
ax2 = self.fig.add_subplot(212)
ax2.scatter(linspace(epoch_min, epoch_max, len(abd_bias_list)), abd_bias_list, alpha=0.2)
ax2.plot(linspace(epoch_min, epoch_max, len(abd_bias_list)), abd_y, color='orange', label=f"ABD Frequency: {abd_frequency} Hz")
ax2.plot(linspace(epoch_min, epoch_max, len(abd_bias_list)), abd_y, color='orange',
label=f"ABD Frequency: {abd_frequency} Hz")
ax2.axhline(y=0, color='red', linestyle='--', alpha=0.3)
ax2.set_xlabel("Epoch")
ax2.set_ylabel("Abd Bias / s")
@ -1038,6 +1089,7 @@ class Data:
self.processed_downsample_Abd = None
def open_file(self):
info = ""
if Path(Config["Path"]["Input_orgBcg"]).is_file():
Config["Path"]["Input_orgBcg"] = str(Path(Config["Path"]["Input_orgBcg"]).parent)
if Path(Config["Path"]["Input_Tho"]).is_file():
@ -1045,6 +1097,13 @@ class Data:
if Path(Config["Path"]["Input_Abd"]).is_file():
Config["Path"]["Input_Abd"] = str(Path(Config["Path"]["Input_Abd"]).parent)
result = PublicFunc.get_machine_start_time_bias(Config["Path"]["Input_Tho"], Config["Path"]["Input_orgBcg"])
if result.status:
Config["TimeBiasSecond"] = result.data["time_bias"]
else:
info += result.info + "\n"
result = PublicFunc.examine_file(Config["Path"]["Input_orgBcg"], Filename.ORGBCG_RAW, Params.ENDSWITH_TXT)
if result.status:
Config["Path"]["Input_orgBcg"] = result.data["path"]
@ -1064,6 +1123,8 @@ class Data:
else:
return result
try:
self.raw_orgBcg = read_csv(Config["Path"]["Input_orgBcg"],
encoding=Params.UTF8_ENCODING,
@ -1078,7 +1139,7 @@ class Data:
return Result().failure(info=Constants.INPUT_FAILURE + Constants.FAILURE_REASON[
"Open_Data_Exception"] + "\n" + format_exc())
return Result().success(info=Constants.INPUT_FINISHED)
return Result().success(info=info + Constants.INPUT_FINISHED)
def save(self, epoch):
try:
@ -1248,12 +1309,18 @@ class Data:
self.processed_downsample_Tho = self.processed_Tho[::int(temp_frequency / Config["ApplyFrequency"])]
self.processed_downsample_Abd = self.processed_Abd[::int(temp_frequency / Config["ApplyFrequency"])]
self.processed_downsample_orgBcg = self.processed_orgBcg[::int(temp_frequency / Config["ApplyFrequency"])]
except Exception as e:
return Result().failure(
info=Constants.APPROXIMATELY_ALIGN_RESAMPLE_FAILURE + Constants.FAILURE_REASON[
"Resample_Exception"] + "\n" + format_exc())
return Result().success(info=Constants.APPROXIMATELY_ALIGN_RESAMPLE_FINISHED)
return Result().success(info=Constants.APPROXIMATELY_ALIGN_RESAMPLE_FINISHED, data={
"tho_length": len(self.processed_downsample_Tho),
"abd_length": len(self.processed_downsample_Abd),
"orgBcg_length": len(self.processed_downsample_orgBcg)
})
def calculate_correlation1(self):
# 计算互相关1/2
@ -1414,9 +1481,8 @@ class Data:
"frequency": frequency,
"slope": slope,
"intercept": theilsen.intercept_},
)
)
except Exception as e:
return Result().failure(
info=Constants.APPROXIMATELY_ESTIMATE_FREQUENCY_FAILURE + Constants.FAILURE_REASON[
"Estimate_Frequency_Exception"] + "\n" + format_exc())

View File

@ -143,6 +143,7 @@ class Constants:
"OrgBCG_Cut_Length_Not_Correct": "OrgBCG的切割长度不正确Pre+Post长度大于信号长度",
"PSG_Cut_Length_Not_Correct": "PSG的切割长度不正确Pre+Post长度大于信号长度",
"Get_Freq_Not_Correct": "(无法获取数据采样率,将填入配置文件中的采样率。可能是因为文件不存在或文件命名格式不正确导致,请检查数据)",
"orgBcg_Machine_Start_Time_Not_Exist": "OrgBCG的设备启动时间不存在",
"Open_Data_Exception": "(打开数据异常)",
"Process_Exception": "(处理异常)",

View File

@ -1,7 +1,8 @@
import traceback
from datetime import datetime
from logging import error, info
from pathlib import Path
import json
from PySide6.QtWidgets import QMessageBox, QWidget, QPushButton, QProgressBar, QApplication, QRadioButton, QCheckBox
from func.utils.Constants import Constants
@ -227,6 +228,76 @@ class PublicFunc:
}
return Result().success(data=data)
@staticmethod
def get_machine_start_time_bias(psg_dir_path, orgBcg_dir_path):
# 查看orgBcg文件夹下是否有zd5y2_jf_info.json文件
orgBcg_info_path = [p for p in Path(orgBcg_dir_path).glob("*info*") if
p.suffix == ".json"]
if len(orgBcg_info_path) == 0:
return Result().failure(
info=Constants.INPUT_FAILURE + "\n" +
"*info.json" +
str(orgBcg_dir_path) +
Constants.FAILURE_REASON["File_Not_Exist"])
elif len(orgBcg_info_path) > 1:
return Result().failure(
info=Constants.INPUT_FAILURE + "\n" +
"*info.json" +
str(orgBcg_dir_path) +
Constants.FAILURE_REASON["File_More_Than_One"])
else:
orgBcg_info_path = orgBcg_info_path[0]
with open(orgBcg_info_path, 'r', encoding='utf-8') as f:
orgBcg_info = json.load(f)
machine_start_time_str = orgBcg_info.get("StartDate", None)
if machine_start_time_str is None:
return Result().failure(
info=Constants.INPUT_FAILURE + "\n" +
"*info.json" +
str(orgBcg_dir_path) +
Constants.FAILURE_REASON["orgBcg_Machine_Start_Time_Not_Exist"])
# 查看psg文件夹下是否有StartTime_Raw.txt文件
psg_start_time_path = [p for p in Path(psg_dir_path).glob("StartTime_Raw*") if
p.suffix == ".txt"]
if len(psg_start_time_path) == 0:
return Result().failure(
info=Constants.INPUT_FAILURE + "\n" +
"StartTime_Raw.txt" +
str(psg_dir_path) +
Constants.FAILURE_REASON["File_Not_Exist"])
elif len(psg_start_time_path) > 1:
return Result().failure(
info=Constants.INPUT_FAILURE + "\n" +
"StartTime_Raw.txt" +
str(psg_dir_path) +
Constants.FAILURE_REASON["File_More_Than_One"])
else:
psg_start_time_path = psg_start_time_path[0]
with open(psg_start_time_path, 'r', encoding='utf-8') as f:
# 读取第一行
psg_start_time_str = f.readline().strip()
print(psg_start_time_str)
try:
# 计算时间差,单位为秒
fmt = "%Y-%m-%d %H:%M:%S"
machine_start_time = datetime.strptime(machine_start_time_str, fmt)
psg_start_time = datetime.strptime(psg_start_time_str, fmt)
time_bias = (psg_start_time - machine_start_time).total_seconds()
except Exception as e:
traceback.print_exc()
return Result().failure(
info=Constants.INPUT_FAILURE + "\n" +
"时间格式错误,无法计算时间差:" +
str(e))
return Result().success(data={"time_bias":time_bias})
@staticmethod
def examine_artifact(artifact):
# 检查体动标签正确性,长度

View File

@ -586,11 +586,17 @@ class Ui_MainWindow_approximately_align(object):
self.pushButton_Standardize.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u5e94\u7528", None))
self.groupBox_get_position.setTitle(QCoreApplication.translate("MainWindow_approximately_align", u"\u622a\u65ad", None))
self.label.setText(QCoreApplication.translate("MainWindow_approximately_align", u"OrgBCG_\u8865\u96f6\uff1a", None))
self.spinBox_orgBcgPreA.setSuffix(QCoreApplication.translate("MainWindow_approximately_align", u" \u79d2", None))
self.label_2.setText(QCoreApplication.translate("MainWindow_approximately_align", u"PSG_\u8865\u96f6\uff1a", None))
self.spinBox_PSGPreA.setSuffix(QCoreApplication.translate("MainWindow_approximately_align", u" \u79d2", None))
self.label_4.setText(QCoreApplication.translate("MainWindow_approximately_align", u"OrgBCG_Pre \uff1a", None))
self.spinBox_orgBcgPreCut.setSuffix(QCoreApplication.translate("MainWindow_approximately_align", u" \u79d2", None))
self.label_5.setText(QCoreApplication.translate("MainWindow_approximately_align", u"PSG_Pre \uff1a", None))
self.spinBox_PSGPreCut.setSuffix(QCoreApplication.translate("MainWindow_approximately_align", u" \u79d2", None))
self.label_7.setText(QCoreApplication.translate("MainWindow_approximately_align", u"OrgBCG_Post\uff1a", None))
self.spinBox_orgBcgPostCut.setSuffix(QCoreApplication.translate("MainWindow_approximately_align", u" \u79d2", None))
self.label_8.setText(QCoreApplication.translate("MainWindow_approximately_align", u"PSG_Post\uff1a", None))
self.spinBox_PSGPostCut.setSuffix(QCoreApplication.translate("MainWindow_approximately_align", u" \u79d2", None))
self.pushButton_CutOff.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u5e94\u7528", None))
self.groupBox_align_position.setTitle(QCoreApplication.translate("MainWindow_approximately_align", u"\u5bf9\u9f50\u8d77\u59cb\u4f4d\u7f6e", None))
self.pushButton_ChangeView.setText(QCoreApplication.translate("MainWindow_approximately_align", u"\u4f30\u8ba1\u91c7\u6837\u7387", None))

View File

@ -334,6 +334,9 @@
<property name="buttonSymbols">
<enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
</property>
<property name="suffix">
<string> 秒</string>
</property>
<property name="maximum">
<number>999999</number>
</property>
@ -370,6 +373,9 @@
<property name="buttonSymbols">
<enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
</property>
<property name="suffix">
<string> 秒</string>
</property>
<property name="maximum">
<number>999999</number>
</property>
@ -404,6 +410,9 @@
<property name="buttonSymbols">
<enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
</property>
<property name="suffix">
<string> 秒</string>
</property>
<property name="maximum">
<number>999999</number>
</property>
@ -434,6 +443,9 @@
<property name="buttonSymbols">
<enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
</property>
<property name="suffix">
<string> 秒</string>
</property>
<property name="maximum">
<number>999999</number>
</property>
@ -474,6 +486,9 @@
<property name="buttonSymbols">
<enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
</property>
<property name="suffix">
<string> 秒</string>
</property>
<property name="maximum">
<number>999999</number>
</property>
@ -510,6 +525,9 @@
<property name="buttonSymbols">
<enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
</property>
<property name="suffix">
<string> 秒</string>
</property>
<property name="maximum">
<number>999999</number>
</property>