BpodTrialManager()

Former Syntax: TrialManagerObject()

Description

In earlier releases of Bpod, the function RunStateMachine() was necessary to run each trial. RunStateMachine() blocks the MATLAB command line for the entire trial, so MATLAB cannot use in-trial time to prepare the next trial's state machine, update online plots or save data. MATLAB must do these things between trials, resulting in a "dead-time" period where the state machine is not recording events or controlling the environment. When MATLAB-side code is efficient, this dead-time is often acceptable - the example protocols included with Bpod have ~15ms of dead time on a modern processor, which occurs during the subject's motion to initiate the next trial. However if your protocol requires complex online analysis or other time-costly computer-side processing, the BpodTrialManager class provides a way for most of this processing to occur in parallel with the trial.

A few points to consider before using TrialManager:

    • Because the state machine uses a single-core Arduino processor, a small dead-time is still necessary for inter-trial data transmission. This dead time is on the order of 200 microseconds, and depends on how many states and state transitions are defined in the next trial.

    • With TrialManager, the code for an experimental protocol becomes slightly more complicated (e.g. this versus this).

    • Because TrialManager requires Bpod's governing computer to multitask instead of simply checking for incoming bytes in a loop, the computer may process soft codes with increased latency and jitter.

NOTE: Protocols based on both RunStateMachine() and BpodTrialManager() will be supported for the indefinite future.

In your protocol, create a TrialManager object with the following syntax:

TrialManager = BpodTrialManager;

Object Fields

    • Timer

      • A MATLAB timer object, used to scan for incoming bytes from the state machine.

      • By default, the timer runs at 1kHz.

Object Functions

  • startTrial(StateMatrix)

    • Sends the next trial's state matrix to the Bpod state machine device, and immediately begins running the trial.

    • StateMatrix = a valid state machine definition, created with AddState().

      • This function is non-blocking; after state matrix transmission is complete, MATLAB executes the next line of code in your protocol, while the trial proceeds in parallel.

      • In the background, a call to startTrial starts TrialManager's MATLAB timer, which checks constantly for new incoming bytes from the state machine.

  • currentTrialEvents = getCurrentEvents(TriggerStates)

      • This is an optional function that stalls MATLAB until a specified trigger state is reached, and then returns all states visited and events captured up to that point in the trial. This can be useful for computing the next trial's state machine while the current trial is still running in an adaptive task (e.g. a task with an anti-bias algorithm).

    • TriggerStates = a cell array of strings specifying the names of trigger states, any of which will trigger the current states and events to be returned.

    • currentTrialEvents is a struct with 3 fields:

      • StatesVisited = cell array of strings listing names of states visited, in order of their occurrence

      • EventsCaptured = cell array of strings listing names of events captured, in order of their occurence

      • RawData = a struct with numerical codes for the states visited and events captured

  • RawEvents = getTrialData()

    • This function stalls until the trial is complete, then retrieves the trial data.

      • It should be called after the next trial's state machine is computed and sent, plots are updated, and data is saved.

    • RawEvents is a struct with raw trial data, formatted exactly like the output of RunStateMachine()

Cleanup

  • The TrialManager object and its associated timer object are cleared when you end the protocol.

Examples

1. An example visual 2AFC protocol using TrialManagerObject is included in /Examples/Protocols/Light/Light2AFC_TrialManager.

For comparison, /Light2AFC is an earlier protocol with ~identical functionality, programmed with RunStateMachine().

2. Template for simple protocol setup (the task does not use adaptive contingencies, so TrialManager.getCurrentEvents() is not used)

function myProtocol % Main protocol file, runs once when session is launched

global BpodSystem % Import the BpodSystem object (used here to detect when the user ends the protocol)

nTrials = 1000; % Number of trials in session

TrialManager = BpodTrialManager; % Create trial manager object

sma = prepareStateMachine; % Prepare first trial's state machine (see function below)

TrialManager.startTrial(sma); % Start first trial

for i = 1:nTrials

sma = prepareStateMachine; % Prepare next trial's state machine

RawEvents = TrialManager.getTrialData; % Hangs here until trial end, then returns the trial's raw data

% // Code to update Bpod modules with the next trial's parameters (if necessary) goes here.

if BpodSystem.Status.BeingUsed == 0; return; end % If user hit console "stop" button, end session

TrialManager.startTrial(sma); % Start next trial's state machine

% // Code to compute online behavior metrics goes here.

% // Code to update online plots goes here.

% // Code to format and save data goes here.

end

end

function sma = prepareStateMachine

sma = NewStateMatrix();

sma = AddState(sma, 'Name', 'MyRandomDelay', ...

'Timer', ceil(rand*1000)/1000,...

'StateChangeConditions', {'Tup', 'exit'},...

'OutputActions', {});

end