1
- # import numpy as np
2
- # from scipy.signal import butter, filtfilt
3
- # from PyQt5.QtWidgets import QApplication, QVBoxLayout, QMainWindow, QWidget, QHBoxLayout
4
- # import pyqtgraph as pg
5
- # import pylsl
6
- # import sys
7
-
8
- # class EOGMonitor(QMainWindow):
9
- # def __init__(self):
10
- # super().__init__()
11
-
12
- # self.setWindowTitle("Real-Time EOG Monitor - Eye Blink Detection")
13
- # self.setGeometry(100, 100, 800, 400)
14
-
15
- # # Create layout
16
- # layout = QVBoxLayout()
17
- # central_widget = QWidget()
18
- # central_widget.setLayout(layout)
19
- # self.setCentralWidget(central_widget)
20
-
21
- # # Create plot widget for EOG
22
- # self.eog_plot = pg.PlotWidget(self)
23
- # self.eog_plot.setBackground('w')
24
- # self.eog_plot.showGrid(x=True, y=True)
25
- # self.eog_plot.setTitle("Filtered EOG Signal (Low Pass: 10 Hz)")
26
-
27
- # # Bottom layout for Blink Detection
28
- # self.bottom_layout = QHBoxLayout()
29
-
30
- # # Blink detection plot
31
- # self.blink_plot = pg.PlotWidget(self)
32
- # self.blink_plot.setBackground('w')
33
- # self.blink_plot.showGrid(x=True, y=True)
34
- # self.blink_plot.setYRange(0, 1, padding=0)
35
- # self.blink_plot.setMouseEnabled(x=False, y=False) # Disable zoom
36
- # self.blink_plot.setTitle("Blink Detection")
37
-
38
- # # Add both plots to the layout
39
- # layout.addWidget(self.eog_plot)
40
- # layout.addWidget(self.blink_plot)
41
-
42
- # # Set up LSL stream inlet
43
- # streams = pylsl.resolve_stream('name', 'BioAmpDataStream')
44
- # if not streams:
45
- # print("No LSL stream found!")
46
- # sys.exit(0)
47
- # self.inlet = pylsl.StreamInlet(streams[0])
48
-
49
- # self.sampling_rate = int(self.inlet.info().nominal_srate())
50
- # print(f"Sampling rate: {self.sampling_rate} Hz")
51
-
52
- # self.buffer_size = self.sampling_rate * 5 # 5 seconds buffer for recent data
53
- # self.eog_data = np.zeros(self.buffer_size)
54
- # self.time_data = np.linspace(0, 5, self.buffer_size)
55
- # self.blink_data = np.zeros(self.buffer_size) # Blink data array
56
- # self.current_index = 0
57
-
58
- # # Low-pass filter for EOG (10 Hz)
59
- # self.b, self.a = butter(4, 10.0 / (0.5 * self.sampling_rate), btype='low')
60
-
61
- # self.eog_plot.setXRange(0, 5, padding=0)
62
- # if self.sampling_rate == 250:
63
- # self.eog_plot.setYRange(-((2**10)/2), ((2**10)/2), padding=0)
64
- # elif self.sampling_rate == 500:
65
- # self.eog_plot.setYRange(-((2**14)/2), ((2**14)/2), padding=0)
66
-
67
- # # Plot curves
68
- # self.eog_curve = self.eog_plot.plot(self.time_data, self.eog_data, pen=pg.mkPen('b', width=1))
69
- # self.blink_curve = self.blink_plot.plot(self.time_data, self.blink_data, pen=pg.mkPen('r', width=2))
70
-
71
- # # Timer for plot update
72
- # self.timer = pg.QtCore.QTimer()
73
- # self.timer.timeout.connect(self.update_plot)
74
- # self.timer.start(15)
75
-
76
- # def update_plot(self):
77
- # samples, _ = self.inlet.pull_chunk(timeout=0.0, max_samples=30)
78
- # if samples:
79
- # for sample in samples:
80
- # # Overwrite the oldest data point in the buffer
81
- # self.eog_data[self.current_index] = sample[0]
82
- # self.current_index = (self.current_index + 1) % self.buffer_size
83
-
84
- # filtered_eog = filtfilt(self.b, self.a, self.eog_data)
85
-
86
- # # Update curve with the filtered EOG signal (5-second window)
87
- # self.eog_plot.clear() # Clear the previous peaks from the plot
88
- # self.eog_curve = self.eog_plot.plot(self.time_data, filtered_eog, pen=pg.mkPen('b', width=1))
89
-
90
- # # Peak detection (1-second moving window)
91
- # self.detect_blinks(filtered_eog)
92
-
93
- # def detect_blinks(self, filtered_eog):
94
- # mean_signal = np.mean(filtered_eog)
95
- # stdev_signal = np.std(filtered_eog)
96
-
97
- # threshold = mean_signal + (2 * stdev_signal)
98
-
99
- # # Calculate the start and end indices for the 1-second window
100
- # window_size = 1 * self.sampling_rate # 1 seconds in samples
101
- # start_index = self.current_index - window_size
102
- # if start_index < 0:
103
- # start_index = 0
104
- # end_index = self.current_index
105
-
106
- # # Use a 1-second window for peak detection
107
- # filtered_window = filtered_eog[start_index:end_index]
108
- # peaks = self.detect_peaks(filtered_window, threshold)
109
-
110
- # # Reset blink data to zero
111
- # self.blink_data[:] = 0
112
-
113
- # # Mark detected peaks in blink_data
114
- # for peak in peaks:
115
- # full_peak_index = start_index + peak
116
- # self.blink_data[full_peak_index] = 1
117
-
118
- # # Mark peaks with red dots on the EOG plot
119
- # self.eog_plot.plot(self.time_data[start_index:end_index][peaks], filtered_window[peaks], pen=None, symbol='o', symbolPen='r', symbolSize=6)
120
-
121
- # # Update the blink plot with the current blink data
122
- # self.blink_curve.setData(self.time_data, self.blink_data)
123
-
124
- # def detect_peaks(self, signal, threshold):
125
- # # List to store detected peak indices
126
- # peaks = []
127
- # prev_peak_time = None # Variable to store the timestamp of the previous peak
128
- # min_peak_gap = 0.1 # Minimum time gap between two peaks in seconds
129
-
130
- # for i in range(1, len(signal) - 1):
131
- # # Check if the current point is greater than the previous and next point (local maximum)
132
- # if signal[i] > signal[i - 1] and signal[i] > signal[i + 1] and signal[i] > threshold:
133
- # current_peak_time = i / self.sampling_rate # Time in seconds based on the sampling rate
134
-
135
- # if prev_peak_time is not None:
136
- # time_gap = current_peak_time - prev_peak_time
137
- # if time_gap < min_peak_gap: # Ignore if the time gap is less than the threshold
138
- # continue
139
-
140
- # peaks.append(i)
141
- # prev_peak_time = current_peak_time # Update previous peak time
142
-
143
- # return peaks
144
-
145
- # if __name__ == "__main__":
146
- # app = QApplication(sys.argv)
147
- # window = EOGMonitor()
148
- # window.show()
149
- # sys.exit(app.exec_())
150
-
151
-
152
-
153
-
154
-
155
- # import numpy as np
156
- # from scipy.signal import butter, lfilter
157
- # from PyQt5.QtWidgets import QApplication, QVBoxLayout, QMainWindow, QWidget, QHBoxLayout
158
- # import pyqtgraph as pg
159
- # import pylsl
160
- # import sys
161
- # import time
162
-
163
- # class EOGMonitor(QMainWindow):
164
- # def __init__(self):
165
- # super().__init__()
166
-
167
- # self.setWindowTitle("Real-Time EOG Monitor - Eye Blink Detection")
168
- # self.setGeometry(100, 100, 800, 400)
169
-
170
- # # Create layout
171
- # layout = QVBoxLayout()
172
- # central_widget = QWidget()
173
- # central_widget.setLayout(layout)
174
- # self.setCentralWidget(central_widget)
175
-
176
- # # Create plot widget for EOG
177
- # self.eog_plot = pg.PlotWidget(self)
178
- # self.eog_plot.setBackground('w')
179
- # self.eog_plot.showGrid(x=True, y=True)
180
- # self.eog_plot.setTitle("Filtered EOG Signal (Low Pass: 10 Hz)")
181
-
182
- # # Bottom layout for Blink Detection
183
- # self.bottom_layout = QHBoxLayout()
184
-
185
- # # Blink detection plot
186
- # self.blink_plot = pg.PlotWidget(self)
187
- # self.blink_plot.setBackground('w')
188
- # self.blink_plot.showGrid(x=True, y=True)
189
- # self.blink_plot.setYRange(0, 1, padding=0)
190
- # self.blink_plot.setMouseEnabled(x=False, y=False) # Disable zoom
191
- # self.blink_plot.setTitle("Blink Detection")
192
-
193
- # # Add both plots to the layout
194
- # layout.addWidget(self.eog_plot)
195
- # layout.addWidget(self.blink_plot)
196
-
197
- # # Set up LSL stream inlet
198
- # streams = pylsl.resolve_stream('name', 'BioAmpDataStream')
199
- # if not streams:
200
- # print("No LSL stream found!")
201
- # sys.exit(0)
202
- # self.inlet = pylsl.StreamInlet(streams[0])
203
-
204
- # self.sampling_rate = int(self.inlet.info().nominal_srate())
205
- # print(f"Sampling rate: {self.sampling_rate} Hz")
206
-
207
- # self.buffer_size = self.sampling_rate * 5 # 5 seconds buffer for recent data
208
- # self.eog_data = np.zeros(self.buffer_size)
209
- # self.time_data = np.linspace(0, 5, self.buffer_size)
210
- # self.blink_data = np.zeros(self.buffer_size) # Blink data array
211
- # self.current_index = 0
212
-
213
- # # Low-pass filter for EOG (10 Hz)
214
- # self.b, self.a = butter(4, 10.0 / (0.5 * self.sampling_rate), btype='low')
215
-
216
- # self.eog_plot.setXRange(0, 5, padding=0)
217
- # if self.sampling_rate == 250:
218
- # self.eog_plot.setYRange(-((2**10)/2), ((2**10)/2), padding=0)
219
- # elif self.sampling_rate == 500:
220
- # self.eog_plot.setYRange(-((2**14)/2), ((2**14)/2), padding=0)
221
-
222
- # # Plot curves
223
- # self.eog_curve = self.eog_plot.plot(self.time_data, self.eog_data, pen=pg.mkPen('b', width=1))
224
- # self.blink_curve = self.blink_plot.plot(self.time_data, self.blink_data, pen=pg.mkPen('r', width=2))
225
-
226
- # # List to store detected peaks with timestamps
227
- # self.detected_peaks = []
228
-
229
- # # Timer for plot update
230
- # self.timer = pg.QtCore.QTimer()
231
- # self.timer.timeout.connect(self.update_plot)
232
- # self.timer.start(15)
233
-
234
- # def update_plot(self):
235
- # samples, _ = self.inlet.pull_chunk(timeout=0.0, max_samples=30)
236
- # if samples:
237
- # for sample in samples:
238
- # # Overwrite the oldest data point in the buffer
239
- # self.eog_data[self.current_index] = sample[0]
240
- # self.current_index = (self.current_index + 1) % self.buffer_size
241
-
242
- # filtered_eog = lfilter(self.b, self.a, self.eog_data)
243
-
244
- # # Update curve with the filtered EOG signal (5-second window)
245
- # self.eog_plot.clear() # Clear the previous peaks from the plot
246
- # self.eog_curve = self.eog_plot.plot(self.time_data, filtered_eog, pen=pg.mkPen('b', width=1))
247
-
248
- # # Peak detection (1-second moving window)
249
- # self.detect_blinks(filtered_eog)
250
-
251
- # # Clear out old peaks from self.detected_peaks after 5 seconds
252
- # current_time = time.time()
253
- # self.detected_peaks = [(index, t) for index, t in self.detected_peaks if current_time - t < 5]
254
-
255
- # # Update the blink plot based on stored peaks
256
- # self.blink_data[:] = 0 # Reset blink data
257
- # for index, _ in self.detected_peaks:
258
- # if 0 <= index < self.buffer_size:
259
- # self.blink_data[index] = 1 # Keep blink data high at detected peaks
260
-
261
- # # Mark the stored peaks on the EOG plot
262
- # peak_indices = [index for index, t in self.detected_peaks]
263
- # peak_values = [filtered_eog[i] for i in peak_indices]
264
- # self.eog_plot.plot(self.time_data[peak_indices], peak_values, pen=None, symbol='o', symbolPen='r', symbolSize=6)
265
-
266
- # # Update the blink plot with the current blink data
267
- # self.blink_curve.setData(self.time_data, self.blink_data)
268
-
269
- # def detect_blinks(self, filtered_eog):
270
- # mean_signal = np.mean(filtered_eog)
271
- # stdev_signal = np.std(filtered_eog)
272
- # threshold = mean_signal + (2 * stdev_signal)
273
-
274
- # # Calculate the start and end indices for the 1-second window
275
- # window_size = 1 * self.sampling_rate
276
- # start_index = self.current_index - window_size
277
- # if start_index < 0:
278
- # start_index = 0
279
- # end_index = self.current_index
280
-
281
- # # Use a 1-second window for peak detection
282
- # filtered_window = filtered_eog[start_index:end_index]
283
- # peaks = self.detect_peaks(filtered_window, threshold)
284
-
285
- # # Mark detected peaks and store them with timestamps
286
- # for peak in peaks:
287
- # full_peak_index = start_index + peak
288
- # self.detected_peaks.append((full_peak_index, time.time())) # Add detected peak with current timestamp
289
-
290
- # def detect_peaks(self, signal, threshold):
291
- # peaks = []
292
- # prev_peak_time = None # Variable to store the timestamp of the previous peak
293
- # min_peak_gap = 0.1 # Minimum time gap between two peaks in seconds
294
-
295
- # for i in range(1, len(signal) - 1):
296
- # if signal[i] > signal[i - 1] and signal[i] > signal[i + 1] and signal[i] > threshold:
297
- # current_peak_time = i / self.sampling_rate # Time in seconds based on the sampling rate
298
-
299
- # if prev_peak_time is not None:
300
- # time_gap = current_peak_time - prev_peak_time
301
- # if time_gap < min_peak_gap:
302
- # continue
303
-
304
- # peaks.append(i)
305
- # prev_peak_time = current_peak_time
306
-
307
- # return peaks
308
-
309
- # if __name__ == "__main__":
310
- # app = QApplication(sys.argv)
311
- # window = EOGMonitor()
312
- # window.show()
313
- # sys.exit(app.exec_())
314
-
315
- #Use deque that remove the oldest peak after 5 seconds.
316
1
import numpy as np
317
2
from scipy .signal import butter , lfilter
318
3
from PyQt5 .QtWidgets import QApplication , QVBoxLayout , QMainWindow , QWidget , QHBoxLayout
@@ -349,7 +34,7 @@ def __init__(self):
349
34
self .blink_plot .setBackground ('w' )
350
35
self .blink_plot .showGrid (x = True , y = True )
351
36
self .blink_plot .setYRange (0 , 1 , padding = 0 )
352
- self .blink_plot .setMouseEnabled (x = False , y = False ) # Disable zoom
37
+ self .blink_plot .setMouseEnabled (x = False , y = False ) # To Disable zoom functionality mark it as true
353
38
self .blink_plot .setTitle ("Blink Detection" )
354
39
355
40
# Add both plots to the layout
@@ -410,7 +95,7 @@ def update_plot(self):
410
95
# Peak detection (1-second moving window)
411
96
self .detect_blinks (filtered_eog )
412
97
413
- # Clear out old peaks from the circular buffer after 4 seconds(because we want to clear the peaks just after the data overwrite.)
98
+ # Clear out old peaks from the circular buffer after 4 seconds(As we want to clear the peaks just after the data overwrite.)
414
99
current_time = time .time ()
415
100
while self .detected_peaks and (current_time - self .detected_peaks [0 ][1 ] > 4 ):
416
101
self .detected_peaks .popleft () # Remove old peaks from the buffer
@@ -432,7 +117,7 @@ def update_plot(self):
432
117
def detect_blinks (self , filtered_eog ):
433
118
mean_signal = np .mean (filtered_eog )
434
119
stdev_signal = np .std (filtered_eog )
435
- threshold = mean_signal + (1.5 * stdev_signal )
120
+ threshold = mean_signal + (1.8 * stdev_signal )
436
121
437
122
# Calculate the start and end indices for the 1-second window
438
123
window_size = 1 * self .sampling_rate
@@ -453,7 +138,7 @@ def detect_blinks(self, filtered_eog):
453
138
def detect_peaks (self , signal , threshold ):
454
139
peaks = []
455
140
prev_peak_time = None # Variable to store the timestamp of the previous peak
456
- min_peak_gap = 0.01 # Minimum time gap between two peaks in seconds
141
+ min_peak_gap = 0.1 # Minimum time gap between two peaks in seconds
457
142
458
143
for i in range (1 , len (signal ) - 1 ):
459
144
if signal [i ] > signal [i - 1 ] and signal [i ] > signal [i + 1 ] and signal [i ] > threshold :
0 commit comments