-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhr_monitor.py
More file actions
135 lines (107 loc) · 4.51 KB
/
Copy pathhr_monitor.py
File metadata and controls
135 lines (107 loc) · 4.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# hr_monitor.py
# -*- coding: utf-8 -*-
'''
Monitor de ritmo cardiaco en tiempo real con PyQt6 y PyQtGraph.
Muestra un buffer de 30 segundos, permite pausar/reanudar la visualización
mientras la señal sigue generándose en segundo plano, e incluye hover interactivo.
'''
# Modulos
import sys
import numpy as np
from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel, QPushButton
from PyQt6.QtCore import QTimer
import pyqtgraph as pg
class HeartRateWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Monitor de ritmo cardiaco")
self.resize(1000, 600)
# --- Parámetros de la señal ---
self.fs = 50 # frecuencia de muestreo (Hz)
self.duration = 30 # duración visible (segundos)
self.buffer_size = self.fs * self.duration
# Buffers circulares
self.t = np.linspace(0, self.duration, self.buffer_size)
self.hr = np.zeros(self.buffer_size)
# Señal en segundo plano
self.background_timer = QTimer()
self.background_timer.timeout.connect(self.generate_signal)
self.background_timer.start(int(1000 / self.fs))
# Control de pausa/reanudación
self.paused = False
# --- Tema oscuro ---
pg.setConfigOption('background', 'black')
pg.setConfigOption('foreground', 'white')
# --- Widget principal ---
central = QWidget()
layout = QVBoxLayout(central)
self.setCentralWidget(central)
# --- Botón de pausa/reanudar ---
self.button = QPushButton("Pausar visualización")
self.button.setStyleSheet("font-size: 16px; padding: 6px;")
self.button.clicked.connect(self.toggle_pause)
layout.addWidget(self.button)
# --- Etiqueta para hover ---
self.label = QLabel("Pasa el cursor por el gráfico para ver valores")
self.label.setStyleSheet("font-size: 16px; color: white; padding: 6px;")
layout.addWidget(self.label)
# --- Gráfico ---
self.plot_widget = pg.PlotWidget()
layout.addWidget(self.plot_widget)
self.plot_widget.setLabel('left', 'Ritmo cardiaco', units='bpm')
self.plot_widget.setLabel('bottom', 'Tiempo', units='s')
self.plot_widget.showGrid(x=True, y=True)
# --- Línea inicial ---
self.curve = self.plot_widget.plot(
self.t,
self.hr,
pen=pg.mkPen(color='lime', width=2),
symbol=None
)
# --- Hover ---
self.proxy = pg.SignalProxy(
self.plot_widget.scene().sigMouseMoved,
rateLimit=60,
slot=self.mouse_moved
)
# --- Timer de visualización (se puede pausar) ---
self.display_timer = QTimer()
self.display_timer.timeout.connect(self.update_display)
self.display_timer.start(int(1000 / self.fs))
self.n = 0 # contador de muestras
def generate_signal(self):
'''Genera la señal en segundo plano'''
new_value = 70 + 5*np.sin(2*np.pi*1.2*(self.n/self.fs)) + np.random.normal(0, 1)
self.n += 1
# Actualizar buffer circular
self.hr[:-1] = self.hr[1:]
self.hr[-1] = new_value
def update_display(self):
'''Actualiza la gráfica solo si no está pausada'''
if not self.paused:
self.curve.setData(self.t, self.hr)
def toggle_pause(self):
'''Pausa o reanuda la visualización'''
self.paused = not self.paused
if self.paused:
self.button.setText("Reanudar visualización")
else:
self.button.setText("Pausar visualización")
# Al reanudar, actualizamos
self.curve.setData(self.t, self.hr)
def mouse_moved(self, evt):
pos = evt[0]
if self.plot_widget.sceneBoundingRect().contains(pos):
mouse_point = self.plot_widget.plotItem.vb.mapSceneToView(pos)
x = mouse_point.x()
idx = int((x / self.duration) * self.buffer_size)
idx = max(0, min(idx, self.buffer_size - 1))
t_val = self.t[idx]
hr_val = self.hr[idx]
self.label.setText(f"Tiempo: {t_val:.2f} s | Ritmo: {hr_val:.1f} bpm")
### Main ###
if __name__ == "__main__":
app = QApplication(sys.argv)
window = HeartRateWindow()
window.show()
sys.exit(app.exec())