Trial objects

Trial objects are optional. For each trial, you only need to make one if you want to change a property from default. Note for some properties you can also change the defaults themselves using pb_prefs, which may be more convenient.

An object of type trial allows some options for a whole trial, e.g. pre-trial interval (default = 0.75 sec). For any trial you define in an experiment script, you can make a trial object using function trialObject and include it with all the element objects in an input to addTrial.

Trial timing

In a PsychBench experiment script use function addTrial to define trials in memory. You only need to define each distinct trial once (each distinct combination of property values across all objects in a trial), and in any order. Then finish with the function setTrialList to add order to run in and repetition if needed. Alternatively in unusual cases you can set order and repetition directly using an input to addTrial and not use setTrialList. See Building and running an experiment.

By default each trial simply ends when no elements in it are left running or waiting to start at definite times. The next trial to run then starts after an interval which you can change in trial object property preTrialInterval (default = 0.75 sec). In this mode trial start and end times are flexible, which is okay for most experiments. However, you can optionally add further end conditions in trial object property end.

You can also set trials to start at fixed times from a trigger in a past trial using trial object property start. Typically you only need to do this for scanner experiments.

Input properties

preTrialInterval

Default: 0.75 sec

preTrialInterval sets (minimum) time from previous trial end to this trial start (sec). By default the pre-trial interval is just a blank screen. You can change its background color using preTrialBackColor below. You also can show a static visual element in it by setting the element’s start field preTrial = <cd>true<cd>. The most common example is a cross object for a fixation cross. See also record properties preTrialInterval_r and preTrialHeadroom.

PsychBench always needs some time in each pre-trial interval to close the previous trial and prepare this one. How much time depends on what elements you run and on your system. If preTrialInterval is too short, PsychBench will automatically extend the interval and the experiment time course will bump forward. This is okay in most experiments. The main exception is if you use start.timeFromTrigger below to set a fixed start time, e.g. in scanner experiments.

preTrialBackColor

Default: same as trial

A 1×3 RGB vector with numbers between 0–1 setting background color for the pre-trial interval. Default is same as trial, which you can set in backColor below.

backColor

Default: same as experiment

A 1×3 RGB vector with numbers between 0–1 setting background color for the trial. Default is same as experiment, which you can set in experiment object property backColor.​ Note if you need to set background color for only part of a trial, use a rectangle element with property size = <cd>inf<cd> instead.

start

Default: trial starts flexibly whenever previous trial ends pre-trial interval

By default a trial starts flexibly whenever the previous trial ends + pre-trial interval. However, if you set start, the trial starts at a fixed time relative to a trigger in a past trial instead. This has three effects:
  • It prevents any drift due to accumulation of small deviations in start and end times across trials.
  • If the previous trial ends early (e.g. the subject responds fast) then this trial will wait to start on time.
  • If the previous trial would run late (e.g. the subject doesn’t respond in time) then it will end so this trial starts on time, including allowing for pre-trial interval. This additionally applies to this trial if it's the last in a sequence of trials with start set (e.g. the last trial in an experiment can still end like this, as if there were a similar next trial).

Setting trial start can be important in experiments where you need precise timing across trials relative to a trigger, e.g. scanner experiments that run multiple or all trials from a trigger. (Note if you re-trigger in each trial, you don’t need to use trial start—just set elements in each trial to start/end from trigger directly using element start/end fields trigger/triggerBy.)

To use trial start, first use an element in one trial to register a trigger, and set the element's property startTrialsFromTrigger = <cd>true<cd>. This activates fixed trial timing. Then for any number of subsequent trials, use trial start to set start times relative to the trigger. Note "subsequent" here refers to the order trials run in, generally set by setTrialList, not necessarily the order you define them in your experiment script.

start is a further struct with one field start.timeFromTrigger containing a 1×2 vector <cd>[t0 dt]<cd>. This works conditionally, so you can set it the same for all subsequent trials:

  1. <cd>t0<cd> = start time relative to trigger (sec) if this is the first trial that runs after the trigger
  2. <cd>dt<cd> = start time increment (sec) if this is a later trial

Notes

  • You can trigger once for the whole experiment or re-trigger any number of times. A trial with start.timeFromTrigger set goes off the most recent trigger.
  • If a trial has start.timeFromTrigger set but fixed trial timing is not active, it defaults to starting flexibly. This happens if no trigger has occurred in the experiment yet. It also happens if a trial without start.timeFromTrigger set runs—this cancels fixed timing until another trigger occurs.
  • Fixed trial timing plays well with staircases—see tutorial 11 in <PsychBench folder>/docs/tutorials>.
  • If you set trial start.timeFromTrigger, it’s important that pre-trial interval is long enough for the processing PsychBench needs to do between trials. If it isn’t, the trial will still start late. See preTrialInterval above.
  • Precise timing is often important in synchronized experiments. If an element starts or ends late, you can check element record properties startLatencyBufferable/endLatencyBufferable in experiment results output and fix using element properties startBuffer/endBuffer. See also Timing precision.

Example 1. Equal trial start increments

This experiment script defines one trial that runs a keyPress element that waits for a trigger signal. It then defines 20 test trials with the same setting for start.timeFromTrigger. The experiment runs one block of the sync trial + the 20 test trials in random order, then a second similar block. i.e. it waits to sync once at experiment start, then again half way through the experiment. In each block, whichever test trial runs first starts 0.75 sec after the trigger, then the others start at 10 sec increments. So trial start times in each block aim for 0.75, 10.75, 20.75, 30.75, … sec from trigger.

newExperiment


<cdcm>% -<cdcm>
syncer = keyPressObject;
syncer.registerTrigger = true;
syncer.startTrialsFromTrigger = true;
syncer.start.t = 0;
<cdcm>% keyPress ends on its own when it registers a trigger<cdcm>

addTrial(syncer, <cdsm>"sync"<cdsm>);
<cdcm>% -<cdcm>


<cdkm>for<cdkm> n = 1:20
    <rm><Make element objects for trial><rm>

    trial = trialObject;
    trial.start.timeFromTrigger = [0.75 10];

    addTrial(<rm><element objects><rm>, trial);
<cdkm>end<cdkm>


nn = [<cdsm>"sync"<cdsm> randomOrder(1:20) <cdsm>"sync"<cdsm> randomOrder(1:20)];
setTrialList(nn)

[results, resultsMatrix] = runExperiment;

Example 2. Jittered trial start increments

In fMRI experiments it’s common to randomize inter-stimulus intervals so that stimulus onset is sampled at different points in the scanner cycle. You can do this by randomly distributing offsets to start.timeFromTrigger across trials. See the scanner tutorial in <PsychBench folder>/docs/tutorials for an example.

end

Default: trial ends when no elements are left running or waiting to start at definite times

You can add further end conditions for the whole trial here. Usage is the same as element property end: this is a further struct with possible fields setting different conditions for the trial to end (e.g. time, duration, response from subject, etc.), or a row struct array for multiple end conditions. You can use all the same fields as for element end.

If an end condition for the trial occurs, all running elements end and the inter-trial interval begins. Note the default end condition (all elements done) still applies.

Example

trial.end.response = true;
trial.end.and = <cdsm>"response == 2"<cdsm>

→ end all elements and the trial if the subject inputs a response = 2.

withStaircase

Default: automatic if trial contains staircased elements and the experiment contains only one staircase

Usually you can leave withStaircase at default, including in most staircase experiments with only one staircase.

If you’re running an experiment with more than one staircase, for each trial that contains staircased elements, you must set withStaircase to specify which staircase to use for the trial.

You can also set withStaircase for a trial if it doesn’t contain staircased elements but you want to associate it with a staircase such that it will be skipped if it would run after the staircase ends. The trial will not actually be in the staircase, e.g. the staircase will not update its value or threshold estimate after the trial.

withStaircase is a string pointing to a staircase object by variable name and possibly index you use in the experiment script. e.g. <cds>"staircase"<cds>, <cds>"staircases(2)"<cds>, etc. Each trial can only be in (or associated with) one staircase. Tip: If you have an index in a numeric variable you can use it in an <cds>"x"<cds> string (but not an <cds>'x'<cds> string) like this: <cds>"pictures("<cds><cd> + n + <cd><cds>")"<cds>. See link above for staircase objects.

Input properties all objects have

report
info

Record properties

PsychBench uses record properties to record information during experiments. You can't set record properties but you can see them in experiment results by listing them input property report.

n_def
n

n_def is trial definition number/label. This is before any order and repetition if you use the command setTrialList. By default PsychBench numbers trial definitions 1, 2, 3, … as addTrial is called in the experiment script. You can also use custom numbers or strings (see addTrial function help).

n is trial run number during the experiment.

preTrialInterval_r
preTrialHeadroom

preTrialInterval_r records time from previous trial end to this trial start (sec). Note this property records the actual interval during the experiment—to set interval, use input property preTrialInterval above.

preTrialHeadroom is time left in the set pre-trial interval when PsychBench completed the processing it needed to do between the trials (sec). < 0 means preTrialInterval was set too short and the interval extended.

startTime
endTime
duration

startTime and endTime record start/end times relative to trial 1 start (sec). These = offset of inter-trial interval at trial start and onset of inter-trial interval at trial end, both at screen refresh. If the trial starts/ends with visual stimuli, these also = those stimulus onset/offset times.

duration records end time − start time.

frameRates
frameIntervals

frameRates is a row vector recording instantaneous frame rates across all frames in the trial, indexed by frame number. At each frame, the frame rate is calculated as 1 / frame interval (frame/sec).

frameIntervals is the corresponding row vector of all frame durations (sec).

frameRates can be used to get a sense of the actual frame rates achieved during the trial, which nominally = screen refresh rate (screen object record properties refreshRate, refreshInterval) but can be lower when frames are dropped due to processing load. Additionally, both properties can be used with element record properties n_startFrame and n_endFrame—for example, you can check if a dropped frame delayed an element start by checking for decreased rate or increased interval at the frame before n_startFrame. For more information on frames see Timing precision.