Main Issue
I’m coding a BCI that should simultaneously generate P300 and SSVEP stimuli on an interface, and collect/process/classify EEG signal. When the interface runs separately from the EEG collection, both run smoothly, but when both run together it takes around twice as much time.
Is there a way to make the stimuli faster? Maybe remove some draw()
's somehow? Se the snippet of my interface below (full code):
TrialLabels = [0,1,1,2,1,0,2,0,2,1,0,2]
def start(self):
T0 = genclock.getTime()
p =[[-0.5, -0.5],[0, 0.5],[0.5, -0.5]] #from the centre; 1 is for 100%, 0 is for 50% and -1 is for 0% of screen
self.stSq0 = visual.Rect(self.win, fillColor = 'black', lineColor = 'black', width = self.pS, height = self.pS, pos = p[0])
self.stSq1 = visual.Rect(self.win, fillColor = 'black', lineColor = 'black', width = self.pS, height = self.pS, pos = p[1])
self.stSq2 = visual.Rect(self.win, fillColor = 'black', lineColor = 'black', width = self.pS, height = self.pS, pos = p[2])
for TL in TrialLabels:
ct = 0
mx_ct = 1799
op_off = 0
op_on = 1
endflag = False
sequenceP300 = []
for m in range (0,3):
for k in range(0,7): #number of blinks per square
sequenceP300.append(m)
random.shuffle(sequenceP300)
blinkLabels = sequenceP300 #copied because sequenceP300 gets destroyed
t0 = p300clock.getTime()
current_P300 = sequenceP300.pop(0)
while not endflag:#True:
try:
##::SSVEP part
if ct%2 >= 1:
self.Sq0 = visual.Rect(self.win, fillColor = '#00388A', lineColor = '#00388A', width = self.sS, height = self.sS, pos = p[0], opacity = op_on) #blue
else:
self.Sq0 = visual.Rect(self.win, fillColor = '#59FF00', lineColor = '#59FF00', width = self.sS, height = self.sS, pos = p[0], opacity = op_on) #green
if ct%4 >= 2:
self.Sq1 = visual.Rect(self.win, fillColor = '#59FF00', lineColor = '#59FF00', width = self.sS, height = self.sS, pos = p[1], opacity = op_on) #green
else:
self.Sq1 = visual.Rect(self.win, fillColor = '#B80117', lineColor = '#B80117', width = self.sS, height = self.sS, pos = p[1], opacity = op_on) #red
if ct%6 >= 3:
self.Sq2 = visual.Rect(self.win, fillColor = '#59FF00', lineColor = '#59FF00', width = self.sS, height = self.sS, pos = p[2], opacity = op_on) #green
else:
self.Sq2 = visual.Rect(self.win, fillColor = '#B80117', lineColor = '#B80117', width = self.sS, height = self.sS, pos = p[2], opacity = op_on) #red
##::P300 part
t1 = p300clock.getTime()
if t1-t0 < 0.2:
if current_P300 == 0:
self.p300Sq0 = visual.Rect(self.win, fillColor = 'white', lineColor = 'white', width = self.p3S, height = self.p3S, pos = p[0], opacity = op_on)
if current_P300 == 1:
self.p300Sq0 = visual.Rect(self.win, fillColor = 'white', lineColor = 'white', width = self.p3S, height = self.p3S, pos = p[1], opacity = op_on)
if current_P300 == 2:
self.p300Sq0 = visual.Rect(self.win, fillColor = 'white', lineColor = 'white', width = self.p3S, height = self.p3S, pos = p[2], opacity = op_on)
elif t1-t0 >= 0.2 and t1-t0 < 0.45:
self.p300Sq0 = visual.Rect(self.win, fillColor = 'black', lineColor = 'black', width = self.p3S, height = self.p3S, pos = p[0], opacity = op_off)
elif t1-t0 >= 0.5:
t0 = p300clock.getTime()
try:
current_P300 = sequenceP300.pop(0)
except IndexError as e:
endflag = True
self.p300Sq0.draw()
self.stSq0.draw()
self.stSq1.draw()
self.stSq2.draw()
self.Sq0.draw()
self.Sq1.draw()
self.Sq2.draw()
self.win.flip()
ct += 1
if ct>= mx_ct:
ct = 0
except KeyboardInterrupt:
self.stop()
Here is what the profiler yields (and that’s why I was wondering if I cant take some draw()
's off):
213360 function calls (208353 primitive calls) in 44.338 seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.004 0.004 44.338 44.338 fb_01_threads.py:70(start)
363 18.329 0.050 21.593 0.059 C:\Users\robotics\AppData\Local\Continuum\anaconda3\envs\psychopy\lib\site-packages\psychopy\visual\shape.py:320(draw)
2776/2772 0.004 0.000 13.424 0.005 C:\Users\robotics\AppData\Local\Continuum\anaconda3\envs\psychopy\lib\site-packages\psychopy\tools\attributetools.py:31(__set__)
4 0.006 0.001 13.399 3.350 C:\Users\robotics\AppData\Local\Continuum\anaconda3\envs\psychopy\lib\site-packages\psychopy\visual\text.py:80(__init__)
387/361 0.000 0.000 13.389 0.037 {built-in method builtins.setattr}
24/20 0.000 0.000 13.389 0.669 C:\Users\robotics\AppData\Local\Continuum\anaconda3\envs\psychopy\lib\site-packages\psychopy\tools\attributetools.py:55(setAttribute)
4 0.000 0.000 12.723 3.181 C:\Users\robotics\AppData\Local\Continuum\anaconda3\envs\psychopy\lib\site-packages\psychopy\visual\text.py:369(setText)
4 0.000 0.000 12.723 3.181 C:\Users\robotics\AppData\Local\Continuum\anaconda3\envs\psychopy\lib\site-packages\psychopy\visual\text.py:334(text)
4 0.000 0.000 12.723 3.181 C:\Users\robotics\AppData\Local\Continuum\anaconda3\envs\psychopy\lib\site-packages\psychopy\visual\text.py:375(_setTextShaders)
4 0.000 0.000 9.789 2.447 C:\Users\robotics\AppData\Local\Continuum\anaconda3\envs\psychopy\lib\site-packages\pyglet\text\__init__.py:399(__init__)
...
And this is what PsychoPy outputs as well:
2.1699 WARNING Monitor specification not found. Creating a temporary one...
4.5121 WARNING Couldn't measure a consistent frame rate.
- Is your graphics card set to sync to vertical blank?
- Are you running other processes on your computer?
16.8873 WARNING t of last frame was 12358.70ms (=1/0)
17.5809 WARNING t of last frame was 693.56ms (=1/1)
18.3954 WARNING t of last frame was 814.52ms (=1/1)
20.0773 WARNING t of last frame was 1681.95ms (=1/0)
21.5205 WARNING Multiple dropped frames have occurred - I'll stop bothering you about them!
Hardware Specs
Item | Description |
---|---|
Processor | Intel® Core™ i5-2400 CPU @ 3.10GHz 3.10 GHz //4 cores |
WinOS | Windows 10 Enterprise |
Monitor Refresh Rate | 60Hz |
Installed RAM | 8.00 GB |
System type | 64-bit operating system, x64-based processor |
Graphics Card | AMD Radeon HD 6450 |
Python | 3.6.10 |
Psychopy | 2020.1.2 |