1
1
import numpy as np
2
- from scipy .signal import butter , lfilter
2
+ from scipy .signal import butter , lfilter , lfilter_zi
3
3
from PyQt5 .QtWidgets import QApplication , QVBoxLayout , QMainWindow , QWidget , QHBoxLayout
4
4
import pyqtgraph as pg
5
5
import pylsl
@@ -24,6 +24,8 @@ def __init__(self):
24
24
self .eog_plot = pg .PlotWidget (self )
25
25
self .eog_plot .setBackground ('w' )
26
26
self .eog_plot .showGrid (x = True , y = True )
27
+ # self.eog_plot.setAutoVisible(y=True) # On Autoscale for y-axis only
28
+ self .eog_plot .setMouseEnabled (x = False , y = False ) # To Disable zoom functionality
27
29
self .eog_plot .setTitle ("Filtered EOG Signal (Low Pass: 10 Hz)" )
28
30
29
31
# Bottom layout for Blink Detection
@@ -59,12 +61,13 @@ def __init__(self):
59
61
60
62
# Low-pass filter for EOG (10 Hz)
61
63
self .b , self .a = butter (4 , 10.0 / (0.5 * self .sampling_rate ), btype = 'low' )
64
+ self .zi = lfilter_zi (self .b , self .a ) # Initialize filter state
62
65
63
66
self .eog_plot .setXRange (0 , 5 , padding = 0 )
64
- if self .sampling_rate == 250 :
65
- self .eog_plot .setYRange (- (( 2 ** 10 ) / 2 ), (( 2 ** 10 ) / 2 ), padding = 0 )
66
- elif self .sampling_rate == 500 :
67
- self .eog_plot .setYRange (- (( 2 ** 14 ) / 2 ), (( 2 ** 14 ) / 2 ), padding = 0 )
67
+ if self .sampling_rate == 250 :
68
+ self .eog_plot .setYRange (0 , 2 ** 10 , padding = 0 ) # for R3 & ensuring no extra spaces at end
69
+ elif self .sampling_rate == 500 :
70
+ self .eog_plot .setYRange (0 , 2 ** 14 , padding = 0 ) # for R4 & ensuring no extra spaces at end
68
71
69
72
# Plot curves
70
73
self .eog_curve = self .eog_plot .plot (self .time_data , self .eog_data , pen = pg .mkPen ('b' , width = 1 ))
@@ -78,22 +81,33 @@ def __init__(self):
78
81
self .timer .timeout .connect (self .update_plot )
79
82
self .timer .start (15 )
80
83
84
+ # self.calibration_time = 5
85
+ self .start_time = time .time ()
86
+ # self.is_calibrating = True
87
+
81
88
def update_plot (self ):
89
+ # if self.is_calibrating:
90
+ # # Skip processing during calibration
91
+ # if time.time() - self.start_time >= self.calibration_time:
92
+ # self.is_calibrating = False
93
+ # print("Calibration complete. Starting peak detection.")
94
+ # return
82
95
samples , _ = self .inlet .pull_chunk (timeout = 0.0 , max_samples = 30 )
83
96
if samples :
84
97
for sample in samples :
85
98
# Overwrite the oldest data point in the buffer
86
99
self .eog_data [self .current_index ] = sample [0 ]
87
100
self .current_index = (self .current_index + 1 ) % self .buffer_size
88
101
89
- filtered_eog = lfilter (self .b , self .a , self .eog_data )
102
+ # Filter only the new data (not the entire buffer)
103
+ filtered_eog , self .zi = lfilter (self .b , self .a , self .eog_data , zi = self .zi )
90
104
91
105
# Update curve with the filtered EOG signal (5-second window)
92
106
self .eog_plot .clear () # Clear the previous peaks from the plot
93
107
self .eog_curve = self .eog_plot .plot (self .time_data , filtered_eog , pen = pg .mkPen ('b' , width = 1 ))
94
108
95
- # Peak detection (1-second moving window)
96
- self .detect_blinks (filtered_eog )
109
+ if time . time () - self . start_time >= 2 :
110
+ self .detect_blinks (filtered_eog )
97
111
98
112
# Clear out old peaks from the circular buffer after 4 seconds(As we want to clear the peaks just after the data overwrite.)
99
113
current_time = time .time ()
@@ -117,7 +131,7 @@ def update_plot(self):
117
131
def detect_blinks (self , filtered_eog ):
118
132
mean_signal = np .mean (filtered_eog )
119
133
stdev_signal = np .std (filtered_eog )
120
- threshold = mean_signal + (1.8 * stdev_signal )
134
+ threshold = mean_signal + (2 * stdev_signal )
121
135
122
136
# Calculate the start and end indices for the 1-second window
123
137
window_size = 1 * self .sampling_rate
@@ -138,7 +152,7 @@ def detect_blinks(self, filtered_eog):
138
152
def detect_peaks (self , signal , threshold ):
139
153
peaks = []
140
154
prev_peak_time = None # Variable to store the timestamp of the previous peak
141
- min_peak_gap = 0.1 # Minimum time gap between two peaks in seconds
155
+ min_peak_gap = 0.1 # Minimum time gap between two peaks in seconds
142
156
143
157
for i in range (1 , len (signal ) - 1 ):
144
158
if signal [i ] > signal [i - 1 ] and signal [i ] > signal [i + 1 ] and signal [i ] > threshold :
@@ -157,5 +171,14 @@ def detect_peaks(self, signal, threshold):
157
171
if __name__ == "__main__" :
158
172
app = QApplication (sys .argv )
159
173
window = EOGMonitor ()
174
+
175
+ # start_time = time.time()
176
+ # calibration_time = 5
177
+
178
+ # while time.time() - start_time < calibration_time:
179
+ # print("Calibrating...")
180
+ # time.sleep(1)
181
+
182
+ print ("Note: There will be a 2s calibration delay before peak detection starts." )
160
183
window .show ()
161
184
sys .exit (app .exec_ ())
0 commit comments