1
+ import pygame
2
+ import pylsl
3
+ import numpy as np
4
+ import time
5
+ from pylsl import StreamInlet , resolve_stream
6
+ from scipy .signal import iirnotch , butter , lfilter
7
+ import math
8
+
9
+ pygame .init ()
10
+
11
+ # Screen setup
12
+ screen = pygame .display .set_mode ((800 , 600 ))
13
+ pygame .display .set_caption ('Beetle Game' )
14
+
15
+ # Beetle properties
16
+ beetle_x , beetle_y = 380 , 530
17
+ focus_speed_upward = 8 # Speed when moving upward
18
+ focus_speed_downward = 4 # Speed when moving downward
19
+ focus_timeout = 2 # Time in seconds to stabilize focus
20
+ focus_threshold = 5 # Threshold for beta power
21
+
22
+ # LSL stream setup
23
+ streams = resolve_stream ('name' , 'BioAmpDataStream' )
24
+ if not streams :
25
+ print ("No LSL stream found!" )
26
+ pygame .quit ()
27
+ exit ()
28
+
29
+ inlet = StreamInlet (streams [0 ])
30
+ print ("LSL Stream Started" )
31
+ sampling_rate = int (inlet .info ().nominal_srate ())
32
+ print (f"Sampling rate: { sampling_rate } Hz" )
33
+
34
+ b_notch , a_notch = iirnotch (50.0 / (500 / 2 ), 30.0 )
35
+ b_band , a_band = butter (4 , [0.5 / (sampling_rate / 2 ), 48.0 / (sampling_rate / 2 )], btype = 'band' )
36
+
37
+ # Buffer for EEG data and Focus tracking variables
38
+ buffer = []
39
+ buffer_size = 500
40
+ focus_timer = 0
41
+ last_focus_time = time .time ()
42
+ last_time = time .time ()
43
+
44
+ # Load the beetle image
45
+ beetle_image = pygame .image .load ('beetle.jpg' )
46
+ beetle_image = pygame .transform .scale (beetle_image , (80 , 80 ))
47
+
48
+ # Function to apply filters
49
+ def apply_filters (eeg_point ):
50
+ filtered = lfilter (b_notch , a_notch , [eeg_point ])
51
+ filtered_point = lfilter (b_band , a_band , filtered )
52
+ return filtered_point [0 ]
53
+
54
+ def calculate_focus_level (eeg_data , sampling_rate = 500 ):
55
+ window = np .hanning (len (eeg_data )) # Apply a Hanning window
56
+ eeg_data_windowed = eeg_data * window
57
+ fft_data = np .abs (np .fft .fft (eeg_data_windowed ))[:len (eeg_data_windowed ) // 2 ]
58
+ fft_data /= len (eeg_data_windowed )
59
+ freqs = np .fft .fftfreq (len (eeg_data_windowed ), d = 1 / sampling_rate )[:len (eeg_data_windowed ) // 2 ]
60
+
61
+ # Compute power in different bands
62
+ delta_power = math .sqrt (np .sum ((fft_data [(freqs >= 0.5 ) & (freqs <= 4 )]) ** 2 ))
63
+ theta_power = math .sqrt (np .sum ((fft_data [(freqs >= 4 ) & (freqs <= 8 )]) ** 2 ))
64
+ alpha_power = math .sqrt (np .sum ((fft_data [(freqs >= 8 ) & (freqs <= 13 )]) ** 2 ))
65
+ beta_power = math .sqrt (np .sum ((fft_data [(freqs >= 13 ) & (freqs <= 30 )]) ** 2 ))
66
+ gamma_power = math .sqrt (np .sum ((fft_data [(freqs >= 30 ) & (freqs <= 45 )]) ** 2 ))
67
+
68
+ power = (beta_power + gamma_power ) / (theta_power + alpha_power )
69
+ print (power )
70
+ return power
71
+
72
+ def update_beetle_position (focus_level , is_focus_stable ):
73
+ global beetle_y
74
+ if is_focus_stable :
75
+ beetle_y = max (10 + beetle_image .get_height () // 2 , beetle_y - focus_speed_upward ) # Prevent moving above border
76
+ else :
77
+ beetle_y = min (580 - beetle_image .get_height () // 2 , beetle_y + focus_speed_downward ) # Prevent moving below border
78
+
79
+ # Game loop
80
+ running = True
81
+ while running :
82
+ try :
83
+ for event in pygame .event .get ():
84
+ if event .type == pygame .QUIT :
85
+ running = False
86
+
87
+ # Read EEG data from the LSL stream
88
+ sample , _ = inlet .pull_sample (timeout = 0.1 )
89
+ if sample :
90
+ filtered_sample = apply_filters (sample [0 ])
91
+ buffer .append (filtered_sample )
92
+
93
+ current_time = time .time ()
94
+ if current_time - last_time >= 1 :
95
+ last_time = current_time
96
+ release_count = int (len (buffer ) * 0.2 ) # Remove oldest 20%
97
+ buffer = buffer [release_count :] # Trim buffer
98
+
99
+ if len (buffer ) >= buffer_size : # Process EEG data when the buffer is full
100
+ eeg_data = np .array (buffer ) # Use filtered data
101
+ buffer = [] # Clear the buffer
102
+
103
+ focus_level = calculate_focus_level (eeg_data )
104
+
105
+ if focus_level > focus_threshold :
106
+ focus_timer = min (focus_timeout , focus_timer + (current_time - last_focus_time ))
107
+ is_focus_stable = focus_timer >= focus_timeout
108
+ update_beetle_position (focus_level , is_focus_stable )
109
+
110
+ elif 7 <= focus_level <= 8 : # No movement of the beetle
111
+ print ("Beetle remains stationary." )
112
+
113
+ else :
114
+ focus_timer = max (0 , focus_timer - (current_time - last_focus_time ))
115
+ is_focus_stable = focus_timer >= focus_timeout
116
+ update_beetle_position (focus_level , is_focus_stable )
117
+
118
+ last_focus_time = current_time
119
+
120
+ # Clear the screen and draw the beetle
121
+ screen .fill ("#FFFFFF" )
122
+ pygame .draw .rect (screen , (0 , 0 , 0 ), (10 , 10 , 780 , 580 ), 5 ) # Draw border
123
+ screen .blit (beetle_image , (beetle_x - beetle_image .get_width () // 2 , beetle_y - beetle_image .get_height () // 2 ))
124
+
125
+ pygame .display .update ()
126
+
127
+ except KeyboardInterrupt :
128
+ print ("Exiting gracefully..." )
129
+ running = False
130
+
131
+ pygame .quit ()
0 commit comments