Weber.addtrial
— Function.addtrial(moments...)
Adds a trial to the experiment, consisting of the specified moments.
Each trial records a "trial_start" code, and increments a counter tracking the number of trials, and (normally) an offset counter. These two numbers are reported on every line of the resulting data file (see record
). They can be retrieved using Weber.trial()
and Weber.offset()
.
Weber.addbreak
— Function.addbreak(moments...)
Identical to addpractice
, but records "break_start" instead of "practice_start".
Weber.addbreak_every
— Function.addbreak_every(n,total,
[response=key":space:"],[response_str="the spacebar"])
Adds a break every n
times this event is added given a known number of total such events.
By default this waits for the user to hit spacebar to move on.
Weber.addpractice
— Function.addpractice(moments...)
Identical to addtrial
, except that it does not incriment the trial count, and records a "practice_start" instead of "trial_start" code.
Weber.moment
— Function.moment([delta_t],[fn],args...;keys...)
Create a moment that occurs delta_t
(default 0) seconds after the onset of the previous moment, running the specified function.
The function fn
is passed the arguments specified in args
and keys
.
moment(moments...)
moment(moments::Array)
Create a single, compound moment by concatentating several moments togethor.
Weber.response
— Function.response(key1 => response1,key2 => response2,...;kwds...)
Create a watcher moment that records press of key[n]
as record(response[n];kwds...)
.
See record
for more details on how events are recorded.
When a key is pressed down, the record event occurs. Key releases are also recorded, but are suffixed, by default, with "_up". This suffix can be changed using the keyup_suffix
keyword argument.
response([fn],adapter,[key1] => ["resp1"],...;correct=[resp],
[show_feedback=true],
[feedback=Dict(true=>"Correct",false=>"Wrong!")]
keys...)
Record a response in a n-alternative forced choice task and update an adapter.
The first response recieved is interpreted as the actual response. Subsequent responses will be recorded, without a delta or correct value set, and appending "late_" to the specified response string.
Function Callback
Optionally, upon participant response, fn
receives two arguments: the provided response, and the correct response.
Keyword Arguments
correct
the response string corresponding to the correct responseshow_feedback
(default = true): whether to show feedback to the participant after they respond.feedback
the text to display to a participant when they are correct (for the true key, defaults to "Correct!") or incorrect (for the false key, defaults to "Wrong!").
Any additional keyword arguments are added as column values when the response is recorded.
Weber.await_response
— Function.await_response(isresponse;[atleast=0.0])
This moment starts when the isresponse
function evaluates to true.
The isresponse
function will be called anytime an event occurs. It should take one parameter (the event that just occured).
If the response is provided before atleast
seconds, the moment does not start until atleast
seconds have passed.
Weber.record
— Function.record(code;keys...)
Record a row to the experiment data file using a given code
.
Each event has a code which identifies it as being a particular type of experiment event. This is normally a string. Each keyword argument is the value of a column (with the same name). By convention when you record something with the same code you should specify the same set of columns.
All calls to record also result in many additional values being written to the data file. The start time and date of the experiment, the trial and offset number, the version of Weber, and the time at which the last moment started are all stored. Additional information can be added during creation of the experiment (see Experiment
).
Each call to record writes a new row to the data file used for the experiment, so there should be no loss of data if the program is terminated prematurely for some reason.
There are several codes that are automatically recorded by Weber. They include:
trial_start - recorded at the start of moments added by
addtrial
practice_start - recorded at the start of moments added by
addpractice
break_start - recorded at the start of moments added by
addbreak
high_latency - recorded whenever a high latency warning is triggered. The "value" column is set to the error between the actual and the desired timing of a moment, in seconds.
paused - recorded when user hits 'escape' and the experiment is paused.
unpaused - recorded when the user ends the pause, continuuing the experiment.
terminated - recorded when the user manually terminates the experiment (via 'escape')
closed - recorded just before the experiment window closes
Weber.timeout
— Function.timeout(fn,isresponse,timeout,[atleast=0s])
This moment starts when either isresponse
evaluates to true or timeout time (in seconds) passes.
The isresponse
function will be called anytime an event occurs. It should take one parameter (the event that just occured).
If the moment times out, the function fn
(with no arguments) will be called.
If the response is provided before atleast
seconds, the moment does not begin until atleast
seconds (fn
will not be called).
Weber.show_cross
— Function.show_cross([delta_t])
Creates a moment that shows a cross hair delta_t
seconds after the start of the previous moment (defaults to 0 seconds).
Weber.when
— Function.when(condition,moments...)
This moment will begin at the start of the previous moment, and presents the following moments (possibly in nested iterable objects) if the condition
function (which takes no arguments) evaluates to true.
Weber.looping
— Function.looping(when=fn,moments...)
This moment will begin at the start of the previous moment, and repeats the listed moments (possibly in nested iterable objects) until the when
function (which takes no arguments) evaluates to false.
Weber.@addtrials
— Macro.@addtrials expr...
Marks a let block, a for loop, or an if expression as dependent on experiment run-time state, leaving the offset counter unincremented within that block. The immediately proceeding loop or conditional logic will be run during experiment run-time rather than setup-time.
Refer to the Advanced Topics
of the manual section for more details.
Weber.update!
— Function.update!(adapter,response,correct)
Updates any internal state for the adapter when the listener responds with response
and the correct response is correct
. Usually not called directly, but instead called within response
, when the adapter is passed as the first argument. May take a while to run.
Weber.estimate
— Function.estimate(adapter)
Returns the mean and error of the adapters threshold estimate. May take some time to run.
Weber.delta
— Function.delta(adapter)
Returns the next delta that should be tested to help estimate the threshold.
Weber.oddball_paradigm
— Function.oddball_paradigm(trial_body_fn,n_oddballs,n_standards;
lead=20,n_standard_after_oddball=1,rng=Base.GLOBAL_RNG)
Helper to generate trials for an oddball paradigm.
The trial_body_fn should setup stimulus presentation: it takes one argument, indicating if the stimulus should be a standard (false) or oddball (true) stimulus.
It is usually best to use oddball_paradigm with a do block syntax. For instance, the following code sets up 20 oddball and 150 standard trials.
oddball_paradigm(20,150) do isoddball
if isoddball
addtrial(...create oddball trial here...)
else
addtrial(...create standard trial here...)
end
end
Alternatively, because oddball_paradigm
returns the result of each function call, you can pass the oddball paradigm as a series of moments to a single trial.
create_oddball_moment(isoddball) =
isoddball ? moment(...oddball...) : moment(...standard...)
addtrial(oddball_paradigm(create_oddball_moment,20,150))
Keyword arguments
lead: determines the number of standards that repeat before any oddballs get presented
oddball_spacing: determines the number of standards after an oddball that must occur before a new oddball can occur
Weber.levitt_adapter
— Function.levitt_adapter([first_delta=0.1],[down=3],[up=1],
[big_reverse=3],[big=0.01],[little=0.005],
[min_reversals=7],[min_delta=-Inf],[max_delta=Inf],
[mult=false])
An adapter that finds a threshold according to a non-parametric statistical procedure. This approach makes fewer explicit assumptions than bayesian_adapter
but may be slower to converge to a threshold.
This finds a threshold by moving the delta down after three correct responses and up after one incorrect response (these default up and down counts can be changed). This is the same approach described in Levitt (1971).
Keyword Arguments
first_delta
: the delta that the first trial should present.up
: how many incorrect responses in a row must occur for the delta to move updown
: how many correct responses in a row must occur for the delta to move down.big
: the amount delta changes by (up or down) at firstbig_reverse
: how many reveresals (up to down or down to up) must occur beforelittle
is used instead ofbig
little
: the amount delta changes by (up or down) afterbig_reverse
reversals.min_reversals
: the smallest number of reversals that can be used to estimate a threshold.min_delta
: the smallest delta allowedmax_delta
: the largest delta allowedmult
: whether the delta change should be additive (false) or multiplicative (true).
Weber.bayesian_adapter
— Function.bayesian_adapter(;first_delta=0.1,
n_samples=1000,miss=0.01,threshold=0.79,
min_delta=0,max_delta=1,
min_plausible_delta = 0.0001,
max_plausible_delta = 0.2,
repeat3_thresh=1.0,repeat2_thresh=0.1,
thresh_prior=
Truncated(LogNormal(log(min_plausible_delta),
log(max_plausible_delta/
min_plausible_delta/2)),
min_delta,max_delta),
inv_slope_prior=TruncatedNormal(0,0.25,0,Inf),
thresh_d=thresh_prior,
inv_slope_d=inv_slope_prior)
An adapter that finds a threshold according to a parametric statistical model. This makes more explicit assumptions than the levitt_adapter
but will normally find a threshold faster.
The psychometric curve is estimated from user responses using a bayesian approach. After estimation, each new delta is selected in a greedy fashion, picking the response that best minimizes entropy according to this psychometric function. This is a modified version of the approach described in Kontsevich & Tyler 1999. Specifically, the approach here uses importance sampling instead of sampling parmeters over a deterministic, uniform grid. This should increase measurement efficiency if the priors are chosen well.
This algorithm assumes the following functional form for the psychometric response as a function of the stimulus difference $Δ$.
$f(Δ) = λ/2 + (1-λ) Φ((Δ - θ)⋅σ/√2)$
In the above $Φ$ is the cumulative distribution function of a normal distribution, $λ$ is the miss-rate parameter, indicating the rate at which listeners make a mistake, even when the delta is large and easily heard, $θ$ is the 50%-correct threshold, and $σ$ is the psychometric slope.
For stability and robustness, this adapter begins by repeating the same delta multiple times and only begins quickly changing deltas trial-by-trial when the ratio of estiamted standard deviation to mean is small. This functionality can be adjusted using repeat3_thresh
and repeat2_thresh
, or, if you do not wish to have any repeats, both values can be set to Inf.
Keyword Arugments
first_delta: the delta to start measuring with
n_samples the number of samples to use during importance sampling. The algorithm for selecting new deltas is O(n²).
miss the expected rate at which listeners will make mistakes even for easy to percieve differences.
threshold the %-response threshold to be estimated
min_delta the smallest possible delta
max_delta the largest possible delta
min_plausible_delta the smallest plausible delta, should be > 0. Used to define a reasonable value for thresh_prior and inv_slope_prior.
max_plausible_delta the largest plausible delta, should be < max_delta. Used to define a reasonable value for thresh_prior and inv_slope_prior.
thresh_prior the prior probability distribution across thresholds. This influence the way the delta is adapted. By default this is defined in terms of min_plausible_delta and max_plausible_delta.
inv_slope_prior the prior probability distribution across inverse slopes. By default this is defined in terms of min_plausible_delta and max_plausible_delta.
thresh_d the distribution over-which to draw samples for the threshold during importance sampling. This defaults to thresh_prior
inv_slope_d the distribution over-which to draw samples for the inverse slope during importance sampling. This defaults to inv_slope_prior.
repeat2_thresh the ratio of sd / mean for theta must suprass to repeat each delta twice.
repeat3_thresh the ratio of sd / mean for theta must surpass to repeat each delta thrice.
Weber.constant_adapter
— Function.constant_adapter(stimuli)
An adapter that can be used to implement the method of constant stimuli: the specified sequence of stimulus deltas is presented in order to participants.
Strictly speaking, this is not an adaptive tracking procedure. However, it can be convienient to have the same programming interface for this method as for adaptive methods. In this way you can easily select between the method of constant stimuli or some kind of adaptive procedure.