Changes

Jump to navigation Jump to search
no edit summary
Line 11: Line 11:  
== Building the experiment ==
 
== Building the experiment ==
   −
As described in the [.DocsSectionsBuildingExperiments Building Experiments] section, a number of files are needed to define an experiment. In the following, we will show how to create each of these files. If you want to have a look at the final result before reading this tutorial, the experiment file (.exp) for this example can be found in <tt>/brainstream_mds/examples/blocks/sentences/sentences.exp</tt>.
+
As described in the [[BrainStreamBuildingExperiments Building|Experiments]] section, a number of files are needed to define an experiment. In the following, we will show how to create each of these files. If you want to have a look at the final result before reading this tutorial, the experiment file (.exp) for this example can be found in <tt>/brainstream_mds/examples/blocks/sentences/sentences.exp</tt>.
    
<div id="BrainStream.[[DocsSectionsBlockFile]]"></div>
 
<div id="BrainStream.[[DocsSectionsBlockFile]]"></div>
 
=== Creating the block file ===
 
=== Creating the block file ===
   −
This experiment consists of only one block (sentences.blk). A number of settings are specified in the [.DocsSectionsBuildingExperiments#SecBlock block file]:
+
This experiment consists of only one block (sentences.blk). A number of settings are specified in the [[BrainStreamBuildingExperiments#SecBlock|block file]]:
 
<pre>[DataSources]
 
<pre>[DataSources]
 
eeg = 'simulate:biosemi_active2';
 
eeg = 'simulate:biosemi_active2';
    
[Files]
 
[Files]
[[ExperimentDefinitionFile|Experiment Definition File]] = 'sentences.edt';
+
ExperimentDefinitionFile = 'sentences.edt';
[[OutFolder|Out Folder]] = '../output/sentences/';
+
OutFolder = '../output/sentences/';
    
[Experiment]
 
[Experiment]
 
Block = 'sentences';
 
Block = 'sentences';
[[MatlabPathFnc|Matlab Path Fnc]] = [];
+
MatlabPathFnc|Matlab Path Fnc = [];
[[MatlabPathAdd|Matlab Path Add]] = {fullfile(bs_folder('BLOCK'),'..','common_functions'),bs_folder('BLOCK')};
+
MatlabPathAdd|Matlab Path Add = {fullfile(bs_folder('BLOCK'),'..','common_functions'),bs_folder('BLOCK')};
 
</pre>
 
</pre>
   −
You can look up the meaning of the topic and key combinations [.DocsSectionsBlockFile here].
+
You can look up the meaning of the topic and key combinations [[BrainStreamBlockFile|here]].
   −
Note that for the keys that specify folders, such as OutFolder and MatlabPathAdd, relative path names are specified. For more information about relative path names, click [.DocsSectionsPathsFolders#RelativePath here].
+
Note that for the keys that specify folders, such as OutFolder and MatlabPathAdd, relative path names are specified. For more information about relative path names, click [[BrainStreamPathsFolders#RelativePath|here]].
    
In addition to the standard topics and keys, we can specify our own settings in the block file. In this example, it would be useful to specify in the block file which sentences we want to show. We could for example define a key StimSequence under topic Experiment:
 
In addition to the standard topics and keys, we can specify our own settings in the block file. In this example, it would be useful to specify in the block file which sentences we want to show. We could for example define a key StimSequence under topic Experiment:
<pre>[Experiment]
+
<pre>
[[StimSequence|Stim Sequence]] = {'Making BCIs','is really fun!'};  
+
[Experiment]
 +
StimSequence = {'Making BCIs','is really fun!'};  
 
</pre>
 
</pre>
   −
The information specified in the block file can be retrieved during the experiment using the [.DocsSectionsProgrmmersGuide#GetBlockVal bs_get_blockvalue] function. In the next section we will show exactly how this works. The advantage of specifying the sentences in the block file is that we can use the same Actions table for displaying any sentence.
+
The information specified in the block file can be retrieved during the experiment using the [[BrainStreamProgrmmersGuide#GetBlockVal|bs_get_blockvalue]] function. In the next section we will show exactly how this works. The advantage of specifying the sentences in the block file is that we can use the same Actions table for displaying any sentence.
 
=== Creating the Actions Table ===
 
=== Creating the Actions Table ===
   Line 45: Line 46:  
# before each sequence, decide whether to start a new sequence or end the experiment
 
# before each sequence, decide whether to start a new sequence or end the experiment
 
# before each epoch, decide whether to start a new epoch or end the sequence
 
# before each epoch, decide whether to start a new epoch or end the sequence
We will write [.DocsSectionsBuildingExperiments#SecUserFun user defined functions] for making these decisions.
+
We will write [[BrainStreamBuildingExperiments#SecUserFun|user defined functions]] for making these decisions.
    
In order to be able to make each decision, we also need to:
 
In order to be able to make each decision, we also need to:
Line 53: Line 54:  
# within each sequence, keep track of how many epochs we have shown so far
 
# within each sequence, keep track of how many epochs we have shown so far
   −
We will make use of [.DocsSectionsBuildingExperiments#SecUserFun user defined variables] for these tasks.
+
We will make use of [[BrainStreamBuildingExperiments#SecUserFun|user defined variables]] for these tasks.
   −
The [.DocsSectionsBuildingExperiments#SecActions Actions table] has three standard columns ''marker, time'' and ''function''. In addition, we will add three columns for our user defined variables. The first user variable, ''stimsequence'', will contain the sequences that we want to show. The second user variable,<em> sequence_count</em>, will keep track of the number of sequences that have been shown already. The third user variable, ''epoch_count'', will keep track how many epochs of a sequence have been shown already. These are the columns of the Actions table:
+
The [[BrainStreamBuildingExperiments#SecActions|Actions table]] has three standard columns ''marker, time'' and ''function''. In addition, we will add three columns for our user defined variables. The first user variable, ''stimsequence'', will contain the sequences that we want to show. The second user variable,<em> sequence_count</em>, will keep track of the number of sequences that have been shown already. The third user variable, ''epoch_count'', will keep track how many epochs of a sequence have been shown already. These are the columns of the Actions table:
{| border="1"
+
{| class="wikitable"
 
|-
 
|-
 
| '''marker''' || '''time''' || '''function''' || '''stimsequence''' || '''sequence_count''' || '''epoch_count'''  
 
| '''marker''' || '''time''' || '''function''' || '''stimsequence''' || '''sequence_count''' || '''epoch_count'''  
 
|-
 
|-
 
| || | || | ||  
 
| || | || | ||  
   
|}
 
|}
   Line 70: Line 70:  
|-
 
|-
 
| BS_INIT || EVENT || | [] || 0 || []  
 
| BS_INIT || EVENT || | [] || 0 || []  
   
|}
 
|}
   −
Information specified in the block file can be retrieved during the experiment using the [.DocsSectionsProgrmmersGuide#GetBlockVal bs_get_blockvalue] function. At the BS_INIT marker, we will insert the marker init_sequence. As this marker does not need to be accurately synchronized with the data, we insert this marker [.DocsSectionsMarkerHandling#BufferMarker via the !FieldTrip buffer]. When the init_sequence marker arrives, we will execute a user defined function <tt>initSequence</tt> to retrieve the content of ''stimsequence'' from the block file and place it in the [.DocsSectionsImportantConcepts#SecVariables global variables].
+
Information specified in the block file can be retrieved during the experiment using the [[BrainStreamProgrmmersGuide#GetBlockVal|bs_get_blockvalue]] function. At the BS_INIT marker, we will insert the marker init_sequence. As this marker does not need to be accurately synchronized with the data, we insert this marker [[BrainStreamMarkerHandling#BufferMarker|via the FieldTrip buffer]]. When the init_sequence marker arrives, we will execute a user defined function <tt>initSequence</tt> to retrieve the content of ''stimsequence'' from the block file and place it in the [[BrainStreamImportantConcepts#SecVariables|global variables]].
{| border="1"
+
{| class="wikitable"
 
|-
 
|-
 
| '''<strong>marker</strong>''' || '''<strong>time</strong>''' || '''<strong>function</strong>''' || '''<strong>stimsequence</strong>''' || '''<strong>sequence_count</strong>''' || '''<strong>epoch_count</strong>'''  
 
| '''<strong>marker</strong>''' || '''<strong>time</strong>''' || '''<strong>function</strong>''' || '''<strong>stimsequence</strong>''' || '''<strong>sequence_count</strong>''' || '''<strong>epoch_count</strong>'''  
Line 81: Line 80:  
|-
 
|-
 
| <strong>init_sequence <br /></strong> || <strong>EVENT <br /></strong> || <strong>initSequence <br /></strong> || <strong>put </strong> || |  
 
| <strong>init_sequence <br /></strong> || <strong>EVENT <br /></strong> || <strong>initSequence <br /></strong> || <strong>put </strong> || |  
   
|}
 
|}
   Line 92: Line 90:     
Now we can proceed to the next step in the flowchart, the point where we need to decide whether to start a new sequence. Using the bs_send_buffer_marker function, we will insert a marker next_sequence to begin this next stage of the experiment. When this marker comes in, first the sequence counter must be increased by 1:
 
Now we can proceed to the next step in the flowchart, the point where we need to decide whether to start a new sequence. Using the bs_send_buffer_marker function, we will insert a marker next_sequence to begin this next stage of the experiment. When this marker comes in, first the sequence counter must be increased by 1:
{| border="1"
+
{| class="wikitable"
 
|-
 
|-
 
| '''<strong>marker</strong>''' || '''<strong>time</strong>''' || '''<strong>function</strong>''' || '''<strong>stimsequence</strong>''' || '''<strong>sequence_count</strong>''' || '''<strong>epoch_count</strong>'''  
 
| '''<strong>marker</strong>''' || '''<strong>time</strong>''' || '''<strong>function</strong>''' || '''<strong>stimsequence</strong>''' || '''<strong>sequence_count</strong>''' || '''<strong>epoch_count</strong>'''  
Line 98: Line 96:  
| BS_INIT || EVENT || bs_send_buffer_marker('init_sequence','eeg',0,'now') || [] || 0 || []  
 
| BS_INIT || EVENT || bs_send_buffer_marker('init_sequence','eeg',0,'now') || [] || 0 || []  
 
|-
 
|-
| init_sequence || EVENT || initSequence || put || |  
+
| init_sequence || EVENT || initSequence || put || ||  
 
|-
 
|-
| || | <strong>bs_send_buffer_marker('next_sequence','eeg',0,'now')</strong> || | ||  
+
| || || <strong>bs_send_buffer_marker('next_sequence','eeg',0,'now')</strong> || || ||  
 
|-
 
|-
| <strong>next_sequence</strong> || <strong>EVENT</strong> || | || <strong>$self+1</strong> ||  
+
| <strong>next_sequence</strong> || <strong>EVENT</strong> || || || <strong>$self+1</strong> ||  
    
|}
 
|}
    
Subsequently, we need to write a function that uses the content of ''stimsequence'' and the current value of ''sequence_count'' to decide whether to start a new sequence. We will call this function <tt>nextSequence</tt>. Because the function needs the content of two of our variables as input, we must specify get statements for these variables.
 
Subsequently, we need to write a function that uses the content of ''stimsequence'' and the current value of ''sequence_count'' to decide whether to start a new sequence. We will call this function <tt>nextSequence</tt>. Because the function needs the content of two of our variables as input, we must specify get statements for these variables.
{| border="1"
+
{| class="wikitable"
 
|-
 
|-
 
| '''<strong>marker</strong>''' || '''<strong>time</strong>''' || '''<strong>function</strong>''' || '''<strong>stimsequence</strong>''' || '''<strong>sequence_count</strong>''' || '''<strong>epoch_count</strong>'''  
 
| '''<strong>marker</strong>''' || '''<strong>time</strong>''' || '''<strong>function</strong>''' || '''<strong>stimsequence</strong>''' || '''<strong>sequence_count</strong>''' || '''<strong>epoch_count</strong>'''  
Line 113: Line 111:  
| BS_INIT || EVENT || bs_send_buffer_marker('init_sequence','eeg',0,'now') || [] || 0 || []  
 
| BS_INIT || EVENT || bs_send_buffer_marker('init_sequence','eeg',0,'now') || [] || 0 || []  
 
|-
 
|-
| init_sequence || EVENT || initSequence || put || |  
+
| init_sequence || EVENT || initSequence || put || ||  
 
|-
 
|-
| || | bs_send_buffer_marker('next_sequence','eeg',0,'now') || | ||  
+
| || || bs_send_buffer_marker('next_sequence','eeg',0,'now') || || ||  
 
|-
 
|-
 
| next_sequence || EVENT || <strong>nextSequence</strong> || <strong>get</strong> || $self+1, <strong>get</strong> ||  
 
| next_sequence || EVENT || <strong>nextSequence</strong> || <strong>get</strong> || $self+1, <strong>get</strong> ||  
Line 140: Line 138:  
| init_sequence || EVENT || initSequence || put || |  
 
| init_sequence || EVENT || initSequence || put || |  
 
|-
 
|-
| || | bs_send_buffer_marker('next_sequence','eeg',0,'now') || | ||  
+
| || || bs_send_buffer_marker('next_sequence','eeg',0,'now') || || ||  
 
|-
 
|-
 
| next_sequence || EVENT || nextSequence || get || $self+1, get ||  
 
| next_sequence || EVENT || nextSequence || get || $self+1, get ||  
Line 146: Line 144:  
| <strong>start_sequence</strong> || <strong>button_1</strong> || <strong>displayString('')</strong> || <strong>get</strong> || <strong>get</strong> || <strong>0</strong>  
 
| <strong>start_sequence</strong> || <strong>button_1</strong> || <strong>displayString('')</strong> || <strong>get</strong> || <strong>get</strong> || <strong>0</strong>  
 
|-
 
|-
| || | <strong>bs_send_buffer_marker('next_epoch','eeg',0,'now')</strong> || | ||  
+
| || || <strong>bs_send_buffer_marker('next_epoch','eeg',0,'now')</strong> || || ||  
    
|}
 
|}
Line 159: Line 157:  
| init_sequence || EVENT || initSequence || put || |  
 
| init_sequence || EVENT || initSequence || put || |  
 
|-
 
|-
| || | bs_send_buffer_marker('next_sequence','eeg',0,'now') || | ||  
+
| || || bs_send_buffer_marker('next_sequence','eeg',0,'now') || || ||  
 
|-
 
|-
 
| next_sequence || EVENT || nextSequence || get || $self+1, get ||  
 
| next_sequence || EVENT || nextSequence || get || $self+1, get ||  
Line 165: Line 163:  
| start_sequence || button_1 || displayString('') || get || get || 0  
 
| start_sequence || button_1 || displayString('') || get || get || 0  
 
|-
 
|-
| || | bs_send_buffer_marker('next_epoch','eeg',0,'now') || | ||  
+
| || || bs_send_buffer_marker('next_epoch','eeg',0,'now') || | ||  
 
|-
 
|-
 
| <strong>next_epoch</strong> || <strong>EVENT</strong> || <strong>nextEpoch</strong> || <strong>get</strong> || <strong>get</strong> || <strong>$self+1, get</strong>  
 
| <strong>next_epoch</strong> || <strong>EVENT</strong> || <strong>nextEpoch</strong> || <strong>get</strong> || <strong>get</strong> || <strong>$self+1, get</strong>  
Line 179: Line 177:  
     event = bs_send_buffer_marker(event,'end_sequence','eeg',0,'now');            % end the sequence
 
     event = bs_send_buffer_marker(event,'end_sequence','eeg',0,'now');            % end the sequence
 
end  
 
end  
</pre>If the outcome of the decision is that another character should be displayed, the marker proc_epoch will be inserted. As we want to use this marker for data selection (see [.DocsSectionsExampleSentences#DataSelection next section]), accurate synchronization between marker and data is required. Therefore, we will insert this marker [.DocsSectionsMarkerHandling#HardwareMarker via the hardware]. When this marker arrives, the displayString function will be used to show the current character. After this has been done, we insert the next_epoch marker and thereby return to the question whether to start another epoch. The next_epoch marker is inserted 0.25 seconds after the bs_send_buffer_marker function is called. As a result, there is a pause of approximately 0.25 seconds between the appearance of each character on the screen.
+
</pre>If the outcome of the decision is that another character should be displayed, the marker proc_epoch will be inserted. As we want to use this marker for data selection (see [[BrainStreamExampleSentences#DataSelection|next section]), accurate synchronization between marker and data is required. Therefore, we will insert this marker [[BrainStreamMarkerHandling#HardwareMarker|via the hardware]. When this marker arrives, the displayString function will be used to show the current character. After this has been done, we insert the next_epoch marker and thereby return to the question whether to start another epoch. The next_epoch marker is inserted 0.25 seconds after the bs_send_buffer_marker function is called. As a result, there is a pause of approximately 0.25 seconds between the appearance of each character on the screen.
    
{| border="1"
 
{| border="1"
Line 189: Line 187:  
| init_sequence || EVENT || initSequence || put || |  
 
| init_sequence || EVENT || initSequence || put || |  
 
|-
 
|-
| || | bs_send_buffer_marker('next_sequence','eeg',0,'now') || | ||  
+
| || || bs_send_buffer_marker('next_sequence','eeg',0,'now') || || ||  
 
|-
 
|-
 
| next_sequence || EVENT || nextSequence || get || $self+1, get ||  
 
| next_sequence || EVENT || nextSequence || get || $self+1, get ||  
Line 195: Line 193:  
| start_sequence || button_1 || displayString('') || get || get || 0  
 
| start_sequence || button_1 || displayString('') || get || get || 0  
 
|-
 
|-
| || | bs_send_buffer_marker('next_epoch','eeg',0,'now') || | ||  
+
| || || bs_send_buffer_marker('next_epoch','eeg',0,'now') || || ||  
 
|-
 
|-
 
| next_epoch || EVENT || nextEpoch || get || get || $self+1, get  
 
| next_epoch || EVENT || nextEpoch || get || get || $self+1, get  
 
|-
 
|-
| <strong>proc_epoch</strong> || <strong>EVENT</strong> || <strong>displayString()</strong> || | ||  
+
| <strong>proc_epoch</strong> || <strong>EVENT</strong> || <strong>displayString()</strong> || || ||  
 
|-
 
|-
| || | <strong>bs_send_buffer_marker('next_epoch','eeg',0.25,'now')</strong> || | ||  
+
| || || <strong>bs_send_buffer_marker('next_epoch','eeg',0.25,'now')</strong> || || ||  
    
|}
 
|}

Navigation menu