
ПРИЛОЖЕНИЕ А
КОД РАЗРАБОТАННОЙ ПРОГРАММЫ
import sys # sys нужен для передачи argv в QApplication
import matplotlib
from PyQt5.QtWidgets import QMessageBox import numpy as np
from numpy import genfromtxt
from scipy.fft import rfft, rfftfreq from scipy.signal import butter, lfilter
matplotlib.use('Qt5Agg') from PyQt5 import QtWidgets
from PyQt5.QtWidgets import * from PyQt5.uic import loadUi
class ExampleApp(QMainWindow):
# Инициализация графического окна def __init__(self):
QMainWindow.__init__(self)
loadUi("design.ui", self) self.plotBtn.clicked.connect(self.update_graph) self.FileBtn.clicked.connect(self.open_sheet)
self.filterCB.addItem('Нет') self.filterCB.addItem('Да')
def update_graph(self): # Кнопка обновления интерфейса
def butter_bandpass(lowcut, highcut, fs, order): # Полосовой фильтр Баттерворта
nyq = 0.5 * fs
low = lowcut / nyq high = highcut / nyq
b, a = butter(order, [low, high], btype='band') return b, a
if self.fsLineEdit.text().isdigit() and float(self.fsLineEdit.text()) > 0: # Если в fs корректное значение
f = self.FileN
data = genfromtxt(f, delimiter=',')
N = len(data)
fs = int(self.fsLineEdit.text()) T = 1.0 / fs
tmax = T * N
x = np.linspace(0.0, N * T, N)
if self.radioTime.isChecked(): # Временная область self.MplWidget.canvas.axes.clear() self.MplWidget.canvas.axes.plot(x, data) self.MplWidget.canvas.axes.set_title('Исходный ЭКГ сигнал') self.MplWidget.canvas.axes.set_xlabel('t, c') self.MplWidget.canvas.axes.set_ylabel('U, В') self.MplWidget.canvas.draw()
if self.filterCB.currentText() == 'Нет':
41
self.MplWidget2.canvas.axes.clear() self.MplWidget2.canvas.axes.plot(x, data) self.MplWidget2.canvas.axes.set_title('Неотфильтрованный
ЭКГ сигнал')
self.MplWidget2.canvas.axes.set_xlabel('t, c') self.MplWidget2.canvas.axes.set_ylabel('U, В') self.MplWidget2.canvas.draw()
elif self.filterCB.currentText() == 'Да':
# Если заданы корректные параметры фильтрации if self.lowFrEdit.text().isdigit() and (
float(self.lowFrEdit.text()) > 0) and self.highFrEdit.text().isdigit() and (
float(self.highFrEdit.text()) > 0) and self.orderEdit.text().isdigit() and (
float(self.highFrEdit.text()) > float(self.lowFrEdit.text())) and (
float(self.orderEdit.text()) > 0) and (float(self.highFrEdit.text()) < fs / 2):
lowFr = float(self.lowFrEdit.text()) hiFr = float(self.highFrEdit.text()) order = float(self.orderEdit.text())
b, a = butter_bandpass(lowFr, hiFr, fs, order=order) fy = lfilter(b, a, data)
self.MplWidget2.canvas.axes.clear() self.MplWidget2.canvas.axes.plot(x, fy)
self.MplWidget2.canvas.axes.set_title('Отфильтрованный ЭКГ сигнал') self.MplWidget2.canvas.axes.set_xlabel('t, c') self.MplWidget2.canvas.axes.set_ylabel('U, В') self.MplWidget2.canvas.draw()
else:
msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Ошибка") msg.setInformativeText(
'Введите корректные значения частот (положительные числа, верхняя частота больше нижней, но меньше частоты Найквиста (1/2 fs)) и порядок фильтра (больше нуля)')
msg.setWindowTitle("Ошибка") msg.exec_()
if self.radioSpectrum.isChecked():
if self.filterCB.currentText() == 'Да':
if self.lowFrEdit.text().isdigit() and ( float(self.lowFrEdit.text()) > 0) and
self.highFrEdit.text().isdigit() and ( float(self.highFrEdit.text()) > 0) and
self.orderEdit.text().isdigit() and ( float(self.highFrEdit.text()) >
float(self.lowFrEdit.text())) and (
float(self.orderEdit.text()) > 0) and (float(self.highFrEdit.text()) < fs / 2):
lowFr = float(self.lowFrEdit.text()) hiFr = float(self.highFrEdit.text()) order = float(self.orderEdit.text())
b, a = butter_bandpass(lowFr, hiFr, fs, order=order) fy = lfilter(b, a, data)
self.MplWidget.canvas.axes.clear() self.MplWidget.canvas.axes.plot(x, fy) self.MplWidget.canvas.axes.set_title('Отфильтрованный
ЭКГ сигнал')
42
self.MplWidget.canvas.axes.set_xlabel('t, c') self.MplWidget.canvas.axes.set_ylabel('U, В') self.MplWidget.canvas.draw()
yf = rfft(fy)
xf = rfftfreq(len(fy), 1 / fs)
self.MplWidget2.canvas.axes.clear() self.MplWidget2.canvas.axes.plot(xf, np.abs(yf)) self.MplWidget2.canvas.axes.set_title('Спектр
отфильтрованного ЭКГ сигнала') self.MplWidget2.canvas.axes.set_xlabel('f, Гц') self.MplWidget2.canvas.axes.set_ylabel('|U|^2,
В^2/Гц')
self.MplWidget2.canvas.draw() else:
msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Ошибка") msg.setInformativeText(
'Введите корректные значения частот (положительные числа, верхняя частота больше нижней, но меньше частоты Найквиста (1/2 fs)) и порядок фильтра (больше нуля)')
msg.setWindowTitle("Ошибка") msg.exec_()
elif self.filterCB.currentText() == 'Нет': self.MplWidget.canvas.axes.clear() self.MplWidget.canvas.axes.plot(x, data) self.MplWidget.canvas.axes.set_title('Исходный ЭКГ
сигнал')
self.MplWidget.canvas.axes.set_xlabel('t, c') self.MplWidget.canvas.axes.set_ylabel('U, В') self.MplWidget.canvas.draw()
yf = rfft(data)
xf = rfftfreq(len(data), 1 / fs)
self.MplWidget2.canvas.axes.clear() self.MplWidget2.canvas.axes.plot(xf, np.abs(yf)) self.MplWidget2.canvas.axes.set_title('Спектр исходного
ЭКГ сигнала')
self.MplWidget2.canvas.axes.set_xlabel('f, Гц') self.MplWidget2.canvas.axes.set_ylabel('|U|^2, В^2/Гц') self.MplWidget2.canvas.draw()
if self.radioACF.isChecked():
if self.filterCB.currentText() == 'Да':
if self.lowFrEdit.text().isdigit() and ( float(self.lowFrEdit.text()) > 0) and
self.highFrEdit.text().isdigit() and ( float(self.highFrEdit.text()) > 0) and
self.orderEdit.text().isdigit() and ( float(self.highFrEdit.text()) >
float(self.lowFrEdit.text())) and (
float(self.orderEdit.text()) > 0) and (float(self.highFrEdit.text()) < fs / 2):
lowFr = float(self.lowFrEdit.text()) hiFr = float(self.highFrEdit.text()) order = float(self.orderEdit.text())
b, a = butter_bandpass(lowFr, hiFr, fs, order=order) fy = lfilter(b, a, data)
self.MplWidget.canvas.axes.clear()
43
self.MplWidget.canvas.axes.plot(x, fy) self.MplWidget.canvas.axes.set_title('Отфильтрованный
ЭКГ сигнал')
self.MplWidget.canvas.axes.set_xlabel('t, c') self.MplWidget.canvas.axes.set_ylabel('U, В') self.MplWidget.canvas.draw()
corr_data = np.correlate(fy, fy, "full") tcf = np.arange(-tmax + T, tmax, T) self.MplWidget2.canvas.axes.clear()
self.MplWidget2.canvas.axes.plot(tcf, corr_data) self.MplWidget2.canvas.axes.set_title('АКФ
отфильтрованного ЭКГ сигнала')
self.MplWidget2.canvas.axes.set_xlabel('Сдвиг t, c') self.MplWidget2.canvas.axes.set_ylabel('Значение') self.MplWidget2.canvas.draw()
else:
msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Ошибка") msg.setInformativeText(
'Введите корректные значения частот (положительные числа, верхняя частота больше нижней, но меньше частоты Найквиста (1/2 fs)) и порядок фильтра (больше нуля)')
msg.setWindowTitle("Ошибка") msg.exec_()
elif self.filterCB.currentText() == 'Нет': self.MplWidget.canvas.axes.clear() self.MplWidget.canvas.axes.plot(x, data) self.MplWidget.canvas.axes.set_title('Исходный ЭКГ
сигнал')
self.MplWidget.canvas.axes.set_xlabel('t, c') self.MplWidget.canvas.axes.set_ylabel('U, В') self.MplWidget.canvas.draw()
corr_data = np.correlate(data, data, "full") tcf = np.arange(-tmax + T, tmax, T) self.MplWidget2.canvas.axes.clear() self.MplWidget2.canvas.axes.plot(tcf, corr_data)
self.MplWidget2.canvas.axes.set_title('АКФ исходного ЭКГ
сигнала')
self.MplWidget2.canvas.axes.set_xlabel('Сдвиг t, c') self.MplWidget2.canvas.axes.set_ylabel('Значение') self.MplWidget2.canvas.draw()
else:
msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Ошибка")
msg.setInformativeText('Введите корректную частоту дискретизации (целочисленное положительное значение)')
msg.setWindowTitle("Ошибка") msg.exec_()
def open_sheet(self): # Выбор и загрузка файла сигнала
path = QFileDialog.getOpenFileName(self, "Open", "", "txt Files (*.txt);;All Files (*)")
if path[0] != '': self.FileN = path[0]
self.plotBtn.setEnabled(True) self.MplWidget.canvas.axes.clear() self.MplWidget2.canvas.axes.clear() self.MplWidget.canvas.draw() self.MplWidget2.canvas.draw()
44
def main():
app = QtWidgets.QApplication(sys.argv) # Новый экземпляр QApplication window = ExampleApp() # Создаём объект класса ExampleApp window.show() # Показываем окно
app.exec_() # и запускаем приложение
if __name__ == '__main__': # Если мы запускаем файл напрямую, а не импортируем
main() # то запускаем функцию main()
45