Hi,
We are trying to use the BCI p300 system to control a wheelchair mounted robotic arm. The screen that I need to flash is in a separate application. I was thinking about using App Connector for this, but I am not sure what control signals I need to listen/send in order to synchronize with the rest of the system.
Also I would prefer to decide which row/column to flash from inside my application. Is it possible to do this ? Where is the function/algorithm that does the flashing in the BCI source code? I went through P3SpellerTask.cpp in P3 speller but couldn't find it.
Thank you in advance for your time
-WMRA
how to control p300 flasing from external application
-
mellinger
- Posts: 1341
- Joined: 12 Feb 2003, 11:06
Re: how to control p300 flasing from external application
Hi,
the flashing ("presentation" of stimuli) is done in P3SpellerTask's base class, which is called StimulusTask (src/shared/modules/application/StimulusTask.cpp). This class defines a number of event handlers which may be overridden in derived classes. One of these event handlers is OnStimulusBegin(), and its default implementation in StimulusTask is to present (e.g., highlight) the stimuli associated with the current stimulus code. Associating stimuli (matrix elements) with stimulus codes (rows and columns) is done in P3SpellerTask::LoadMenu(), and the sequence of stimulus codes is defined in P3SpellerTask::OnNextStimulusCode(). There is no way to control the sequence of stimulus codes via the AppConnector protocol.
As you want to do both stimulus display and sequencing in your separate application, there is probably not much sense in using the P3Speller module at all. Instead, consider using the DummyApplication module which has no functionality other than providing the AppConnector protocol. Your application may then flash rows and columns as it likes, and the P3SignalProcessing will cooperate as long as you set the StimulusCode state via the AppConnector protocol while presenting a row/column stimulus. Whenever a stimulus has been presented EpochsToAverage times, P3SignalProcessing will send a classification score in Signal( 0, 0 ), and set the StimulusCodeRes state to the stimulus code associated with this stimulus. Your application should listen to the StimulusCodeRes state, and once it has received scores for all stimuli, it should choose the stimulus with the greatest score as a classification result.
For details about the P3SignalProcessing module, see http://www.bci2000.org/wiki/index.php/U ... oralFilter
Regards,
Juergen
the flashing ("presentation" of stimuli) is done in P3SpellerTask's base class, which is called StimulusTask (src/shared/modules/application/StimulusTask.cpp). This class defines a number of event handlers which may be overridden in derived classes. One of these event handlers is OnStimulusBegin(), and its default implementation in StimulusTask is to present (e.g., highlight) the stimuli associated with the current stimulus code. Associating stimuli (matrix elements) with stimulus codes (rows and columns) is done in P3SpellerTask::LoadMenu(), and the sequence of stimulus codes is defined in P3SpellerTask::OnNextStimulusCode(). There is no way to control the sequence of stimulus codes via the AppConnector protocol.
As you want to do both stimulus display and sequencing in your separate application, there is probably not much sense in using the P3Speller module at all. Instead, consider using the DummyApplication module which has no functionality other than providing the AppConnector protocol. Your application may then flash rows and columns as it likes, and the P3SignalProcessing will cooperate as long as you set the StimulusCode state via the AppConnector protocol while presenting a row/column stimulus. Whenever a stimulus has been presented EpochsToAverage times, P3SignalProcessing will send a classification score in Signal( 0, 0 ), and set the StimulusCodeRes state to the stimulus code associated with this stimulus. Your application should listen to the StimulusCodeRes state, and once it has received scores for all stimuli, it should choose the stimulus with the greatest score as a classification result.
For details about the P3SignalProcessing module, see http://www.bci2000.org/wiki/index.php/U ... oralFilter
Regards,
Juergen
-
WMRA
- Posts: 3
- Joined: 20 Jun 2011, 19:12
Re: how to control p300 flasing from external application
Hi,
Thank you very much for the reply.
I am trying to get the BCI system running with the DummyApplication.exe module. but its giving me the following error when I press set config. I loaded the "P3Speller_CopySpelling.prm" file.
P3TemporalFilter::Preflight: State "StimulusCode" is inaccessible.
P3TemporalFilter::Preflight: State "StimulusType" is inaccessible.
If I understood your previous post correctly I only need to send the StimulusCode state when I present a stimulus. And I beleive I don't need the StimulusType state for my specific application. Am I correct?
I would really appreciate if you could tell me how resolve this issue.
Thank you very much for your time.
-WMRA
Thank you very much for the reply.
I am trying to get the BCI system running with the DummyApplication.exe module. but its giving me the following error when I press set config. I loaded the "P3Speller_CopySpelling.prm" file.
P3TemporalFilter::Preflight: State "StimulusCode" is inaccessible.
P3TemporalFilter::Preflight: State "StimulusType" is inaccessible.
If I understood your previous post correctly I only need to send the StimulusCode state when I present a stimulus. And I beleive I don't need the StimulusType state for my specific application. Am I correct?
I would really appreciate if you could tell me how resolve this issue.
Thank you very much for your time.
-WMRA
-
mellinger
- Posts: 1341
- Joined: 12 Feb 2003, 11:06
Re: how to control p300 flasing from external application
Hi,
StimulusCode and StimulusType states are not defined by the DummyApplication module, so you need to create them via the Operator module.
You can do that by specifying an Operator script that inserts those states into the system. This may be done either by adding a command-line option to the batch file that starts up BCI2000, or by specifying a script in the Operator module's preferences dialog.
For the first option, add the following to the line that starts up the Operator module in the batch file:
start operator.exe 127.0.0.1 --OnConnect "-INSERT STATE StimulusCode 8 0; INSERT STATE StimulusType 1 0"
For the second option, copy everything inside the quotes in the above line, and put it into the "Script Files->After all modules connected" field in the Operator module's preferences dialog.
For more information, see
http://www.bci2000.org/wiki/index.php/U ... _Scripting
and
http://www.bci2000.org/wiki/index.php/U ... ces_Dialog
Regarding the StimulusType state, you need to set it if you want to use the recorded data as training data for a classifier, e.g. with BCI2000's P300Classifier program. But this requires the concept of an "attended stimulus" which is known beforehand, and this information may not be available when using your application. You will then need to use the standard StimulusPresentation or P3Speller modules to record training data.
Regards,
Juergen
StimulusCode and StimulusType states are not defined by the DummyApplication module, so you need to create them via the Operator module.
You can do that by specifying an Operator script that inserts those states into the system. This may be done either by adding a command-line option to the batch file that starts up BCI2000, or by specifying a script in the Operator module's preferences dialog.
For the first option, add the following to the line that starts up the Operator module in the batch file:
start operator.exe 127.0.0.1 --OnConnect "-INSERT STATE StimulusCode 8 0; INSERT STATE StimulusType 1 0"
For the second option, copy everything inside the quotes in the above line, and put it into the "Script Files->After all modules connected" field in the Operator module's preferences dialog.
For more information, see
http://www.bci2000.org/wiki/index.php/U ... _Scripting
and
http://www.bci2000.org/wiki/index.php/U ... ces_Dialog
The StimulusCode state should be set to a stimulus ID during stimulus presentation, and to 0 otherwise, yes. Please note that in the script above I specified 8 bits as the width of the StimulusType state, so stimulus IDs may range from 1 to 255. If you need larger stimulus IDs, you may specify up to 32 bits as a stimulus width.If I understood your previous post correctly I only need to send the StimulusCode state when I present a stimulus. And I beleive I don't need the StimulusType state for my specific application. Am I correct?
Regarding the StimulusType state, you need to set it if you want to use the recorded data as training data for a classifier, e.g. with BCI2000's P300Classifier program. But this requires the concept of an "attended stimulus" which is known beforehand, and this information may not be available when using your application. You will then need to use the standard StimulusPresentation or P3Speller modules to record training data.
Regards,
Juergen
-
WMRA
- Posts: 3
- Joined: 20 Jun 2011, 19:12
Re: how to control p300 flasing from external application
Hi,
I am not getting accurate results from the BCI program and I am having a hard time figuring out where the problem is. I want to make sure I am reading the Appconnector data properly. What is the best way to parse the Appconnector data coming via UDP for p300 classification scores?
I currently use the following code segment to read and parse Appconnector stream for classification scores. This code runs in a separate thread.
Is this the correct way? or is there a better way?
I read here http://www.bci2000.org/phpbb/viewtopic.php?f=1&t=1103 that appconnector will send the BCI states first in alphabetical order and then the Signal values, but that this may change in the future.
I am not getting accurate results from the BCI program and I am having a hard time figuring out where the problem is. I want to make sure I am reading the Appconnector data properly. What is the best way to parse the Appconnector data coming via UDP for p300 classification scores?
I currently use the following code segment to read and parse Appconnector stream for classification scores. This code runs in a separate thread.
Is this the correct way? or is there a better way?
I read here http://www.bci2000.org/phpbb/viewtopic.php?f=1&t=1103 that appconnector will send the BCI states first in alphabetical order and then the Signal values, but that this may change in the future.
Code: Select all
/* these variables are declared earlier in code
int numTotalStimuli; // Total number of stimuli I presented. this is dynamically set elsewhere in the code
int resultCount = 0; // number of clasification scores received
result_codes[]; // array to store classification scores.*/
while(resultCount < numTotalStimuli){
getline( read_sock, temp_str_buf ); // reads from UDP into temp_str_buf
if( temp_str_buf.find("StimulusCodeRes")!= string::npos ){
sscanf(temp_str_buf.c_str() , "%s %d",temp_buf, &stimulus_id);
if(stimulus_id > 0){
bool got_result = false;
while(!got_result){
getline(read_sock, temp_str_buf );
if( temp_str_buf.find("Signal(0,0)")!= string::npos ){
sscanf(temp_str_buf.c_str() , "%s %lf",temp_buf, &temp_result);
result_codes[stimulus_id] = temp_result;
got_result = true;
resultCount ++;
}
}
}
}
}
-
mellinger
- Posts: 1341
- Joined: 12 Feb 2003, 11:06
Re: how to control p300 flasing from external application
Hi,
as far as I can see, there is nothing wrong with your code. It should work as expected.
However, you should make sure to choose a rather small sample block size in BCI2000, as you will only have a stimulus timing accuracy of one sample block in your setup. Typically, the classifier will downsample data to 20Hz before classification, so sample block duration (=SampleBlockSize/SamplingRate) will need to be below 50ms for accurate classification.
Regards,
Juergen
as far as I can see, there is nothing wrong with your code. It should work as expected.
However, you should make sure to choose a rather small sample block size in BCI2000, as you will only have a stimulus timing accuracy of one sample block in your setup. Typically, the classifier will downsample data to 20Hz before classification, so sample block duration (=SampleBlockSize/SamplingRate) will need to be below 50ms for accurate classification.
Regards,
Juergen
Who is online
Users browsing this forum: No registered users and 0 guests
