Full Threshold

Share:

Description

FT begins with a 4-2dB staircase beginning at level est. If the final estimate (last seen) is more than 4dB away from est, a second 4-2 staircase is completed beginning at the estimate returned from the first.

Usage

1
2
3
4
5
6
7
FT(est = 25, instRange = c(0, 40), verbose = FALSE, makeStim, ...)

FT.start(est=25, instRange=c(0,40), makeStim, ...)
FT.step(state, nextStim=NULL)
FT.stop(state) 
FT.final(state)
FT.final.details(state)

Arguments

est

Starting estimate in dB

instRange

Dynamic range of the instrument c(min,max) in dB

verbose

True if you want each presentation printed

makeStim

A function that takes a dB value and numPresentations and returns an OPI datatype ready for passing to opiPresent

...

Extra parameters to pass to the opiPresent function

state

Current state of the FT returned by FT.start and FT.step.

nextStim

A valid object for opiPresent to use as its nextStim.

Details

This is an implementation of a 4-2 1-up 1-down staircase as implemented in the first Humphrey Field Analyzer. The initial staircase starts at est and proceeds in steps of 4dB until the first reversal, and 2dB until the next reversal. The last seen stimulus is taken as the threshold value. If, after the first staircase, the threshold is more than 4 dB away from the starting point, then a second staircase is initiated with a starting point equal to the threshold found with the first staircase.

Note this function will repeatedly call opiPresent for a stimulus until opiPresent returns NULL (ie no error occured).

If more than one FT is to be interleaved (for example, testing multiple locations), then the FT.start, FT.step, FT.stop and FT.final calls can maintain the state of the FT after each presentation, and should be used. If only a single FT is required, then the simpler FT can be used. See examples below.

Value

Single location

Returns a list containing

  • npres Total number of presentations

  • respSeq Response sequence stored as a list of (seen,dB) pairs

  • first First staircase estimate in dB

  • final Final threshold estimate in dB

Multilple locations

FT.start returns a list that can be passed to FT.step, FT.stop and FT.final. It represents the state of a FT at a single location at a point in time and contains the following.

  • name: FT

  • A copy of all of the parameters supplied to FT.start: startingEstimate=est, minStimulus=instRange[1], maxStimulus=instRange[2], makeStim, and opiParams=list(...).

  • currentLevel: The next stimulus to present.

  • lastSeen: The last seen stimulus.

  • lastResponse: The last response given.

  • firstStairResult: The result of the first staircase (initially NA).

  • secondStairResult: The result of the first staircase (initially NA, and could remain NA).

  • finished: TRUE if staircae has finished (2 reversals, or max/min seen/not-seen twice).

  • numberOfReversals: Number of reversals so far.

  • currSeenLimit: Number of times maxStimulus has been seen.

  • currNotSeenLimit: Number of times minStimulus not seen.

  • numPresentations: Number of presentations so far.

  • stimuli: Vector of stimuli shown at each call to FT.step.

  • responses: Vector of responses received (1 seen, 0 not) receieved at each call to FT.step.

  • responseTimes: Vector of response times receieved at each call to FT.step.

FT.step returns a list containing

  • state: The new state after presenting a stimuli and getting a response.

  • resp: The return from the opiPresent call that was made.

FT.stop returns TRUE if the first staircase has had 2 reversals, or maxStimulus is seen twice or minStimulus is not seen twice and the final estimate is within 4 dB of the starting stimulus. Returns TRUE if the second staircase has had 2 reversals, or maxStimulus is seen twice or minStimulus is not seen twice.

FT.final returns the final estimate of threshold based on state, which is the last seen in the second staircase, if it ran, or the first staircase otherwise.

FT.final.details returns a list containing

  • final: The final threshold.

  • first: The threshold determined by the first staircase (might be different from final).

  • stopReason: Either Reversals, Max, or Min which are the three ways in which FT can terminate.

  • np: Number of presentation for the whole procedure (indcluding both staircases if run).

Author(s)

Andrew Turpin <aturpin@unimelb.edu.au>

References

Please cite: 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.

H. Bebie, F. Fankhauser and J. Spahr. "Static perimetry: strategies", Acta Ophthalmology 54 1976.

C.A. Johnson, B.C. Chauhan, and L.R. Shapiro. "Properties of staircase procedures for estimating thresholds in automated perimetry", Investagative Ophthalmology and Vision Science 33 1993.

http://perimetry.org/OPI

See Also

dbTocd, opiPresent

Examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    # Stimulus is Size III white-on-white as in the HFA
makeStim <- function(db, n) { 
    s <- list(x=9, y=9, level=dbTocd(db), size=0.43, color="white",
             duration=200, responseWindow=1500)
    class(s) <- "opiStaticStimulus"

    return(s)
}
chooseOpi("SimHenson")
if (!is.null(opiInitialize(type="C", cap=6)))
    stop("opiInitialize failed")

result <- FT(makeStim=makeStim, tt=30, fpr=0.15, fnr=0.01)

if (!is.null(opiClose()))
    warning("opiClose() failed")

    ##############################################
    # This section is for multiple FTs
    ##############################################
makeStimHelper <- function(db,n, x, y) {  # returns a function of (db,n)
    ff <- function(db, n) db+n

    body(ff) <- substitute(
        {s <- list(x=x, y=y, level=dbTocd(db), size=0.43, color="white",
                  duration=200, responseWindow=1500)
         class(s) <- "opiStaticStimulus"
         return(s)
        }
        , list(x=x,y=y))
    return(ff)
}

    # List of (x, y, true threshold) triples
locations <- list(c(9,9,30), c(-9,-9,32), c(9,-9,31), c(-9,9,33))

    # Setup starting states for each location
states <- lapply(locations, function(loc) {
    FT.start( makeStim=makeStimHelper(db,n,loc[1],loc[2]),
              tt=loc[3], fpr=0.03, fnr=0.01)
})

    # Loop through until all states are "stop"
while(!all(st <- unlist(lapply(states, FT.stop)))) {
    i <- which(!st)                         # choose a random, 
    i <- i[runif(1, min=1, max=length(i))]  # unstopped state
    r <- FT.step(states[[i]])               # step it
    states[[i]] <- r$state                  # update the states
}

finals <- lapply(states, FT.final)    # get final estimates of threshold
for(i in 1:length(locations)) {
    cat(sprintf("Location (%+2d,%+2d) ",locations[[i]][1], locations[[i]][2]))
    cat(sprintf("has threshold %4.2f\n", finals[[i]]))
}

if (!is.null(opiClose()))
    warning("opiClose() failed")