Page 2 of 3
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 08 Aug 2014, 09:52
by boulay
athanoid wrote:
Would it be wise if I use few electrodes (maybe 3) for control (in a closed loop VR) in order to reduce complexity for classifying simple left/right hand imagery but keep the 8 electrode montage for offline analysis?
Yes, I think that's a good idea. Be sure to examine your data after 1 or 2 subjects to see if you would have been better off using more/different electrodes for control.
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 12 Aug 2014, 12:41
by athanoid
boulay wrote:BCI2000 sends data in blocks. Is the rate that the blocks are being sent insufficient, is that why it appears non-continuous? I don't think there's anyway to get real continuous control unless you set your block size to 1, but I'm sure your hardware can't handle that.
I mean without the trials. Just online control.
Is it possible through changing the cursor control settings or any other way?
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 12 Aug 2014, 13:21
by boulay
athanoid wrote:
I mean without the trials. Just online control.
Is it possible through changing the cursor control settings or any other way?
Maybe I'm misunderstanding what you mean by "continuous control". Do you mean you want the VR object to be controlled at all times, even in between trials, or do you mean that you want the VR object to be controlled on a sample-by-sample basis?
The former should be easy (and I expect it's the default when using UDP, unless you are relying on cursor states instead of control signals).
The latter is impractical.
Hardware devices make their data available in blocks. e.g., you'll get 32 samples (* N channels) at each time you request samples.
BCI2000 processes data in blocks. The block of data moves along the filter chain from source->spatial filter->frequency transformation->classifier->normalizer->application (I skipped some).
Since data are sent in blocks, and the application can only update whenever it receives a block, it is assumed that you only need 1 control signal (per dimension) per block.
You could theoretically configure the system to run through its chain for every sample (i.e. a block size of 1), but I really doubt your computer could keep up. Instead, you may want to try finding the minimum block size that the amplifier allows and that your computer can keep up with. Be careful though, just because BCI2000 is keeping up with the processing doesn't mean that your network stack is. UDP is designed to drop packets silently.
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 12 Aug 2014, 14:38
by athanoid
boulay wrote:
Maybe I'm misunderstanding what you mean by "continuous control". Do you mean you want the VR object to be controlled at all times, even in between trials, or do you mean that you want the VR object to be controlled on a sample-by-sample basis?
The former should be easy (and I expect it's the default when using UDP, unless you are relying on cursor states instead of control signals).
Sorry for the confusion. I mean the VR object to be controlled at all times.
For example I get via UDP the variables below and I use CursorPosX for 1D control in my Game.
The problem rises when the trials are paused or stopped.
What I want is either (a) an online session for controlling 1D movement either by using a trained cllassifier or (b) online training like the cursortask BUT defining the target code (left or right target) via UDP back to BCI2000 for classification purposes.
Option (a) will work better for me.
Running
Recording
SourceTime
StimulusTime
Signal(0,0)
Signal(1,0)
PauseApplication
TargetCode
ResultCode
Feedback
CursorPosX
CursorPosY
CursorPosZ
Edit: I can see the the control signal (Signal(0,0) for X) is continuously running but do I need to sync the VR based on the TargetCodes (L/R) that are displayed for training the classifier? I hope i pass the msg

Re: Configuration for Cursor Task (Motor Imagery)
Posted: 12 Aug 2014, 15:32
by boulay
athanoid wrote:
Sorry for the confusion. I mean the VR object to be controlled at all times.
For example I get via UDP the variables below and I use CursorPosX for 1D control in my Game.
The problem rises when the trials are paused or stopped.
Code: Select all
Running
Recording
SourceTime
StimulusTime
Signal(0,0)
Signal(1,0)
PauseApplication
TargetCode
ResultCode
Feedback
CursorPosX
CursorPosY
CursorPosZ
You could set all of your duration parameters to 0s (PreFeedbackDuration, PostFeedbackDuration, ITIDuration), then you will always be in Feedback state.
Or don't user CursorPosX. Use Signal(0, 0).
I recommend using Signal(0, 0) because it is independent of the Application module. In particular, it is not limited by the CursorTask screen's bounding box.
See BCI2000\src\core\Application\CursorTask\CursorFeedbackTask.cpp (I snipped out quite a bit)
Code: Select all
void
CursorFeedbackTask::DoFeedback( const GenericSignal& ControlSignal, bool& doProgress )
{
float x = mpFeedbackScene->CursorXPosition(),
if( ControlSignal.Channels() > 0 )
x += mCursorSpeedX * ControlSignal( 0, 0 );
// Restrict cursor movement to the inside of the bounding box:
float r = mpFeedbackScene->CursorRadius();
x = max( r, min( 100 - r, x ) ),
mpFeedbackScene->SetCursorPosition( x, y, z );
const float coordToState = ( ( 1 << cCursorPosBits ) - 1 ) / 100.0;
State( "CursorPosX" ) = static_cast<int>( x * coordToState );
}
There are some things that it does that you may have to reproduce in your Unity application. For example, it remembers the last cursor x position then on each block it updates the cursor x position with mCursorSpeedX * ControlSignal(0, 0). As we discussed previously, you'll probably want to do something similar (i.e., animations) instead of setting the position directly.
Also, you'll probably want to limit your virtual feedback somehow, but not to the bounding box of the cursorTask.
athanoid wrote:
What I want is either (a) an online session for controlling 1D movement either by using a trained cllassifier or (b) online training like the cursortask BUT defining the target code (left or right target) via UDP back to BCI2000 for classification purposes.
Option (a) will work better for me.
To collect training data (which you will use to build your classifier), your analysis needs to know the user's intention (i.e. the class) during each data segment. The best way to maintain a record of each data segment's class is to store it in the BCI2000 dat file. You could do this by writing a state back through UDP as you suggested (I have no idea how to do that but I think it's possible), or you could let the CursorTask define the task in TargetCode State, then Unity will use the TargetCode state to display some cue to instruct the user.
I'm not really willing to dive into figuring out how to write the state back through UDP because this technique will be made obsolete by the SharedMemoryConnector method that we hope to implement. I'm getting my Oculus Rift DK2 in about 2 weeks; I'll start development then.
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 12 Aug 2014, 16:36
by athanoid
Than you very much, I will try that.
Do you know how can I get the classification results after each session on the default CursorTask example?
I can see there is for P300 (
http://www.bci2000.org/wiki/index.php/P300_GUI_Guide) but not for MI.
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 12 Aug 2014, 19:39
by boulay
I think
this is what you are looking for.
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 13 Aug 2014, 04:55
by athanoid
boulay wrote:I think
this is what you are looking for.
Can I get the correctly classified percentage or should I count the successful hits of the targets on each trial?
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 13 Aug 2014, 14:45
by boulay
Online or during offline analysis? Online I think the Operator Log maintains a record of hits and misses, then at the end gives you a percentage. Offline, I expect it to be somewhere. Sorry I don't use any of the precompiled analysis tools.
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 14 Aug 2014, 06:56
by athanoid
During the CursorTask, is the TargetCode used to train (or add weights) the classifier or just only whenever Mu Rhythm signals are identified on the specified channels?
Example: Since I get data from Signal(0,0) while the CursorTask application is paused, is this data valid to use in an external application?
I'm trying to see if i have to use these codes in sync with my VR application in order to get adequate results over time.
boulay wrote:Online or during offline analysis? Online I think the Operator Log maintains a record of hits and misses, then at the end gives you a percentage. Offline, I expect it to be somewhere. Sorry I don't use any of the precompiled analysis tools.
I want it offline in order to compare different montages.
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 15 Aug 2014, 13:55
by boulay
As far as I know, none of the core BCI2000 signal processing modules are able to update the classifier in real time. What does happen, though, is that the normalization is adaptive. That means that the baseline mean-subtraction and baseline variance-division that the normalizer does is based on a FIFO buffer of baseline data, and that buffer of data changes throughout the experiment.
It can all be parameterized, but typically a 10-30 sec buffer is maintained per channel per class. The reason you maintain a buffer per class (instead of using only one buffer for all classes) is so that each class has equal representation in determining where the 0-point is (i.e. the mean of the baseline). This is especially important if your classes are not presented with equal frequency.
Then, at the end of every trial, the data from that trial is inserted into the buffer for the appropriate class. The average and variance of the buffers are then calculated to determine the offset and scale factor for Signal(0, 0).
When the application is paused, the buffer is never updated, and thus your offset and scale are never updated. This can be problematic over long durations when there is signal drift (e.g., due to changing electrode impedances).
If you are confident that your classes will be presented with roughly equal frequency, then you can keep BCI2000 running with many trials so it updates the buffer but only maintain a single class-independent buffer per channel. That will at least give you some baseline normalization and you don't have to pay attention to TargetCode.
WIKI Normalizer.
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 27 Aug 2014, 11:32
by athanoid
I want to use the control signal for navigation (left/right) in a Virtual Environment, there're no target codes.
I need to expose participants for at least 10 minutes. How can I have the optimal result without having problems with the normalizer?
edit: is my approach wrong through the Cursor Task? should I try any other example for MI?
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 01 Sep 2014, 20:35
by boulay
Sorry for the delay.
The only reason to use the CursorTask (over another task) is if the visual feedback of the cursor position is useful to the subject or the experimenter. If you are not using the feedback, then I suggest using DummyApplication.
You can still get by without knowing TargetCodes, but it's a bit risky. I'll try to explain why. Let's say your subject gets stuck somewhere and they are continually trying to turn left. You may have 2 minutes of data where the subject is performing the mental task associated with modulating the signal for left turns; let's say this is left hand motor imagery --> mu ERD under C4. If the Normalizer doesn't know anything about the task, the best it can do is lump all data together in its buffer. If the buffer is < 2 minutes, then the entirety of the buffer will be filled with relatively desynchronized mu under C4. Then, when you subtract the mean of the buffer from the current data, you'll essentially be setting the desynchronized level as the zero-point. Attempting "left" will give you a control signal of ~0 and slightly worse ERD now appears to the application as a very strong "Right" signal.
[When the Normalizer knows the task, it can maintain separate buffers for left and right, so even if you are stuck going left, you'll always have an equal amount of 'right' data in the buffer, so you're zero point should be somewhere in between the two.]
Here are some alternatives:
-Don't use adaptive normalization.
---Analyze a little bit of per-session data to get the mean and standard deviation then use those to parameterize your non-adaptive offset and gain.
---Program your 3D game to do some normalization, adaptive or not.
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 30 Sep 2014, 05:22
by athanoid
Hi,
For the same number and position of electrodes can I use these weights on the spatial filter?
http://www.bci2000.org/wiki/index.php/U ... ial_Filter
Thanks
Re: Configuration for Cursor Task (Motor Imagery)
Posted: 30 Sep 2014, 10:36
by boulay
Sure. There's nothing special about those. They are simply of the following format.
Code: Select all
Output = Input - R1/N - R2/N ... - Rn/N
Where R1 to Rn are the reference electrodes, and N is the number of reference electrodes used.