First commit

This commit is contained in:
SimonovaMI 2025-04-29 16:31:44 +03:00
commit 97c6be4e8d
9 changed files with 3612 additions and 0 deletions

5
README.txt Normal file
View File

@ -0,0 +1,5 @@
Для ознакомления с кодом проще всего запустить программу в PyCharm
1. создать папку с проектом
2. в папке с проектом создать папку project
3. в папку project поместить файлы с кодом
4. в папку с проектом разместить файл ui и ico

2423
design_viewer.ui Normal file

File diff suppressed because it is too large Load Diff

BIN
logo.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

8
project/__init__.py Normal file
View File

@ -0,0 +1,8 @@
"""Режимы работы, переменные, влияющие на работу, которые с некоторой вероятностью будут меняться."""
DATA_RATE = 200 # скорость передачи данных
# mes = "AT+CONA11899AA1670B\r\n"
mes = "AT+CONA11899AA21438\r\n" # для связи со стимулятором

472
project/controller.py Normal file
View File

@ -0,0 +1,472 @@
"""Преобразование данных"""
import struct
import numpy as np
from project import DATA_RATE
import model
NORMAL_LENGTH = 32 # размер пакета
Start_byte = b'\x55' # стартовый байт, нужен для парсинга сообщения
Stop_byte = b'\x77' # стоповый байт, нужен для парсинга сообщения
threshold_MIN = 100 # минимално возможная амплитуда выше которой ищем пики в базовом режиме
threshold_MAX = 400 # максимально возможная амплитуда выше которой не сохраняем
# методы чтения передаваемых данных
def shift_or(one, two, three, four):
"""Чтение 4-ёх байтного параметра"""
a = one << 24 | two << 16 | three << 8 | four
return a
def shift_or_24(two, three, four):
"""Чтение 3-ёх байтного параметра"""
a = two << 16 | three << 8 | four
return a
def shift_or_16(three, four):
"""Чтение 2-ух байтного параметра"""
a = three << 8 | four
return a
def get_data_bin(file, data_in):
"""
Получение данных из бинарного файла - записанных данных
:param file: файл для чтения
:param data_in: объект для хранения модели данных
"""
chunk = list(model.get_data_bin(file, data_in))
data_in.chunk = [item.to_bytes() for item in list(chunk)]
def write_file():
"""
Открытие на запись файла
"""
return model.write_file()
def write_in_file(file, rx):
"""
Запись данных в файл
:param file: файл
:param rx: серия данных
"""
model.write_in_file(file, rx)
def close_file(file):
"""
Закрыть файл
:param file: файл
"""
return model.close_file(file)
def create_mess(send_mode, param_code, param, size, type_param):
"""
Создание сообщения для передачи параметров
:param send_mode: режим передачи данных 433 - 0(Bluetooth - 1)
:param param_code: код для идентификации параметра для передачи(задано протоколом взаимодействия)
:param param: передаваемое значение
:param size: размер передаваемого значения
:param type_param: тип передаваемого значения
"""
index = 2
if send_mode:
index = 10
init_mes = [0x41, 0x54, 0x2b, 0x44, 0x41, 0x54, 0x41, 0x31, 0x55, param_code, 0x77, 0x0D, 0x0A]
else:
init_mes = [0x55, param_code, 0x77]
param_in_bytes = []
if type_param == float:
param = struct.unpack('i', struct.pack('f', param))[0]
param_in_bytes = [int(((param & 0xFF000000)) >> 24), int(((param & 0xFF0000)) >> 16),
int(((param & 0xFF00) >> 8)),
int((param & 0xFF))]
if type_param == int:
if size == 4:
param_in_bytes = [int(((param & 0xFF000000)) >> 24), int(((param & 0xFF0000)) >> 16),
int(((param & 0xFF00) >> 8)),
int((param & 0xFF))]
if size == 3:
param_in_bytes = [0, int(((param & 0xFF0000)) >> 16),
int(((param & 0xFF00) >> 8)),
int((param & 0xFF))]
if size == 2:
param_in_bytes = [0, 0, int(((param & 0xFF00) >> 8)),
int((param & 0xFF))]
if size == 1:
param_in_bytes = [0, 0, 0, int((param & 0xFF))]
for _ in param_in_bytes[::-1]:
init_mes.insert(index, _)
mes = bytes(init_mes)
return mes
def state_packet(send_mode, serial, param_code, param, size, type_param):
"""
Отправка пакета параметров
:param send_mode: режим передачи данных 433 - 0(Bluetooth - 1)
:param serial: канал передачи
:param param_code: код для идентификации параметра для передачи(задано протоколом взаимодействия)
:param param: передаваемое значение
:param size: размер передаваемого значения
:param type_param: тип передаваемого значения
"""
if serial.isOpen():
serial.writeData(create_mess(send_mode, param_code, param, size, type_param))
class DataClass:
"""
Класс модель данных для отображения на графике
"""
def __init__(self):
# переменные для работы с потоком данных с устройства
self.data_rx = [] # список в котором храним данные
self.draw_cnt = np.uint16(0) # x-координата точки в текущий момент
self.data_length = 0 # кол-во отсчетов для отрисовки графика по x-координате
self.pac_count = 0 # счетчик для распознавания пакетов
self.counter = [] # счетчик небитых пакетов
# переменные для работы с записанным файлом
self.i = 0 # счетчик для чтения файла
self.chunk = [] # считанный массив из файла
# переменные для отрисовки графиков
# Сигнал по которому определяют ЧСС ЭКГ сигнал если у нас кардиограф
# Правый желудочек (используется основной канал)
self.ECG_RA = [] # np.zeros(self.data_length, np.int16)
# позитивно отраженный сигнал
self.ECG_RA_pos_sig = [] # np.zeros(self.data_length, np.int16)
# динамический порог рассчитываемый в зависимости от нижнего и верхнего порогов
self.ECG_RA_din_threshold = [] # np.zeros(self.data_length, np.int16)
# нижний порог порог для метода треугольников при его пересечении считаем ЧСС событие
self.ECG_RA_min_threshold = np.int16(threshold_MIN)
# верхний порог для метода треугольников выше него мы не берём данные
self.ECG_RA_max_threshold = np.int16(threshold_MAX)
self.Last_RR_poz_rel = [] # время до прошлого события
self.text_list = {} # список label на графике для динамического обновления
self.last_period = [] # мгновенный период для отрисовки label
self.rr_now = [] # есть ли удар сердца в текущий момент
self.last_QRS = [] # тип последнего события Vsense = 0 нормальное сокращение
# Vpace = 1 пришлось стимулировать сейчас не используем
# Vnoise = 2 шумы в QRS комплексе(пока не реализовали)
# переменные для отрисовки label (обозначение на графике событий)
self.V_print = 0 # необходимость отображения события
self.draw_cnt_last = 0 # x-координата события
self.draw_last_period = 0 # мгновенный период для отображения
self.draw_last_QRS = 0 # тип последнего события для отображения
# переменные для передачи параметров стимулятору и отображения текущих значений
self.dc_cut = 1 # вывод сигнала с постоянной составляющей или без
self.channel = 3 # активный канал передачи
self.signal = 0 # вывод сигнала с фильтром или без
self.sd_card = 0 # запись на sd-карту
self.hv_volt = 0 # напряжение на конденсаторе
self.bat_volt = 0 # напряжение на батарее
self.bat_pers = 0 # напряжение на батарее в процентах
self.spi_pot_set = 0 # коэффициент усиления
self.Work_Mode_pacemaker = 0 # текущий режим работы стимулятора
self.redet_num = 0 # размер буфера редетекции
self.redet_bad = 0 # порог буфера редетекции
self.standby_timer = 0 # таймаут отключения
self.hv_blind_time = 0 # время слепоты после разряда
self.max_energy = 0 # максимальная энергия
self.min_energy = 0 # минимальная энергия
self.hv_step_number = 0 # кол-во ступеней высоковольтной терапии
self.fibr_max_tres = 0 # порог корзины фибриляций
self.tachy_2_tres = 0 # пороговое значение для тахикардии 2ст
self.tachy_1_tres = 0 # пороговое значение для тахикардии 1ст
self.fibr_tres = 0 # пороговое значение для фибрилляции
self.max_search_time = 135 # длительность поиска максимума
self.square_coef = 0.75 # порог чувствительности Т волны
self.square_time = 350 # длительность защиты от T волны
self.max_treshold = 8.0 # максимальная чувствительность
self.min_treshold = 2.0 # минимальная чувствительность
self.max_time = 1250 # максимальный размер RR интервала
self.fibr_cnt = 0 # кол-во событий фибрилляции (прогресс-бар)
self.norm_cnt = 0 # кол-во нормальных сокращений (прогресс-бар)
self.tachy_1_cnt = 0 # кол-во событий тахикардии 1ст (прогресс-бар)
self.tachy_2_cnt = 0 # кол-во событий тахикардии 2ст (прогресс-бар)
self.hv_step_cnt = 0 # текущая ступень ВВ терапии
self.last_period_stat = 0 # мгновенный период
self.filt_period = 0 # усредненный период
self.now_energy = 0 # текущая энергия
self.Vn_cnt = 0 # счетчик Vn
self.Vp_cnt = 0 # счетчик Vp
self.Vs_cnt = 0 # счетчик Vs
self.sub_mode = 0 # текущий подрежим терапии
self.terapy_now = 0 # текущий режим терапии
def clear_data(self):
"""
Очистить модель хранения данных
"""
self.__init__()
# self.data_rx.clear()
# self.data_length = 0
# self.counter = np.zeros(self.data_length, np.int16) # np.zeros(self.data_length, np.int16)
# self.pac_count = 0
# self.draw_cnt = 0
#
# self.i = 0
# self.chunk = []
# self.update_data(self.data_length)
# # Сигнал по которому определяют ЧСС ЭКГ сигнал если у нас кардиограф и производная фильрованного ФПГ если часы
# # Правый желудочек (используется основной канал)
# self.ECG_RA = []
#
# # позитивно отраженный сигнал
# self.ECG_RA_pos_sig = [] # np.zeros(self.data_length, np.int16)
#
# # динамический порог рассчитываемый в зависимости от нижнего и верхнего порогов
# self.ECG_RA_din_threshold = [] # np.zeros(self.data_length, np.int16)
#
# # нижний порог порог для метода треугольников при его пересечении считаем ЧСС событие
# self.ECG_RA_min_threshold = np.int16(threshold_MIN)
#
# # верхний порог для метода треугольников выше него мы не берём данные
# self.ECG_RA_max_threshold = np.int16(threshold_MAX)
# счетчик пакетов для вывод на график(визуальный контроль)
def update_data(self, data_length):
"""
Создание нулевых массивов для хранения в них даных для отображения
:param data_length: длина массива (сколько значений поместится в окно)
"""
self.ECG_RA = np.zeros(data_length, np.float32)
self.ECG_RA_pos_sig = np.zeros(data_length, np.float32)
self.ECG_RA_din_threshold = np.zeros(data_length, np.float32)
self.counter = np.zeros(data_length, np.float32)
self.ECG_RA_min_threshold = np.zeros(data_length, np.float32)
self.ECG_RA_max_threshold = np.zeros(data_length, np.float32)
self.Last_RR_poz_rel = np.zeros(data_length, np.uint16)
self.last_QRS = np.zeros(data_length, np.uint16)
self.rr_now = np.zeros(data_length, np.uint16)
self.last_period = np.zeros(data_length, np.uint16)
def parse_list(self, data_in):
"""
Расшифровка полученной серии данных
:param data_in: ссылка на объект модели данных
"""
self.data_rx = self.data_rx + list(data_in)
if len(self.data_rx) >= NORMAL_LENGTH * 2: # парсить имеет смысл при длинне пакета больше минимальной
while self.pac_count <= len(self.data_rx) - NORMAL_LENGTH:
if (self.data_rx[self.pac_count] == Start_byte) and (
self.data_rx[self.pac_count + NORMAL_LENGTH - 1] == Stop_byte) \
and ((len(self.data_rx) - self.pac_count) >= NORMAL_LENGTH + 0):
self.draw_cnt += 1
if self.draw_cnt >= self.data_length:
self.draw_cnt = 0
self.text_list = {}
self.parse_part_from_1_to_20_byte()
if self.draw_cnt > 1:
self.ECG_RA_min_threshold[self.draw_cnt] = self.ECG_RA_min_threshold[self.draw_cnt - 1]
self.ECG_RA_max_threshold[self.draw_cnt] = self.ECG_RA_max_threshold[self.draw_cnt - 1]
self.last_period[self.draw_cnt] = self.last_period[self.draw_cnt - 1]
else:
self.ECG_RA_min_threshold[self.draw_cnt] = self.ECG_RA_min_threshold[self.data_length - 1]
self.ECG_RA_max_threshold[self.draw_cnt] = self.ECG_RA_max_threshold[self.data_length - 1]
self.last_period[self.draw_cnt] = self.last_period[self.data_length - 1]
self.parse_part_from_23_to_30_byte()
if self.rr_now[self.draw_cnt] == 1:
self.V_print = 1
self.draw_cnt_last = self.draw_cnt
self.draw_last_period = self.last_period[self.draw_cnt]
# в конце парсинга шагаем по массиву
self.pac_count += NORMAL_LENGTH - 1
del self.data_rx[0:self.pac_count]
self.pac_count = 0
self.pac_count += 1
def parse_part_from_1_to_20_byte(self):
"""
Парсинг с 1 по 20 байт
"""
self.counter[self.draw_cnt] = shift_or(int.from_bytes(self.data_rx[self.pac_count + 1], "big"),
int.from_bytes(self.data_rx[self.pac_count + 2], "big"),
int.from_bytes(self.data_rx[self.pac_count + 3], "big"),
int.from_bytes(self.data_rx[self.pac_count + 4], "big"))
int1 = (shift_or(int.from_bytes(self.data_rx[self.pac_count + 5], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 6], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 7], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 8], "big", signed=False)))
self.ECG_RA_din_threshold[self.draw_cnt] = struct.unpack('f', int1.to_bytes(4, 'big'))[0]
int1 = (shift_or(int.from_bytes(self.data_rx[self.pac_count + 9], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 10], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 11], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 12], "big", signed=False)))
self.ECG_RA_pos_sig[self.draw_cnt] = struct.unpack('f', int1.to_bytes(4, 'big'))[0]
int1 = (shift_or(int.from_bytes(self.data_rx[self.pac_count + 13], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 14], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 15], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 16], "big", signed=False)))
self.ECG_RA[self.draw_cnt] = struct.unpack('f', int1.to_bytes(4, 'big'))[0]
self.Last_RR_poz_rel[self.draw_cnt] = shift_or_16(
int.from_bytes(self.data_rx[self.pac_count + 17], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 18], "big"))
int1 = int.from_bytes(self.data_rx[self.pac_count + 19], "big")
self.terapy_now = int1 & 0x3
self.sub_mode = (int1 & 0x1C) >> 2
int1 = int.from_bytes(self.data_rx[self.pac_count + 20], "big")
self.last_QRS[self.draw_cnt] = int1 & 0x3
self.draw_last_QRS = int1 & 0x3
self.rr_now[self.draw_cnt] = (int1 & 0x4) >> 2
self.Work_Mode_pacemaker = (int1 & 0x60) >> 5
self.signal = (int1 & 0x80) >> 7
def parse_part_from_23_to_30_byte(self):
"""
Парсинг с 23 по 30 байт (передача значений в зависимости от остатка от деления счетчика)
"""
if self.counter[self.draw_cnt] % 10 == 0:
int1 = (shift_or(int.from_bytes(self.data_rx[self.pac_count + 23], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 24], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 25], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 26], "big", signed=False)))
self.ECG_RA_min_threshold[self.draw_cnt] = struct.unpack('f', int1.to_bytes(4, 'big'))[0]
self.min_treshold = self.ECG_RA_min_threshold[self.draw_cnt]
int1 = (shift_or(int.from_bytes(self.data_rx[self.pac_count + 27], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 28], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 29], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 30], "big", signed=False)))
self.ECG_RA_max_threshold[self.draw_cnt] = struct.unpack('f', int1.to_bytes(4, 'big'))[0]
self.max_treshold = self.ECG_RA_max_threshold[self.draw_cnt]
if self.counter[self.draw_cnt] % 10 == 1:
int1 = (
shift_or(int.from_bytes(self.data_rx[self.pac_count + 23], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 24], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 25], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 26], "big", signed=False)))
self.square_coef = struct.unpack('f', int1.to_bytes(4, 'big'))[0]
if self.counter[self.draw_cnt] % 10 == 2:
self.square_time = (
shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 29], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 30], "big", signed=False)))
self.max_search_time = (
shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 27], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 28], "big", signed=False)))
if self.counter[self.draw_cnt] % 10 == 3:
int1 = int.from_bytes(self.data_rx[self.pac_count + 24], "big")
self.sd_card = (int1 & 0x4) >> 2
self.channel = int1 & 0x3
self.dc_cut = (int1 & 0x8) >> 3
self.spi_pot_set = int.from_bytes(self.data_rx[self.pac_count + 25], "big")
self.bat_pers = int.from_bytes(self.data_rx[self.pac_count + 26], "big")
self.bat_volt = (
shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 27], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 28], "big", signed=False)))
self.hv_volt = (
shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 29], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 30], "big", signed=False)))
if self.counter[self.draw_cnt] % 10 == 4:
self.last_period[self.draw_cnt] = (
shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 27], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 28], "big", signed=False)))
self.last_period_stat = self.last_period[self.draw_cnt]
self.max_time = (
shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 25], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 26], "big", signed=False)))
if self.counter[self.draw_cnt] % 10 == 5:
self.Vs_cnt = (
shift_or_24(int.from_bytes(self.data_rx[self.pac_count + 23], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 24], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 25], "big", signed=False)))
self.Vp_cnt = (
shift_or_24(int.from_bytes(self.data_rx[self.pac_count + 28], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 29], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 30], "big", signed=False)))
self.Vn_cnt = (
shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 26], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 27], "big", signed=False),
))
if self.counter[self.draw_cnt] % 10 == 6:
self.fibr_tres = (
shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 23], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 24], "big", signed=False)
))
self.tachy_2_tres = (
shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 25], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 26], "big", signed=False)
))
self.tachy_1_tres = (
shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 27], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 28], "big", signed=False)
))
if self.counter[self.draw_cnt] % 10 == 7:
self.fibr_cnt = int.from_bytes(self.data_rx[self.pac_count + 25], "big")
self.tachy_2_cnt = int.from_bytes(self.data_rx[self.pac_count + 26], "big")
self.tachy_1_cnt = int.from_bytes(self.data_rx[self.pac_count + 27], "big")
self.norm_cnt = int.from_bytes(self.data_rx[self.pac_count + 28], "big")
self.fibr_max_tres = int.from_bytes(self.data_rx[self.pac_count + 29], "big")
self.filt_period = (
shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 23], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 24], "big", signed=False)))
if self.counter[self.draw_cnt] % 10 == 8:
self.now_energy = (shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 27], "big",
signed=False),
int.from_bytes(self.data_rx[self.pac_count + 28], "big",
signed=False))) / 10
self.min_energy = (int.from_bytes(self.data_rx[self.pac_count + 26], "big",
signed=False)) // 10
self.max_energy = (shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 29], "big",
signed=False),
int.from_bytes(self.data_rx[self.pac_count + 30], "big",
signed=False))) // 10
int1 = int.from_bytes(self.data_rx[self.pac_count + 23], "big")
self.hv_step_cnt = int1 & 0xF
self.hv_step_number = (int1 & 0xF0) >> 4
if self.counter[self.draw_cnt] % 10 == 9:
self.hv_blind_time = (
shift_or_16(int.from_bytes(self.data_rx[self.pac_count + 23], "big", signed=False),
int.from_bytes(self.data_rx[self.pac_count + 24], "big", signed=False)))
self.standby_timer = (
shift_or(int.from_bytes(self.data_rx[self.pac_count + 27], "big",
signed=False),
int.from_bytes(self.data_rx[self.pac_count + 28], "big",
signed=False),
int.from_bytes(self.data_rx[self.pac_count + 29], "big",
signed=False),
int.from_bytes(self.data_rx[self.pac_count + 30], "big",
signed=False)
)) // 1000
int1 = int.from_bytes(self.data_rx[self.pac_count + 25], "big", signed=False)
self.redet_bad = int1 & 0xF
self.redet_num = (int1 & 0xF0) >> 4

15
project/main.py Normal file
View File

@ -0,0 +1,15 @@
"""
Запуск программы
Два режим работы:
1. чтение из com-порта, отображение, запись данных, передача настраиваемых параметров в стимулятор,
управелние перезагрузкой
2. чтение данных из файла и отображение
"""
import project.view
app = project.view.app
window = project.view.Ui()
window.show()
app.exec_()

58
project/model.py Normal file
View File

@ -0,0 +1,58 @@
"""Получение сырых данных из различных источников. Работа с файлами"""
import datetime
import os.path
# from PyQt5.QtSerialPort import QSerialPort
# def on_read():
#
#
#
# # создание соединения с устройством для передачи данных
# serial = QSerialPort()
# serial.setBaudRate(115200)
# serial.readyRead.connect(on_read)
def get_data_bin(file_name, data_in):
"""
Получение данных из бинарного файла
:param file_name: файл
:param data_in: объект модели данных для отрисовки
:return: массив данных
"""
f = open(file_name, 'rb')
size = os.path.getsize(file_name)
chunk = f.read(size)
data_in.data_length = int(size / 32)
data_in.update_data(data_in.data_length)
f.close()
return chunk
def write_file():
"""
Запись файла
"""
# создание папки data(если её нет)
if not os.path.isdir("data"):
os.mkdir("data")
file_name = datetime.datetime.now().strftime('%d%m%y%H%M%S')
file = open('data/' + file_name + '.txt', 'wb')
return file, file_name
def write_in_file(file, rx):
file.write(rx)
def close_file(file):
"""
Закончить запись и закрыть файл
"""
if file != "":
file.close()
return ""

626
project/view.py Normal file
View File

@ -0,0 +1,626 @@
"""Отображение данных"""
import sys
import os.path
import datetime
import time
import numpy as np
from PyQt5.QtCore import QIODevice
from PyQt5.QtSerialPort import QSerialPortInfo, QSerialPort
from PyQt5.QtGui import *
from PyQt5 import QtWidgets, uic, QtGui
from PyQt5.QtWidgets import QFileDialog
from PyQt5 import QtCore
from pyqtgraph import TextItem
import pyqtgraph as pg
import project.controller as my_data
from project import mes
# выбор режима чения из файла или из com-порта
MODE_COM_PORT = False
MODE_FILE = False
# объявили экземпляры класса, для обработки данных из файла или из com-порта
data_IN_FILE = my_data.DataClass()
data_IN_COM = my_data.DataClass()
# создание приложения
app = QtWidgets.QApplication(sys.argv)
class Ui(QtWidgets.QMainWindow):
"""Класс отображения данных"""
def __init__(self):
# создание графического отображения
super(Ui, self).__init__()
uic.loadUi('design_viewer.ui', self)
self.setWindowTitle("Pacemaker viewer")
self.setWindowIcon(QtGui.QIcon("logo.ICO"))
self.counter_com_port = [] # координата x для вывода графиков
self.point = 0 # координата, откуда начинать отрисовку, если используется полоса прокрутки??
self.file = "" # файл
self.file_name = "" # наименование файла
# Создание графиков
self.graph_init()
def set_up_controls():
"""
Настройка элементов управления в визуале
"""
self.OpenB.setVisible(False)
self.CloseB.setVisible(False)
self.Play.setVisible(False)
self.Pause.setVisible(False)
self.horizontalScrollBar.setVisible(False)
self.horizontalScrollBar.valueChanged.connect(self.on_scroll)
self.radioButton_work_mode_com_port.toggled.connect(self.check_work_mode_viewer)
self.OpenB.clicked.connect(self.on_open)
self.CloseB.clicked.connect(self.on_close)
self.Write_file.clicked.connect(self.write_file)
self.Close_file.clicked.connect(self.close_file)
self.Read.clicked.connect(self.on_start)
self.Stop.clicked.connect(self.on_stop)
self.Restart.clicked.connect(self.restart)
self.SD_card_Box.currentTextChanged.connect(self.set_SD_card)
self.Send_mode_Box.currentTextChanged.connect(self.set_send_mode)
self.ComL.addItems(self.update_list())
self.horizontalScrollBar.valueChanged.connect(self.on_scroll)
self.RA_scale_BOX.currentTextChanged.connect(self.on_scale_change)
self.Low_V_spinBox.valueChanged.connect(self.set_fibr_cnt_max)
self.Low_V_spinBox_3.valueChanged.connect(self.set_tachy_2_cnt_max)
self.Low_V_spinBox_4.valueChanged.connect(self.set_tachy_1_cnt_max)
self.RA_max_time_ms_BOX.editTextChanged.connect(self.set_RA_max_time_ms_BOX)
self.RA_min_sensitivity_BOX.editTextChanged.connect(self.set_RA_min_sensitivity_BOX)
self.RA_max_sensitivity_BOX.editTextChanged.connect(self.set_RA_max_sensitivity_BOX)
self.RA_square_time_ms_BOX.editTextChanged.connect(self.set_RA_square_time_ms_BOX)
self.RA_square_coeff_BOX.editTextChanged.connect(self.set_RA_square_coeff_BOX)
self.RA_all_time_ms_BOX.editTextChanged.connect(self.set_RA_all_time_ms_BOX)
self.Signal_Box.currentIndexChanged.connect(self.set_Signal_Box)
self.Channel_Box.currentIndexChanged.connect(self.set_Channel_Box)
self.DC_cut_Box.currentIndexChanged.connect(self.set_DC_cut_Box)
self.High_Tf_spinBox.valueChanged.connect(self.set_High_Tf_spinBox)
self.High_Tt2_spinBox.valueChanged.connect(self.set_High_Tt2_spinBox)
self.High_Tt1_spinBox.valueChanged.connect(self.set_High_Tt1_spinBox)
self.Low_V_spinBox.valueChanged.connect(self.set_Low_V_spinBox)
self.Work_Mode_pacemaker.editTextChanged.connect(self.set_Work_Mode_pacemaker)
self.hv_step_number_spinBox.valueChanged.connect(self.set_hv_step_number_spinBox)
self.min_energy_spinBox.valueChanged.connect(self.set_min_energy_spinBox)
self.max_energy_spinBox.valueChanged.connect(self.set_max_energy_spinBox)
self.hv_blind_time_spinBox.valueChanged.connect(self.set_hv_blind_time_spinBox)
self.standby_timer_spinBox.valueChanged.connect(self.set_standby_timer_spinBox)
self.redet_num_spinBox.valueChanged.connect(self.set_redet_num_spinBox)
self.redet_bad_spinBox.valueChanged.connect(self.set_redet_bad_spinBox)
self.Spi_spot_set_spinBox.valueChanged.connect(self.set_Spi_spot_set_spinBox)
set_up_controls()
# создание соединения с устройством для передачи данных
self.serial = QSerialPort()
self.serial.setBaudRate(115200)
self.serial.readyRead.connect(self.on_read)
self.send_mode = 0
# Создание таймера для отрисовки графиков
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.timerEvent)
self.timer.start(20)
# Создание таймера для отображения параметров стимулятора
self.timer_LS = QtCore.QTimer()
self.timer_LS.timeout.connect(self.timerEvent_param)
self.timer_LS.start(2000)
def write_file(self):
"""
Открытие на запись файла
"""
self.file, file_name = my_data.write_file()
self.Write_file.setStyleSheet('background-color: green; color: white')
self.Fname_w_label.setText(os.path.abspath(file_name))
def close_file(self):
"""
Закончить запись и закрыть файл
"""
self.Fname_w_label.setText('')
self.Write_file.setStyleSheet('background-color: grey; color: black')
self.file = my_data.close_file(self.file)
def restart(self):
"""
Перезагрузка устройства
"""
param = 1
my_data.state_packet(self.send_mode, self.serial, 0x1D, param, 1, int)
def timerEvent_param(self):
"""Запуск по таймеру, для синхронизации параметров стимулятора"""
if MODE_COM_PORT:
self.synchronise_param(data_IN_COM)
if MODE_FILE:
self.synchronise_param(data_IN_FILE)
# отрисовка
app.processEvents()
def synchronise_param(self, data_in):
"""Синхронизация параметров стимулятора"""
self.SD_card_Box.setCurrentIndex(int(data_in.sd_card))
self.Signal_Box.setCurrentIndex(int(data_in.signal))
self.Channel_Box.setCurrentIndex(int(data_in.channel))
self.DC_cut_Box.setCurrentIndex(int(data_in.dc_cut))
self.RA_max_time_ms_BOX.setEditText(str(data_in.max_search_time))
self.RA_min_sensitivity_BOX.setEditText(str(data_in.min_treshold))
self.RA_max_sensitivity_BOX.setEditText(str(data_in.max_treshold))
self.RA_square_time_ms_BOX.setEditText(str(data_in.square_time))
self.RA_square_coeff_BOX.setEditText(f'{data_in.square_coef: .2f}')
self.RA_all_time_ms_BOX.setEditText(str(data_in.max_time))
self.High_Tf_spinBox.setValue(data_in.fibr_tres)
self.High_Tt2_spinBox.setValue(data_in.tachy_2_tres)
self.High_Tt1_spinBox.setValue(data_in.tachy_1_tres)
self.Low_V_spinBox.setValue(data_in.fibr_max_tres)
self.hv_step_number_spinBox.setValue(data_in.hv_step_number)
self.min_energy_spinBox.setValue(data_in.min_energy)
self.max_energy_spinBox.setValue(data_in.max_energy)
self.hv_blind_time_spinBox.setValue(data_in.hv_blind_time)
self.standby_timer_spinBox.setValue(data_in.standby_timer)
self.redet_num_spinBox.setValue(data_in.redet_num)
self.redet_bad_spinBox.setValue(data_in.redet_bad)
self.Work_Mode_pacemaker.setCurrentIndex(data_in.Work_Mode_pacemaker)
self.Spi_spot_set_spinBox.setValue(data_in.spi_pot_set)
def timerEvent(self):
if MODE_COM_PORT:
self.draw_data(data_IN_COM)
if MODE_FILE:
scale = self.get_scale()
data_IN_FILE.data_length = scale * my_data.DATA_RATE
data_IN_FILE.parse_list(data_IN_FILE.chunk[data_IN_FILE.i:data_IN_FILE.i + 640])
data_IN_FILE.i += 640
self.graph_1.setXRange(self.counter_com_port[0], self.counter_com_port[0] + scale)
self.graph_2.setXRange(self.counter_com_port[0], self.counter_com_port[0] + scale)
self.graph_3.setXRange(self.counter_com_port[0], self.counter_com_port[0] + scale)
self.draw_data(data_IN_FILE)
# отрисовка
app.processEvents()
def on_start(self):
"""
Старт обменя с com-портом
"""
global MODE_COM_PORT
data_IN_COM.clear_data()
self.serial.setPortName(self.ComL.currentText())
self.serial.open(QIODevice.ReadWrite)
self.serial.flush()
self.serial.write(mes.encode())
self.on_close()
MODE_COM_PORT = True
self.graph_init()
scale = self.get_scale()
data_IN_COM.data_length = scale * my_data.DATA_RATE
data_IN_COM.update_data(data_IN_COM.data_length)
self.counter_com_port = list(map(lambda x: x / my_data.DATA_RATE, range(0, data_IN_COM.data_length)))
def graph_init(self):
"""
Создние графиков
"""
# Создание графиков
self.curve10 = self.graph_1.plot(pen=(0, 0, 255))
self.curve20 = self.graph_2.plot(pen=(0, 0, 0))
pen_din_tres = pg.mkPen(color=(255, 0, 0), width=1)
self.curve21 = self.graph_2.plot(pen=pen_din_tres)
pen_peak = None
self.curve22 = self.graph_2.plot(pen=pen_peak)
self.curve23 = self.graph_2.plot(pen=pen_peak)
pen_min_tres = pg.mkPen(color=(0, 255, 0), width=2, style=QtCore.Qt.DashLine)
pen_max_tres = pg.mkPen(color=(0, 0, 255), width=2, style=QtCore.Qt.DashLine)
self.curve24 = self.graph_2.plot(pen=pen_min_tres)
self.curve25 = self.graph_2.plot(pen=pen_max_tres)
self.curve26 = self.graph_2.plot(pen=(0, 0, 0))
self.curve30 = self.graph_3.plot(pen=(0, 0, 255))
def edit_graph(graph):
"""
Форматирование полей графиков
:param graph: поле графика
"""
graph.showGrid(x=True, y=True)
graph.setBackground('w')
# делаем поле графика нечувствительным к мышке
graph.setMouseEnabled(x=False, y=False)
graph.hideButtons()
graph.getPlotItem().setMenuEnabled(False)
graph.addLegend(enableMouse=False)
edit_graph(self.graph_1)
edit_graph(self.graph_2)
edit_graph(self.graph_3)
def graph_clear(self):
"""
Очистка графиков
"""
self.graph_1.clear()
self.graph_2.clear()
self.graph_3.clear()
def on_read(self):
"""
Чтение серии данных
"""
rx = self.serial.readAll()
if self.file != "":
my_data.write_in_file(self.file, rx)
data_IN_COM.parse_list(rx)
def draw_data(self, data_in):
"""
Отрисовка данных
:param data_in: модель данных
"""
self.curve10.setData(self.counter_com_port, data_in.ECG_RA)
self.curve20.setData(self.counter_com_port, data_in.ECG_RA_pos_sig)
self.curve21.setData(self.counter_com_port, data_in.ECG_RA_din_threshold)
self.curve26.setData(self.counter_com_port, np.zeros(len(data_in.ECG_RA)))
self.curve24.setData(self.counter_com_port, data_in.ECG_RA_min_threshold)
self.curve25.setData(self.counter_com_port, data_in.ECG_RA_max_threshold)
self.curve30.setData(self.counter_com_port, data_in.Last_RR_poz_rel)
self.Vs_cnt_label.setText(str(data_in.Vs_cnt))
self.Vp_cnt_label.setText(str(data_in.Vp_cnt))
self.Vn_cnt_label.setText(str(data_in.Vn_cnt))
self.U_batt_label.setText(str(float(data_in.bat_volt / 1000)))
self.U_batt_p_label.setText(str(data_in.bat_pers))
self.U_cap_label.setText(str(float(data_in.hv_volt / 100)))
self.now_energy_label.setText(str(data_in.now_energy))
self.filt_period_label.setText(str(data_in.filt_period))
self.last_period_label.setText(str(data_in.last_period_stat))
self.hv_step_cnt_label.setText(str(data_in.hv_step_cnt))
self.progressBar_f.setValue(data_in.fibr_cnt)
self.progressBar_t2.setValue(data_in.tachy_2_cnt)
self.progressBar_t1.setValue(data_in.tachy_1_cnt)
self.progressBar_n.setValue(data_in.norm_cnt)
if data_in.terapy_now == 0:
self.terapy_nowB.setStyleSheet('background-color: green; color: white')
self.terapy_nowB.setText("Поиск корзин")
if data_in.terapy_now == 1:
self.terapy_nowB.setStyleSheet('background-color: red; color: white')
self.terapy_nowB.setText("Терапия фибрилляции")
if data_in.terapy_now == 2:
self.terapy_nowB.setStyleSheet('background-color: yellow; color: black')
self.terapy_nowB.setText("Терапия сильной тахикардии")
if data_in.terapy_now == 3:
self.terapy_nowB.setStyleSheet('background-color: yellow; color: black')
self.terapy_nowB.setText("Терапия слабой тахикардии")
if data_in.sub_mode == 0:
self.sub_modeB.setStyleSheet('background-color: green; color: white')
self.sub_modeB.setText("Терапия неактивна")
if data_in.sub_mode == 1:
self.sub_modeB.setStyleSheet('background-color: blue; color: white')
self.sub_modeB.setText("Зарядка конденсатора")
if data_in.sub_mode == 2:
self.sub_modeB.setStyleSheet('background-color: yellow; color: black')
self.sub_modeB.setText("Редетекция")
if data_in.sub_mode == 3:
self.sub_modeB.setStyleSheet('background-color: red; color: white')
self.sub_modeB.setText("Стимуляция")
if data_in.sub_mode == 4:
self.sub_modeB.setStyleSheet('background-color: grey; color: black')
self.sub_modeB.setText("Терапия не сработала")
# так удаляются элементы
# стирание элементов спереди
all_items = self.graph_1.items() # Получаем все элементы
text_items = [item for item in all_items if isinstance(item, TextItem)]
for text_item in text_items:
if data_in.draw_cnt / my_data.DATA_RATE - 0.02 < text_item.pos().x() and data_in.draw_cnt / my_data.DATA_RATE + 0.1 > text_item.pos().x():
self.graph_1.removeItem(text_item)
if data_in.V_print:
data_in.V_print = 0
if data_in.draw_last_QRS == 0:
self.text = pg.TextItem('Vs\nT:' + str(data_in.draw_last_period))
self.text.setColor('green')
self.text.setFont(QFont('Arial', 7))
self.text.setPos(data_in.draw_cnt_last / my_data.DATA_RATE, (0 if data_in.dc_cut else 15))
self.graph_1.addItem(self.text)
if data_in.draw_last_QRS == 1:
self.text = pg.TextItem('Vp\nT:' + str(data_in.draw_last_period))
self.text.setColor('red')
self.text.setPos(data_in.draw_cnt_last / my_data.DATA_RATE, (0 if data_in.dc_cut else 15))
self.graph_1.addItem(self.text)
def on_stop(self):
self.close_file()
global MODE_COM_PORT
MODE_COM_PORT = False
self.graph_clear()
# Создание графиков
self.graph_init()
self.serial.flush()
self.serial.close()
data_IN_COM.clear_data()
self.terapy_nowB.setStyleSheet('background-color: lightGray; color: black')
self.terapy_nowB.setText("")
self.sub_modeB.setStyleSheet('background-color: lightGray; color: black')
self.sub_modeB.setText("")
self.last_period_label.setText("")
self.filt_period_label.setText("")
self.Vs_cnt_label.setText("")
self.Vp_cnt_label.setText("")
self.Vn_cnt_label.setText("")
self.progressBar_f.setValue(0)
self.progressBar_t2.setValue(0)
self.progressBar_t1.setValue(0)
self.progressBar_n.setValue(0)
self.hv_step_cnt_label.setText("")
self.now_energy_label.setText("")
self.HR_label.setText("")
self.OpenB.setEnabled(True)
self.CloseB.setEnabled(True)
def on_open(self):
"""
Открыть файл для чтения
"""
global MODE_FILE
self.on_close()
file, _ = QFileDialog.getOpenFileName(self, 'Open File')
if file:
data_IN_FILE.clear_data()
self.file_name = file
self.Fname_label.setText(self.file_name)
my_data.get_data_bin(self.file_name, data_IN_FILE)
self.counter_com_port = list(map(lambda x: x / my_data.DATA_RATE, range(0, data_IN_FILE.data_length)))
MODE_FILE = True
def draw_file(self):
scale = self.get_scale()
size = scale * my_data.DATA_RATE
for x in range(self.point, data_IN_FILE.data_length, 20):
self.curve10.setData(self.counter_com_port[x: x + size], data_IN_FILE.ECG_RA[x: x + size])
self.curve20.setData(self.counter_com_port[x: x + size], data_IN_FILE.ECG_RA_pos_sig[x: x + size])
self.curve21.setData(self.counter_com_port[x: x + size], data_IN_FILE.ECG_RA_din_threshold[x: x + size])
self.curve26.setData(self.counter_com_port[x: x + size], np.zeros(len(self.counter_com_port[x: x + size])))
self.curve24.setData(self.counter_com_port[x: x + size], data_IN_FILE.ECG_RA_min_threshold[x: x + size])
self.curve25.setData(self.counter_com_port[x: x + size], data_IN_FILE.ECG_RA_max_threshold[x: x + size])
self.curve30.setData(self.counter_com_port[x: x + size], data_IN_FILE.Last_RR_poz_rel[x: x + size])
app.processEvents()
time.sleep(0.05)
def re_scale(self):
scale = self.get_scale()
if len(data_IN_FILE.counter) != 0:
position = self.horizontalScrollBar.value()
self.point = int((len(data_IN_FILE.counter) / my_data.DATA_RATE) * (position / 1000))
def on_scroll(self):
self.re_scale()
def on_close(self):
"""
Закрыть открытый для чтения файл
"""
global MODE_FILE
MODE_FILE = False
# очистка графиков
self.graph_clear()
# Пересоздание графиков
self.graph_init()
# очистка модели
data_IN_FILE.clear_data()
self.Fname_label.setText('')
def get_scale(self):
scale = int(self.RA_scale_BOX.currentText())
return scale
def on_scale_change(self):
scale = self.get_scale()
data_IN_COM.data_length = scale * my_data.DATA_RATE
data_IN_COM.update_data(data_IN_COM.data_length)
if MODE_FILE:
self.draw_file()
all_items = self.graph_1.items() # Получаем все элементы
text_items = [item for item in all_items if isinstance(item, TextItem)]
for text_item in text_items:
self.graph_1.removeItem(text_item)
self.counter_com_port = list(map(lambda x: x / my_data.DATA_RATE, range(0, data_IN_COM.data_length)))
def update_list(self):
"""Создание списка доступных для ввода/вывода портов"""
portlist = [] # создадим пустой список в который и будем всё записывать
ports = QSerialPortInfo().availablePorts() # доступные порты для обмена данными
for port in ports:
portlist.append(port.portName())
return portlist
def check_work_mode_viewer(self):
"""
Выбор режима работы (чтение данных из файла/из com-порта), в случае чего некоторые элементы отображения
становятся видимыми и доступными, а другие наоборот становятся недоступными.
"""
if self.radioButton_work_mode_com_port.isChecked():
self.OpenB.setVisible(False)
self.CloseB.setVisible(False)
self.Play.setVisible(False)
self.Pause.setVisible(False)
self.Fname_label_com_port.setVisible(True)
self.Fname_w_label.setVisible(True)
self.ComL.setVisible(True)
self.Read.setVisible(True)
self.Stop.setVisible(True)
self.Write_file.setVisible(True)
self.Close_file.setVisible(True)
self.Restart.setVisible(True)
self.horizontalScrollBar.setVisible(False)
else:
self.on_stop()
self.OpenB.setVisible(True)
self.CloseB.setVisible(True)
self.Play.setVisible(True)
self.Pause.setVisible(True)
self.Fname_label_com_port.setVisible(False)
self.Fname_w_label.setVisible(False)
self.ComL.setVisible(False)
self.Read.setVisible(False)
self.Stop.setVisible(False)
self.Write_file.setVisible(False)
self.Close_file.setVisible(False)
self.Restart.setVisible(False)
self.horizontalScrollBar.setVisible(True)
def set_send_mode(self):
"""Установка режима передачи данных (Bluetooth/433)"""
self.send_mode = int(self.Send_mode_Box.currentIndex())
# настройка параметров работы стимулятора с помощью программы
def set_DC_cut_Box(self):
"""Настройка вывода сигнала с/без постоянной составляющей"""
param = int(self.DC_cut_Box.currentIndex())
my_data.state_packet(self.send_mode, self.serial, 0x21, param, 1, int)
def set_Signal_Box(self):
"""Настройка вывода сигнала с/без фильтром(а)"""
param = int(self.Signal_Box.currentIndex())
my_data.state_packet(self.send_mode, self.serial, 0x1E, param, 1, int)
def set_Channel_Box(self):
"""Установка активного канала передачи"""
param = int(self.Channel_Box.currentIndex())
my_data.state_packet(self.send_mode, self.serial, 0x1F, param, 1, int)
def set_SD_card(self):
"""Установка режима записи на карту памяти"""
param = int(self.SD_card_Box.currentIndex())
my_data.state_packet(self.send_mode, self.serial, 0x20, param, 1, int)
def set_Spi_spot_set_spinBox(self):
"""Установка коэффициента усиления сигнала"""
param = int(self.Spi_spot_set_spinBox.value())
my_data.state_packet(self.send_mode, self.serial, 0x1C, param, 1, int)
def set_Work_Mode_pacemaker(self):
"""Установка текущего режима работы стимулятора(без/с стимуляцией или в режиме принудительной стимуляции)"""
param = int(self.Work_Mode_pacemaker.currentIndex()) # << 20
my_data.state_packet(self.send_mode, self.serial, 0x05, param, 2, int)
def set_RA_max_time_ms_BOX(self):
"""Установка длительности поиска максимума"""
param = int(self.RA_max_time_ms_BOX.currentText())
my_data.state_packet(self.send_mode, self.serial, 0x0D, param, 2, int)
def set_RA_min_sensitivity_BOX(self):
"""Установка минимальной чувствительности"""
param = float(self.RA_min_sensitivity_BOX.currentText())
my_data.state_packet(self.send_mode, self.serial, 0x01, param, 4, float)
def set_RA_max_sensitivity_BOX(self):
"""Установка максимальной чувствительности"""
param = float(self.RA_max_sensitivity_BOX.currentText())
my_data.state_packet(self.send_mode, self.serial, 0x02, param, 4, float)
def set_RA_square_time_ms_BOX(self):
"""Установка длительности защиты от Т волны"""
param = int(self.RA_square_time_ms_BOX.currentText())
my_data.state_packet(self.send_mode, self.serial, 0x07, param, 2, int)
def set_RA_square_coeff_BOX(self):
"""Установка порога чувствительности Т волны"""
param = float(self.RA_square_coeff_BOX.currentText())
my_data.state_packet(self.send_mode, self.serial, 0x03, param, 4, float)
def set_RA_all_time_ms_BOX(self):
"""Установка максимального размера RR-интервала"""
param = int(self.RA_all_time_ms_BOX.currentText())
my_data.state_packet(self.send_mode, self.serial, 0x09, param, 2, int)
def set_High_Tf_spinBox(self):
"""Установка длительности RR-интервала для определения события как фибрилляции"""
param = self.High_Tf_spinBox.value()
my_data.state_packet(self.send_mode, self.serial, 0x10, param, 2, int)
def set_High_Tt2_spinBox(self):
"""Установка длительности RR-интервала для определения события как тахикардии 2ст"""
param = self.High_Tt2_spinBox.value()
my_data.state_packet(self.send_mode, self.serial, 0x11, param, 2, int)
def set_High_Tt1_spinBox(self):
"""Установка длительности RR-интервала для определения события как тахикардии 1ст"""
param = self.High_Tt1_spinBox.value()
my_data.state_packet(self.send_mode, self.serial, 0x12, param, 2, int)
def set_Low_V_spinBox(self):
"""Установка порога корзины фибрилляции"""
param = self.Low_V_spinBox.value()
my_data.state_packet(self.send_mode, self.serial, 0x13, param, 1, int)
def set_hv_step_number_spinBox(self):
"""Установка количества ступеней BB - терапии"""
param = self.hv_step_number_spinBox.value()
my_data.state_packet(self.send_mode, self.serial, 0x14, param, 1, int)
def set_min_energy_spinBox(self):
"""Установка минимальной энергии стимулятора"""
param = self.min_energy_spinBox.value()
my_data.state_packet(self.send_mode, self.serial, 0x15, param, 2, int)
def set_max_energy_spinBox(self):
"""Установка максимальной энергии стимулятора"""
param = self.max_energy_spinBox.value()
my_data.state_packet(self.send_mode, self.serial, 0x16, param, 2, int)
def set_hv_blind_time_spinBox(self):
"""Установка времени слепоты после разряда"""
param = self.hv_blind_time_spinBox.value()
my_data.state_packet(self.send_mode, self.serial, 0x18, param, 2, int)
def set_standby_timer_spinBox(self):
"""Установка таймаута отключения"""
param = self.standby_timer_spinBox.value()
my_data.state_packet(self.send_mode, self.serial, 0x1B, param, 4, int)
def set_redet_num_spinBox(self):
"""Установка размера буффера редетекции"""
param = self.redet_num_spinBox.value()
my_data.state_packet(self.send_mode, self.serial, 0x19, param, 1, int)
def set_redet_bad_spinBox(self):
"""Установка порога буффера редетекции"""
param = self.redet_bad_spinBox.value()
my_data.state_packet(self.send_mode, self.serial, 0x1A, param, 1, int)
def set_fibr_cnt_max(self):
"""Визуализация корзины фибрилляции"""
# + отправить стимулятору
self.progressBar_f.setMaximum(self.Low_V_spinBox.value())
def set_tachy_2_cnt_max(self):
"""Визуализация корзины тахикардии 2ст"""
self.progressBar_t2.setMaximum(self.Low_V_spinBox_3.value())
def set_tachy_1_cnt_max(self):
"""Визуализация корзины тахикардии 1ст"""
self.progressBar_t1.setMaximum(self.Low_V_spinBox_4.value())

5
requirements.txt Normal file
View File

@ -0,0 +1,5 @@
# python12
PyQt5~=5.15.11
pyqtgraph~=0.13.7
numpy~=2.2.3