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 EOGMonitor (QMainWindow ):
10
+ def __init__ (self ):
11
+ super ().__init__ ()
12
+
13
+ self .setWindowTitle ("Real-Time EOG Monitor - Eye Blink Detection" )
14
+ self .setGeometry (100 , 100 , 800 , 400 )
15
+
16
+ # Create layout
17
+ layout = QVBoxLayout ()
18
+
19
+ # Create plot widget for EOG
20
+ self .eog_plot = PlotWidget (self )
21
+ self .eog_plot .setBackground ('w' )
22
+ self .eog_plot .showGrid (x = True , y = True )
23
+ self .eog_plot .setTitle ("Filtered EOG Signal (Low Pass: 10 Hz)" )
24
+
25
+ # Add plot to layout
26
+ layout .addWidget (self .eog_plot )
27
+
28
+ # Central widget
29
+ central_widget = QWidget ()
30
+ central_widget .setLayout (layout )
31
+ self .setCentralWidget (central_widget )
32
+
33
+ # Set up LSL stream inlet
34
+ streams = pylsl .resolve_stream ('name' , 'BioAmpDataStream' )
35
+ if not streams :
36
+ print ("No LSL stream found!" )
37
+ sys .exit (0 )
38
+ self .inlet = pylsl .StreamInlet (streams [0 ])
39
+
40
+ # Sampling rate
41
+ self .sampling_rate = int (self .inlet .info ().nominal_srate ())
42
+ print (f"Sampling rate: { self .sampling_rate } Hz" )
43
+
44
+ # Data and buffer
45
+ self .buffer_size = self .sampling_rate * 5 # 5 seconds buffer for recent data
46
+ self .eog_data = np .zeros (self .buffer_size )
47
+ self .time_data = np .linspace (0 , 5 , self .buffer_size )
48
+ self .current_index = 0
49
+
50
+ # Low-pass filter for EOG (10 Hz)
51
+ self .b , self .a = butter (4 , 10.0 / (0.5 * self .sampling_rate ), btype = 'low' )
52
+
53
+ # Set fixed axis ranges
54
+ self .eog_plot .setXRange (0 , 5 , padding = 0 )
55
+ if self .sampling_rate == 250 :
56
+ self .eog_plot .setYRange (- ((2 ** 10 )/ 2 ), ((2 ** 10 )/ 2 ), padding = 0 )
57
+ elif self .sampling_rate == 500 :
58
+ self .eog_plot .setYRange (- ((2 ** 14 )/ 2 ), ((2 ** 14 )/ 2 ), padding = 0 )
59
+
60
+ # Plot curve for EOG data
61
+ self .eog_curve = self .eog_plot .plot (self .time_data , self .eog_data , pen = pg .mkPen ('b' , width = 1 ))
62
+
63
+ # Timer for plot update
64
+ self .timer = pg .QtCore .QTimer ()
65
+ self .timer .timeout .connect (self .update_plot )
66
+ self .timer .start (15 )
67
+
68
+ def update_plot (self ):
69
+ samples , _ = self .inlet .pull_chunk (timeout = 0.0 , max_samples = 30 )
70
+ if samples :
71
+ for sample in samples :
72
+ # Overwrite the oldest data point in the buffer
73
+ self .eog_data [self .current_index ] = sample [0 ]
74
+ self .current_index = (self .current_index + 1 ) % self .buffer_size
75
+
76
+ # Apply only the low-pass filter to the EOG data
77
+ filtered_eog = filtfilt (self .b , self .a , self .eog_data )
78
+
79
+ # Update curve with the low-pass filtered EOG signal
80
+ self .eog_curve .setData (self .time_data , filtered_eog )
81
+
82
+ if __name__ == "__main__" :
83
+ app = QApplication (sys .argv )
84
+ window = EOGMonitor ()
85
+ window .show ()
86
+ sys .exit (app .exec_ ())
0 commit comments