Skip to content

Commit

Permalink
Merge 6ba837a into 4d352be
Browse files Browse the repository at this point in the history
  • Loading branch information
isolver committed Mar 18, 2021
2 parents 4d352be + 6ba837a commit 81cf671
Show file tree
Hide file tree
Showing 52 changed files with 1,167 additions and 3,806 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
Keyboard:
# name: The name you want to assign the keyboard device for the experiment
# This name is what will be used to access the device within the experiment
# script via the devices.[device_name] property of the ioHubConnection or
# ioHubExperimentRuntime classes.
# script via the devices.[device_name] property of the ioHubConnection
#
name: keyboard

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
Mouse:
# name: The name you want to assign the Mouse device for the experiment
# This name is what will be used to access the device within the experiment
# script via the devices.[device_name] property of the ioHubConnection or
# ioHubExperimentRuntime classes.
# script via the devices.[device_name] property of the ioHubConnection
#
name: mouse

Expand Down
228 changes: 228 additions & 0 deletions psychopy/demos/coder/iohub/delaytest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Tests the round trip delay from when the experiment runtime requests
new events from the ioHub server to when a response with >=1 new
event is received and ready for use within the experiment script.
Only getEvent requests that return with at least one new event are used in
the calculated statistics to try and ensure the reported delay is measuring
the higher processing load case of new events being returned, vs. the
case of no new events being available.
At the end of the test, a MatPlotLib figure is displayed showing a
histogram of the round trip event request delays as well as two figures
representing the retrace onset detection stability of PsychoPy.
"""

from __future__ import absolute_import, division, print_function

from numpy import zeros
from scipy.stats import norm
from psychopy import visual
from psychopy.iohub import Computer, launchHubServer
from psychopy.iohub.constants import EventConstants
from collections import OrderedDict

totalEventRequestsForTest = 1000
numEventRequests = 0

def run():
global numEventRequests
io = launchHubServer(experiment_code='delay_test')

lastFlipTime = 0.0

# create fullscreen pyglet window at current resolution, as well as required resources / drawings
psychoWindow, psychoStim = createPsychoGraphicsWindow(io)

# create stats numpy arrays, set experiment process to high priority.
# Init Results numpy array
results= zeros((totalEventRequestsForTest,3),dtype='f4')

numEventRequests=0

# clear the ioHub event Buffer before starting the test.
# This is VERY IMPORTANT, given an existing bug in ioHub.
# You would want to do this before each trial started until the bug is fixed.
io.clearEvents('all')

# draw and flip to the updated graphics state.
flipTime = drawAndFlipPsychoWindow(psychoStim, psychoWindow, io, None)
ifi = flipTime - lastFlipTime
lastFlipTime = flipTime

# START TEST LOOP >>>>>>>>>>>>>>>>>>>>>>>>>>
while numEventRequests < totalEventRequestsForTest:
# send an Experiment Event to the ioHub server process
io.sendMessageEvent("This is a test message %.3f" % flipTime)

# check for any new events from any of the devices, and return the events list and the time it took to
# request the events and receive the reply
events, callDuration = checkForEvents(io)
if events:
# events were available
results[numEventRequests][0] = callDuration # ctime it took to get events from ioHub
results[numEventRequests][1] = len(events) # number of events returned
results[numEventRequests][2] = ifi * 1000.0 # calculating inter flip interval.
numEventRequests += 1 # incrementing tally counterfgh
# draw and flip to the updated graphics state.

flipTime = drawAndFlipPsychoWindow(psychoStim, psychoWindow, io, events)
ifi = flipTime - lastFlipTime
lastFlipTime = flipTime

# END TEST LOOP <<<<<<<<<<<<<<<<<<<<<<<<<<

psychoWindow.close()

# plot collected delay and retrace detection results.
plotResults(results)
printResults(results)

def createPsychoGraphicsWindow(io):
#create a window
psychoStim = OrderedDict()
psychoWindow = visual.Window(io.devices.display.getPixelResolution(),
monitor=io.devices.display.getPsychopyMonitorName(),
units=io.devices.display.getCoordinateType(),
color=[128,128,128], colorSpace='rgb255',
fullscr=True, allowGUI=False,
screen=io.devices.display.getIndex()
)

currentPosition= io.devices.mouse.setPosition((0,0))
psychoWindow.setMouseVisible(False)

fixation = visual.PatchStim(psychoWindow, size=25, pos=[0,0], sf=0,
color=[-1,-1,-1], colorSpace='rgb')
title = visual.TextStim(win=psychoWindow,
text="ioHub getEvents Delay Test", pos = [0,125],
height=36, color=[1,.5,0], colorSpace='rgb',
wrapWidth=800.0)

instr = visual.TextStim(win=psychoWindow,
text='Move the mouse around, press keyboard keys and mouse buttons',
pos = [0,-125], height=32, color=[-1,-1,-1],
colorSpace='rgb', wrapWidth=800.0)

psychoStim['static'] = visual.BufferImageStim(win=psychoWindow,
stim=(fixation, title, instr))
psychoStim['grating'] = visual.PatchStim(psychoWindow,
mask="circle", size=75,pos=[-100,0],
sf=.075)
psychoStim['keytext'] = visual.TextStim(win=psychoWindow,
text='key', pos = [0,300], height=48,
color=[-1,-1,-1], colorSpace='rgb',
wrapWidth=800.0)
psychoStim['mouseDot'] = visual.GratingStim(win=psychoWindow,
tex=None, mask="gauss",
pos=currentPosition,size=(50,50),
color='purple')
psychoStim['progress'] = visual.ShapeStim(win=psychoWindow,
vertices=[(0,0),(0,0),(0,0),(0,0)],
pos=(400, -300))

return psychoWindow, psychoStim

def drawAndFlipPsychoWindow(psychoStim, psychoWindow, io, events):
psychoStim['grating'].setPhase(0.05, '+')#advance phase by 0.05 of a cycle
currentPosition,currentDisplayIndex =io.devices.mouse.getPosition(return_display_index=True)

if currentDisplayIndex == io.devices.display.getIndex():
currentPosition=(float(currentPosition[0]),float(currentPosition[1]))
psychoStim['mouseDot'].setPos(currentPosition)

if events:
diff = totalEventRequestsForTest - numEventRequests
v = psychoWindow.size[1] / 2.0 * diff / totalEventRequestsForTest
vert = [[0,0], [0,v], [2,v],[2,0]]
psychoStim['progress'].setVertices(vert)

for r in events:
if r.type is EventConstants.KEYBOARD_PRESS: #keypress code
psychoStim['keytext'].setText(r.key)

[psychoStim[skey].draw() for skey in psychoStim]

flipTime=psychoWindow.flip()
return flipTime

def checkForEvents(io):
# get the time we request events from the ioHub
stime=Computer.getTime()
r = io.getEvents()
if r and len(r) > 0:
# so there were events returned in the request, so include this getEvent request in the tally
etime=Computer.getTime()
dur=etime-stime
return r, dur*1000.0
return None, None


def plotResults(results):
#### calculate stats on collected data and draw some plots ####
from matplotlib.pyplot import axis, title, xlabel, hist, grid, show, ylabel, plot
import pylab

durations=results[:,0]
flips=results[1:,2]

dmean=durations.mean()
dstd=durations.std()

fmean=flips.mean()
fstd=flips.std()

pylab.figure(figsize=(7,5))
pylab.subplot(1,3,1)

# the histogram of the delay data
n, bins, patches = hist(durations, 50, facecolor='blue', alpha=0.75)
# add a 'best fit' line
y = norm.pdf( bins, dmean, dstd)
plot(bins, y, 'r--', linewidth=1)
xlabel('ioHub getEvents Delay')
ylabel('Percentage')
title('ioHub Event Delays (msec):\n'+r'$\ \mu={0:.3f},\ \sigma={1:.3f}$'.format(dmean, dstd))
axis([0, durations.max()+1.0, 0, 25.0])
grid(True)

# graphs of the retrace data ( taken from retrace example in psychopy demos folder)
intervalsMS = flips
m=fmean
sd=fstd
distString= "Mean={0:.1f}ms, s.d.={1:.1f}, 99%CI={2:.1f}-{3:.1f}".format(
m, sd, m - 3 * sd, m + 3 * sd)
nTotal=len(intervalsMS)
nDropped=sum(intervalsMS>(1.5*m))
droppedString = "Dropped/Frames = {0:d}/{1:d} = {2:0.2f}%".format(
nDropped, nTotal, int(nDropped) / float(nTotal))

pylab.subplot(1,3,2)

#plot the frameintervals
pylab.plot(intervalsMS, '-')
pylab.ylabel('t (ms)')
pylab.xlabel('frame N')
pylab.title(droppedString)

pylab.subplot(1,3,3)
pylab.hist(intervalsMS, 50, histtype='stepfilled')
pylab.xlabel('t (ms)')
pylab.ylabel('n frames')
pylab.title(distString)
show()

def printResults(results):
durations=results[:,0]
dmean=durations.mean()
dstd=durations.std()
print("ioHub getEvent Delays:")
print("\tMEAN: ", dmean)
print("\tSDEV: ", dstd)


if __name__ == "__main__":
run()
10 changes: 0 additions & 10 deletions psychopy/demos/coder/iohub/delaytest/experiment_config.yaml

This file was deleted.

27 changes: 0 additions & 27 deletions psychopy/demos/coder/iohub/delaytest/iohub_config.yaml

This file was deleted.

Loading

0 comments on commit 81cf671

Please sign in to comment.