| MOCS | R Documentation |
MOCS performs either a yes/no or n-interval-forced-choice Method of Constant Stimuli test
MOCS(
params = NA,
order = "random",
responseWindowMeth = "constant",
responseFloor = 1500,
responseHistory = 5,
keyHandler = function(correct, ret) return(list(seen = TRUE, time = 0, err = NULL)),
interStimMin = 200,
interStimMax = 500,
beep_function,
makeStim,
stim_print,
...
)
params |
A matrix where each row is
|
order |
Control the order in which the stimuli are presented.
|
responseWindowMeth |
Control time perimeter waits for response.
|
responseFloor |
Minimum response window (for any |
responseHistory |
Number of past yeses to average to get response window
(only used if |
keyHandler |
Function to get a keyboard input and returns as for |
interStimMin |
Regardless of response, wait |
interStimMax |
Regardless of response, wait |
beep_function |
A function that takes the string |
makeStim |
A helper function to take a row of |
stim_print |
A function that takes an |
... |
Extra parameters to pass to the opiPresent function. |
Whether the test is yes/no or forced-choice is determined by the number of columns
in params. The code simply presents all columns from 5 onwards and collects a
response at the end. So if there is only 5 columns, it is a yes/no task. If there are 6
columns it is a 2-interval-forced-choice. Generally, an nIFC experiment has 4+n columns in
params.
Note that when the order is "random", the number of trials in the test will be
the sum of the 3rd column of params. When the order is "fixed", there is
only one presentation per row, regardless of the value in the 3rd column of params.
If a response is received before the final trial in a nIFC experiment, it is ignored.
If the checkFixationOK function is present in a stimulus, then it is called after each
presentation, and the result is “anded” with each stimulus in a trial to get a TRUE/FALSE
for fixating on all stimuli in a trial.
Returns a data.frame with one row per stimulus copied from params with extra columns
appended: checkFixation checks, and the return values from opiPresent()
(see example). These last values will differ depending on which
machine/simulation you are running (as chosen with chooseOpi().
column 1: x
column 2: y
column 3: location number
column 4: number of times to repeat this stim
column 5: correct stimulus index
column 6: TRUE/FALSE was fixating for all presentations in this trial according to checkFixationOK
column 7...: columns from params
...: columns from opiPresent return
A. Turpin, P.H. Artes and A.M. McKendrick. "The Open Perimetry Interface: An enabling tool for clinical visual psychophysics", Journal of Vision 12(11) 2012.
dbTocd, opiPresent
# For the Octopus 900
# Check if pupil centre is within 10 pixels of (160,140)
checkFixationOK <- function(ret) return(sqrt((ret$pupilX - 160)^2 + (ret$pupilY - 140)^2) < 10)
# Return a list of opi stim objects (list of class opiStaticStimulus) for each level (dB) in
# p[5:length(p)]. Each stim has responseWindow BETWEEN_FLASH_TIME, except the last which has
# rwin. This one assumes p is on old Octopus 900 dB scale (0dB == 4000 cd/m^2).
makeStim <- function(p, rwin) {
BETWEEN_FLASH_TIME <- 750 # ms
res <- NULL
for(i in 5:length(p)) {
s <- list(x=p[1], y=p[2], level=dbTocd(p[i],4000/pi), size=0.43, duration=200,
responseWindow=ifelse(i < length(p), BETWEEN_FLASH_TIME, rwin),
checkFixationOK=NULL)
class(s) <- "opiStaticStimulus"
res <- c(res, list(s))
}
return(res)
}
################################################################
# Read in a key press 'z' is correct==1, 'm' otherwise
# correct is either 1 or 2, whichever is the correct interval
#
# Return list(seen={TRUE|FALSE}, time=time, err=NULL))
# seen is TRUE if correct key pressed
################################################################
## Not run:
if (length(dir(".", "getKeyPress.py")) < 1)
stop('Python script getKeyPress.py missing?')
## End(Not run)
keyHandler <- function(correct, ret) {
return(list(seen=TRUE, time=0, err=NULL))
ONE <- "b'z'"
TWO <- "b'm'"
time <- Sys.time()
key <- 'q'
while (key != ONE && key != TWO) {
a <- system('python getKeyPress.py', intern=TRUE)
key <- a # substr(a, nchar(a), nchar(a))
print(paste('Key pressed: ',key,'from',a))
if (key == "b'8'")
stop('Key 8 pressed')
}
time <- Sys.time() - time
if ((key == ONE && correct == 1) || (key == TWO && correct == 2))
return(list(seen=TRUE, time=time, err=NULL))
else
return(list(seen=FALSE, time=time, err=NULL))
}
################################################################
# Read in return value from opipresent with F310 controller.
# First param is correct, next is 1 for left button, 2 for right button
# Left button (LB) is correct for interval 1, RB for interval 2
# correct is either 1 or 2, whichever is the correct interval
#
# Return list(seen={TRUE|FALSE}, time=time, err=NULL))
# seen is TRUE if correct key pressed
################################################################
F310Handler <- function(correct, opiResult) {
z <- opiResult$seen == correct
opiResult$seen <- z
return(opiResult)
}
################################################################
# 2 example beep_function
################################################################
## Not run:
require(beepr)
myBeep <- function(type='None') {
if (type == 'correct') {
beepr::beep(2) # coin noise
Sys.sleep(0.5)
}
if (type == 'incorrect') {
beepr::beep(1) # system("rundll32 user32.dll,MessageBeep -1") # system beep
#Sys.sleep(0.0)
}
}
require(audio)
myBeep <- function(type="None") {
if (type == 'correct') {
wait(audio::play(sin(1:10000/10)))
}
if (type == 'incorrect') {
wait(audio::play(sin(1:10000/20)))
}
}
## End(Not run)
################################################################
# An example stim_print function
################################################################
## Not run:
stim_print <- function(s, ret) {
sprintf("%4.1f %2.0f",cdTodb(s$level,10000/pi), ret$seen)
}
## End(Not run)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.