Skip to content

Commit 06fd1ad

Browse files
committed
emgenvelope working
1 parent 77fd937 commit 06fd1ad

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

applications/emgenvelope.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import numpy as np
2+
from scipy.signal import butter, filtfilt
3+
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QMainWindow, QWidget
4+
from pyqtgraph import PlotWidget
5+
import pyqtgraph as pg
6+
import pylsl
7+
import sys
8+
9+
class EMGMonitor(QMainWindow):
10+
def __init__(self):
11+
super().__init__()
12+
13+
self.setWindowTitle("Real-Time EMG Monitor with EMG Envelope")
14+
self.setGeometry(100, 100, 800, 600)
15+
16+
self.plot_widget = PlotWidget(self)
17+
self.plot_widget.setBackground('w')
18+
self.plot_widget.showGrid(x=True, y=True)
19+
20+
layout = QVBoxLayout()
21+
layout.addWidget(self.plot_widget)
22+
23+
central_widget = QWidget()
24+
central_widget.setLayout(layout)
25+
self.setCentralWidget(central_widget)
26+
27+
# Set up LSL stream inlet
28+
streams = pylsl.resolve_stream('name', 'BioAmpDataStream')
29+
if not streams:
30+
print("No LSL stream found!")
31+
sys.exit(0)
32+
self.inlet = pylsl.StreamInlet(streams[0])
33+
34+
# Sampling rate
35+
self.sampling_rate = int(self.inlet.info().nominal_srate())
36+
print(f"Sampling rate: {self.sampling_rate} Hz")
37+
38+
# Data and buffers
39+
self.buffer_size = self.sampling_rate * 10 # Fixed-size buffer for 10 seconds
40+
self.emg_data = np.zeros(self.buffer_size) # Fixed-size array for circular buffer
41+
self.time_data = np.linspace(0, 10, self.buffer_size) # Fixed time array for plotting
42+
self.current_index = 0 # Index for overwriting data
43+
44+
self.b, self.a = butter(4, 70.0 / (0.5 * self.sampling_rate), btype='high')
45+
46+
# Moving RMS window size (50 for 250 sampling rate and 100 for 500 sampling rate)
47+
self.rms_window_size = int(0.1 * self.sampling_rate)
48+
49+
# Set fixed axis ranges
50+
self.plot_widget.setXRange(0, 10, padding=0)
51+
52+
# Set y-axis limits based on sampling rate
53+
if self.sampling_rate == 250:
54+
self.plot_widget.setYRange(400,600 ,padding=0) # for R3 & ensuring no extra spaces at end
55+
elif self.sampling_rate == 500:
56+
self.plot_widget.setYRange(400, 10000,padding=0) # for R4 & ensuring no extra spaces at end
57+
58+
# Plot curves for EMG data and envelope
59+
self.emg_curve = self.plot_widget.plot(self.time_data, self.emg_data, pen=pg.mkPen('b', width=1))
60+
self.envelope_curve = self.plot_widget.plot(self.time_data, self.emg_data, pen=pg.mkPen('r', width=2))
61+
62+
# Timer for plot update
63+
self.timer = pg.QtCore.QTimer()
64+
self.timer.timeout.connect(self.update_plot)
65+
self.timer.start(15)
66+
67+
def calculate_moving_rms(self, signal, window_size):
68+
# Calculate RMS using a moving window
69+
rms = np.sqrt(np.convolve(signal**2, np.ones(window_size) / window_size, mode='valid'))
70+
return np.pad(rms, (len(signal) - len(rms), 0), 'constant')
71+
72+
def update_plot(self):
73+
samples, _ = self.inlet.pull_chunk(timeout=0.0, max_samples=30)
74+
if samples:
75+
for sample in samples:
76+
# Overwrite the oldest data point in the buffer
77+
self.emg_data[self.current_index] = sample[0]
78+
self.current_index = (self.current_index + 1) % self.buffer_size # Circular increment
79+
80+
# Filter the EMG data
81+
filtered_emg = filtfilt(self.b, self.a, self.emg_data)
82+
# print(filtered_emg)
83+
84+
# Take absolute value before calculating RMS envelope
85+
abs_filtered_emg = np.abs(filtered_emg)
86+
# print(abs_filtered_emg)
87+
88+
# Calculate the RMS envelope
89+
rms_envelope = self.calculate_moving_rms(abs_filtered_emg, self.rms_window_size)
90+
91+
# Update curves
92+
self.emg_curve.setData(self.time_data, filtered_emg) # Plot filtered EMG in blue
93+
self.envelope_curve.setData(self.time_data, rms_envelope) # Plot EMG envelope in red
94+
95+
if __name__ == "__main__":
96+
app = QApplication(sys.argv)
97+
window = EMGMonitor()
98+
window.show()
99+
sys.exit(app.exec_())

0 commit comments

Comments
 (0)