Skip to content

Commit b743972

Browse files
committed
Updating eog.py with the moving window approach
1 parent a6e5cd7 commit b743972

File tree

1 file changed

+22
-327
lines changed

1 file changed

+22
-327
lines changed

applications/eog.py

Lines changed: 22 additions & 327 deletions
Original file line numberDiff line numberDiff line change
@@ -1,298 +1,3 @@
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
2961
import numpy as np
2972
from scipy.signal import butter, filtfilt
2983
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QMainWindow, QWidget, QHBoxLayout
@@ -368,10 +73,6 @@ def __init__(self):
36873
self.timer.timeout.connect(self.update_plot)
36974
self.timer.start(15)
37075

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-
37576
def update_plot(self):
37677
samples, _ = self.inlet.pull_chunk(timeout=0.0, max_samples=30)
37778
if samples:
@@ -382,47 +83,40 @@ def update_plot(self):
38283

38384
filtered_eog = filtfilt(self.b, self.a, self.eog_data)
38485

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
38888
self.eog_curve = self.eog_plot.plot(self.time_data, filtered_eog, pen=pg.mkPen('b', width=1))
38989

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)
39292

39393
def detect_blinks(self, filtered_eog):
394-
# Calculate dynamic threshold based on the mean and standard deviation of the signal
39594
mean_signal = np.mean(filtered_eog)
39695
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)
40298

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
407105

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)
410109

411110
# Reset blink data to zero
412111
self.blink_data[:] = 0
413112

414-
# Set a short window to 1 around each detected blink peak
113+
# Mark detected peaks in blink_data
415114
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
423117

424118
# 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)
426120

427121
# Update the blink plot with the current blink data
428122
self.blink_curve.setData(self.time_data, self.blink_data)
@@ -433,18 +127,19 @@ def detect_peaks(self, signal, threshold):
433127
prev_peak_time = None # Variable to store the timestamp of the previous peak
434128
min_peak_gap = 0.1 # Minimum time gap between two peaks in seconds
435129

436-
# Loop over the signal (starting from the second point and ending at the second to last)
437130
for i in range(1, len(signal) - 1):
438131
# Check if the current point is greater than the previous and next point (local maximum)
439132
if signal[i] > signal[i - 1] and signal[i] > signal[i + 1] and signal[i] > threshold:
440133
current_peak_time = i / self.sampling_rate # Time in seconds based on the sampling rate
441-
peaks.append(i)
442134

443135
if prev_peak_time is not None:
444136
time_gap = current_peak_time - prev_peak_time
445137
if time_gap < min_peak_gap: # Ignore if the time gap is less than the threshold
446138
continue
447139

140+
peaks.append(i)
141+
prev_peak_time = current_peak_time # Update previous peak time
142+
448143
return peaks
449144

450145
if __name__ == "__main__":

0 commit comments

Comments
 (0)