In parallel mode
, it is possible to use looptick functions. Looptick functions will be put in a while-loop running at a client
. The advantage of looptick functions is that the behavior of the loop can be modified from the BrainStream side.
Defining looptick functions
Structure of looptick functions
The figure below gives a schematic overview of a looptick function:
A looptick function always has the input arguments tick_count and abort_loop. The tick_count variable is automatically increased by one each time the looptick function is called.
A looptick function should always produce the output arguments stoploop and waittime. If stoploop is set to 1, the loop will be finalized. If stoploop is set to 0, the looptick function will be called again. The waittime variable specifies the time in seconds until the next looptick call. For example, if you want to have an interval of 200 ms between successive calls to the looptick function, you must set the waittime variable to 0.2.
All calls to the looptick function belong to the same event. Thus, information can be passed between different calls to the looptick functions via the event structure. For example, your looptick function might present a sequence of stimuli to the subject. If you want to pass the last presented stimuli to the next call of the looptick function, you could make a field event.laststim and place your last stimulus in this field every time the looptick function is called. During the next call, the information can be retrieved from this event field.
Format of looptick functions
Looptick functions should have the following format:
function [event, stoploop, waittime] = looptickfunction(event, tick_count, abort_loop)
stoploop = 0;
waittime = 0;
if tick_count == 1
% do initializations before the loop starts
if dosomething % add your own expression to determine moment of action
% do it
% set waittime > 0 if next looptick call can be delayed
% set stoploop = 1 if you want to stop the loop
% finalize stuff before BrainStream forces the loop to exit
In addition to tick_count, looptick functions have another input parameter: abort_loop. If an error occurs in BrainStream while a looptick function is running, BrainStream will set the abort_loop parameter to 1 the next time the looptick function is called. This call to the looptick function will be the last one. When it is finished, BrainStream will force the loop to end and close the client. Therefore, you can define actions for the abort_loop parameter to finalize your looptick function. For example, you may want to close or save objects which would otherwise be lost.
Specifying looptick functions in the Actions table
In order to specify a looptick function in the experiment definition table, you must add a column with header 'looptick'. In this column, one function can be specified. Defining a second looptick function for one marker will produce an error. In the client column, specify on which client the looptick function should run. If the function column defines functions as well, they will be executed prior to entering the loop.
Below an example Actions table is shown:
When marker mrk1 arrives, first functions fnc1 and fnc2 will be executed on client 'stim'. When these functions have finished, looptick function my_looptick will be called. It will keep running on the client until the loop is finished or BrainStream aborts the loop.
Modifying the loop
Information from the BrainStream side can be sent to clients to influence the behavior of looptick functions. In the BrainStream Matlab session, you can execute the function
success = bs_send_user_client(event, client_nickname, uservars)
event = event structure
client_nickname = name of the client as specified in block file
uservars = variables to be sent
success = whether variables were sent successfully
On the client side, the user variables that were sent from BrainStream can be received with the function
varargout = bs_recv_user_brainstream(event, client_nickname)
So, you can start each call to the looptick function with checking if there is new information from the BrainStream side. This way, stimulus presentation can adapt itself to the current classified results. For example, your classification function (running on the BrainStream side) might send information about which stimulus a subject is attending to. The looptick function might respond to it by shortening, changing or even end the stimulus presentation sequence. In the latter case, the stoploop variable can be set to 1 and the looptick function will end. In this way, actions at a client can be influenced by information from the BrainStream side.
An example of a looptick function is described in Part 5
of the Visual Speller example.