Difference: DocsSectionsExampleSentences (1 vs. 10)

Revision 1018 Nov 2011 - Main.MarjoleinVanDerWaal

Line: 1 to 1
 
META TOPICPARENT name="WebHome"
<---Start1--->

Example 1: Sentences

Line: 34 to 34
 MatlabPathAdd? = {fullfile(bs_folder('BLOCK'),'..','common_functions'),bs_folder('BLOCK')};
Changed:
<
<
You can look up the meaning of the topic and key combinations here? .
>
>
You can look up the meaning of the topic and key combinations 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 here.

Revision 914 Nov 2011 - Main.MarjoleinVanDerWaal

Line: 1 to 1
Changed:
<
<
META TOPICPARENT name="BrainStreamDocs"
>
>
META TOPICPARENT name="WebHome"
 
<---Start1--->

Example 1: Sentences

Changed:
<
<
Generate current PDF
>
>
Generate current PDF
 

Experiment description

Line: 17 to 17
  As described in the 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 /brainstream_mds/examples/blocks/sentences/sentences.exp.
Changed:
<
<
>
>
.BrainStreamDocs.DocsSectionsBlockFile
 

Creating the block file

This experiment consists of only one block (sentences.blk). A number of settings are specified in the block file:

Line: 180 to 180
 
marker begintime endtime datasource
proc_epoch 0 1 eeg
Changed:
<
<
In this experiment, the fourth column datasource is not absolutely necessary. As only one data source (simulated EEG data, see blocksettings) is used, BrainStream will automatically apply all data selection settings to this data source.
>
>
In this experiment, the fourth column datasource is not absolutely necessary. As only one data source (simulated EEG data, see blocksettings? ) is used, BrainStream will automatically apply all data selection settings to this data source.
 

Creating the Dictionary table

The Dictionary table specifies a marker number for each marker that is used in this experiment. The Dictionary table looks like this:

Line: 193 to 193
 
end_sequence stimulus 6 eeg
button_1 stimulus 7 eeg
Changed:
<
<
In this experiment, the fourth column datasource is not absolutely necessary. As only one data source (simulated EEG data, see blocksettings) is used, BrainStream will automatically apply all marker settings to this data source.
>
>
In this experiment, the fourth column datasource is not absolutely necessary. As only one data source (simulated EEG data, see blocksettings? ) is used, BrainStream will automatically apply all marker settings to this data source.
 

Testing the experiment

The easiest way to create all files that define this experiment is via the BrainStream editor. You can open the editor by typing bs_editor in the Matlab command window (make sure that brainstream_mds/core is your current working directory). An experiment file (.exp) has already been created for this example experiment and is located in /brainstream_mds/examples/blocks/sentences/sentences.exp. If you open this file in the BrainStream editor, the experiment looks like this:

Line: 214 to 214
 
META FILEATTACHMENT attachment="BS_Editor.png" attr="" comment="" date="1318927625" name="BS_Editor.png" path="BS_Editor.png" size="277868" stream="BS_Editor.png" tmpFilename="/var/tmp/CGItemp45754" user="MarjoleinVanDerWaal" version="3"
META FILEATTACHMENT attachment="Flowchart.png" attr="" comment="" date="1318923483" name="Flowchart.png" path="Flowchart.png" size="139304" stream="Flowchart.png" tmpFilename="/var/tmp/CGItemp45485" user="MarjoleinVanDerWaal" version="4"
META FILEATTACHMENT attachment="BS_editor.png" attr="" comment="" date="1320834915" name="BS_editor.png" path="BS_editor.png" size="263426" stream="BS_editor.png" tmpFilename="/var/tmp/CGItemp58056" user="MarjoleinVanDerWaal" version="1"
Added:
>
>
META TOPICMOVED by="MarjoleinVanDerWaal" date="1321267137" from="BrainStream.DocsSectionsExampleSentences" to="BrainStreamDocs.DocsSectionsExampleSentences"

Revision 809 Nov 2011 - Main.MarjoleinVanDerWaal

Line: 1 to 1
 
META TOPICPARENT name="BrainStreamDocs"
<---Start1--->

Example 1: Sentences

Deleted:
<
<
(Under construction)
 Generate current PDF
Line: 38 to 36
  You can look up the meaning of the topic and key combinations here? .
Changed:
<
<
Note that for the keys that specify folders, such as OutFolder and MatlabPathAdd, relative path names are specified. The command bs_folder('BLOCK') finds the path to the current block file (which in this case is /brainstream_mds/examples/blocks/sentences/). The other folders are specified relative to this folder, for example the output folder is located in /brainstream_mds/examples/blocks/output/sentences. It is recommended to always use relative path names, as this ensures that the proper paths will be added on any computer you run your experiment on.
>
>
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 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:
[Experiment]

Revision 709 Nov 2011 - Main.MarjoleinVanDerWaal

Line: 1 to 1
 
META TOPICPARENT name="BrainStreamDocs"
<---Start1--->

Example 1: Sentences

Line: 69 to 69
 
marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT   [] 0 []
Changed:
<
<
Information specified in the block file can be retrieved during the experiment using the bs_get_blockvalue function. At the BS_INIT marker, we will insert the marker init_sequence via the FieldTrip buffer (for more information about inserting markers, click here). When this marker arrives, we will execute a user defined function initSequence to retrieve the content of stimsequence from the block file and place it in the global variables.
>
>
Information specified in the block file can be retrieved during the experiment using the 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 via the FieldTrip buffer. When the init_sequence marker arrives, we will execute a user defined function initSequence to retrieve the content of stimsequence from the block file and place it in the global variables.
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
>
>
BS_INIT EVENT bs_send_buffer_marker('init_sequence','eeg',0,'now')
[] 0 []
 
init_sequence
EVENT
initSequence
put    

This is the initSequence function:

Line: 81 to 81
  The bs_get_blockvalue function will get the content specified under topic Experiment and key StimSequence and will use the default sentences 'Making BCIs' and 'is fun!' if no specification is found in the block file. The value that is retrieved from the block file will be placed in the field event.stimsequence. Because a put statement is specified for this variable in the Actions table, this new content will be updated to the global variables from where it can be accessed later in the experiment .
Changed:
<
<
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_insert_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:
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
>
>
BS_INIT EVENT bs_send_buffer_marker('init_sequence','eeg',0,'now') [] 0 []
 
init_sequence EVENT initSequence put    
Changed:
<
<
    bs_insert_marker('next_sequence',0)      
>
>
    bs_send_buffer_marker('next_sequence','eeg',0,'now')      
 
next_sequence EVENT     $self+1  

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 nextSequence. Because the function needs the content of two of our variables as input, we must specify get statements for these variables.

marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
>
>
BS_INIT EVENT bs_send_buffer_marker('init_sequence','eeg',0,'now') [] 0 []
 
init_sequence EVENT initSequence put    
Changed:
<
<
    bs_insert_marker('next_sequence',0)      
>
>
    bs_send_buffer_marker('next_sequence','eeg',0,'now')      
 
next_sequence EVENT nextSequence get $self+1, get  

This is function nextSequence:

function event = nextSequence(event)
if event.sequence_count <= numel(event.stimsequence)            % if sequence_count <= number of sequences
    event = displayIt(event,'string','Press button_1 (<ctrl>-b) to start sequence',[1 0 0]); % display instruction to press button
Changed:
<
<
event = bs_insert_marker(event,'start_sequence',0); % start this sequence
>
>
event = bs_send_buffer_marker(event,'start_sequence','eeg',0,'now'); % start this sequence
 else % all sequences processed
Changed:
<
<
event = bs_insert_marker(event,'BS_EXIT',0); % exit block (insert BS_EXIT marker) end The first input argument of a user defined function is always event. The content of variables for which a get statement is specified, is copied into fields of the event structure. Thus, event.stimsequence contains the content of stimsequence and event.sequence_count contains the content of sequence_count.
>
>
event = bs_send_buffer_marker(event,'BS_EXIT','eeg',0,'now'); % exit block (insert BS_EXIT marker) end The first input argument of a user defined function is always event. The content of variables for which a get statement is specified, is copied into fields of the event structure. Thus, event.stimsequence contains the content of stimsequence and event.sequence_count contains the content of sequence_count.
  If the outcome of the decision is that another sequence should be displayed, the marker start_sequence will be inserted. At the start of a new sequence, the variable epoch_count must be set to 0. Then BrainStream must wait for a button press from the participant, which is achieved by specifying timepoint 'button_1' for this event. The displaying of the characters is handled by the function displayString. This function will not be discussed in detail, but it is important to know that it requires the content of the variables stimsequence and sequence_count. Therefore, get statements must be specified for these variables. Now we have reached the next decision point in the experiment flowchart, where we need to decide whether to start a new epoch or end the sequence. We will insert marker next_epoch to trigger this decision making step.
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
>
>
BS_INIT EVENT bs_send_buffer_marker('init_sequence','eeg',0,'now') [] 0 []
 
init_sequence EVENT initSequence put    
Changed:
<
<
    bs_insert_marker('next_sequence',0)      
>
>
    bs_send_buffer_marker('next_sequence','eeg',0,'now')      
 
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
Changed:
<
<
    bs_insert_marker('next_epoch',0)      
>
>
    bs_send_buffer_marker('next_epoch','eeg',0,'now')      
  When the next_epoch marker comes in, first the epoch counter must be increased by 1. Subsequently, we need to write a function that uses the content of stimsequence and the current values of sequence_count and epoch_count to decide whether to start a new epoch. We will call this function nextEpoch. Because the function needs the content of all our variables as input, we must specify get statements for these variables. The Actions table now looks like this:
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
>
>
BS_INIT EVENT bs_send_buffer_marker('init_sequence','eeg',0,'now') [] 0 []
 
init_sequence EVENT initSequence put    
Changed:
<
<
    bs_insert_marker('next_sequence',0)      
>
>
    bs_send_buffer_marker('next_sequence','eeg',0,'now')      
 
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
Changed:
<
<
    bs_insert_marker('next_epoch',0)      
>
>
    bs_send_buffer_marker('next_epoch','eeg',0,'now')      
 
next_epoch EVENT nextEpoch get get $self+1, get

This is function nextEpoch:

function event = nextEpoch(event)
if event.epoch_count <= numel(event.stimsequence{event.sequence_count})            % if epoch_count <= number of epochs in this sentence
    event.character = event.stimsequence{event.sequence_count}(event.epoch_count); % this line is required for displayString function - ignore
Changed:
<
<
event = bs_insert_marker(event,'proc_epoch',0); % insert marker to process this epoch
>
>
event = bs_send_hardware_marker(event,'proc_epoch','eeg'); % insert marker to process this epoch
 else % all characters processed
Changed:
<
<
event = bs_insert_marker(event,'end_sequence',0); % end the sequence
>
>
event = bs_send_buffer_marker(event,'end_sequence','eeg',0,'now'); % end the sequence
 end
Changed:
<
<
If the outcome of the decision is that another character should be displayed, the marker proc_epoch will be inserted. 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 arrival of marker proc_epoch. As a result, there is a pause of 0.25 seconds between the appearance of each character on the screen.
>
>
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 next section), accurate synchronization between marker and data is required. Therefore, we will insert this marker 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.
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
>
>
BS_INIT EVENT bs_send_buffer_marker('init_sequence','eeg',0,'now') [] 0 []
 
init_sequence EVENT initSequence put    
Changed:
<
<
    bs_insert_marker('next_sequence',0)      
>
>
    bs_send_buffer_marker('next_sequence','eeg',0,'now')      
 
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
Changed:
<
<
    bs_insert_marker('next_epoch',0)      
>
>
    bs_send_buffer_marker('next_epoch','eeg',0,'now')      
 
next_epoch EVENT nextEpoch get get $self+1, get
proc_epoch EVENT displayString()      
Changed:
<
<
    bs_insert_marker(next_epoch,0.25)      
end_sequence EVENT bs_insert_marker('next_sequence',1)      
>
>
    bs_send_buffer_marker('next_epoch','eeg',0.25,'now')      
 
Changed:
<
<
When all epochs of a sequence have been processed, the nextEpoch function will insert the end_sequence marker. When this marker arrives, BrainStream inserts the next_sequence marker, thereby returning to the question whether to start another sequence. The next_sequence marker is inserted 1 second after arrival of marker end_sequence. As a result, there is a pause of 1 second between each sequence. The Actions table now contains all the necessary steps of the experiment.
>
>
When all epochs of a sequence have been processed, the nextEpoch function will insert the end_sequence marker. When this marker arrives, we immediately insert the next_sequence marker, thereby returning to the question whether to start another sequence. The next_sequence marker is inserted 1 second after the bs_send_buffer_marker function is called. As a result, there is a pause of approximately 1 second between each sequence. The Actions table now contains all the necessary steps of the experiment.
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
>
>
BS_INIT EVENT bs_send_buffer_marker('init_sequence','eeg',0,'now') [] 0 []
 
init_sequence EVENT initSequence put    
Changed:
<
<
    bs_insert_marker('next_sequence',0)      
>
>
    bs_send_buffer_marker('next_sequence','eeg',0,'now')      
 
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
Changed:
<
<
    bs_insert_marker('next_epoch',0)      
>
>
    bs_send_buffer_marker('next_epoch','eeg',0,'now')      
 
next_epoch EVENT nextEpoch get get $self+1, get
proc_epoch EVENT displayString()      
Changed:
<
<
    bs_insert_marker(next_epoch,0.25)      
end_sequence EVENT bs_insert_marker('next_sequence',1)      
>
>
    bs_send_buffer_marker('next_epoch','eeg',0.25,'now')      
end_sequence EVENT bs_send_buffer_marker('next_sequence','eeg',1,'now')      
 
Added:
>
>
 

Specifying Data Selection

For BCI applications, you will often want to collect data associated with stimuli. In this example, you might want to collect one second of EEG data every time a new character appears on the screen. In your Actions table, you must specify at which marker you want to collect data. In a DataSelection table, you must specify exactly how much data you want to select and from which data source.

Line: 165 to 166
 New epochs are started by the proc_epoch marker. We will therefore use this marker to trigger data selection. For now, we will only print the message 'Process the data' in the Matlab command window every time data is collected. However, instead of showing a simple message you could also write functions to actually process the data. This is the new Actions table:

marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
>
>
BS_INIT EVENT bs_send_buffer_marker('init_sequence','eeg',0,'now') [] 0 []
 
init_sequence EVENT initSequence put    
Changed:
<
<
    bs_insert_marker('next_sequence',0)      
>
>
    bs_send_buffer_marker('next_sequence','eeg',0,'now')      
 
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
Changed:
<
<
    bs_insert_marker('next_epoch',0)      
>
>
    bs_send_buffer_marker('next_epoch','eeg',0,'now')      
 
next_epoch EVENT nextEpoch get get $self+1, get
proc_epoch EVENT displayString()      
Changed:
<
<
    bs_insert_marker(next_epoch,0.25)      
>
>
    bs_send_buffer_marker('next_epoch','eeg',0.25,'now')      
 
  DATA
bs_disp('Process the data')      
Changed:
<
<
end_sequence EVENT bs_insert_marker('next_sequence',1)      
>
>
end_sequence EVENT bs_send_buffer_marker('next_sequence','eeg',1,'now')      
  We also need a DataSelection table to specify the exact time window of data selection. If we want to record one second of data after the onset of each epoch, our DataSelection table looks like this:
marker begintime endtime datasource
Line: 199 to 200
  The easiest way to create all files that define this experiment is via the BrainStream editor. You can open the editor by typing bs_editor in the Matlab command window (make sure that brainstream_mds/core is your current working directory). An experiment file (.exp) has already been created for this example experiment and is located in /brainstream_mds/examples/blocks/sentences/sentences.exp. If you open this file in the BrainStream editor, the experiment looks like this:
Changed:
<
<
BS_Editor.png
>
>
BS_editor.png
  Figure 2: The Sentences Experiment in the BrainStream Editor
Line: 214 to 215
 
META FILEATTACHMENT attachment="BS_Editor.png" attr="" comment="" date="1318927625" name="BS_Editor.png" path="BS_Editor.png" size="277868" stream="BS_Editor.png" tmpFilename="/var/tmp/CGItemp45754" user="MarjoleinVanDerWaal" version="3"
META FILEATTACHMENT attachment="Flowchart.png" attr="" comment="" date="1318923483" name="Flowchart.png" path="Flowchart.png" size="139304" stream="Flowchart.png" tmpFilename="/var/tmp/CGItemp45485" user="MarjoleinVanDerWaal" version="4"
Added:
>
>
META FILEATTACHMENT attachment="BS_editor.png" attr="" comment="" date="1320834915" name="BS_editor.png" path="BS_editor.png" size="263426" stream="BS_editor.png" tmpFilename="/var/tmp/CGItemp58056" user="MarjoleinVanDerWaal" version="1"

Revision 604 Nov 2011 - Main.MarjoleinVanDerWaal

Line: 1 to 1
 
META TOPICPARENT name="BrainStreamDocs"
<---Start1--->

Example 1: Sentences

Line: 69 to 69
 
marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT   [] 0 []
Changed:
<
<
Information specified in the block file can be retrieved during the experiment using the bs_get_blockvalue function. At the BS_INIT marker, we will insert the marker init_sequence. When this marker arrives, we will execute a user defined function initSequence to retrieve the content of stimsequence from the block file and place it in the global variables.
>
>
Information specified in the block file can be retrieved during the experiment using the bs_get_blockvalue function. At the BS_INIT marker, we will insert the marker init_sequence via the FieldTrip buffer (for more information about inserting markers, click here). When this marker arrives, we will execute a user defined function initSequence to retrieve the content of stimsequence from the block file and place it in the global variables.
 
marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
init_sequence
EVENT
initSequence
put    

Revision 518 Oct 2011 - Main.MarjoleinVanDerWaal

Line: 1 to 1
 
META TOPICPARENT name="BrainStreamDocs"
<---Start1--->

Example 1: Sentences

Line: 8 to 8
 Generate current PDF
Added:
>
>

Experiment description

 
Changed:
<
<
This is an example of a very simple 'experiment' in which letters will appear on the screen one by one to form sentences. The appearance of an individual letter is called an epoch. A series of epochs that results in a sentence is called a sequence. Subjects can press a button when they are ready for the next sentence (sequence). A flowchart of the experiment is shown below:
>
>
This is an example of a very simple 'experiment' in which letters will appear on the screen one by one to form sentences. In this experiment, adding a new character to a string is called an epoch. A series of epochs that results in a complete sentence is called a sequence. Subjects can press a button when they are ready for the next sentence (sequence). A flowchart of the experiment is shown below:
 
Changed:
<
<
Flowchart.png
>
>
Flowchart.png
  Figure 1: Flowchart of the Sentences example experiment
Deleted:
<
<
As described in the 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 components. If you want to have a look at the final result, the experiment file (.exp) for this example can be found in /brainstream_mds/examples/blocks/sentences/sentences.exp.
 

Building the experiment

Changed:
<
<
The most striking characteristic of this experiment is that throughout the experiment we must often choose whether to continue or end the experiment. From the flowchart in figure 1, it can be seen that two types of decisions must be made:
>
>
As described in the 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 /brainstream_mds/examples/blocks/sentences/sentences.exp.

Creating the block file

This experiment consists of only one block (sentences.blk). A number of settings are specified in the block file:

[DataSources]
eeg = 'simulate:biosemi_active2';
 
[Files]
ExperimentDefinitionFile = 'sentences.edt';
OutFolder = '../output/sentences/';
 
[Experiment]
Block = 'sentences';
MatlabPathFnc = [];
MatlabPathAdd = {fullfile(bs_folder('BLOCK'),'..','common_functions'),bs_folder('BLOCK')};

You can look up the meaning of the topic and key combinations here? .

Note that for the keys that specify folders, such as OutFolder and MatlabPathAdd, relative path names are specified. The command bs_folder('BLOCK') finds the path to the current block file (which in this case is /brainstream_mds/examples/blocks/sentences/). The other folders are specified relative to this folder, for example the output folder is located in /brainstream_mds/examples/blocks/output/sentences. It is recommended to always use relative path names, as this ensures that the proper paths will be added on any computer you run your experiment on.

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:

[Experiment]
StimSequence = {'Making BCIs','is really fun!'}; 

The information specified in the block file can be retrieved during the experiment using the 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

The most striking characteristic of this experiment is the need for decision making throughout the experiment. From the flowchart in figure 1, it can be seen that two types of decisions must be made:

 
  1. before each sequence, decide whether to start a new sequence or end the experiment
  2. before each epoch, decide whether to start a new epoch or end the sequence
Changed:
<
<
We will write user defined functions in order to make these decisions.
>
>
We will write user defined functions for making these decisions.
  In order to be able to make each decision, we also need to:
  1. specify how many sequences need to be shown
Line: 31 to 61
  We will make use of user defined variables for these tasks.
Deleted:
<
<
In the next section, we will show how to create the user defined functions and variables and put them together in the Actions table.

Creating the Actions Table

 The 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, sequence_count, 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:
marker time function stimsequence sequence_count epoch_count
           
Changed:
<
<
We will initialize these variables at the beginning of the experiment. The easiest way to do this is to define the initialization actions at the BS_INIT marker, as this is always the first marker to arrive within an experiment. At the beginning of the experiment, the sequence counter will be set to 0. The epoch counter is initialized as empty and will be set to 0 at the beginning of each new sequence. The variable stimsequence must contain the sentences that will be shown. In this example, we will show two sentences: 'Making BCIs' and 'is really fun!'. For the moment, we will define these sentences in the Actions table, but later on we will show how to specify the sentences in the block files instead.
>
>
We will initialize these variables at the beginning of the experiment. It is usually good to define the initialization actions at the BS_INIT marker, as this is always the first marker to arrive within an experiment. At the beginning of the experiment, the sequence counter will be set to 0. The epoch counter is initialized as empty and will be set to 0 at the beginning of each new sequence. The variable stimsequence must contain the sentences that will be shown. We will initialize it as empty and retrieve its content from the block file in the next step.
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT   {'Making BCIs','is really fun!'} 0 []
>
>
BS_INIT EVENT   [] 0 []

Information specified in the block file can be retrieved during the experiment using the bs_get_blockvalue function. At the BS_INIT marker, we will insert the marker init_sequence. When this marker arrives, we will execute a user defined function initSequence to retrieve the content of stimsequence from the block file and place it in the global variables.

marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
init_sequence
EVENT
initSequence
put    

This is the initSequence function:

function event = initSequence(event)
event.stimsequence = bs_get_blockvalue('Experiment','StimSequence',{'Making BCIs','is fun!'});

The bs_get_blockvalue function will get the content specified under topic Experiment and key StimSequence and will use the default sentences 'Making BCIs' and 'is fun!' if no specification is found in the block file. The value that is retrieved from the block file will be placed in the field event.stimsequence. Because a put statement is specified for this variable in the Actions table, this new content will be updated to the global variables from where it can be accessed later in the experiment .

  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_insert_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:
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun!'} 0 []
>
>
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
init_sequence EVENT initSequence put    
    bs_insert_marker('next_sequence',0)      
 
next_sequence EVENT     $self+1  

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 nextSequence. Because the function needs the content of two of our variables as input, we must specify get statements for these variables.

marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun!'} 0 []
>
>
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
init_sequence EVENT initSequence put    
    bs_insert_marker('next_sequence',0)      
 
next_sequence EVENT nextSequence get $self+1, get  

This is function nextSequence:

function event = nextSequence(event)
if event.sequence_count <= numel(event.stimsequence)            % if sequence_count <= number of sequences
Deleted:
<
<
event.sentence = event.stimsequence{event.sequence_count}; % pick sentence corresponding to sequence_count
  event = displayIt(event,'string','Press button_1 (-b) to start sequence',[1 0 0]); % display instruction to press button event = bs_insert_marker(event,'start_sequence',0); % start this sequence else % all sequences processed event = bs_insert_marker(event,'BS_EXIT',0); % exit block (insert BS_EXIT marker)
Changed:
<
<
end

The first input argument of a user defined function is always event. The content of variables for which a get statement is specified, is copied into fields of the event structure. Thus, event.stimsequence contains the content of stimsequence and event.sequence_count contains the content of sequence_count.

>
>
end The first input argument of a user defined function is always event. The content of variables for which a get statement is specified, is copied into fields of the event structure. Thus, event.stimsequence contains the content of stimsequence and event.sequence_count contains the content of sequence_count.
  If the outcome of the decision is that another sequence should be displayed, the marker start_sequence will be inserted. At the start of a new sequence, the variable epoch_count must be set to 0. Then BrainStream must wait for a button press from the participant, which is achieved by specifying timepoint 'button_1' for this event. The displaying of the characters is handled by the function displayString. This function will not be discussed in detail, but it is important to know that it requires the content of the variables stimsequence and sequence_count. Therefore, get statements must be specified for these variables. Now we have reached the next decision point in the experiment flowchart, where we need to decide whether to start a new epoch or end the sequence. We will insert marker next_epoch to trigger this decision making step.
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun!'} 0 []
>
>
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
init_sequence EVENT initSequence put    
    bs_insert_marker('next_sequence',0)      
 
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
Changed:
<
<
When the next_epoch marker comes in, first the epoch counter must be increased by 1. Subsequently, we need to write a function that uses the content of stimsequence and the current values of stimulus_count and epoch_count to decide whether to start a new epoch. We will call this function nextEpoch. Because the function needs the content of all our variables as input, we must specify get statements for these variables. The Actions table now looks like this:
>
>
When the next_epoch marker comes in, first the epoch counter must be increased by 1. Subsequently, we need to write a function that uses the content of stimsequence and the current values of sequence_count and epoch_count to decide whether to start a new epoch. We will call this function nextEpoch. Because the function needs the content of all our variables as input, we must specify get statements for these variables. The Actions table now looks like this:
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun!'} 0 []
>
>
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
init_sequence EVENT initSequence put    
    bs_insert_marker('next_sequence',0)      
 
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
Line: 82 to 125
  This is function nextEpoch:
function event = nextEpoch(event)
Changed:
<
<
if event.epoch_count <= numel(event.sentence) % if epoch_count <= number of epochs in this sentence event.character = event.sentence(event.epoch_count); % pick character corresponding to epoch_count
>
>
if event.epoch_count <= numel(event.stimsequence{event.sequence_count}) % if epoch_count <= number of epochs in this sentence event.character = event.stimsequence{event.sequence_count}(event.epoch_count); % this line is required for displayString function - ignore
  event = bs_insert_marker(event,'proc_epoch',0); % insert marker to process this epoch else % all characters processed event = bs_insert_marker(event,'end_sequence',0); % end the sequence end
Changed:
<
<
>
>
If the outcome of the decision is that another character should be displayed, the marker proc_epoch will be inserted. 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 arrival of marker proc_epoch. As a result, there is a pause of 0.25 seconds between the appearance of each character on the screen.
 
Deleted:
<
<
If the outcome of the decision is that another character should be displayed, the marker proc_epoch will be inserted. 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 arrival of marker proc_epoch. As a result, there is a pause of 0.25 seconds between the appearance of each character on the screen.
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun!'} 0 []
>
>
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
init_sequence EVENT initSequence put    
    bs_insert_marker('next_sequence',0)      
 
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
next_epoch EVENT nextEpoch get get $self+1, get
proc_epoch EVENT displayString()      
    bs_insert_marker(next_epoch,0.25)      
Added:
>
>
end_sequence EVENT bs_insert_marker('next_sequence',1)      
 
Changed:
<
<
When all epochs of a sequence have been processed, the nextEpoch function will insert the end_sequence marker. When this marker arrives, BrainStream inserts the next_sequence marker, thereby returning to the question whether to start another sequence. The next_sequence marker is inserted 1 second after arrival of marker end_sequence. As a result, there is a pause of 1 second between each sequence. The Actions table now contains all the important steps of the experiment.
>
>
When all epochs of a sequence have been processed, the nextEpoch function will insert the end_sequence marker. When this marker arrives, BrainStream inserts the next_sequence marker, thereby returning to the question whether to start another sequence. The next_sequence marker is inserted 1 second after arrival of marker end_sequence. As a result, there is a pause of 1 second between each sequence. The Actions table now contains all the necessary steps of the experiment.
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun!'} 0 []
>
>
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
init_sequence EVENT initSequence put    
    bs_insert_marker('next_sequence',0)      
 
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
Line: 111 to 158
 
    bs_insert_marker(next_epoch,0.25)      
end_sequence EVENT bs_insert_marker('next_sequence',1)      
Deleted:
<
<

Creating the block file

Standard blocksettings

This experiment consists of only one block (sentences.blk). A number of settings are specified in the block file:

[DataSources]
eeg = 'simulate:biosemi_active2';
 
[Files]
ExperimentDefinitionFile = 'sentences.edt';
OutFolder = '../output/sentences/';
 
[Experiment]
Block = 'sentences';
MatlabPathFnc = [];
MatlabPathAdd = {fullfile(bs_folder('BLOCK'),'..','common_functions'),bs_folder('BLOCK')};

You can look up the meaning of the topic and key combinations here? .

Note that for the keys that specify folders, such as OutFolder and MatlabPathAdd, relative path names are specified. The command bs_folder('BLOCK') finds the path to the current block file (which in this case is /brainstream_mds/examples/blocks/sentences/). The other folders are specified relative to this folder, for example the output folder is located in /brainstream_mds/examples/blocks/output/sentences. It is recommended to always use relative path names, as this ensures that the proper paths will be added on any computer you run your experiment on.

User blocksettings

In addition to the standard topics and keys, we can specify our own settings. In this example, it would be useful to specify the content of the stimsequence variable in the block file instead of in the Actions table. We could do this for example under topic [Experiment] and key StimSequence:

[Experiment]
StimSequence = {'Making BCIs','is really fun!'}; 

The information specified in the block file can be retrieved during the experiment using the bs_get_blockvalue function. In our experiment, it would be easiest to do this at the beginning of the experiment. At the BS_INIT marker, instead of specifying the content of the stimsequence variable, we will initialize it as empty and insert a marker init_sequence. When this marker arrives, we will execute a user defined function initSequence to retrieve the content of stimsequence from the block file and place it in the global variables. After this, we will insert the marker next_sequence to start the experiment as described above. This is the new Actions table:

marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
init_sequence
EVENT
initSequence
put    
    bs_insert_marker('next_sequence',0)      
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
next_epoch EVENT nextEpoch get get $self+1, get
proc_epoch EVENT displayString()      
    bs_insert_marker(next_epoch,0.25)      
end_sequence EVENT bs_insert_marker('next_sequence',1)      

This is the initSequence function:

function event = initSequence(event)
event.stimsequence = bs_get_blockvalue('Experiment','StimSequence',{'Making BCIs','is fun!'});

The bs_get_blockvalue function will get the content specified under topic Experiment and key StimSequence and will use the default sentences 'Making BCIs' and 'is fun!' if no specification is found. The value that is retrieved from the block file will be placed in the field event.stimsequence. Because a put statement is specified for this variable in the Actions table, this new content will be updated to the global variables from where it can be retrieved by other events.

The advantage of specifying the stimsequence information in the block file is that we can now use the same Actions table for displaying an unlimited number of sentences.

 

Specifying Data Selection

Changed:
<
<
For BCI applications, you often want to collect data associated with stimuli. In this example, you might want to collect one second of EEG data every time a new character appears on the screen. In your Actions table, you must specify at which marker you want to collect data. In a DataSelection table, you must specify exactly how much data you want to select and from which data source.
>
>
For BCI applications, you will often want to collect data associated with stimuli. In this example, you might want to collect one second of EEG data every time a new character appears on the screen. In your Actions table, you must specify at which marker you want to collect data. In a DataSelection table, you must specify exactly how much data you want to select and from which data source.
 
Changed:
<
<
New epochs are started by the proc_epoch marker. We will therefore use this marker for specifying actions associated with data selection. For now, we will only print the message 'Process the data' in the Matlab command window every time data is collected. However, instead of showing a simple message you may also write functions to actually process the data. This is the new Actions table:
>
>
New epochs are started by the proc_epoch marker. We will therefore use this marker to trigger data selection. For now, we will only print the message 'Process the data' in the Matlab command window every time data is collected. However, instead of showing a simple message you could also write functions to actually process the data. This is the new Actions table:
 
marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
Line: 203 to 199
  The easiest way to create all files that define this experiment is via the BrainStream editor. You can open the editor by typing bs_editor in the Matlab command window (make sure that brainstream_mds/core is your current working directory). An experiment file (.exp) has already been created for this example experiment and is located in /brainstream_mds/examples/blocks/sentences/sentences.exp. If you open this file in the BrainStream editor, the experiment looks like this:
Changed:
<
<
BS_Editor.png
>
>
BS_Editor.png
  Figure 2: The Sentences Experiment in the BrainStream Editor
Line: 216 to 212
 
    • Set DENYTOPICVIEW =
-->
Changed:
<
<
META FILEATTACHMENT attachment="BS_Editor.png" attr="" comment="" date="1318594012" name="BS_Editor.png" path="BS_Editor.png" size="260544" stream="BS_Editor.png" tmpFilename="/var/tmp/CGItemp45912" user="MarjoleinVanDerWaal" version="2"
META FILEATTACHMENT attachment="Flowchart.png" attr="" comment="" date="1318847242" name="Flowchart.png" path="Flowchart.png" size="131911" stream="Flowchart.png" tmpFilename="/var/tmp/CGItemp31414" user="MarjoleinVanDerWaal" version="3"
>
>
META FILEATTACHMENT attachment="BS_Editor.png" attr="" comment="" date="1318927625" name="BS_Editor.png" path="BS_Editor.png" size="277868" stream="BS_Editor.png" tmpFilename="/var/tmp/CGItemp45754" user="MarjoleinVanDerWaal" version="3"
META FILEATTACHMENT attachment="Flowchart.png" attr="" comment="" date="1318923483" name="Flowchart.png" path="Flowchart.png" size="139304" stream="Flowchart.png" tmpFilename="/var/tmp/CGItemp45485" user="MarjoleinVanDerWaal" version="4"

Revision 417 Oct 2011 - Main.MarjoleinVanDerWaal

Line: 1 to 1
 
META TOPICPARENT name="BrainStreamDocs"
<---Start1--->

Example 1: Sentences

Line: 15 to 15
  Figure 1: Flowchart of the Sentences example experiment
Changed:
<
<
The experiment file can be found in /brainstream_mds/examples/blocks/sentences/sentences.exp.
>
>
As described in the 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 components. If you want to have a look at the final result, the experiment file (.exp) for this example can be found in /brainstream_mds/examples/blocks/sentences/sentences.exp.
 

Building the experiment

Changed:
<
<
As described in the Building Experiments section, a number of files are needed to define an experiment. We will start with the Actions table.

From the flowchart in figure 1, it can be seen that we need to make two types of decisions throughout the experiment:

>
>
The most striking characteristic of this experiment is that throughout the experiment we must often choose whether to continue or end the experiment. From the flowchart in figure 1, it can be seen that two types of decisions must be made:
 
  1. before each sequence, decide whether to start a new sequence or end the experiment
  2. before each epoch, decide whether to start a new epoch or end the sequence
Changed:
<
<
We will write user functions in order to make these decisions.
>
>
We will write user defined functions in order to make these decisions.
  In order to be able to make each decision, we also need to:
  1. specify how many sequences need to be shown
  2. keep track of how many sequences we have shown so far
  3. specify how many epochs are in each sequence
Changed:
<
<
  1. keep track of how many epochs we have shown so far
>
>
  1. within each sequence, keep track of how many epochs we have shown so far
  We will make use of user defined variables for these tasks.
Changed:
<
<
In the following, we will show how to create the user defined functions and variables and put them together in the Actions table.
>
>
In the next section, we will show how to create the user defined functions and variables and put them together in the Actions table.
 

Creating the Actions Table

Changed:
<
<
The Actions table has the 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, sequence_count, 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 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, sequence_count, 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:
 
marker time function stimsequence sequence_count epoch_count
           
Changed:
<
<
We will initialize these variables at the beginning of the experiment. The easiest way to do this is to define the initialization actions at the BS_INIT marker, as this is always the first marker to arrive within an experiment. At the beginning of the experiment, the sequence counter will be set to 0. The epoch counter is initialized as empty and will be set to 0 at the beginning of each new sequence. The variable stimsequence must contain the sentences that will be shown. In this example, we will show two sentences: 'Making BCIs' and 'is really fun'. For the moment, we will define these sentences in the Actions table, but later on we will show how to specify the sentences in the block files instead.
>
>
We will initialize these variables at the beginning of the experiment. The easiest way to do this is to define the initialization actions at the BS_INIT marker, as this is always the first marker to arrive within an experiment. At the beginning of the experiment, the sequence counter will be set to 0. The epoch counter is initialized as empty and will be set to 0 at the beginning of each new sequence. The variable stimsequence must contain the sentences that will be shown. In this example, we will show two sentences: 'Making BCIs' and 'is really fun!'. For the moment, we will define these sentences in the Actions table, but later on we will show how to specify the sentences in the block files instead.
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT   {'Making BCIs','is really fun'} 0 []
>
>
BS_INIT EVENT   {'Making BCIs','is really fun!'} 0 []
 
Changed:
<
<
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_insert_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_insert_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:
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun'} 0 []
next_sequence EVENT     $self+1  
>
>
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun!'} 0 []
next_sequence EVENT     $self+1  
  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 nextSequence. Because the function needs the content of two of our variables as input, we must specify get statements for these variables.
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun'} 0 []
next_sequence EVENT nextSequence get $self+1, get  
>
>
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun!'} 0 []
next_sequence EVENT nextSequence get $self+1, get  
  This is function nextSequence:
function event = nextSequence(event)
Line: 67 to 65
  The first input argument of a user defined function is always event. The content of variables for which a get statement is specified, is copied into fields of the event structure. Thus, event.stimsequence contains the content of stimsequence and event.sequence_count contains the content of sequence_count.
Changed:
<
<
If the outcome of the decision is that another sequence should be displayed, the marker start_sequence will be inserted. At the start of a new sequence, the variable epoch_count must be set to 0. Then BrainStream must wait for a button press from the participant, which is achieved by specifying timepoint 'button_1' for this event. The displaying of the characters is handled by the function displayString. This function will not be discussed in detail, but it is important to know that it requires the content of the variables stimsequence and sequence_count. Therefore, get statements must be specified for these variables. Now we have reached the next decision point in the experiment flowchart, where we need to decide whether to start a new epoch or end the sequence. We will insert marker next_epoch to trigger this decision making step.
>
>
If the outcome of the decision is that another sequence should be displayed, the marker start_sequence will be inserted. At the start of a new sequence, the variable epoch_count must be set to 0. Then BrainStream must wait for a button press from the participant, which is achieved by specifying timepoint 'button_1' for this event. The displaying of the characters is handled by the function displayString. This function will not be discussed in detail, but it is important to know that it requires the content of the variables stimsequence and sequence_count. Therefore, get statements must be specified for these variables. Now we have reached the next decision point in the experiment flowchart, where we need to decide whether to start a new epoch or end the sequence. We will insert marker next_epoch to trigger this decision making step.
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun'} 0 []
>
>
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun!'} 0 []
 
next_sequence EVENT nextSequence get $self+1, get  
Changed:
<
<
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
>
>
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
 
Changed:
<
<
When the next_epoch marker comes in, first the epoch counter must be increased by 1. Subsequently, we need to write a function that uses the content of sentence and the current value of epoch_count to decide whether to start a new epoch. We will call this function nextEpoch. Because the function needs the content of two of our variables as input, we must specify get statements for these variables. The Actions table now looks like this:
>
>
When the next_epoch marker comes in, first the epoch counter must be increased by 1. Subsequently, we need to write a function that uses the content of stimsequence and the current values of stimulus_count and epoch_count to decide whether to start a new epoch. We will call this function nextEpoch. Because the function needs the content of all our variables as input, we must specify get statements for these variables. The Actions table now looks like this:
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun'} 0 []
>
>
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun!'} 0 []
 
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
Changed:
<
<
next_epoch EVENT nextEpoch     $self+1, get
>
>
next_epoch EVENT nextEpoch get get $self+1, get
  This is function nextEpoch:
function event = nextEpoch(event)
Line: 92 to 90
 end
Changed:
<
<
If the outcome of the decision is that another character should be displayed, the marker proc_epoch will be inserted. 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 arrival of marker proc_epoch. As a result, there is a pause of 0.25 seconds between the appearance of each character on the screen.
>
>
If the outcome of the decision is that another character should be displayed, the marker proc_epoch will be inserted. 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 arrival of marker proc_epoch. As a result, there is a pause of 0.25 seconds between the appearance of each character on the screen.
marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun!'} 0 []
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
next_epoch EVENT nextEpoch get get $self+1, get
proc_epoch EVENT displayString()      
    bs_insert_marker(next_epoch,0.25)      

When all epochs of a sequence have been processed, the nextEpoch function will insert the end_sequence marker. When this marker arrives, BrainStream inserts the next_sequence marker, thereby returning to the question whether to start another sequence. The next_sequence marker is inserted 1 second after arrival of marker end_sequence. As a result, there is a pause of 1 second between each sequence. The Actions table now contains all the important steps of the experiment.

 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun'} 0 0
>
>
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun!'} 0 []
 
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
Changed:
<
<
next_epoch EVENT nextEpoch     $self+1, get
>
>
next_epoch EVENT nextEpoch get get $self+1, get
 
proc_epoch EVENT displayString()      
    bs_insert_marker(next_epoch,0.25)      
Added:
>
>
end_sequence EVENT bs_insert_marker('next_sequence',1)      

Creating the block file

Standard blocksettings

This experiment consists of only one block (sentences.blk). A number of settings are specified in the block file:

[DataSources]
eeg = 'simulate:biosemi_active2';
 
[Files]
ExperimentDefinitionFile = 'sentences.edt';
OutFolder = '../output/sentences/';
 
[Experiment]
Block = 'sentences';
MatlabPathFnc = [];
MatlabPathAdd = {fullfile(bs_folder('BLOCK'),'..','common_functions'),bs_folder('BLOCK')};

You can look up the meaning of the topic and key combinations here? .

Note that for the keys that specify folders, such as OutFolder and MatlabPathAdd, relative path names are specified. The command bs_folder('BLOCK') finds the path to the current block file (which in this case is /brainstream_mds/examples/blocks/sentences/). The other folders are specified relative to this folder, for example the output folder is located in /brainstream_mds/examples/blocks/output/sentences. It is recommended to always use relative path names, as this ensures that the proper paths will be added on any computer you run your experiment on.

User blocksettings

In addition to the standard topics and keys, we can specify our own settings. In this example, it would be useful to specify the content of the stimsequence variable in the block file instead of in the Actions table. We could do this for example under topic [Experiment] and key StimSequence:

[Experiment]
StimSequence = {'Making BCIs','is really fun!'}; 
 
Changed:
<
<
When all epochs of a sequence have been processed, the nextEpoch function will insert the end_sequence marker. When this marker arrives, BrainStream inserts the next_sequence marker, thereby returning to the question whether to start another sequence. The next_sequence marker is inserted 1 second after arrival of marker end_sequence. As a result, there is a pause of 1 second between each sequence. The Actions table now contains all the important steps of the experiment.
>
>
The information specified in the block file can be retrieved during the experiment using the bs_get_blockvalue function. In our experiment, it would be easiest to do this at the beginning of the experiment. At the BS_INIT marker, instead of specifying the content of the stimsequence variable, we will initialize it as empty and insert a marker init_sequence. When this marker arrives, we will execute a user defined function initSequence to retrieve the content of stimsequence from the block file and place it in the global variables. After this, we will insert the marker next_sequence to start the experiment as described above. This is the new Actions table:
 
marker time function stimsequence sequence_count epoch_count
Changed:
<
<
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun'} 0 0
>
>
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
init_sequence
EVENT
initSequence
put    
    bs_insert_marker('next_sequence',0)      
 
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
Changed:
<
<
next_epoch EVENT nextEpoch     $self+1, get
>
>
next_epoch EVENT nextEpoch get get $self+1, get
 
proc_epoch EVENT displayString()      
    bs_insert_marker(next_epoch,0.25)      
end_sequence EVENT bs_insert_marker('next_sequence',1)      
Changed:
<
<

Opening the experiment

>
>
This is the initSequence function:
function event = initSequence(event)
event.stimsequence = bs_get_blockvalue('Experiment','StimSequence',{'Making BCIs','is fun!'});
 
Changed:
<
<
The easiest way to get an overview of all files that define this experiment is via the BrainStream editor. You can open the editor by typing bs_editor in the Matlab command window (make sure that brainstream_mds/core is your current working directory). In the BrainStream editor, the experiment looks like this:
>
>
The bs_get_blockvalue function will get the content specified under topic Experiment and key StimSequence and will use the default sentences 'Making BCIs' and 'is fun!' if no specification is found. The value that is retrieved from the block file will be placed in the field event.stimsequence. Because a put statement is specified for this variable in the Actions table, this new content will be updated to the global variables from where it can be retrieved by other events.
 
Changed:
<
<
BS_Editor.png
>
>
The advantage of specifying the stimsequence information in the block file is that we can now use the same Actions table for displaying an unlimited number of sentences.

Specifying Data Selection

 
Changed:
<
<
Figure 2: The Sentences Experiment in the BrainStream Editor
>
>
For BCI applications, you often want to collect data associated with stimuli. In this example, you might want to collect one second of EEG data every time a new character appears on the screen. In your Actions table, you must specify at which marker you want to collect data. In a DataSelection table, you must specify exactly how much data you want to select and from which data source.

New epochs are started by the proc_epoch marker. We will therefore use this marker for specifying actions associated with data selection. For now, we will only print the message 'Process the data' in the Matlab command window every time data is collected. However, instead of showing a simple message you may also write functions to actually process the data. This is the new Actions table:

marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT bs_insert_marker('init_sequence',0) [] 0 []
init_sequence EVENT initSequence put    
    bs_insert_marker('next_sequence',0)      
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
next_epoch EVENT nextEpoch get get $self+1, get
proc_epoch EVENT displayString()      
    bs_insert_marker(next_epoch,0.25)      
  DATA
bs_disp('Process the data')      
end_sequence EVENT bs_insert_marker('next_sequence',1)      
 
Changed:
<
<
You can click the 'Test block' button to see how the experiment looks for the subject. We will now discuss the different files and functions that define this experiment.

Block File

>
>
We also need a DataSelection table to specify the exact time window of data selection. If we want to record one second of data after the onset of each epoch, our DataSelection table looks like this:
marker begintime endtime datasource
proc_epoch 0 1 eeg

In this experiment, the fourth column datasource is not absolutely necessary. As only one data source (simulated EEG data, see blocksettings) is used, BrainStream will automatically apply all data selection settings to this data source.

Creating the Dictionary table

The Dictionary table specifies a marker number for each marker that is used in this experiment. The Dictionary table looks like this:

marker type value datasource
init_sequence stimulus 1 eeg
next_sequence stimulus 2 eeg
start_sequence stimulus 3 eeg
next_epoch stimulus 4 eeg
proc_epoch stimulus 5 eeg
end_sequence stimulus 6 eeg
button_1 stimulus 7 eeg
 
Changed:
<
<
This experiment consists of only one block (sentences.blk). A number of settings are specified in the block file. You can look up the meaning of the topic and key combinations here? .
>
>
In this experiment, the fourth column datasource is not absolutely necessary. As only one data source (simulated EEG data, see blocksettings) is used, BrainStream will automatically apply all marker settings to this data source.

Testing the experiment

 
Changed:
<
<
Note that for the keys that specify folders, such as OutFolder and MatlabPathAdd, relative path names are specified. The command bs_folder('BLOCK') finds the path name of the current block file (which in this case is /brainstream_mds/examples/blocks/sentences/). The other folders are specified relative to this folder, for example the output folder is located in /brainstream_mds/examples/blocks/output/sentences. It is recommended to always use relative path names, as this ensures that the proper paths will be added on any computer you run your experiment on.
>
>
The easiest way to create all files that define this experiment is via the BrainStream editor. You can open the editor by typing bs_editor in the Matlab command window (make sure that brainstream_mds/core is your current working directory). An experiment file (.exp) has already been created for this example experiment and is located in /brainstream_mds/examples/blocks/sentences/sentences.exp. If you open this file in the BrainStream editor, the experiment looks like this:

BS_Editor.png

Figure 2: The Sentences Experiment in the BrainStream Editor

 
Changed:
<
<
The only key that is not in the list of standard topics and keys is StimSequence. During the experiment, a user defined function will retrieve the information specified under this key for use in the experiment. Specifying this information in the block file allows you to easily adjust your experiment. Try changing the text to something else and see what happens when you click 'Test block'.
>
>
You will see that this Actions table has two additional columns: character and fig. These two variables are required for the displayString function and will not be discussed here. You can click the 'Test block' button to see how the experiment looks. In addition, try changing the StimSequence blocksetting and see how easy it is to show different sentences.
 
<---End1--->

Revision 317 Oct 2011 - Main.MarjoleinVanDerWaal

Line: 1 to 1
 
META TOPICPARENT name="BrainStreamDocs"
<---Start1--->

Example 1: Sentences

Line: 11 to 11
  This is an example of a very simple 'experiment' in which letters will appear on the screen one by one to form sentences. The appearance of an individual letter is called an epoch. A series of epochs that results in a sentence is called a sequence. Subjects can press a button when they are ready for the next sentence (sequence). A flowchart of the experiment is shown below:
Changed:
<
<
Flowchart.png
>
>
Flowchart.png
  Figure 1: Flowchart of the Sentences example experiment
Line: 20 to 20
  As described in the Building Experiments section, a number of files are needed to define an experiment. We will start with the Actions table.
Changed:
<
<
From the flowchart in figure 1, it can be seen that we need to do a number of things:
  1. define which sentences (sequences) we want to show
  2. keep track of the number of sequences we have completed
  3. within each sequence, keep track of the number of epochs we have completed
  4. after each epoch, decide whether to start a new epoch or end the sequence
  5. after each sequence, decide whether to start a new sequence or end the experiment

>
>
From the flowchart in figure 1, it can be seen that we need to make two types of decisions throughout the experiment:
  1. before each sequence, decide whether to start a new sequence or end the experiment
  2. before each epoch, decide whether to start a new epoch or end the sequence
We will write user functions in order to make these decisions.

In order to be able to make each decision, we also need to:

  1. specify how many sequences need to be shown
  2. keep track of how many sequences we have shown so far
  3. specify how many epochs are in each sequence
  4. keep track of how many epochs we have shown so far

We will make use of user defined variables for these tasks.

In the following, we will show how to create the user defined functions and variables and put them together in the Actions table.

Creating the Actions Table

The Actions table has the 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, sequence_count, 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:

marker time function stimsequence sequence_count epoch_count
           

We will initialize these variables at the beginning of the experiment. The easiest way to do this is to define the initialization actions at the BS_INIT marker, as this is always the first marker to arrive within an experiment. At the beginning of the experiment, the sequence counter will be set to 0. The epoch counter is initialized as empty and will be set to 0 at the beginning of each new sequence. The variable stimsequence must contain the sentences that will be shown. In this example, we will show two sentences: 'Making BCIs' and 'is really fun'. For the moment, we will define these sentences in the Actions table, but later on we will show how to specify the sentences in the block files instead.

marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT   {'Making BCIs','is really fun'} 0 []

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_insert_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:

marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun'} 0 []
next_sequence EVENT     $self+1  

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 nextSequence. Because the function needs the content of two of our variables as input, we must specify get statements for these variables.

marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun'} 0 []
next_sequence EVENT nextSequence get $self+1, get  

This is function nextSequence:

function event = nextSequence(event)
if event.sequence_count <= numel(event.stimsequence)            % if sequence_count <= number of sequences
    event.sentence  = event.stimsequence{event.sequence_count}; % pick sentence corresponding to sequence_count
    event = displayIt(event,'string','Press button_1 (<ctrl>-b) to start sequence',[1 0 0]); % display instruction to press button
    event = bs_insert_marker(event,'start_sequence',0);         % start this sequence
else                                                            % all sequences processed
    event = bs_insert_marker(event,'BS_EXIT',0);                % exit block (insert BS_EXIT marker)
end

The first input argument of a user defined function is always event. The content of variables for which a get statement is specified, is copied into fields of the event structure. Thus, event.stimsequence contains the content of stimsequence and event.sequence_count contains the content of sequence_count.

If the outcome of the decision is that another sequence should be displayed, the marker start_sequence will be inserted. At the start of a new sequence, the variable epoch_count must be set to 0. Then BrainStream must wait for a button press from the participant, which is achieved by specifying timepoint 'button_1' for this event. The displaying of the characters is handled by the function displayString. This function will not be discussed in detail, but it is important to know that it requires the content of the variables stimsequence and sequence_count. Therefore, get statements must be specified for these variables. Now we have reached the next decision point in the experiment flowchart, where we need to decide whether to start a new epoch or end the sequence. We will insert marker next_epoch to trigger this decision making step.

marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun'} 0 []
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      

When the next_epoch marker comes in, first the epoch counter must be increased by 1. Subsequently, we need to write a function that uses the content of sentence and the current value of epoch_count to decide whether to start a new epoch. We will call this function nextEpoch. Because the function needs the content of two of our variables as input, we must specify get statements for these variables. The Actions table now looks like this:

marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun'} 0 []
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
next_epoch EVENT nextEpoch     $self+1, get

This is function nextEpoch:

function event = nextEpoch(event)
if event.epoch_count <= numel(event.sentence)            % if epoch_count <= number of epochs in this sentence
    event.character = event.sentence(event.epoch_count); % pick character corresponding to epoch_count
    event = bs_insert_marker(event,'proc_epoch',0);      % insert marker to process this epoch
else                                                     % all characters processed
    event = bs_insert_marker(event,'end_sequence',0);    % end the sequence
end 

If the outcome of the decision is that another character should be displayed, the marker proc_epoch will be inserted. 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 arrival of marker proc_epoch. As a result, there is a pause of 0.25 seconds between the appearance of each character on the screen.

marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun'} 0 0
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
next_epoch EVENT nextEpoch     $self+1, get
proc_epoch EVENT displayString()      
    bs_insert_marker(next_epoch,0.25)      

When all epochs of a sequence have been processed, the nextEpoch function will insert the end_sequence marker. When this marker arrives, BrainStream inserts the next_sequence marker, thereby returning to the question whether to start another sequence. The next_sequence marker is inserted 1 second after arrival of marker end_sequence. As a result, there is a pause of 1 second between each sequence. The Actions table now contains all the important steps of the experiment.

marker time function stimsequence sequence_count epoch_count
BS_INIT EVENT bs_insert_marker('next_sequence',0) {'Making BCIs','is really fun'} 0 0
next_sequence EVENT nextSequence get $self+1, get  
start_sequence button_1 displayString('') get get 0
    bs_insert_marker('next_epoch',0)      
next_epoch EVENT nextEpoch     $self+1, get
proc_epoch EVENT displayString()      
    bs_insert_marker(next_epoch,0.25)      
end_sequence EVENT bs_insert_marker('next_sequence',1)      
 

Opening the experiment

The easiest way to get an overview of all files that define this experiment is via the BrainStream editor. You can open the editor by typing bs_editor in the Matlab command window (make sure that brainstream_mds/core is your current working directory). In the BrainStream editor, the experiment looks like this:

Line: 43 to 129
 Note that for the keys that specify folders, such as OutFolder and MatlabPathAdd, relative path names are specified. The command bs_folder('BLOCK') finds the path name of the current block file (which in this case is /brainstream_mds/examples/blocks/sentences/). The other folders are specified relative to this folder, for example the output folder is located in /brainstream_mds/examples/blocks/output/sentences. It is recommended to always use relative path names, as this ensures that the proper paths will be added on any computer you run your experiment on.

The only key that is not in the list of standard topics and keys is StimSequence. During the experiment, a user defined function will retrieve the information specified under this key for use in the experiment. Specifying this information in the block file allows you to easily adjust your experiment. Try changing the text to something else and see what happens when you click 'Test block'.

Deleted:
<
<

Experiment definition tables

Actions table

 
<---End1--->
Line: 54 to 138
 -->

META FILEATTACHMENT attachment="BS_Editor.png" attr="" comment="" date="1318594012" name="BS_Editor.png" path="BS_Editor.png" size="260544" stream="BS_Editor.png" tmpFilename="/var/tmp/CGItemp45912" user="MarjoleinVanDerWaal" version="2"
Changed:
<
<
META FILEATTACHMENT attachment="Flowchart.png" attr="" comment="" date="1318599742" name="Flowchart.png" path="Flowchart.png" size="132644" stream="Flowchart.png" tmpFilename="/var/tmp/CGItemp45888" user="MarjoleinVanDerWaal" version="2"
>
>
META FILEATTACHMENT attachment="Flowchart.png" attr="" comment="" date="1318847242" name="Flowchart.png" path="Flowchart.png" size="131911" stream="Flowchart.png" tmpFilename="/var/tmp/CGItemp31414" user="MarjoleinVanDerWaal" version="3"

Revision 214 Oct 2011 - Main.MarjoleinVanDerWaal

Line: 1 to 1
 
META TOPICPARENT name="BrainStreamDocs"
Changed:
<
<

Example 1: Sentences

>
>
<---Start1--->

Example 1: Sentences

(Under construction)

Generate current PDF

This is an example of a very simple 'experiment' in which letters will appear on the screen one by one to form sentences. The appearance of an individual letter is called an epoch. A series of epochs that results in a sentence is called a sequence. Subjects can press a button when they are ready for the next sentence (sequence). A flowchart of the experiment is shown below:

Flowchart.png

Figure 1: Flowchart of the Sentences example experiment

The experiment file can be found in /brainstream_mds/examples/blocks/sentences/sentences.exp.

Building the experiment

As described in the Building Experiments section, a number of files are needed to define an experiment. We will start with the Actions table.

From the flowchart in figure 1, it can be seen that we need to do a number of things:

  1. define which sentences (sequences) we want to show
  2. keep track of the number of sequences we have completed
  3. within each sequence, keep track of the number of epochs we have completed
  4. after each epoch, decide whether to start a new epoch or end the sequence
  5. after each sequence, decide whether to start a new sequence or end the experiment

Opening the experiment

The easiest way to get an overview of all files that define this experiment is via the BrainStream editor. You can open the editor by typing bs_editor in the Matlab command window (make sure that brainstream_mds/core is your current working directory). In the BrainStream editor, the experiment looks like this:

BS_Editor.png

Figure 2: The Sentences Experiment in the BrainStream Editor

You can click the 'Test block' button to see how the experiment looks for the subject. We will now discuss the different files and functions that define this experiment.

Block File

This experiment consists of only one block (sentences.blk). A number of settings are specified in the block file. You can look up the meaning of the topic and key combinations here? .

Note that for the keys that specify folders, such as OutFolder and MatlabPathAdd, relative path names are specified. The command bs_folder('BLOCK') finds the path name of the current block file (which in this case is /brainstream_mds/examples/blocks/sentences/). The other folders are specified relative to this folder, for example the output folder is located in /brainstream_mds/examples/blocks/output/sentences. It is recommended to always use relative path names, as this ensures that the proper paths will be added on any computer you run your experiment on.

The only key that is not in the list of standard topics and keys is StimSequence. During the experiment, a user defined function will retrieve the information specified under this key for use in the experiment. Specifying this information in the block file allows you to easily adjust your experiment. Try changing the text to something else and see what happens when you click 'Test block'.

Experiment definition tables

Actions table

<---End1--->

<-- 
  • Access control
    • Set DENYTOPICVIEW =
-->

META FILEATTACHMENT attachment="BS_Editor.png" attr="" comment="" date="1318594012" name="BS_Editor.png" path="BS_Editor.png" size="260544" stream="BS_Editor.png" tmpFilename="/var/tmp/CGItemp45912" user="MarjoleinVanDerWaal" version="2"
META FILEATTACHMENT attachment="Flowchart.png" attr="" comment="" date="1318599742" name="Flowchart.png" path="Flowchart.png" size="132644" stream="Flowchart.png" tmpFilename="/var/tmp/CGItemp45888" user="MarjoleinVanDerWaal" version="2"

Revision 114 Oct 2011 - Main.MarjoleinVanDerWaal

Line: 1 to 1
Added:
>
>
META TOPICPARENT name="BrainStreamDocs"

Example 1: Sentences

 
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback