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
- # # self.eog_plot.clear() # Clear the previous peaks from the plot
87
-
88
- # # # Update curve with the filtered EOG signal
89
- # # self.eog_curve = self.eog_plot.plot(self.time_data, filtered_eog, pen=pg.mkPen('b', width=1))
90
-
91
- # # self.detect_blinks(filtered_eog) # Blink detection
92
-
93
- # # def detect_blinks(self, filtered_eog):
94
- # # # Set the blink threshold as 60% of the max
95
- # # threshold = np.max(np.abs(filtered_eog)) * 0.8
96
- # # peaks = self.detect_peaks(filtered_eog, threshold)
97
-
98
- # # # Reset blink data to zero
99
- # # self.blink_data[:] = 0
100
-
101
- # # # Set a short window to 1 around each detected blink peak
102
- # # for peak in peaks:
103
- # # # Ensure the peak window doesn’t exceed the array bounds
104
- # # start = max(0, peak - 5) # Start a few samples before the peak
105
- # # end = min(self.buffer_size, peak + 5) # End a few samples after the peak
106
- # # self.blink_data[start:end] = 1
107
-
108
- # # # Mark peaks with red dots on the EOG plot
109
- # # self.eog_plot.plot(self.time_data[peaks], filtered_eog[peaks], pen=None, symbol='o', symbolPen='r', symbolSize=6)
110
-
111
- # # # Update the blink plot with the current blink data
112
- # # self.blink_curve.setData(self.time_data, self.blink_data)
113
-
114
- # # def detect_peaks(self, signal, threshold):
115
- # # # List to store detected peak indices
116
- # # peaks = []
117
- # # prev_peak_time = None # Variable to store the timestamp of the previous peak
118
- # # min_peak_gap = 0.1 # Minimum time gap between two peaks in seconds
119
-
120
- # # # Loop over the signal (starting from the second point and ending at the second to last)
121
- # # for i in range(1, len(signal) - 1):
122
- # # # Check if the current point is greater than the previous and next point (local maximum)
123
- # # if signal[i] > signal[i - 1] and signal[i] > signal[i + 1] and signal[i] > threshold:
124
- # # current_peak_time = i / self.sampling_rate # Time in seconds based on the sampling rate
125
-
126
- # # if prev_peak_time is not None:
127
- # # time_gap = current_peak_time - prev_peak_time
128
- # # if time_gap < min_peak_gap: # Ignore if the time gap is less than the threshold
129
- # # continue
130
-
131
- # # peaks.append(i)
132
- # # prev_peak_time = current_peak_time # Update previous peak time
133
-
134
- # # return peaks
135
-
136
- # # if __name__ == "__main__":
137
- # # app = QApplication(sys.argv)
138
- # # window = EOGMonitor()
139
- # # window.show()
140
- # # sys.exit(app.exec_())
141
-
142
-
143
-
144
-
145
- # #Blink is ok but moving window remains.
146
- # import numpy as np
147
- # from scipy.signal import butter, filtfilt
148
- # from PyQt5.QtWidgets import QApplication, QVBoxLayout, QMainWindow, QWidget, QHBoxLayout
149
- # import pyqtgraph as pg
150
- # import pylsl
151
- # import sys
152
-
153
- # class EOGMonitor(QMainWindow):
154
- # def __init__(self):
155
- # super().__init__()
156
-
157
- # self.setWindowTitle("Real-Time EOG Monitor - Eye Blink Detection")
158
- # self.setGeometry(100, 100, 800, 400)
159
-
160
- # # Create layout
161
- # layout = QVBoxLayout()
162
- # central_widget = QWidget()
163
- # central_widget.setLayout(layout)
164
- # self.setCentralWidget(central_widget)
165
-
166
- # # Create plot widget for EOG
167
- # self.eog_plot = pg.PlotWidget(self)
168
- # self.eog_plot.setBackground('w')
169
- # self.eog_plot.showGrid(x=True, y=True)
170
- # self.eog_plot.setTitle("Filtered EOG Signal (Low Pass: 10 Hz)")
171
-
172
- # # Bottom layout for Blink Detection
173
- # self.bottom_layout = QHBoxLayout()
174
-
175
- # # Blink detection plot
176
- # self.blink_plot = pg.PlotWidget(self)
177
- # self.blink_plot.setBackground('w')
178
- # self.blink_plot.showGrid(x=True, y=True)
179
- # self.blink_plot.setYRange(0, 1, padding=0)
180
- # self.blink_plot.setMouseEnabled(x=False, y=False) # Disable zoom
181
- # self.blink_plot.setTitle("Blink Detection")
182
-
183
- # # Add both plots to the layout
184
- # layout.addWidget(self.eog_plot)
185
- # layout.addWidget(self.blink_plot)
186
-
187
- # # Set up LSL stream inlet
188
- # streams = pylsl.resolve_stream('name', 'BioAmpDataStream')
189
- # if not streams:
190
- # print("No LSL stream found!")
191
- # sys.exit(0)
192
- # self.inlet = pylsl.StreamInlet(streams[0])
193
-
194
- # self.sampling_rate = int(self.inlet.info().nominal_srate())
195
- # print(f"Sampling rate: {self.sampling_rate} Hz")
196
-
197
- # self.buffer_size = self.sampling_rate * 5 # 5 seconds buffer for recent data
198
- # self.eog_data = np.zeros(self.buffer_size)
199
- # self.time_data = np.linspace(0, 5, self.buffer_size)
200
- # self.blink_data = np.zeros(self.buffer_size) # Blink data array
201
- # self.current_index = 0
202
-
203
- # # Low-pass filter for EOG (10 Hz)
204
- # self.b, self.a = butter(4, 10.0 / (0.5 * self.sampling_rate), btype='low')
205
-
206
- # self.eog_plot.setXRange(0, 5, padding=0)
207
- # if self.sampling_rate == 250:
208
- # self.eog_plot.setYRange(-((2**10)/2), ((2**10)/2), padding=0)
209
- # elif self.sampling_rate == 500:
210
- # self.eog_plot.setYRange(-((2**14)/2), ((2**14)/2), padding=0)
211
-
212
- # # Plot curves
213
- # self.eog_curve = self.eog_plot.plot(self.time_data, self.eog_data, pen=pg.mkPen('b', width=1))
214
- # self.blink_curve = self.blink_plot.plot(self.time_data, self.blink_data, pen=pg.mkPen('r', width=2))
215
-
216
- # # Timer for plot update
217
- # self.timer = pg.QtCore.QTimer()
218
- # self.timer.timeout.connect(self.update_plot)
219
- # self.timer.start(15)
220
-
221
- # def update_plot(self):
222
- # samples, _ = self.inlet.pull_chunk(timeout=0.0, max_samples=30)
223
- # if samples:
224
- # for sample in samples:
225
- # # Overwrite the oldest data point in the buffer
226
- # self.eog_data[self.current_index] = sample[0]
227
- # self.current_index = (self.current_index + 1) % self.buffer_size
228
-
229
- # filtered_eog = filtfilt(self.b, self.a, self.eog_data)
230
-
231
- # self.eog_plot.clear() # Clear the previous peaks from the plot
232
-
233
- # # Update curve with the filtered EOG signal
234
- # self.eog_curve = self.eog_plot.plot(self.time_data, filtered_eog, pen=pg.mkPen('b', width=1))
235
-
236
- # self.detect_blinks(filtered_eog) # Blink detection
237
-
238
- # def detect_blinks(self, filtered_eog):
239
- # # Calculate dynamic threshold based on the mean and standard deviation of the signal
240
- # mean_signal = np.mean(filtered_eog)
241
- # stdev_signal = np.std(filtered_eog)
242
-
243
- # # Set the threshold
244
- # threshold = mean_signal + (2 * stdev_signal)
245
-
246
- # peaks = self.detect_peaks(filtered_eog, threshold)
247
-
248
- # # Reset blink data to zero
249
- # self.blink_data[:] = 0
250
-
251
- # # Set a short window to 1 around each detected blink peak
252
- # for peak in peaks:
253
- # # Ensure the peak window doesn’t exceed the array bounds
254
- # start = max(0, peak - 5) # Start a few samples before the peak
255
- # end = min(self.buffer_size, peak + 5) # End a few samples after the peak
256
- # self.blink_data[start:end] = 1
257
-
258
- # # Mark peaks with red dots on the EOG plot
259
- # self.eog_plot.plot(self.time_data[peaks], filtered_eog[peaks], pen=None, symbol='o', symbolPen='r', symbolSize=6)
260
-
261
- # # Update the blink plot with the current blink data
262
- # self.blink_curve.setData(self.time_data, self.blink_data)
263
-
264
- # def detect_peaks(self, signal, threshold):
265
- # # List to store detected peak indices
266
- # peaks = []
267
- # prev_peak_time = None # Variable to store the timestamp of the previous peak
268
- # min_peak_gap = 0.1 # Minimum time gap between two peaks in seconds
269
-
270
- # # Loop over the signal (starting from the second point and ending at the second to last)
271
- # for i in range(1, len(signal) - 1):
272
- # # Check if the current point is greater than the previous and next point (local maximum)
273
- # if signal[i] > signal[i - 1] and signal[i] > signal[i + 1] and signal[i] > threshold:
274
- # current_peak_time = i / self.sampling_rate # Time in seconds based on the sampling rate
275
-
276
- # if prev_peak_time is not None:
277
- # time_gap = current_peak_time - prev_peak_time
278
- # if time_gap < min_peak_gap: # Ignore if the time gap is less than the threshold
279
- # continue
280
-
281
- # peaks.append(i)
282
- # prev_peak_time = current_peak_time # Update previous peak time
283
-
284
- # return peaks
285
-
286
- # if __name__ == "__main__":
287
- # app = QApplication(sys.argv)
288
- # window = EOGMonitor()
289
- # window.show()
290
- # sys.exit(app.exec_())
291
-
292
-
293
-
294
-
295
- #Working Now but now the issue is with the blink detection plot
296
1
import numpy as np
297
2
from scipy .signal import butter , filtfilt
298
3
from PyQt5 .QtWidgets import QApplication , QVBoxLayout , QMainWindow , QWidget , QHBoxLayout
@@ -368,10 +73,6 @@ def __init__(self):
368
73
self .timer .timeout .connect (self .update_plot )
369
74
self .timer .start (15 )
370
75
371
- # Define window size and shift size (in samples)
372
- self .window_size = self .sampling_rate * 3 # 3 seconds window
373
- self .shift_size = self .sampling_rate * 0.5 # 500 ms shift
374
-
375
76
def update_plot (self ):
376
77
samples , _ = self .inlet .pull_chunk (timeout = 0.0 , max_samples = 30 )
377
78
if samples :
@@ -382,47 +83,40 @@ def update_plot(self):
382
83
383
84
filtered_eog = filtfilt (self .b , self .a , self .eog_data )
384
85
385
- self .eog_plot .clear () # Clear the previous peaks from the plot
386
-
387
- # Update curve with the filtered EOG signal
86
+ # Update curve with the filtered EOG signal (5-second window)
87
+ self .eog_plot .clear () # Clear the previous peaks from the plot
388
88
self .eog_curve = self .eog_plot .plot (self .time_data , filtered_eog , pen = pg .mkPen ('b' , width = 1 ))
389
89
390
- # Detect peaks within the current moving window
391
- self .detect_blinks (filtered_eog ) # Blink detection
90
+ # Peak detection (2-second moving window)
91
+ self .detect_blinks (filtered_eog )
392
92
393
93
def detect_blinks (self , filtered_eog ):
394
- # Calculate dynamic threshold based on the mean and standard deviation of the signal
395
94
mean_signal = np .mean (filtered_eog )
396
95
stdev_signal = np .std (filtered_eog )
397
- # print(stdev_signal)
398
-
399
- # Set the threshold
400
- # threshold = mean_signal + (2 * stdev_signal)
401
- threshold = 500
96
+
97
+ threshold = mean_signal + (2 * stdev_signal )
402
98
403
- # Process the signal in windows
404
- start_idx = self .current_index - self .window_size
405
- if start_idx < 0 :
406
- start_idx = 0
99
+ # Calculate the start and end indices for the 2-second window
100
+ window_size = 2 * self .sampling_rate # 2 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
407
105
408
- window_eog = filtered_eog [start_idx :start_idx + self .window_size ]
409
- peaks = self .detect_peaks (window_eog , threshold )
106
+ # Use a 2-second window for peak detection
107
+ filtered_window = filtered_eog [start_index :end_index ]
108
+ peaks = self .detect_peaks (filtered_window , threshold )
410
109
411
110
# Reset blink data to zero
412
111
self .blink_data [:] = 0
413
112
414
- # Set a short window to 1 around each detected blink peak
113
+ # Mark detected peaks in blink_data
415
114
for peak in peaks :
416
- # Ensure the peak window doesn’t exceed the array bounds
417
- start = max (0 , peak - 5 ) # Start a few samples before the peak
418
- end = min (self .buffer_size , peak + 5 ) # End a few samples after the peak
419
- self .blink_data [start :end ] = 1
420
-
421
- # Ensure peak indices are integers for plotting
422
- peak_indices = np .array (peaks , dtype = int )
115
+ full_peak_index = start_index + peak
116
+ self .blink_data [full_peak_index ] = 1
423
117
424
118
# Mark peaks with red dots on the EOG plot
425
- self .eog_plot .plot (self .time_data [start_idx + peak_indices ], window_eog [ peak_indices ], pen = None , symbol = 'o' , symbolPen = 'r' , symbolSize = 6 )
119
+ self .eog_plot .plot (self .time_data [start_index : end_index ][ peaks ], filtered_window [ peaks ], pen = None , symbol = 'o' , symbolPen = 'r' , symbolSize = 6 )
426
120
427
121
# Update the blink plot with the current blink data
428
122
self .blink_curve .setData (self .time_data , self .blink_data )
@@ -433,18 +127,19 @@ def detect_peaks(self, signal, threshold):
433
127
prev_peak_time = None # Variable to store the timestamp of the previous peak
434
128
min_peak_gap = 0.1 # Minimum time gap between two peaks in seconds
435
129
436
- # Loop over the signal (starting from the second point and ending at the second to last)
437
130
for i in range (1 , len (signal ) - 1 ):
438
131
# Check if the current point is greater than the previous and next point (local maximum)
439
132
if signal [i ] > signal [i - 1 ] and signal [i ] > signal [i + 1 ] and signal [i ] > threshold :
440
133
current_peak_time = i / self .sampling_rate # Time in seconds based on the sampling rate
441
- peaks .append (i )
442
134
443
135
if prev_peak_time is not None :
444
136
time_gap = current_peak_time - prev_peak_time
445
137
if time_gap < min_peak_gap : # Ignore if the time gap is less than the threshold
446
138
continue
447
139
140
+ peaks .append (i )
141
+ prev_peak_time = current_peak_time # Update previous peak time
142
+
448
143
return peaks
449
144
450
145
if __name__ == "__main__" :
0 commit comments