Parameter file from P300 Speller applied to new application

Forum for discussion on different user applications
Locked
ahsanNawroj
Posts: 2
Joined: 26 Aug 2011, 12:42

Parameter file from P300 Speller applied to new application

Post by ahsanNawroj » 26 Apr 2012, 13:46

Hello,

I am trying to take a parameter file I generated using the P300 classifier and data from P300 Speller copy-mode sessions, and apply this parameter file into my own application which models the Spelling task.

My choice grid is much smaller, a 3 x 3 square of 9 choices. Is it necessary for me to create a classifier for data from this application? Can I not use the classifier from the spelling task?

During spelling tasks, accuracy of classification is over 90% (90% of selected characters are the ones the person was focusing on). In my application, the person can only select about 40-50% of the choices correctly. The same parameter files are used in both applications.

(My application presents either text or images as stimuli, and flashes just like the P300 speller. I am working in Python.)

Is there something I am missing in the experimental setup or is this a function of the similarity of the spelling task's signal processing with my application?

Any advice would help greatly. Thanks!

mellinger
Posts: 1056
Joined: 12 Feb 2003, 11:06

Re: Parameter file from P300 Speller applied to new applicat

Post by mellinger » 27 Apr 2012, 06:20

In principle, you should be able to use classifier weights trained from BCI2000 data with your own application. Possible reasons for the difference in performance are:

1) In your application, epochs are not started at the same time relative to the stimulus as in BCI2000, i.e. there is a time offset between epochs as measured by your application, and epochs as expected by the classifier. In BCI2000, the screen update corresponding to a stimulus presentation occurs close to the beginning of the first data block that has the stimulus' StimulusCode set.

2) The actual display of your stimuli is not consistent with the information contained in the StimulusCode variable, i.e. there is a variable delay between the two. This may happen when your stimulus presentation code runs in a separate thread, not being synchronized to BCI2000 data packets, or when you don't force a screen update after updating stimulus properties. To make stimulus presentation consistent with the StimulusCode variable, change stimulus properties from the thread that processes BCI2000 data packets, and force an immediate video memory update by calling the appropriate function from the library you are using. Also, you should not attempt to synchronize stimulus presentation with screen refreshes (vertical blank interrupts) because this may lead to timing that is worse than without VBL synchronization when done improperly.

Regards,
Juergen

ahsanNawroj
Posts: 2
Joined: 26 Aug 2011, 12:42

Re: Parameter file from P300 Speller applied to new applicat

Post by ahsanNawroj » 30 Apr 2012, 01:24

Thank you for getting back to me.

1) In your application, epochs are not started at the same time relative to the stimulus as in BCI2000, i.e. there is a time offset between epochs as measured by your application, and epochs as expected by the classifier. In BCI2000, the screen update corresponding to a stimulus presentation occurs close to the beginning of the first data block that has the stimulus' StimulusCode set.

I set the StimulusCode variable when I am about to flash a particular row or column. In fact, I set it to the stimulus code of the row/column. Since I am trying to use a small grid (3x3), I have six stimuli (1-6) and these codes are used to set StimulusCode to a non-zero value.

Since I am using BCPy2000, a phase machine is run where after the 'flash' state, a 'noflash' state follows. Now as 'flash' sets StimulusCode (to the code for the stimulus) and 'noflash' clears StimulusCode (to be reused), the transition between the two will be when BCI2000 begins its 'epoch', am I right? Also, after every transition of states in the finite state machine of BCPy2000, the screen is updated and the 'flash'ing of the correct stimuli is seen.

If my understanding of the process is correct, then BCI2000 beginning its 'epoch' and actual visual stimulus presentation (flashing) occurs at the transition of the state machine. Should this not be accurate enough for the Signal Processing module to handle?


2) The actual display of your stimuli is not consistent with the information contained in the StimulusCode variable, i.e. there is a variable delay between the two. This may happen when your stimulus presentation code runs in a separate thread, not being synchronized to BCI2000 data packets, or when you don't force a screen update after updating stimulus properties. To make stimulus presentation consistent with the StimulusCode variable, change stimulus properties from the thread that processes BCI2000 data packets, and force an immediate video memory update by calling the appropriate function from the library you are using. Also, you should not attempt to synchronize stimulus presentation with screen refreshes (vertical blank interrupts) because this may lead to timing that is worse than without VBL synchronization when done improperly.

About your second point: I am not using multithreading, and this should eliminate some of the timing issues. But more importantly, at the end of every setting or clearing of the StimulusCode variable, the screen is refreshed. I should note that the transition time between states is something of a design decision in BCPy2000 that is pre-decided. I use a StimulusDuration variable as a parameter which corresponds to the transition time in the 'flash' state. Essentially this means that if StimulusDuration is set to 31.25ms, then 'flash' lasts 31.25ms. In order to make this flashing infrequent (P300 requirement), I make 'noflash' last between 5 and 7 times this value.

I understand that resolving my inaccurate classification needs some understanding of BCPy2000, but perhaps you might be able to see some obvious problem with my approach.

Once again, thank you for your time: I appreciate your help.

boulay
Posts: 382
Joined: 25 Dec 2011, 21:14

Re: Parameter file from P300 Speller applied to new applicat

Post by boulay » 30 Apr 2012, 12:31

You seem to have a good handle on it, but just to make sure we and future readers are using the same terminology, please read the last paragraph on the page linked here:
http://bci2000.org/downloads/BCPy2000/P ... chine.html
The point is that a BCPy2000 phase is a trial segment whereas a BCI2000 state is a variable.

I do not know the particulars, but I am under the impression that BCI2000 state variables can only be updated with each block because the states are transmitted as a state vector once per block. I think you can get more precision using Events, though I'm not sure that this is applicable here.

I understand that your transition to the 'flash' phase and 'noflash' phase are setting your state variable 'StimulusCode'. The BCPy2000 phase machine runs in a thread separate from the data processing thread. Thus the updating of the screen and the message to set the state variable happen nearly simultaneously but the updated state variable will not be transmitted until the start of the next block, or even worse it might not be updated at all if StimulusCode is changed to nonzero and back again within the same block. Can you look at your data files to verify that your StimulusCode is changing as expected? Are StimulusCode changes always occurring at some multiple of nSamplesPerBlock?

If you think that the problem is in the jitter between the phase transition and the updating of the state variable, you can try locking your phase transitions to blocks using lock_transitions http://bci2000.org/downloads/BCPy2000/B ... ation.html

Or you can try decreasing your block size to something around 10 ms. I am not up-to-date on the P300 literature but I believe a 10 ms jitter should not impact classification much.

jhill
Posts: 31
Joined: 17 Nov 2009, 15:15

Re: Parameter file from P300 Speller applied to new applicat

Post by jhill » 03 May 2012, 19:54

When doing this kind of thing:

Code: Select all

def Transition(self, phasename):
    if phasename == 'flash':
        self.states['StimulusCode'] = 1
        self.stimuli['Foo'].color = (1,1,1)
boulay correctly points out the important point that changes to State variables (StimulusCode in this example) will not appear precisely time-locked to stimulus events (actual physical flashes) if the lines responsible for these two events happen in during self.Transition() There will be a jitter between the actual transition time and the time at which BCI2000 can acknowledge it system-wide (or in the file) via the state variables: that is discussed at http://bci2000.org/downloads/BCPy2000/Timing.html and a useful API method is self.detect_event() as documented at http://bci2000.org/downloads/BCPy2000/B ... tect_event

I see three potential solutions. lock_transitions() would be one, as Chad suggested. Another solution might be to use the phase machine to sketch only the broad strokes (don't have separate "flash on" and "flash off" phases, but rather just one phase called "flash on and off for a while") and then use self.Process() to handle the actual offsets and onsets, and the associated manipulations of StimulusCode:

Code: Select all

def StartRun(self):
    self.forget('flash')
def Process(self, sig):
    if self.in_phase('flash on and off for a while'):
           if self.since('flash')['packets'] >= self.flash_PERIOD_in_packets:
                  self.states['StimulusCode'] = 1
                  self.stimuli['Foo'].color = (1,  1,  1)
                  self.remember('flash')
           elif self.since('flash')['packets'] >= self.flash_DURATION_in_packets:
                  self.states['StimulusCode'] = 0
                  self.stimuli['Foo'].color = (0.5,  0.5,   0.5)
Yet a third solution would be to do the signal-processing module in Python and make use of the offset returned by self.detect_event() there. In my own Python-implemented speller I use a TriggerlessTrapSequence object from the SigTools.Buffering module: that has an input argument that supports event offsets.

Chad is right that Events (i.e. State-variable changes whose timing is not quantized to the packet boundaries) aren't currently possible from BCPy2000.

Locked

Who is online

Users browsing this forum: No registered users and 1 guest