Thursday, October 22, 2009

Presenting a stimulus for a fixed duration (despite button presses)

Especially with fMRI, I want my trials to last a particular duration, whether or not the subject responded by pressing a button.

The standard PRESENT function terminates as soon as a button has been pressed. You could immediately re-present the stimulus for the remaining duration, but this creates an annoying flicker.

I sub-classed Text and Image to add a PRESENT_FIXED_DUR function that deals with this problem. This issue was also raised on the PyEPL mailing list.

For images:

#!/usr/bin/python

# from pyepl.hardware.graphics import Image
from pyepl.locals import Image
from pyepl.display import VideoTrack
from pyepl.locals import PresentationClock

class Image2(Image):

    def present_fixed_dur(self, clk=None, duration=None, bc=None, minDuration=None):
        """
        This is just like the standard Image.present, except
        that if you press a button, the image stays on the
        screen until the full duration has passed.

        I got rid of the jitter argument, because it makes
        things complicated.
        """

        v = VideoTrack.lastInstance()
        
        # get the clock if needed
        if clk is None: clk = PresentationClock()

        # show the image
        t = v.showCentered(self)
        timestamp = v.updateScreen(clk)

        if bc:
            # wait for button press
            button,bc_time = bc.waitWithTime(minDuration,duration,clk)
            # figure out how much time is remaining, now
            # that they've pressed the button, and delay for
            # just that
            rt = bc_time[0] - timestamp[0]
            clk.delay(duration-rt)
        else:
            clk.delay(duration)

        # unshow that image
        v.unshow(t)
        upd_ts = v.updateScreen(clk)
        # print 'presented for %ims' % (upd_ts[0] - timestamp[0])

        if bc: return timestamp,button,bc_time
        else: return timestamp

For text:

#!/usr/bin/python

# from pyepl.hardware.graphics import Image
from pyepl.locals import Text
from pyepl.display import VideoTrack

class Text2(Text):

    def present_fixed_dur(self, clk=None, duration=None, bc=None, minDuration=None, xProp=.5, yProp=.5):
        """
        Just as Text2.present, but (like
        Image2.present_fixed_dur): the standard
        Text.present, except that if you press a button, the
        stimulus stays on the screen until the full duration
        has passed.
        """

        # print 'starting present_fixed_dur'
        v = VideoTrack.lastInstance()
        
        # get the clock if needed
        if clk is None: clk = exputils.PresentationClock()

        # show the image
        t = v.showProportional(self,xProp,yProp)
        timestamp = v.updateScreen(clk)

        if bc:
            # wait for button press
            button,bc_time = bc.waitWithTime(minDuration,duration,clk)
            rt = bc_time[0] - timestamp[0]
            # print 'delaying by %i' % (duration-rt)
            # only delay if duration is True
            if duration and (duration-rt): clk.delay(duration-rt)
        else:
            # print 'delaying by %i' % duration
            if duration: clk.delay(duration)

        v.unshow(t)
        v.updateScreen(clk)

        # print 'ending present_fixed_dur'

        if bc: return timestamp,button,bc_time
        else: return timestamp

No comments: