Skip to content

Commit 13893bb

Browse files
committed
update the heartbeat_ecg code with moving window approach(5 sec).
1 parent ef20ef3 commit 13893bb

File tree

1 file changed

+21
-18
lines changed

1 file changed

+21
-18
lines changed

applications/heartbeat_ecg.py

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@
1212
class ECGMonitor(QMainWindow):
1313
def __init__(self, invert=False): # Add the invert parameter
1414
super().__init__()
15-
self.invert = invert # Store the invert flag
15+
self.invert = invert
1616

17-
# Set up GUI window
18-
self.setWindowTitle("Real-Time ECG Monitor")
17+
self.setWindowTitle("Real-Time ECG Monitor") # Set up GUI window
1918
self.setGeometry(100, 100, 800, 600)
2019

2120
self.plot_widget = PlotWidget(self)
@@ -54,11 +53,9 @@ def __init__(self, invert=False): # Add the invert parameter
5453
self.heart_rate = None
5554
self.current_index = 0 # Index for overwriting data
5655

57-
# Low-pass filter coefficients
58-
self.b, self.a = butter(4, 20.0 / (0.5 * self.sampling_rate), btype='low')
56+
self.b, self.a = butter(4, 20.0 / (0.5 * self.sampling_rate), btype='low') # Low-pass filter coefficients
5957

60-
# Timer for updating the plot
61-
self.timer = pg.QtCore.QTimer()
58+
self.timer = pg.QtCore.QTimer() # Timer for updating the plot
6259
self.timer.timeout.connect(self.update_plot)
6360
self.timer.start(10)
6461

@@ -71,9 +68,11 @@ def __init__(self, invert=False): # Add the invert parameter
7168
# Set fixed x-axis range
7269
self.plot_widget.setXRange(0, 10) # 10 seconds
7370

74-
# Initialize the plot curves
7571
self.ecg_curve = self.plot_widget.plot(self.time_data, self.ecg_data, pen=pg.mkPen('k', width=1))
7672
self.r_peak_curve = self.plot_widget.plot([], [], pen=None, symbol='o', symbolBrush='r', symbolSize=10) # R-peaks in red
73+
74+
self.moving_average_window_size = 5 # Initialize moving average buffer
75+
self.heart_rate_history = [] # Buffer to store heart rates for moving average
7776

7877
def update_plot(self):
7978
samples, _ = self.inlet.pull_chunk(timeout=0.0, max_samples=30)
@@ -83,14 +82,12 @@ def update_plot(self):
8382
self.ecg_data[self.current_index] = sample[0]
8483
self.current_index = (self.current_index + 1) % self.buffer_size # Circular increment
8584

86-
# Filter the signal
87-
filtered_ecg = filtfilt(self.b, self.a, self.ecg_data)
85+
filtered_ecg = filtfilt(self.b, self.a, self.ecg_data) # Filter the signal
8886

8987
# Invert the signal if the invert flag is set
9088
if self.invert:
9189
filtered_ecg = -filtered_ecg
9290

93-
# Update the plot data
9491
self.ecg_curve.setData(self.time_data, filtered_ecg) # Use current buffer for plotting
9592

9693
# Detect R-peaks and update heart rate
@@ -109,24 +106,30 @@ def calculate_heart_rate(self):
109106
if len(rr_intervals) > 0:
110107
avg_rr = np.mean(rr_intervals) # Average RR interval
111108
self.heart_rate = 60.0 / avg_rr # Convert to heart rate (BPM)
112-
self.heart_rate_label.setText(f"Heart Rate: {int(self.heart_rate)} BPM")
109+
self.heart_rate_history.append(self.heart_rate) # Update moving average
110+
if len(self.heart_rate_history) > self.moving_average_window_size:
111+
self.heart_rate_history.pop(0) # Remove the oldest heart rate
112+
113+
# Calculate the moving average heart rate
114+
moving_average_hr = np.mean(self.heart_rate_history)
115+
116+
# Update heart rate label with moving average & convert into int
117+
self.heart_rate_label.setText(f"Heart Rate: {int(moving_average_hr)} BPM")
113118
else:
114-
self.heart_rate_label.setText("Heart Rate: Calculating...") # If fewer than 10 R-peaks are detected, show "Calculating"
119+
self.heart_rate_label.setText("Heart Rate: Calculating...")
115120

116121
def plot_r_peaks(self, filtered_ecg):
117-
# Extract the time of detected R-peaks
118-
r_peak_times = self.time_data[self.r_peaks]
122+
r_peak_times = self.time_data[self.r_peaks] # Extract the time of detected R-peaks
119123
r_peak_values = filtered_ecg[self.r_peaks]
120124
self.r_peak_curve.setData(r_peak_times, r_peak_values) # Plot R-peaks as red dots
121125

122126
if __name__ == "__main__":
123-
# Set up argument parser
124127
parser = argparse.ArgumentParser(description="Real-Time ECG Monitor")
125128
parser.add_argument("--invert", action="store_true", help="Invert the ECG signal plot")
126129

127130
args = parser.parse_args()
128131

129132
app = QApplication(sys.argv)
130-
window = ECGMonitor(invert=args.invert) # Pass the invert flag to ECGMonitor
133+
window = ECGMonitor(invert=args.invert) # Pass the invert flag
131134
window.show()
132-
sys.exit(app.exec_())
135+
sys.exit(app.exec_())

0 commit comments

Comments
 (0)