def Preflight(self, sigprops):
        #Setup screen
        siz = float(self.params['WindowSize'])
        screenid = int(self.params['ScreenId'])  # ScreenId 0 is the first screen, 1 the second, -1 the last
        fullscreen(scale=siz, id=screenid, frameless_window=(siz==1)) # only use a borderless window if the window is set to fill the whole screen

        self.nclasses = len(self.params['GoCueText'])#Must be defined in Preflight because it is used by extension preflight.

        n_trials = self.params['TrialsPerBlock'].val * self.params['BlocksPerRun'].val
        trials_per_class = int(n_trials / self.nclasses)
        if self.params['ClusterTargets'].val>0 and not (trials_per_class % self.params['ClusterTargets'].val == 0):
            raise EndUserError, "ClusterTargets must be a integer factor of the number of trials per target"

        #If using gating or visual feedback, check that the target ranges make sense.
        if ('GatingEnable' in self.params and int(self.params['GatingEnable'].val) or ('ContFeedbackEnable' in self.params and self.params['ContFeedbackEnable'].val)==1):
            targrange=self.params['TargetRange'].val
            if targrange.shape[0] != self.nclasses: raise EndUserError, "TargetRange must have entries for each target"
            if targrange.shape[1]!=2: raise EndUserError, "TargetRange must have Min and Max values"
            if any([ar[(0,0)] > ar[(0,1)] for ar in targrange]): raise EndUserError, "TargetRange must be in increasing order"
            self.target_range=np.asarray(targrange,dtype='float64')

        if 'GatingEnable' in self.params:	GatingApp.preflight(self, sigprops)
        if 'MSEnable' in self.params:	MagstimApp.preflight(self, sigprops)
        if 'DigitimerEnable' in self.params:	DigitimerApp.preflight(self, sigprops)
        if 'ERPDatabaseEnable' in self.params:	ERPApp.preflight(self, sigprops)
        if 'ContFeedbackEnable' in self.params:	FeedbackApp.preflight(self, sigprops)
Example #2
0
    def Process(self, sig):
        #Process is called on every packet
        #Phase transitions occur independently of packets
        #Therefore it is not desirable to use phases for application logic in Process
        if 'MSEnable' in self.params: MagstimApp.process(self, sig)
        if 'DigitimerEnable' in self.params: DigitimerApp.process(self, sig)
        if 'ERPDatabaseEnable' in self.params: ERPApp.process(self, sig)
        if 'ContFeedbackEnable' in self.params: FeedbackApp.process(self, sig)
        if 'GatingEnable' in self.params: GatingApp.process(self, sig)

        #If we are in Task, and we are using GatingApp or MagstimApp or DigitimerApp
        if self.taskMaxNBlocks > 0 and self.in_phase(
                'task', min_packets=self.taskMaxNBlocks):
            self.change_phase('response')
        elif self.in_phase('task', min_packets=self.states['TaskMinNBlocks']):
            criteria_met = not 'GatingEnable' in self.params or not int(
                self.params['GatingEnable']) or self.states['GatingOK']
            magstim_ready = not 'MSEnable' in self.params or not int(
                self.params['MSEnable']) or self.states['MagstimReady']
            digitimer_ready = not 'DigitimerEnable' in self.params or not int(
                self.params['DigitimerEnable']
            ) or self.states['DigitimerReady']
            if criteria_met and magstim_ready and digitimer_ready:
                self.change_phase('response')

        #If we are in Response and we are using ERPApp and the ERP has been collected
        if self.in_phase('response') and \
                'ERPDatabaseEnable' in self.params and int(self.params['ERPDatabaseEnable']) and self.states['ERPCollected']:
            self.change_phase('stopcue')
    def Event(self, phase, event):
        if 'MSEnable' in self.params:	MagstimApp.event(self, phase, event)
        if 'DigitimerEnable' in self.params:	DigitimerApp.event(self, phase, event)
        if 'GatingEnable' in self.params:	GatingApp.event(self, phase, event)
        if 'ERPDatabaseEnable' in self.params:	ERPApp.event(self, phase, event)
        if 'ContFeedbackEnable' in self.params:	FeedbackApp.event(self, phase, event)

#################################################################
#################################################################
 def StartRun(self):
     #if int(self.params['ShowFixation']):
     self.states['LastTargetClass'] = self.target_codes[0]
     self.stimuli['fixation'].on = True
     if 'MSEnable' in self.params:	MagstimApp.startrun(self)
     if 'DigitimerEnable' in self.params:	DigitimerApp.startrun(self)
     if 'GatingEnable' in self.params:	GatingApp.startrun(self)
     if 'ERPDatabaseEnable' in self.params:	ERPApp.startrun(self)
     if 'ContFeedbackEnable' in self.params:	FeedbackApp.startrun(self)
Example #5
0
 def StartRun(self):
     #if int(self.params['ShowFixation']):
     self.states['LastTargetClass'] = self.target_codes[0]
     self.stimuli['fixation'].on = True
     if 'MSEnable' in self.params: MagstimApp.startrun(self)
     if 'DigitimerEnable' in self.params: DigitimerApp.startrun(self)
     if 'GatingEnable' in self.params: GatingApp.startrun(self)
     if 'ERPDatabaseEnable' in self.params: ERPApp.startrun(self)
     if 'ContFeedbackEnable' in self.params: FeedbackApp.startrun(self)
Example #6
0
    def Event(self, phase, event):
        if 'MSEnable' in self.params: MagstimApp.event(self, phase, event)
        if 'DigitimerEnable' in self.params:
            DigitimerApp.event(self, phase, event)
        if 'GatingEnable' in self.params: GatingApp.event(self, phase, event)
        if 'ERPDatabaseEnable' in self.params: ERPApp.event(self, phase, event)
        if 'ContFeedbackEnable' in self.params:
            FeedbackApp.event(self, phase, event)


#################################################################
#################################################################
Example #7
0
    def Transition(self, phase):
        # present stimuli and update state variables to record what is going on
        #=======================================================================
        # #Update some states
        # self.states['Intertrial'] = int(phase in ['intertrial'])
        self.states['Baseline'] = int(phase in ['baseline'])
        self.states['GoCue'] = int(phase in ['gocue'])
        self.states['Task'] = int(phase in ['task'])
        # self.states['Response']  = int(phase in ['response'])
        # self.states['StopCue']  = int(phase in ['stopcue'])
        #=======================================================================

        if phase == 'intertrial':
            pass

        elif phase == 'baseline':
            pass
        #Do I need the new TargetClass in baseline for any of the addons?
        #If not, then it belongs in gocue for consistency with regular BCI2000 modules.

        elif phase == 'gocue':
            self.states['TargetClass'] = self.target_codes[
                self.states['CurrentTrial'] - 1]
            t = self.states[
                'TargetClass']  #It's useful to pull from states in case "enslave states" is used.
            self.states[
                'LastTargetClass'] = t  #LastTargetClass maintains throughout baseline.
            self.stimuli['cue'].text = self.params['GoCueText'][t - 1]

        elif phase == 'task':
            task_length = self.params['TaskDur'].val + random(
            ) * self.params['TaskRand'].val
            self.states['TaskMinNBlocks'] = task_length * self.eegfs / self.spb

        elif phase == 'response':
            pass

        elif phase == 'stopcue':
            self.stimuli['cue'].text = "Relax"
            self.states[
                'TargetClass'] = 0  #Note we don't turn off the LastTargetClass

        self.stimuli['cue'].on = (phase in ['gocue', 'stopcue'])

        if 'MSEnable' in self.params: MagstimApp.transition(self, phase)
        if 'DigitimerEnable' in self.params:
            DigitimerApp.transition(self, phase)
        if 'GatingEnable' in self.params: GatingApp.transition(self, phase)
        if 'ERPDatabaseEnable' in self.params: ERPApp.transition(self, phase)
        if 'ContFeedbackEnable' in self.params:
            FeedbackApp.transition(self, phase)
    def Transition(self, phase):
        # present stimuli and update state variables to record what is going on
        #=======================================================================
        # #Update some states
        # self.states['Intertrial'] = int(phase in ['intertrial'])
        self.states['Baseline'] = int(phase in ['baseline'])
        self.states['GoCue'] = int(phase in ['gocue'])
        self.states['Task'] = int(phase in ['task'])
        # self.states['Response']  = int(phase in ['response'])
        # self.states['StopCue']  = int(phase in ['stopcue'])
        #=======================================================================

        if phase == 'intertrial':
            pass

        elif phase == 'baseline':
            pass
        #Do I need the new TargetClass in baseline for any of the addons?
        #If not, then it belongs in gocue for consistency with regular BCI2000 modules.

        elif phase == 'gocue':
            self.states['TargetClass'] = self.target_codes[self.states['CurrentTrial']-1]
            t = self.states['TargetClass'] #It's useful to pull from states in case "enslave states" is used.
            self.states['LastTargetClass'] = t#LastTargetClass maintains throughout baseline.
            self.stimuli['cue'].text = self.params['GoCueText'][t-1]

        elif phase == 'task':
            task_length = self.params['TaskDur'].val + random()*self.params['TaskRand'].val
            self.states['TaskMinNBlocks'] = task_length * self.eegfs / self.spb

        elif phase == 'response':
            pass

        elif phase == 'stopcue':
            self.stimuli['cue'].text = "Relax"
            self.states['TargetClass'] = 0 #Note we don't turn off the LastTargetClass

        self.stimuli['cue'].on = (phase in ['gocue', 'stopcue'])

        if 'MSEnable' in self.params:	MagstimApp.transition(self, phase)
        if 'DigitimerEnable' in self.params:	DigitimerApp.transition(self, phase)
        if 'GatingEnable' in self.params:	GatingApp.transition(self, phase)
        if 'ERPDatabaseEnable' in self.params:	ERPApp.transition(self, phase)
        if 'ContFeedbackEnable' in self.params:	FeedbackApp.transition(self, phase)
Example #9
0
    def Preflight(self, sigprops):
        #Setup screen
        siz = float(self.params['WindowSize'])
        screenid = int(
            self.params['ScreenId']
        )  # ScreenId 0 is the first screen, 1 the second, -1 the last
        fullscreen(
            scale=siz, id=screenid, frameless_window=(siz == 1)
        )  # only use a borderless window if the window is set to fill the whole screen

        self.nclasses = len(
            self.params['GoCueText']
        )  #Must be defined in Preflight because it is used by extension preflight.

        n_trials = self.params['TrialsPerBlock'].val * self.params[
            'BlocksPerRun'].val
        trials_per_class = int(n_trials / self.nclasses)
        if self.params['ClusterTargets'].val > 0 and not (
                trials_per_class % self.params['ClusterTargets'].val == 0):
            raise EndUserError, "ClusterTargets must be a integer factor of the number of trials per target"

        #If using gating or visual feedback, check that the target ranges make sense.
        if ('GatingEnable' in self.params
                and int(self.params['GatingEnable'].val)
                or ('ContFeedbackEnable' in self.params
                    and self.params['ContFeedbackEnable'].val) == 1):
            targrange = self.params['TargetRange'].val
            if targrange.shape[0] != self.nclasses:
                raise EndUserError, "TargetRange must have entries for each target"
            if targrange.shape[1] != 2:
                raise EndUserError, "TargetRange must have Min and Max values"
            if any([ar[(0, 0)] > ar[(0, 1)] for ar in targrange]):
                raise EndUserError, "TargetRange must be in increasing order"
            self.target_range = np.asarray(targrange, dtype='float64')

        if 'GatingEnable' in self.params: GatingApp.preflight(self, sigprops)
        if 'MSEnable' in self.params: MagstimApp.preflight(self, sigprops)
        if 'DigitimerEnable' in self.params:
            DigitimerApp.preflight(self, sigprops)
        if 'ERPDatabaseEnable' in self.params: ERPApp.preflight(self, sigprops)
        if 'ContFeedbackEnable' in self.params:
            FeedbackApp.preflight(self, sigprops)
    def Process(self, sig):
        #Process is called on every packet
        #Phase transitions occur independently of packets
        #Therefore it is not desirable to use phases for application logic in Process
        if 'MSEnable' in self.params:	MagstimApp.process(self, sig)
        if 'DigitimerEnable' in self.params:	DigitimerApp.process(self, sig)
        if 'ERPDatabaseEnable' in self.params:	ERPApp.process(self, sig)
        if 'ContFeedbackEnable' in self.params:	FeedbackApp.process(self, sig)
        if 'GatingEnable' in self.params:	GatingApp.process(self, sig)

        #If we are in Task, and we are using GatingApp or MagstimApp or DigitimerApp
        if self.taskMaxNBlocks>0 and self.in_phase('task', min_packets=self.taskMaxNBlocks):
            self.change_phase('response')
        elif self.in_phase('task', min_packets=self.states['TaskMinNBlocks']):
            criteria_met = not 'GatingEnable' in self.params or not int(self.params['GatingEnable']) or self.states['GatingOK']
            magstim_ready = not 'MSEnable' in self.params or not int(self.params['MSEnable']) or self.states['MagstimReady']
            digitimer_ready = not 'DigitimerEnable' in self.params or not int(self.params['DigitimerEnable']) or self.states['DigitimerReady']
            if criteria_met and magstim_ready and digitimer_ready:
                self.change_phase('response')

        #If we are in Response and we are using ERPApp and the ERP has been collected
        if self.in_phase('response') and \
                'ERPDatabaseEnable' in self.params and int(self.params['ERPDatabaseEnable']) and self.states['ERPCollected']:
            self.change_phase('stopcue')
 def StopRun(self):
     if 'MSEnable' in self.params:	MagstimApp.stoprun(self)
     if 'DigitimerEnable' in self.params:	DigitimerApp.stoprun(self)
     if 'GatingEnable' in self.params:	GatingApp.stoprun(self)
     if 'ERPDatabaseEnable' in self.params:	ERPApp.stoprun(self)
     if 'ContFeedbackEnable' in self.params:	FeedbackApp.stoprun(self)
    def Initialize(self, indim, outdim):       
        #=======================================================================
        # Set the list of TargetClasss (pseudorandomized)
        #=======================================================================
        n_trials = self.params['TrialsPerBlock'].val * self.params['BlocksPerRun'].val
        classes_per_cluster = self.params['ClusterTargets'].val
        trials_per_class = int(n_trials / self.nclasses)
        if classes_per_cluster == 0: #We will cycle through targets.
            self.target_codes = [item for sublist in [range(self.nclasses) for j in range(trials_per_class)] for item in sublist]
            self.target_codes = [x+1 for x in self.target_codes]
        elif classes_per_cluster ==1:
            self.target_codes = [1 + x / trials_per_class for x in range(n_trials)] #Forcing int yields e.g., [0,0,0,1,1,1,2,2,2]
            shuffle(self.target_codes)
        else:
            n_clusters = trials_per_class / classes_per_cluster
            temp = []
            for cc in range(n_clusters):
                temp2 = [[j for jj in range(classes_per_cluster)] for j in range(self.nclasses)] #Generate a list of clusters, one per target
                shuffle(temp2) #Shuffle the list of clusters
                temp.append(temp2) #Append the list of clusters to what we have already.
            self.target_codes = 1 + [x2 for x3 in [item for sublist in temp for item in sublist] for x2 in x3] #Flatten

        #=======================================================================
        # Screen
        #=======================================================================
        self.screen.color = (0,0,0) #let's have a black background
        self.scrw,self.scrh = self.screen.size #Get the screen dimensions.

        #===================================================================
        # Create a box object as the coordinate frame for the screen.
        # Manipulate its properties to get positional information for stimuli.
        #===================================================================
        scrsiz = min(self.scrw,self.scrh)
        siz = (scrsiz, scrsiz)
        b = box(size=siz, position=(self.scrw/2.0,self.scrh/2.0), sticky=True)
        center = b.map((0.5,0.5), 'position')
        self.positions = {'origin': np.matrix(center)} #Save the origin for later.

        #=======================================================================
        # Register the basic stimuli.
        #=======================================================================
        self.stimulus('cue', z=5, stim=VisualStimuli.Text(text='?', position=center, anchor='center', color=(1,1,1), font_size=50, on=False))
        self.stimulus('fixation', z=4.2, stim=Disc(position=center, radius=5, color=(1,1,1), on=False))

        #=======================================================================
        # Make a few variables easier to access.
        #=======================================================================
        self.eegfs = self.nominal['SamplesPerSecond'] #Sampling rate
        self.spb = self.nominal['SamplesPerPacket'] #Samples per block/packet
        self.block_dur = 1000*self.spb/self.eegfs#duration (ms) of a sample block
        self.taskMaxNBlocks = self.params['TaskMax'].val * self.eegfs / self.spb#Task will always go to response after this many blocks, even if extensions not ready

        #=======================================================================
        # State monitors for debugging.
        #=======================================================================
        if int(self.params['ShowSignalTime']):
            # turn on state monitors iff the packet clock is also turned on
            addstatemonitor(self, 'Running', showtime=True)
            addstatemonitor(self, 'CurrentBlock')
            addstatemonitor(self, 'CurrentTrial')
            addstatemonitor(self, 'TargetClass')
            addstatemonitor(self, 'LastTargetClass')
            addstatemonitor(self, 'TaskMinNBlocks')
            addphasemonitor(self, 'phase', showtime=True)

            m = addstatemonitor(self, 'fs_reg')
            m.func = lambda x: '% 6.1fHz' % x._regfs.get('SamplesPerSecond', 0)
            m.pargs = (self,)
            m = addstatemonitor(self, 'fs_avg')
            m.func = lambda x: '% 6.1fHz' % x.estimated.get('SamplesPerSecond',{}).get('global', 0)
            m.pargs = (self,)
            m = addstatemonitor(self, 'fs_run')
            m.func = lambda x: '% 6.1fHz' % x.estimated.get('SamplesPerSecond',{}).get('running', 0)
            m.pargs = (self,)
            m = addstatemonitor(self, 'fr_run')
            m.func = lambda x: '% 6.1fHz' % x.estimated.get('FramesPerSecond',{}).get('running', 0)
            m.pargs = (self,)

        if 'MSEnable' in self.params:	MagstimApp.initialize(self, indim, outdim)
        if 'DigitimerEnable' in self.params:	DigitimerApp.initialize(self, indim, outdim)
        if 'GatingEnable' in self.params:	GatingApp.initialize(self, indim, outdim)
        if 'ERPDatabaseEnable' in self.params:	ERPApp.initialize(self, indim, outdim)
        if 'ContFeedbackEnable' in self.params:	FeedbackApp.initialize(self, indim, outdim)
Example #13
0
 def StopRun(self):
     if 'MSEnable' in self.params: MagstimApp.stoprun(self)
     if 'DigitimerEnable' in self.params: DigitimerApp.stoprun(self)
     if 'GatingEnable' in self.params: GatingApp.stoprun(self)
     if 'ERPDatabaseEnable' in self.params: ERPApp.stoprun(self)
     if 'ContFeedbackEnable' in self.params: FeedbackApp.stoprun(self)
Example #14
0
    def Initialize(self, indim, outdim):
        #=======================================================================
        # Set the list of TargetClasss (pseudorandomized)
        #=======================================================================
        n_trials = self.params['TrialsPerBlock'].val * self.params[
            'BlocksPerRun'].val
        classes_per_cluster = self.params['ClusterTargets'].val
        trials_per_class = int(n_trials / self.nclasses)
        if classes_per_cluster == 0:  #We will cycle through targets.
            self.target_codes = [
                item for sublist in
                [range(self.nclasses) for j in range(trials_per_class)]
                for item in sublist
            ]
            self.target_codes = [x + 1 for x in self.target_codes]
        elif classes_per_cluster == 1:
            self.target_codes = [
                1 + x / trials_per_class for x in range(n_trials)
            ]  #Forcing int yields e.g., [0,0,0,1,1,1,2,2,2]
            shuffle(self.target_codes)
        else:
            n_clusters = trials_per_class / classes_per_cluster
            temp = []
            for cc in range(n_clusters):
                temp2 = [[j for jj in range(classes_per_cluster)]
                         for j in range(self.nclasses)
                         ]  #Generate a list of clusters, one per target
                shuffle(temp2)  #Shuffle the list of clusters
                temp.append(
                    temp2
                )  #Append the list of clusters to what we have already.
            self.target_codes = 1 + [
                x2 for x3 in [item for sublist in temp for item in sublist]
                for x2 in x3
            ]  #Flatten

        #=======================================================================
        # Screen
        #=======================================================================
        self.screen.color = (0, 0, 0)  #let's have a black background
        self.scrw, self.scrh = self.screen.size  #Get the screen dimensions.

        #===================================================================
        # Create a box object as the coordinate frame for the screen.
        # Manipulate its properties to get positional information for stimuli.
        #===================================================================
        scrsiz = min(self.scrw, self.scrh)
        siz = (scrsiz, scrsiz)
        b = box(size=siz,
                position=(self.scrw / 2.0, self.scrh / 2.0),
                sticky=True)
        center = b.map((0.5, 0.5), 'position')
        self.positions = {
            'origin': np.matrix(center)
        }  #Save the origin for later.

        #=======================================================================
        # Register the basic stimuli.
        #=======================================================================
        self.stimulus('cue',
                      z=5,
                      stim=VisualStimuli.Text(text='?',
                                              position=center,
                                              anchor='center',
                                              color=(1, 1, 1),
                                              font_size=50,
                                              on=False))
        self.stimulus('fixation',
                      z=4.2,
                      stim=Disc(position=center,
                                radius=5,
                                color=(1, 1, 1),
                                on=False))

        #=======================================================================
        # Make a few variables easier to access.
        #=======================================================================
        self.eegfs = self.nominal['SamplesPerSecond']  #Sampling rate
        self.spb = self.nominal['SamplesPerPacket']  #Samples per block/packet
        self.block_dur = 1000 * self.spb / self.eegfs  #duration (ms) of a sample block
        self.taskMaxNBlocks = self.params[
            'TaskMax'].val * self.eegfs / self.spb  #Task will always go to response after this many blocks, even if extensions not ready

        #=======================================================================
        # State monitors for debugging.
        #=======================================================================
        if int(self.params['ShowSignalTime']):
            # turn on state monitors iff the packet clock is also turned on
            addstatemonitor(self, 'Running', showtime=True)
            addstatemonitor(self, 'CurrentBlock')
            addstatemonitor(self, 'CurrentTrial')
            addstatemonitor(self, 'TargetClass')
            addstatemonitor(self, 'LastTargetClass')
            addstatemonitor(self, 'TaskMinNBlocks')
            addphasemonitor(self, 'phase', showtime=True)

            m = addstatemonitor(self, 'fs_reg')
            m.func = lambda x: '% 6.1fHz' % x._regfs.get('SamplesPerSecond', 0)
            m.pargs = (self, )
            m = addstatemonitor(self, 'fs_avg')
            m.func = lambda x: '% 6.1fHz' % x.estimated.get(
                'SamplesPerSecond', {}).get('global', 0)
            m.pargs = (self, )
            m = addstatemonitor(self, 'fs_run')
            m.func = lambda x: '% 6.1fHz' % x.estimated.get(
                'SamplesPerSecond', {}).get('running', 0)
            m.pargs = (self, )
            m = addstatemonitor(self, 'fr_run')
            m.func = lambda x: '% 6.1fHz' % x.estimated.get(
                'FramesPerSecond', {}).get('running', 0)
            m.pargs = (self, )

        if 'MSEnable' in self.params:
            MagstimApp.initialize(self, indim, outdim)
        if 'DigitimerEnable' in self.params:
            DigitimerApp.initialize(self, indim, outdim)
        if 'GatingEnable' in self.params:
            GatingApp.initialize(self, indim, outdim)
        if 'ERPDatabaseEnable' in self.params:
            ERPApp.initialize(self, indim, outdim)
        if 'ContFeedbackEnable' in self.params:
            FeedbackApp.initialize(self, indim, outdim)