예제 #1
0
파일: noise.py 프로젝트: zlager26/psychopy
 def _filter(self, FT):
     """ Helper function to apply Butterworth filter in 
         frequensy domain.
     """
     filterSize = numpy.max(self._size)
     pin=filters.makeRadialMatrix(matrixSize=filterSize, center=(0,0), radius=1.0)
     pin[int(filterSize / 2)][int(filterSize / 2)] = 0.00000001  # Prevents divide by zero error. This is DC and is set to zero later anyway.
     FT = numpy.multiply(FT,(pin) ** self.noiseFractalPower)
     if self.noiseFilterOrder > 0.01:
         if self._upsf<(filterSize/2.0):
             filter = filters.butter2d_lp_elliptic(size = [filterSize,filterSize], 
                                                         cutoff_x = self._upsf / filterSize, 
                                                         cutoff_y = self._upsf / filterSize, 
                                                         n=self.noiseFilterOrder, 
                                                         alpha=0, 
                                                             offset_x = 0.5/filterSize,  #becuase FFTs are slightly off centred.
                                                             offset_y = 0.5/filterSize)
         else:
             filter = numpy.ones((int(filterSize),int(filterSize)))
         if self._lowsf > 0:
             if self._lowsf > filterSize/2:
                 msg = ('Lower cut off frequency for filtered '
                 'noise is too high (exceeds Nyquist limit).')
                 raise Warning(msg)
             filter = filter-filters.butter2d_lp_elliptic(size = [filterSize,filterSize], 
                                                             cutoff_x = self._lowsf / filterSize, 
                                                             cutoff_y = self._lowsf / filterSize, 
                                                             n = self.noiseFilterOrder, 
                                                             alpha = 0, 
                                                             offset_x = 0.5/filterSize, #becuase FFTs are slightly off centred.
                                                             offset_y = 0.5/filterSize)
         return FT * filter
     else:
         return FT
예제 #2
0
파일: noise.py 프로젝트: isolver/psychopy
 def _filter(self, FT):
     """ Helper function to apply Butterworth filter in 
         frequensy domain.
     """
     filterSize = numpy.max(self._size)
     pin=filters.makeRadialMatrix(matrixSize=filterSize, center=(0,0), radius=1.0)
     pin[int(filterSize / 2)][int(filterSize / 2)] = 0.00000001  # Prevents divide by zero error. This is DC and is set to zero later anyway.
     FT = numpy.multiply(FT,(pin) ** self.noiseFractalPower)
     if self.noiseFilterOrder > 0.01:
         if self._upsf<(filterSize/2.0):
             filter = filters.butter2d_lp_elliptic(size = [filterSize,filterSize], 
                                                         cutoff_x = self._upsf / filterSize, 
                                                         cutoff_y = self._upsf / filterSize, 
                                                         n=self.noiseFilterOrder, 
                                                         alpha=0, 
                                                             offset_x = 0.5/filterSize,  #becuase FFTs are slightly off centred.
                                                             offset_y = 0.5/filterSize)
         else:
             filter = numpy.ones((int(filterSize),int(filterSize)))
         if self._lowsf > 0:
             if self._lowsf > filterSize/2:
                 msg = ('Lower cut off frequency for filtered '
                 'noise is too high (exceeds Nyquist limit).')
                 raise Warning(msg)
             filter = filter-filters.butter2d_lp_elliptic(size = [filterSize,filterSize], 
                                                             cutoff_x = self._lowsf / filterSize, 
                                                             cutoff_y = self._lowsf / filterSize, 
                                                             n = self.noiseFilterOrder, 
                                                             alpha = 0, 
                                                             offset_x = 0.5/filterSize, #becuase FFTs are slightly off centred.
                                                             offset_y = 0.5/filterSize)
         return FT * filter
     else:
         return FT
예제 #3
0
파일: noise.py 프로젝트: zlager26/psychopy
 def _isotropic(self, FT):
     """ Helper function to apply isotropic filter in 
         frequensy domain.
     """
     if self._sf > self._size / 2:
         msg = ('Base frequency for isotropic '
               'noise is  too high (exceeds Nyquist limit).')
         raise Warning(msg)
     localf = self._sf / self._size
     linbw = 2 ** self.noiseBW
     lowf = 2.0 * localf / (linbw+1.0)
     highf = linbw * lowf
     FWF = highf - lowf
     sigmaF = FWF / (2*numpy.sqrt(2*numpy.log(2)))
     pin = filters.makeRadialMatrix(matrixSize=self._size, center=(0,0), radius=2)
     filter = filters.makeGauss(pin, mean=localf, sd=sigmaF)
     return FT*filter
예제 #4
0
파일: noise.py 프로젝트: isolver/psychopy
 def _isotropic(self, FT):
     """ Helper function to apply isotropic filter in 
         frequensy domain.
     """
     if self._sf > self._size / 2:
         msg = ('Base frequency for isotropic '
               'noise is  too high (exceeds Nyquist limit).')
         raise Warning(msg)
     localf = self._sf / self._size
     linbw = 2 ** self.noiseBW
     lowf = 2.0 * localf / (linbw+1.0)
     highf = linbw * lowf
     FWF = highf - lowf
     sigmaF = FWF / (2*numpy.sqrt(2*numpy.log(2)))
     pin = filters.makeRadialMatrix(matrixSize=self._size, center=(0,0), radius=2)
     filter = filters.makeGauss(pin, mean=localf, sd=sigmaF)
     return FT*filter
예제 #5
0
    def buildNoise(self):
        """build a new noise sample. Required to act on changes to any noise parameters or texRes.
        """

        if self.units == 'pix':
            if not (self.noiseType in ['Binary','binary','Normal','normal','uniform','Uniform']):
                mysize = numpy.max(self.size)
            else:
                mysize = self.size
            sampleSize = self.noiseElementSize
            mysf = self.__dict__['noiseBaseSf']*mysize
            lowsf = self.noiseFilterLower*mysize
            upsf = self.noiseFilterUpper*mysize
        else:
            mysize = self.texRes
            pixSize = self.size/self.texRes
            sampleSize = self.noiseElementSize/pixSize
            mysf = self.size[0]*self.noiseBaseSf
            lowsf = self.size[0]*self.noiseFilterLower
            upsf = self.size[0]*self.noiseFilterUpper
       
        self._size = mysize  # store for use by updateNoise()
        self._sf = mysf
        if self.noiseType in ['binary','Binary','normal','Normal','uniform','Uniform']:
            self._sideLength = numpy.round(mysize/sampleSize)  # dummy side length for use when unpacking noise samples in updateNoise()
            self._sideLength.astype(int)
            if ((self._sideLength[0] < 2) and (self._sideLength[1] < 2)):
                msg=('Noise sample size '
                     'must result in more than '
                     '1 sample per image dimension.')
                raise ValueError(msg)
            totalSamples = self._sideLength[0]*self._sideLength[1]
            if self.noiseType in ['binary','Binary']:
                self.noiseTex=numpy.append(numpy.ones(int(numpy.round(totalSamples/2.0))),-1*numpy.ones(int(numpy.round(totalSamples/2.0))))
        elif self.noiseType in ['White','white']:
            self.noiseTex = numpy.ones((int(mysize),int(mysize)))
            self.noiseTex[0][0] = 0
        #elif self.noiseType in ['Coloured','coloured']:
        #    pin=filters.makeRadialMatrix(matrixSize=mysize, center=(0,0), radius=1.0)
        #    self.noiseTex=numpy.multiply(numpy.ones((int(mysize),int(mysize))),(pin)**self.noiseFractalPower) 
        #    self.noiseTex=fftshift(self.noiseTex)
        #    self.noiseTex[0][0]=0
        elif self.noiseType in ['Isotropic','isotropic']:
            if mysf > mysize/2:
                msg = ('Base frequency for isotropic '
                      'noise is definitely too high.')
                raise Warning(msg)
            localf = mysf/mysize
            linbw = 2**self.noiseBW
            lowf = 2.0*localf/(linbw+1.0)
            highf = linbw*lowf
            FWF = highf-lowf
            sigmaF = FWF/(2*numpy.sqrt(2*numpy.log(2)))
            self.noiseTex = numpy.zeros(int(mysize**2))
            self.noiseTex = numpy.reshape(self.noiseTex,(int(mysize),int(mysize)))
            pin = filters.makeRadialMatrix(matrixSize=mysize, center=(0,0), radius=2)
            self.noiseTex = filters.makeGauss(pin, mean=localf, sd=sigmaF)
            self.noiseTex = fftshift(self.noiseTex)
            self.noiseTex[0][0] = 0
        elif self.noiseType in ['Gabor','gabor']:
            if mysf > mysize/2:
                msg = ('Base frequency for Gabor '
                      'noise is definitely too high.')
                raise Warning(msg)
            localf = mysf/mysize
            linbw = 2**self.noiseBW
            lowf = 2.0*localf/(linbw+1.0)
            highf = linbw*lowf
            FWF = highf-lowf
            sigmaF = FWF/(2*numpy.sqrt(2*numpy.log(2)))
            FWO = 2.0*localf*numpy.tan(numpy.pi*self.noiseBWO/360.0)
            sigmaO = FWO/(2*numpy.sqrt(2*numpy.log(2)))
            self.noiseTex=numpy.zeros(int(mysize**2))
            self.noiseTex=numpy.reshape(self.noiseTex,(int(mysize),int(mysize)))
            yy, xx = numpy.mgrid[0:mysize, 0:mysize]
            xx = (0.5 - 1.0 / mysize * xx) 
            yy = (0.5 - 1.0 / mysize * yy) 
            self.noiseTex=filters.make2DGauss(xx,yy,mean=(localf,0), sd=(sigmaF,sigmaO))
            self.noiseTex=self.noiseTex+filters.make2DGauss(xx,yy, mean=(-localf,0), sd=(sigmaF,sigmaO))
            self.noiseTex=fftshift(self.noiseTex)
            self.noiseTex[0][0]=0
        elif self.noiseType in ['Image','image']:
            if not(self.noiseImage in ['None','none']):  
                im = Image.open(self.noiseImage)
                im = im.transpose(Image.FLIP_TOP_BOTTOM)
                im = im.convert("L")  # FORCE TO LUMINANCE
                intensity = numpy.array(im).astype(
                        numpy.float32) * 0.0078431372549019607 - 1.0
                self.noiseTex =  numpy.absolute(fft2(intensity))
            else:
                self.noiseTex = numpy.ones((int(mysize),int(mysize)))  # if image is 'None' will make white noise as tempary measure
            self.noiseTex[0][0]=0
        elif self.noiseType in ['filtered','Filtered']:
            pin=filters.makeRadialMatrix(matrixSize=mysize, center=(0,0), radius=1.0)
            self.noiseTex = numpy.multiply(numpy.ones((int(mysize),int(mysize))),(pin)**self.noiseFractalPower)
            if lowsf > mysize/2:
                msg = ('Lower cut off frequency for filtered '
                      'noise is definitely too high.')
                raise Warning(msg)
            if self.noiseFilterOrder > 0.01:
                if upsf<(mysize/2.0):
                    filter = filters.butter2d_lp_elliptic(size=[mysize,mysize], cutoff_x=upsf/mysize, cutoff_y=upsf/mysize, n=self.noiseFilterOrder, alpha=0, offset_x=2/(mysize-1),offset_y=2/(mysize-1))
                else:
                    filter = numpy.ones((int(mysize),int(mysize)))
                if lowsf>0:
                    filter = filter-filters.butter2d_lp_elliptic(size=[mysize,mysize], cutoff_x=lowsf/mysize, cutoff_y=lowsf/mysize, n=self.noiseFilterOrder, alpha=0, offset_x=2/(mysize-1),offset_y=2/(mysize-1))
                self.noiseTex = self.noiseTex*filter
            self.noiseTex = fftshift(self.noiseTex)
            self.noiseTex[0][0] = 0
        else:
            raise ValueError('Noise type not recognised.')
        self._needBuild = False # prevent noise from being re-built at next draw() unless a parameter is chnaged in the mean time.
        self.updateNoise()  # now choose the initial random sample.
예제 #6
0
    def buildNoise(self):
        """build a new noise sample. Required to act on changes to any noise parameters or texRes.
        """

        if self.units == 'pix':
            if not (self.noiseType in ['Binary','binary','Normal','normal','uniform','Uniform']):
                mysize = numpy.max(self.size)
            else:
                mysize = self.size
            sampleSize = self.noiseElementSize
            mysf = self.__dict__['noiseBaseSf']*mysize
            lowsf = self.noiseFilterLower*mysize
            upsf = self.noiseFilterUpper*mysize
        else:
            mysize = self.texRes
            pixSize = self.size/self.texRes
            sampleSize = self.noiseElementSize/pixSize
            mysf = self.size[0]*self.noiseBaseSf
            lowsf = self.size[0]*self.noiseFilterLower
            upsf = self.size[0]*self.noiseFilterUpper
       
        self._size = mysize  # store for use by updateNoise()
        self._sf = mysf
        if self.noiseType in ['binary','Binary','normal','Normal','uniform','Uniform']:
            self._sideLength = numpy.round(mysize/sampleSize)  # dummy side length for use when unpacking noise samples in updateNoise()
            self._sideLength.astype(int)
            if ((self._sideLength[0] < 2) and (self._sideLength[1] < 2)):
                msg=('Noise sample size '
                     'must result in more than '
                     '1 sample per image dimension.')
                raise ValueError(msg)
            totalSamples = self._sideLength[0]*self._sideLength[1]
            if self.noiseType in ['binary','Binary']:
                self.noiseTex=numpy.append(numpy.ones(int(numpy.round(totalSamples/2.0))),-1*numpy.ones(int(numpy.round(totalSamples/2.0))))
        elif self.noiseType in ['White','white']:
            self.noiseTex = numpy.ones((int(mysize),int(mysize)))
            self.noiseTex[0][0] = 0
        #elif self.noiseType in ['Coloured','coloured']:
        #    pin=filters.makeRadialMatrix(matrixSize=mysize, center=(0,0), radius=1.0)
        #    self.noiseTex=numpy.multiply(numpy.ones((int(mysize),int(mysize))),(pin)**self.noiseFractalPower) 
        #    self.noiseTex=fftshift(self.noiseTex)
        #    self.noiseTex[0][0]=0
        elif self.noiseType in ['Isotropic','isotropic']:
            if mysf > mysize/2:
                msg = ('Base frequency for isotropic '
                      'noise is definitely too high.')
                raise Warning(msg)
            localf = mysf/mysize
            linbw = 2**self.noiseBW
            lowf = 2.0*localf/(linbw+1.0)
            highf = linbw*lowf
            FWF = highf-lowf
            sigmaF = FWF/(2*numpy.sqrt(2*numpy.log(2)))
            self.noiseTex = numpy.zeros(int(mysize**2))
            self.noiseTex = numpy.reshape(self.noiseTex,(int(mysize),int(mysize)))
            pin = filters.makeRadialMatrix(matrixSize=mysize, center=(0,0), radius=2)
            self.noiseTex = filters.makeGauss(pin, mean=localf, sd=sigmaF)
            self.noiseTex = fftshift(self.noiseTex)
            self.noiseTex[0][0] = 0
        elif self.noiseType in ['Gabor','gabor']:
            if mysf > mysize/2:
                msg = ('Base frequency for Gabor '
                      'noise is definitely too high.')
                raise Warning(msg)
            localf = mysf/mysize
            linbw = 2**self.noiseBW
            lowf = 2.0*localf/(linbw+1.0)
            highf = linbw*lowf
            FWF = highf-lowf
            sigmaF = FWF/(2*numpy.sqrt(2*numpy.log(2)))
            FWO = 2.0*localf*numpy.tan(numpy.pi*self.noiseBWO/360.0)
            sigmaO = FWO/(2*numpy.sqrt(2*numpy.log(2)))
            self.noiseTex=numpy.zeros(int(mysize**2))
            self.noiseTex=numpy.reshape(self.noiseTex,(int(mysize),int(mysize)))
            yy, xx = numpy.mgrid[0:mysize, 0:mysize]
            xx = (0.5 - 1.0 / mysize * xx) 
            yy = (0.5 - 1.0 / mysize * yy) 
            self.noiseTex=filters.make2DGauss(xx,yy,mean=(localf,0), sd=(sigmaF,sigmaO))
            self.noiseTex=self.noiseTex+filters.make2DGauss(xx,yy, mean=(-localf,0), sd=(sigmaF,sigmaO))
            self.noiseTex=fftshift(self.noiseTex)
            self.noiseTex[0][0]=0
        elif self.noiseType in ['Image','image']:
            if not(self.noiseImage in ['None','none']):  
                im = Image.open(self.noiseImage)
                im = im.transpose(Image.FLIP_TOP_BOTTOM)
                im = im.convert("L")  # FORCE TO LUMINANCE
                intensity = numpy.array(im).astype(
                        numpy.float32) * 0.0078431372549019607 - 1.0
                self.noiseTex =  numpy.absolute(fft2(intensity))
            else:
                self.noiseTex = numpy.ones((int(mysize),int(mysize)))  # if image is 'None' will make white noise as tempary measure
            self.noiseTex[0][0]=0
        elif self.noiseType in ['filtered','Filtered']:
            pin=filters.makeRadialMatrix(matrixSize=mysize, center=(0,0), radius=1.0)
            self.noiseTex = numpy.multiply(numpy.ones((int(mysize),int(mysize))),(pin)**self.noiseFractalPower)
            if lowsf > mysize/2:
                msg = ('Lower cut off frequency for filtered '
                      'noise is definitely too high.')
                raise Warning(msg)
            if self.noiseFilterOrder > 0.01:
                if upsf<(mysize/2.0):
                    filter = filters.butter2d_lp_elliptic(size=[mysize,mysize], cutoff_x=upsf/mysize, cutoff_y=upsf/mysize, n=self.noiseFilterOrder, alpha=0, offset_x=2/(mysize-1),offset_y=2/(mysize-1))
                else:
                    filter = numpy.ones((int(mysize),int(mysize)))
                if lowsf>0:
                    filter = filter-filters.butter2d_lp_elliptic(size=[mysize,mysize], cutoff_x=lowsf/mysize, cutoff_y=lowsf/mysize, n=self.noiseFilterOrder, alpha=0, offset_x=2/(mysize-1),offset_y=2/(mysize-1))
                self.noiseTex = self.noiseTex*filter
            self.noiseTex = fftshift(self.noiseTex)
            self.noiseTex[0][0] = 0
        else:
            raise ValueError('Noise type not recognised.')
        self._needBuild = False # prevent noise from being re-built at next draw() unless a parameter is chnaged in the mean time.
        self.updateNoise()  # now choose the inital random sample.
예제 #7
0
A 256x256x3 array has its color defined by the array (obviously).

This demo creates a radial array as a patch stimulus, using helper functions from
psychopy.filters and then creates a second sub-stimulus created from a section of
the original. Both are masked simply by circles.
"""
from psychopy import visual, event, core
from psychopy.visual import filters
import numpy as np

win = visual.Window([800, 600], units='pix')

# Generate the radial textures
cycles = 6
res = 512
radius = filters.makeRadialMatrix(res)
radialTexture = np.sin(radius * 2 * np.pi * cycles)
mainMask = filters.makeMask(res)

# Select the upper left quadrant of our radial stimulus
radialTexture_sub = radialTexture[256:, 0:256]
# and create an appropriate mask for it
subMask = filters.makeMask(res, radius=0.5, center=[-0, 0])

bigStim = visual.GratingStim(win,
                             tex=radialTexture,
                             mask=mainMask,
                             color='white',
                             size=512,
                             sf=1.0 / 512,
                             interpolate=True)
예제 #8
0
def driftChecker3mask(scanDict,
                      screenSize=[1024, 768],
                      offTimeBehavior=1,
                      maskType=1):
    #do wedge
    #length of scan in s
    scanLength = float(scanDict['numCycles'] * scanDict['period'] +
                       scanDict['preScanRest'])
    #count number of screens
    if scanDict['operatorScreen'] == scanDict['subjectScreen']:
        screenCount = 1
    else:
        screenCount = 2
    thisPlatform = scanDict['platform']
    screenSize = scanDict['screenSize']
    #if there is only one window, need to display the winOp stuff and then clear it

    if screenCount == 1:
        #pop up the Tr info and wait for "ok"
        winOp = visual.Window([500, 500],
                              monitor='testMonitor',
                              units='norm',
                              screen=scanDict['operatorScreen'],
                              color=[0.0, 0.0, 0.0],
                              colorSpace='rgb')
        msgScanLength = visual.TextStim(winOp,
                                        pos=[0, 0.5],
                                        units='norm',
                                        height=0.1,
                                        text='Scan length (s): %.1f' %
                                        scanLength)
        msgScanTr = visual.TextStim(
            winOp,
            pos=[0, 0],
            units='norm',
            height=0.1,
            text='No. of Volumes (at Tr=%.2f): %.1f' %
            (scanDict['Tr'], scanLength / scanDict['Tr']))
        msgOK = visual.TextStim(winOp,
                                pos=[0, -0.5],
                                units='norm',
                                height=0.1,
                                text='Operator, press any key to proceed')
        msgScanLength.draw()
        msgScanTr.draw()
        msgOK.draw()
        winOp.flip()
        #wait for keypress
        thisKey = None
        while thisKey == None:
            thisKey = event.waitKeys()
        if thisKey in ['q', 'escape']:
            core.quit()  #abort
        else:
            event.clearEvents()
        #close the winOp
        winOp.close()
    else:
        winOp = visual.Window([500, 500],
                              monitor='testMonitor',
                              units='norm',
                              screen=scanDict['operatorScreen'],
                              color=[0.0, 0.0, 0.0],
                              colorSpace='rgb')
        msgScanLength = visual.TextStim(winOp,
                                        pos=[0, 0.5],
                                        units='norm',
                                        height=0.1,
                                        text='Scan length (s): %.1f' %
                                        scanLength)
        msgScanTr = visual.TextStim(
            winOp,
            pos=[0, 0],
            units='norm',
            height=0.1,
            text='No. of Volumes (at Tr=%.2f): %.1f' %
            (scanDict['Tr'], scanLength / scanDict['Tr']))
        msgScanLength.draw()
        msgScanTr.draw()
        winOp.flip()
    #open subject window
    winSub = visual.Window(screenSize,
                           monitor=scanDict['monCalFile'],
                           units='deg',
                           screen=scanDict['subjectScreen'],
                           color=[0.0, 0.0, 0.0],
                           colorSpace='rgb',
                           fullscr=False,
                           allowGUI=False)

    #parse out vars from scanDict
    IR = scanDict['innerRadius']
    OR = scanDict['outerRadius']
    Ralpha = scanDict['Ralpha']
    Rbeta = scanDict['Rbeta']
    preScanRest = scanDict['preScanRest']
    contrast = scanDict['contrast']

    #get actual size of window--useful in the functions
    subWinSize = winSub.size
    screenSize = numpy.array([subWinSize[0], subWinSize[1]])
    fixPercentage = scanDict['fixFraction']
    fixDuration = 0.2
    respDuration = 1.0
    dummyLength = int(numpy.ceil(scanLength * 60 / 100))
    subjectResponse = numpy.zeros((dummyLength, 1))
    subjectResponse[:] = numpy.nan
    white = [1.0, 1.0, 1.0]
    gray = [0.0, 0.0, 0.0]
    black = [-1.0, -1.0, -1.0]

    #print winSub.fps()

    #test "refresh" rate
    #[frameTimeAvg,frameTimeStd,frameTimeMed] = visual.getMsPerFrame(winSub,nFrames=120, showVisual=True, msg='', msDelay=0.0)
    #print frameTimeAvg
    #print frameTimeMed
    #refreshRate = 1000.0/frameTimeMed
    #runInfo=psychopy.info.RunTimeInfo(win = winSub,refreshTest='grating',verbose=True)
    #print runInfo
    #create stimulus
    #make 3 wedges, each 7.5 degrees wide, with opposite phase
    #use visibleWedge=[0, 45]???
    #initial orientations
    wedgeSize = [0.0, 18]
    startOris = range(0, 360, 18)
    startPhases = numpy.random.rand(10)
    #    wedgeWidth=360.0/12.0
    numRadialCycles = OR / 2.0
    #   wedgeOriInit=numpy.arange(0,360,30)
    #   wedgeSize=[0.0,30.0]
    wedge1 = visual.RadialStim(winSub,
                               pos=[0, 0],
                               tex='sqrXsqr',
                               radialCycles=numRadialCycles,
                               angularCycles=0,
                               size=OR * 2,
                               color=1,
                               visibleWedge=wedgeSize,
                               ori=0,
                               interpolate=False,
                               contrast=contrast,
                               autoLog=False)

    altWedges = numpy.random.rand(10)
    for iGrr in range(0, 10):
        altWedges[iGrr] = (-1)**iGrr
    #organize the masks for the two masked runs
    if offTimeBehavior == 3 and maskType == 1:
        #center innersurround outersurround
        #mask out just the parts necessary
        #make a square array filled with radii
        myfilterRaw = filters.makeRadialMatrix(1024)
        #get monitor infor==need max visual angle to scale filter dimensions
        thisMonitor = monitors.Monitor(scanDict['monCalFile'])

        maxVisualAngleRad = numpy.arctan(0.5 * thisMonitor.getWidth() /
                                         thisMonitor.getDistance())
        maxVisualAngle = maxVisualAngleRad * 180.0 / numpy.pi

        myfilter = myfilterRaw * maxVisualAngle
        #mask surround to show only the center--set things outside Ralpha to zero
        #myAnn=numpy.where(myfilter*OR>Ralpha,1,0)*2-1
        myAnn = numpy.where(myfilter > Ralpha, 1, 0) * 2 - 1
        maskA = visual.GratingStim(winSub,
                                   tex=None,
                                   mask=myAnn,
                                   units='pix',
                                   size=screenSize[0],
                                   color=gray,
                                   colorSpace='rgb')

        #mask the center and outersurround to show the innersurround
        # myAnn2=(numpy.where(myfilter*OR<Ralpha,1,0) + numpy.where(myfilter*OR>Rbeta,1,0))*numpy.where(myfilter*OR>0,1,0)*2-1
        #$myAnn2=(numpy.where(myfilter<Ralpha,1,0) + numpy.where(myfilter>Rbeta,1,0))*numpy.where(myfilter>OR,1,0)*2-1
        #myAnn2=(myfilter>Rbeta,1,0)*2-1
        #        myAnn2a=numpy.where(myfilter>Rbeta,1,0)
        #        myAnn2b=numpy.where(myfilter<OR,1,0)
        #        myAnn2=myAnn2a*2-1 + myAnn2b*2-1
        myAnn2 = (numpy.where(myfilter < Ralpha, 1, 0) +
                  numpy.where(myfilter > Rbeta, 1, 0)) * 2 - 1
        maskB = visual.GratingStim(winSub,
                                   tex=None,
                                   mask=myAnn2,
                                   units='pix',
                                   size=screenSize[0],
                                   color=gray,
                                   colorSpace='rgb')
        #mask the center and innersurround to show the outersurround
        #myAnn3=numpy.where(myfilter*OR<Rbeta,1,0)*numpy.where(myfilter*OR,1,0)*2-1
        myAnn3 = (numpy.where(myfilter < Rbeta, 1, 0) +
                  numpy.where(myfilter > OR, 1, 0)) * 2 - 1
        maskC = visual.GratingStim(winSub,
                                   tex=None,
                                   mask=myAnn3,
                                   units='pix',
                                   size=screenSize[0],
                                   color=gray,
                                   colorSpace='rgb')
#    elif offTimeBehavior==3 and maskType==2:
#        #left and right masks
#        maskA=visual.Rect(win=winSub,units='norm',pos=(-0.5,0),width=1.0, height=2.0,fillColor=gray,fillColorSpace='rgb',lineColor=None)
#        maskB=visual.Rect(win=winSub,units='norm',pos=(0.5,0),width=1.0, height=2.0,fillColor=gray,fillColorSpace='rgb',lineColor=None)

    driftFreq = scanDict['animFreq']
    driftReverseFreq = 0.5  #Hz

    #make a fixation cross which will rotate 45 deg on occasion
    fix0 = visual.Circle(winSub,
                         radius=IR / 2.0,
                         edges=32,
                         lineColor=gray,
                         lineColorSpace='rgb',
                         fillColor=gray,
                         fillColorSpace='rgb',
                         autoLog=False)
    fix1 = visual.ShapeStim(winSub,
                            pos=[0.0, 0.0],
                            vertices=((0.0, -0.15), (0.0, 0.15)),
                            lineWidth=3.0,
                            lineColor=black,
                            lineColorSpace='rgb',
                            fillColor=black,
                            fillColorSpace='rgb',
                            autoLog=False)

    fix2 = visual.ShapeStim(winSub,
                            pos=[0.0, 0.0],
                            vertices=((-0.15, 0.0), (0.15, 0.0)),
                            lineWidth=3.0,
                            lineColor=black,
                            lineColorSpace='rgb',
                            fillColor=black,
                            fillColorSpace='rgb',
                            autoLog=False)

    if offTimeBehavior == 1:
        scanNameText = 'drifting checkerboard, on/off'
    elif offTimeBehavior == 2:
        scanNameText = 'drifting checkerboard, drift/static'
    else:
        if maskType == 1:
            scanNameText = 'drifting checkerboard, center/inner surround/outer surround'
        else:
            scanNameText = 'drifting checkerboard, alternating halves'

    msg1 = visual.TextStim(winSub,
                           pos=[0, +2],
                           text='%s \n\nSubject: press a button when ready.' %
                           scanNameText)
    msg1.draw()
    winSub.flip()

    #wait for subject
    thisKey = None
    responseKeys = list(scanDict['subjectResponse'])
    responseKeys.extend('q')
    responseKeys.extend('escape')
    while thisKey == None:
        thisKey = event.waitKeys(keyList=responseKeys)
    if thisKey in ['q', 'escape']:
        core.quit()  #abort
    else:
        event.clearEvents()
#    while len(event.getKeys())==0:
#        core.wait(0.05)
#    event.clearEvents()
    responseKeys = list(scanDict['subjectResponse'])
    msg1 = visual.TextStim(winSub, pos=[0, +3], text='Noise coming....')
    msg1.draw()
    winSub.flip()

    #wait for trigger
    trig = None
    triggerKeys = list(scanDict['trigger'])
    triggerKeys.extend('q')
    triggerKeys.extend('escape')
    while trig == None:
        #wait for trigger "keypress"
        trig = event.waitKeys(keyList=triggerKeys)
    if trig in ['q', 'escape']:
        core.quit()
    else:  #stray key
        event.clearEvents()

    #start the timer
    scanTimer = core.Clock()
    startTime = scanTimer.getTime()
    #    #set up the stimulus but don't draw it yet
    for iWedge in range(0, 20, 2):
        wedge1.setOri(startOris[iWedge])
        wedge1.setRadialPhase(startPhases[int(iWedge / 2)])
        #        wedge1.draw()
        wedge1.setOri(startOris[iWedge + 1])
        wedge1.setRadialPhase(startPhases[int(iWedge / 2)] + 0.5)
#        wedge1.draw()
    if offTimeBehavior == 3:
        nowMask = maskA
#        maskA.draw()
    fix0.draw()
    fix1.draw()
    fix2.draw()
    winSub.flip()
    nowPhase = startPhases
    # and drift it
    timeNow = scanTimer.getTime()
    #row=1
    #    #msg = visual.TextStim(winSub, pos=[-screenSize[0]/2+45,-screenSize[1]/2+15],units='pix',text = 't = %.3f' %timeNow)
    if screenCount == 2:
        msg = visual.TextStim(winOp, pos=[0, -0.5], text='t = %.3f' % timeNow)
        msg.draw()
        msgScanLength.draw()
        msgScanTr.draw()
        winOp.flip()
    loopCounter = 0
    fixTimer = core.Clock()
    respTimer = core.Clock()
    fixOri = 0
    numCoins = 0
    event.clearEvents()

    #prescan rest
    while timeNow < preScanRest:
        timeBefore = timeNow
        timeNow = scanTimer.getTime()
        deltaT = timeNow - startTime
        deltaTinc = timeNow - timeBefore
        oldPhases = nowPhase.copy()

        #every 100 frames, decide if the fixation point should change or not
        if loopCounter % 100 == 0 and loopCounter > 10:
            #flip a coin to decide
            flipCoin = numpy.random.ranf()
            if flipCoin < fixPercentage:
                #reset timers/change ori
                fixOri = 45
                fixTimer.reset()
                respTimer.reset()
                numCoins += 1
                subjectResponse[numCoins] = 0
        fixTimeCheck = fixTimer.getTime()
        respTimeCheck = respTimer.getTime()
        if fixTimeCheck > fixDuration:  #timer expired--reset ori
            fixOri = 0
        fix1.setOri(fixOri)
        fix2.setOri(fixOri)
        #just draw fixations
        fix0.draw()
        fix1.draw()
        fix2.draw()
        winSub.flip()
        if screenCount == 2:
            msg.setText('t = %.3f' % timeNow)
            msg.draw()
            msgScanLength.draw()
            msgScanTr.draw()
            winOp.flip()
        #count number of keypresses since previous frame, break if non-zero
        for key in event.getKeys():
            if key in ['q', 'escape']:
                core.quit()
            elif key in responseKeys and respTimeCheck < respDuration:
                subjectResponse[numCoins] = 1

        loopCounter += 1
    #start the epoch timer
    epochTimer = core.Clock()

    while timeNow < startTime + scanLength:  #loop for scan duration
        timeBefore = timeNow
        timeNow = scanTimer.getTime()
        deltaT = timeNow - startTime
        deltaTinc = timeNow - timeBefore
        oldPhases = nowPhase.copy()

        #every 100 frames, decide if the fixation point should change or not
        if loopCounter % 100 == 0 and loopCounter > 10:
            #flip a coin to decide
            flipCoin = numpy.random.ranf()
            if flipCoin < fixPercentage:
                #reset timers/change ori
                fixOri = 45
                fixTimer.reset()
                respTimer.reset()
                numCoins += 1
                subjectResponse[numCoins] = 0
        fixTimeCheck = fixTimer.getTime()
        respTimeCheck = respTimer.getTime()
        if fixTimeCheck > fixDuration:  #timer expired--reset ori
            fixOri = 0
        fix1.setOri(fixOri)
        fix2.setOri(fixOri)

        epochTime = epochTimer.getTime()
        #display for 1st third of period time
        if epochTime < scanDict['period'] / 3.0:
            #lastPhase=nowPhase.copy()
            #            deltaPhase=driftFreq*deltaT
            deltaPhaseInc = driftFreq * deltaTinc
            #NowPhase=lastpHase+deltaPhase
            #set direction of drift--alternate every cycle
            setSign = math.floor(driftReverseFreq * deltaT)
            if setSign % 2 == 0:
                phaseSign = 1.0
            else:
                phaseSign = -1.0
            phaseSignVec = phaseSign * altWedges
            #            nowPhase=startPhases + deltaPhase*(phaseSignVec)
            nowPhase = oldPhases + deltaPhaseInc * (phaseSignVec)
            for iWedge in range(0, 20, 2):
                wedge1.setOri(startOris[iWedge])
                wedge1.setRadialPhase(nowPhase[int(iWedge / 2)])
                wedge1.draw()
                wedge1.setOri(startOris[iWedge + 1])
                wedge1.setRadialPhase(nowPhase[int(iWedge / 2)] +
                                      0.5 * phaseSignVec[int(iWedge / 2)])
                wedge1.setRadialCycles(OR)
                wedge1.draw()

            if offTimeBehavior == 3:
                nowMask.draw()
#            fix0.draw()
#            fix1.draw()
#            fix2.draw()
#second third of period
        elif epochTime < 2.0 * scanDict['period'] / 3.0:
            #draw either no checkerboard or static checkerboard, depending on scan
            if offTimeBehavior == 1:
                #turn it OFF
                #just draw fixation
                fix0.draw()
                fix1.draw()
                fix2.draw()
            elif offTimeBehavior == 2:
                #draw static
                for iWedge in range(0, 20, 2):
                    wedge1.setOri(startOris[iWedge])
                    wedge1.setRadialPhase(nowPhase[int(iWedge / 2)])
                    wedge1.draw()
                    wedge1.setOri(startOris[iWedge + 1])
                    wedge1.setRadialPhase(nowPhase[int(iWedge / 2)] +
                                          0.5 * phaseSignVec[int(iWedge / 2)])
                    wedge1.draw()
                    wedge1.setRadialCycles(OR)

                fix0.draw()
                fix1.draw()
                fix2.draw()
            elif offTimeBehavior == 3:
                #keep drifting, change mask
                nowMask = maskB
                #lastPhase=nowPhase.copy()
                #                deltaPhase=driftFreq*deltaT
                deltaPhaseInc = driftFreq * deltaTinc
                #set direction of drift--alternate every cycle
                setSign = math.floor(driftReverseFreq * deltaT)
                if setSign % 2 == 0:
                    phaseSign = 1.0
                else:
                    phaseSign = -1.0
                phaseSignVec = phaseSign * altWedges
                #                nowPhase=startPhases + deltaPhase*(phaseSignVec)
                nowPhase = oldPhases + deltaPhaseInc * (phaseSignVec)
                for iWedge in range(0, 20, 2):
                    wedge1.setOri(startOris[iWedge])
                    wedge1.setRadialPhase(nowPhase[int(iWedge / 2)])
                    wedge1.draw()
                    wedge1.setOri(startOris[iWedge + 1])
                    wedge1.setRadialPhase(nowPhase[int(iWedge / 2)] +
                                          0.5 * phaseSignVec[int(iWedge / 2)])
                    wedge1.setRadialCycles(OR)
                    wedge1.draw()
                nowMask.draw()
                fix0.draw()
                fix1.draw()
                fix2.draw()
        elif epochTime < scanDict['period']:
            #final third of period
            if offTimeBehavior == 1:
                #turn it OFF
                #just draw fixation
                fix0.draw()
                fix1.draw()
                fix2.draw()
            elif offTimeBehavior == 2:
                #draw static
                for iWedge in range(0, 20, 2):
                    wedge1.setOri(startOris[iWedge])
                    wedge1.setRadialPhase(nowPhase[int(iWedge / 2)])
                    wedge1.draw()
                    wedge1.setOri(startOris[iWedge + 1])
                    wedge1.setRadialPhase(nowPhase[int(iWedge / 2)] +
                                          0.5 * phaseSignVec[int(iWedge / 2)])
                    wedge1.setRadialCycles(OR / 2.0)
                    wedge1.draw()

                fix0.draw()
                fix1.draw()
                fix2.draw()
            elif offTimeBehavior == 3:
                #keep drifting, change mask
                nowMask = maskC
                #lastPhase=nowPhase.copy()
                #                deltaPhase=driftFreq*deltaT
                deltaPhaseInc = driftFreq * deltaTinc
                #set direction of drift--alternate every cycle
                setSign = math.floor(driftReverseFreq * deltaT)
                if setSign % 2 == 0:
                    phaseSign = 1.0
                else:
                    phaseSign = -1.0
                phaseSignVec = phaseSign * altWedges
                #                nowPhase=startPhases + deltaPhase*(phaseSignVec)
                nowPhase = oldPhases + deltaPhaseInc * (phaseSignVec)
                for iWedge in range(0, 20, 2):
                    wedge1.setOri(startOris[iWedge])
                    wedge1.setRadialPhase(nowPhase[int(iWedge / 2)])
                    wedge1.draw()
                    wedge1.setOri(startOris[iWedge + 1])
                    wedge1.setRadialPhase(nowPhase[int(iWedge / 2)] +
                                          0.5 * phaseSignVec[int(iWedge / 2)])
                    wedge1.setRadialCycles(OR / 2.0)
                    wedge1.draw()
                nowMask.draw()
                fix0.draw()
                fix1.draw()
                fix2.draw()
        else:
            #reset the epoch timer
            epochTimer.reset()
            #if using a mask, set back to first one
            if offTimeBehavior == 3:
                nowMask = maskA
        winSub.flip()

        if screenCount == 2:
            msg.setText('t = %.3f' % timeNow)
            msg.draw()
            msgScanLength.draw()
            msgScanTr.draw()
            winOp.flip()
        #row+=1
        #core.wait(3.0/60.0)

        #count number of keypresses since previous frame, break if non-zero
        for key in event.getKeys():
            if key in ['q', 'escape']:
                core.quit()
            elif key in responseKeys and respTimeCheck < respDuration:
                subjectResponse[numCoins] = 1

        loopCounter += 1
        #core.wait(5.0)
        #outFile = open("debug.txt","w")
        #outFile.write(str(debugVar))
        #outFile.close()
        #numpy.savetxt('debug.txt',debugVar,fmt='%.3f')
        #numpy.savetxt('debugchop.txt',debugVar[:row,],fmt='%.3f')

    #calculate %age of responses that were correct
    #find non-nan
    #np.isnan(a) gives boolean array of true/a=false
    #np.isnan(a).any(1) gives a col vector of the rows with nans
    #~np.isnan(a).any(1) inverts the logic
    #myarray[~np.isnan(a).any(1)] gives the subset that I want
    findResp = subjectResponse[~numpy.isnan(subjectResponse)]
    calcResp = findResp[findResp == 1]
    numCorrect = float(calcResp.shape[0])
    if numCoins > 0:
        percentCorrect = 100.0 * float(numCorrect) / (float(numCoins))
    else:
        percentCorrect = 100.0

    msgText = 'You got %.0f %% correct!' % (percentCorrect, )
    msgPC = visual.TextStim(winSub, pos=[0, +3], text=msgText)
    msgPC.draw()
    winSub.flip()

    #create an output file in a subdirectory
    #check for the subdirectory
    if os.path.isdir('subjectResponseFiles') == False:
        #create directory
        os.makedirs('subjectResponseFiles')
    nowTime = datetime.datetime.now()
    outFile = 'drift3Response%04d%02d%02d_%02d%02d.txt' % (
        nowTime.year, nowTime.month, nowTime.day, nowTime.hour, nowTime.minute)
    outFilePath = os.path.join('subjectResponseFiles', outFile)
    numpy.savetxt(outFilePath, findResp, fmt='%.0f')
    core.wait(2)
    winSub.close()
    if screenCount == 2:
        winOp.close()
예제 #9
0
psychopy.filters and then creates a second sub-stimulus created from a section of
the original. Both are masked simply by circles.
"""

from __future__ import division

from psychopy import visual, event, core
from psychopy.visual import filters
import numpy as np

win = visual.Window([800, 600], units='pix')

# Generate the radial textures
cycles = 6
res = 512
radius = filters.makeRadialMatrix(res)
radialTexture = np.sin(radius * 2 * np.pi * cycles)
mainMask = filters.makeMask(res)

# Select the upper left quadrant of our radial stimulus
radialTexture_sub = radialTexture[256:, 0:256]
# and create an appropriate mask for it
subMask = filters.makeMask(res, radius=0.5, center=[-0, 0])

bigStim = visual.GratingStim(win, tex=radialTexture, mask=mainMask,
   color='white', size=512, sf=1.0 / 512, interpolate=True)
# draw the quadrant stimulus centered in the top left quadrant of the 'base' stimulus (so they're aligned)
subStim = visual.GratingStim(win, tex=radialTexture_sub, pos=(-128, 128), mask=subMask,
   color=[1, 1, 1], size=256, sf=1.0 / 256, interpolate=True, autoLog=False)

bigStim.draw()
예제 #10
0
def driftCheckerArb(scanDict,screenSize=[1024,768],offTimeBehavior=1,maskType=1):

    #offtimeBehaior:
        #1--full field, drift vs rest
        #2--full field, drift vs static
        #3--full field masked
        #           mask = 1: center vs surround
        #           mask = 2: alternating halves (left vs right)

    #20151222 adding two options:
    # 1) arbitrary timing for cond A vs cond B vs rest
    # 2) inclusion of possible rest (gray screen)...
    #issues: how flexible can the timing be? blocks of A/B with rest in between?

# "period" timing: duration of A and B (no longer Period/2)
# "block details": number of reps per block (AB or ABAB or ABABAB ....) abd number of blocks
# "rest details"---duration of rest after each block (see above)    and rest at beginning/end (which is lready there)

    durA=scanDict['stimDurationA']
    durB=scanDict['stimDurationB']
    durRest=scanDict['stimDurationRest']

    #length of scan in s
    blockLength=(scanDict['numReps']*(durA+durB))+durRest
    scanLength=float(scanDict['numBlocks']*blockLength+scanDict['preScanRest']+scanDict['postScanRest'])

    #This structure is much more complicated and I need to create a sort of design matrix
    #2 stim types (A&B)* numReps + 1 rest in a block ... times the numebr of blocks .... +rest on eitehr end
    numEvents=(2*scanDict['numReps']+1)*scanDict['numBlocks']+2
    #create a designmatrix with the event type (rest, A, B) and OFFset time
    designMatrix=numpy.zeros((numEvents,2))
    #prescan rest
    designMatrix[0][0]=0#event type
    designMatrix[0][1]=scanDict['preScanRest']#end time

    #loop through blocks and then reps
    iEvent=1
    for iBlock in range(scanDict['numBlocks']):
        for iRep in range(scanDict['numReps']):
            #stim A
            designMatrix[iEvent][0]=1 #event type
            designMatrix[iEvent][1]=designMatrix[iEvent-1][1]+durA  #END time
            iEvent+=1
            #stim b
            designMatrix[iEvent][0]=2 #event type
            designMatrix[iEvent][1]=designMatrix[iEvent-1][1]+durB  #END time
            iEvent+=1
        #rest after nReps
        designMatrix[iEvent][0]=0 #event type
        designMatrix[iEvent][1]=designMatrix[iEvent-1][1]+durRest  #END time
        iEvent+=1

    #post-scanrest
    designMatrix[iEvent][0]=0 #event type
    designMatrix[iEvent][1]=designMatrix[iEvent-1][1]+scanDict['postScanRest']  #END time
    numpy.savetxt('debug.txt',designMatrix)
    #count number of screens
    if scanDict['operatorScreen']==scanDict['subjectScreen']:
        screenCount=1
    else:
        screenCount=2
    thisPlatform=scanDict['platform']
    screenSize=scanDict['screenSize']
    #if there is only one window, need to display the winOp stuff and then clear it

    if screenCount==1:
        #pop up the Tr info and wait for "ok"
        winOp = visual.Window([500,500],monitor='testMonitor',units='norm',screen=scanDict['operatorScreen'],
                                  color=[0.0,0.0,0.0],colorSpace='rgb')
        msgScanLength=visual.TextStim(winOp,pos=[0,0.5],units='norm',height=0.1,text='Scan length (s): %.1f' %scanLength)
        msgScanTr=visual.TextStim(winOp,pos=[0,0],units='norm',height=0.1,text='No. of Volumes (at Tr=%.2f): %.1f' %(scanDict['Tr'],scanLength/scanDict['Tr']) )
        msgOK=visual.TextStim(winOp,pos=[0,-0.5],units='norm',height=0.1,text='Operator, press any key to proceed')
        msgScanLength.draw()
        msgScanTr.draw()
        msgOK.draw()
        winOp.flip()
        #wait for keypress
        thisKey=None
        while thisKey==None:
            thisKey = event.waitKeys()
        if thisKey in ['q','escape']:
            core.quit() #abort
        else:
            event.clearEvents()
        #close the winOp
        winOp.close()
    else:
        winOp = visual.Window([500,500],monitor='testMonitor',units='norm',screen=scanDict['operatorScreen'],
                              color=[0.0,0.0,0.0],colorSpace='rgb')
        msgScanLength=visual.TextStim(winOp,pos=[0,0.5],units='norm',height=0.1,text='Scan length (s): %.1f' %scanLength)
        msgScanTr=visual.TextStim(winOp,pos=[0,0],units='norm',height=0.1,text='No. of Volumes (at Tr=%.2f): %.1f' %(scanDict['Tr'],scanLength/scanDict['Tr']) )
        msgScanLength.draw()
        msgScanTr.draw()
        winOp.flip()
    #open subject window
    print(screenSize)
    winSub = visual.Window(screenSize,monitor=scanDict['monCalFile'],units='deg',screen=scanDict['subjectScreen'],
                           color=[0.0,0.0,0.0],colorSpace='rgb',fullscr=False,allowGUI=False)

    #parse out vars from scanDict
    IR=scanDict['innerRadius']
    OR=scanDict['outerRadius']
    contrast=scanDict['contrast']
    #get actual size of window--useful in the functions
    subWinSize=winSub.size
    screenSize=numpy.array([subWinSize[0],subWinSize[1]])
    fixPercentage = scanDict['fixFraction']
    fixDuration=0.2
    respDuration=1.0
    dummyLength=int(numpy.ceil(scanLength*60/100))
    subjectResponse=numpy.zeros(( dummyLength,1))
    subjectResponse[:]=numpy.nan
    white=[1.0,1.0,1.0]
    gray=[0.0,0.0,0.0]
    black=[-1.0,-1.0,-1.0]

    #print winSub.fps()

    #test "refresh" rate
    #[frameTimeAvg,frameTimeStd,frameTimeMed] = visual.getMsPerFrame(winSub,nFrames=120, showVisual=True, msg='', msDelay=0.0)
    #print frameTimeAvg
    #print frameTimeMed
    #refreshRate = 1000.0/frameTimeMed
    #runInfo=psychopy.info.RunTimeInfo(win = winSub,refreshTest='grating',verbose=True)
    #print runInfo
    #create stimulus
    #make 3 wedges, each 7.5 degrees wide, with opposite phase
    #use visibleWedge=[0, 45]???
    #initial orientations
    wedgeSize=[0.0,18]
    startOris = range(0,360,18)
    startPhases=numpy.random.rand(10)
#    wedgeWidth=360.0/12.0
    numRadialCycles = OR/2.0
 #   wedgeOriInit=numpy.arange(0,360,30)
 #   wedgeSize=[0.0,30.0]
    wedge1 = visual.RadialStim(winSub,pos = [0, 0],tex='sqrXsqr',radialCycles=numRadialCycles,
         angularCycles=0,
         size=OR*2,color=1,visibleWedge=wedgeSize,ori=0,interpolate=False,contrast=contrast,
         autoLog=False)

    altWedges=numpy.random.rand(10)
    for iGrr in range(0,10):
        altWedges[iGrr]=(-1)**iGrr
    #organize the masks for the two masked runs
    if offTimeBehavior==3 and maskType==1:
        #center surround
        #mask out just the parts necessary
        #make a square array filled with radii
        myfilter=filters.makeRadialMatrix(512)
        #mask surround to show only the center
        myAnn=numpy.where(myfilter*OR>4.0,1,0)*2-1
        maskA=visual.GratingStim(winSub,tex=None,mask=myAnn,units='pix',size=screenSize[0],color=gray,colorSpace='rgb')
        #mask the center to show the surround
        myAnn2=numpy.where(myfilter*OR<4.0,1,0)*numpy.where(myfilter*OR>0,1,0)*2-1
        maskB=visual.GratingStim(winSub,tex=None,mask=myAnn2,units='pix',size=screenSize[0],color=gray,colorSpace='rgb')
    elif offTimeBehavior==3 and maskType==2:
        #left and right masks
        maskA=visual.Rect(win=winSub,units='norm',pos=(-0.5,0),width=1.0, height=2.0,fillColor=gray,fillColorSpace='rgb',lineColor=None)
        maskB=visual.Rect(win=winSub,units='norm',pos=(0.5,0),width=1.0, height=2.0,fillColor=gray,fillColorSpace='rgb',lineColor=None)

    driftFreq=scanDict['animFreq']
    driftReverseFreq = 0.5 #Hz

    #make a fixation cross which will rotate 45 deg on occasion
    fix0 = visual.Circle(winSub,radius=IR/2.0,edges=32,lineColor=gray,lineColorSpace='rgb',
            fillColor=gray,fillColorSpace='rgb',autoLog=False)
    fix1 = visual.ShapeStim(winSub, pos=[0.0,0.0],vertices=((0.0,-0.15),(0.0,0.15)),lineWidth=3.0,
            lineColor=black,lineColorSpace='rgb',
            fillColor=black,fillColorSpace='rgb',autoLog=False)

    fix2 = visual.ShapeStim(winSub, pos=[0.0,0.0],vertices=((-0.15,0.0),(0.15,0.0)),lineWidth=3.0,
            lineColor=black,lineColorSpace='rgb',
            fillColor=black,fillColorSpace='rgb',autoLog=False)


    if offTimeBehavior==1:
        scanNameText='drifting checkerboard, on/off'
    elif offTimeBehavior==2:
        scanNameText='drifting checkerboard, drift/static'
    else:
        if maskType==1:
            scanNameText='drifting checkerboard, center/surround'
        else:
            scanNameText='drifting checkerboard, alternating halves'

    msgSB=visual.TextStim(winSub,pos=[0,+2],text='%s \n\nSubject: press a button when ready.'%scanNameText)
    msgSB.draw()
    winSub.flip()

    #wait for subject
    thisKey=None
    responseKeys=list(scanDict['subjectResponse'])
    responseKeys.extend('q')
    responseKeys.extend('escape')
    while thisKey==None:
        thisKey = event.waitKeys(keyList=responseKeys)
    if thisKey in ['q','escape']:
        core.quit() #abort
    else:
        event.clearEvents()
#    while len(event.getKeys())==0:
#        core.wait(0.05)
#    event.clearEvents()
    responseKeys=list(scanDict['subjectResponse'])
    msgNC=visual.TextStim(winSub,pos=[0,+3],text='Noise coming....')
    msgNC.draw()
    winSub.flip()
    #wait for trigger
    trig=None
    triggerKeys=list(scanDict['trigger'])
    triggerKeys.extend('q')
    triggerKeys.extend('escape')
    while trig==None:
        #wait for trigger "keypress"
        trig=event.waitKeys(keyList=triggerKeys)
    if trig in ['q','escape']:
        core.quit()
    else: #stray key
        event.clearEvents()

    #start the timer
    scanTimer=core.Clock()
    startTime=scanTimer.getTime()
    epochTimer = core.Clock()
    #draw the stimulus
    for iWedge in range(0,20,2):
        wedge1.setOri(startOris[iWedge])
        wedge1.setRadialPhase(startPhases[int(iWedge/2)])
        #wedge1.draw()
        wedge1.setOri(startOris[iWedge+1])
        wedge1.setRadialPhase(startPhases[int(iWedge/2)]+0.5)
        #wedge1.draw()
    if offTimeBehavior==3:
        nowMask=maskA
        #maskA.draw()
    fix0.draw()
    fix1.draw()
    fix2.draw()
    winSub.flip()
    nowPhase=startPhases
    # and drift it
    timeNow = scanTimer.getTime()
    #row=1
#    #msg = visual.TextStim(winSub, pos=[-screenSize[0]/2+45,-screenSize[1]/2+15],units='pix',text = 't = %.3f' %timeNow)
    if screenCount==2:
        msg = visual.TextStim(winOp,pos=[0,-0.5],text = 't = %.3f' %timeNow)
        msg.draw()
    loopCounter=0
    fixTimer=core.Clock()
    respTimer=core.Clock()
    fixOri=0
    numCoins=0
    event.clearEvents()

    #start the actual stimulus part

    #loop through the blocks ... which are events
    for iEvent in range(numEvents):
        #print(iEvent)
        eventType=designMatrix[iEvent][0]
        eventEnd=designMatrix[iEvent][1]
        epochTimer.reset()
        epochTime=epochTimer.getTime()
        timeNow = scanTimer.getTime()
        while timeNow<eventEnd:
            epochTime=epochTimer.getTime()
            if screenCount==2:
                msg.setText('t = %.3f' %timeNow)
                msg.draw()
                msgScanLength.draw()
                msgScanTr.draw()
                winOp.flip()
            timeBefore = timeNow
            timeNow = scanTimer.getTime()
            deltaT=timeNow - startTime
            deltaTinc=timeNow-timeBefore
            oldPhases=nowPhase.copy()
            #every 100 frames, decide if the fixation point should change or not
            if loopCounter%100 ==0 and loopCounter>10:
                #flip a coin to decide
                flipCoin=numpy.random.ranf()
                if flipCoin<fixPercentage:
                    #reset timers/change ori
                    fixOri=45
                    fixTimer.reset()
                    respTimer.reset()
                    numCoins+=1
                    subjectResponse[numCoins]=0
            fixTimeCheck=fixTimer.getTime()
            respTimeCheck=respTimer.getTime()
            if fixTimeCheck >fixDuration: #timer expired--reset ori
                fixOri=0
            fix1.setOri(fixOri)
            fix2.setOri(fixOri)


            #decide which stimulus should be shown

            if eventType==1:
                #stimA
                if offTimeBehavior==3:
                    nowMask=maskA
                #lastPhase=nowPhase.copy()
    #            deltaPhase=driftFreq*deltaT
                deltaPhaseInc=driftFreq*deltaTinc
                #NowPhase=lastpHase+deltaPhase
                #set direction of drift--alternate every Ns, where N is set by driftReverseFreq
                setSign=math.floor(driftReverseFreq*deltaT)
                if setSign%2==0:
                    phaseSign = 1.0
                else:
                    phaseSign = -1.0
                phaseSignVec=phaseSign*altWedges
    #            nowPhase=startPhases + deltaPhase*(phaseSignVec)
                nowPhase=oldPhases+deltaPhaseInc*(phaseSignVec)
                for iWedge in range(0,20,2):
                    wedge1.setOri(startOris[iWedge])
                    wedge1.setRadialPhase(nowPhase[int(iWedge/2)])
                    wedge1.draw()
                    wedge1.setOri(startOris[iWedge+1])
                    wedge1.setRadialPhase(nowPhase[int(iWedge/2)]+0.5*phaseSignVec[int(iWedge/2)])
                    wedge1.draw()

                if offTimeBehavior==3:
                    nowMask.draw()
                fix0.draw()
                fix1.draw()
                fix2.draw()
            elif eventType==2:
                #print('B')
                #second epoch ... stimB
                #draw either no checkerboard or static checkerboard, depending on scan
                if offTimeBehavior==1:
                    #turn it OFF
                    #just draw fixation
                    fix0.draw()
                    fix1.draw()
                    fix2.draw()
                elif offTimeBehavior==2:
                    #draw static
                    for iWedge in range(0,20,2):
                        wedge1.setOri(startOris[iWedge])
                        wedge1.setRadialPhase(nowPhase[int(iWedge/2)])
                        wedge1.draw()
                        wedge1.setOri(startOris[iWedge+1])
                        wedge1.setRadialPhase(nowPhase[int(iWedge/2)]+0.5*phaseSignVec[int(iWedge/2)])
                        wedge1.draw()

                    fix0.draw()
                    fix1.draw()
                    fix2.draw()
                elif offTimeBehavior==3:
                    #keep drifting, change mask
                    nowMask=maskB
                    #lastPhase=nowPhase.copy()
    #                deltaPhase=driftFreq*deltaT
                    deltaPhaseInc=driftFreq*deltaTinc
                    #set direction of drift--alternate every cycle
                    setSign=math.floor(driftReverseFreq*deltaT)
                    if setSign%2==0:
                        phaseSign = 1.0
                    else:
                        phaseSign = -1.0
                    phaseSignVec=phaseSign*altWedges
    #                nowPhase=startPhases + deltaPhase*(phaseSignVec)
                    nowPhase=oldPhases + deltaPhaseInc*(phaseSignVec)
                    for iWedge in range(0,20,2):
                        wedge1.setOri(startOris[iWedge])
                        wedge1.setRadialPhase(nowPhase[int(iWedge/2)])
                        wedge1.draw()
                        wedge1.setOri(startOris[iWedge+1])
                        wedge1.setRadialPhase(nowPhase[int(iWedge/2)]+0.5*phaseSignVec[int(iWedge/2)])
                        wedge1.draw()
                    nowMask.draw()
                    fix0.draw()
                    fix1.draw()
                    fix2.draw()
            elif eventType==0:
                #rest
                fix0.draw()
                fix1.draw()
                fix2.draw()

            winSub.flip()
            #row+=1
            #core.wait(3.0/60.0)

            #count number of keypresses since previous frame, break if non-zero
            for key in event.getKeys():
                if key in ['q','escape']:
                    core.quit()
                elif key in responseKeys and respTimeCheck<respDuration:
                    subjectResponse[numCoins]=1

            loopCounter +=1

        #print('end of while loop in this event')
    #calculate %age of responses that were correct
    #find non-nan
    #np.isnan(a) gives boolean array of true/a=false
    #np.isnan(a).any(1) gives a col vector of the rows with nans
    #~np.isnan(a).any(1) inverts the logic
    #myarray[~np.isnan(a).any(1)] gives the subset that I want
    findResp=subjectResponse[~numpy.isnan(subjectResponse)]
    calcResp=findResp[findResp==1]
    numCorrect=float(calcResp.shape[0])
    if numCoins>0:
        percentCorrect=100.0*float(numCorrect)/(float(numCoins))
    else:
        percentCorrect=100.0

    msgText='You got %.0f %% correct!' %(percentCorrect,)
    msgPC=visual.TextStim(winSub,pos=[0,+3],text=msgText)
    msgPC.draw()
    winSub.flip()

    #create an output file in a subdirectory
    #check for the subdirectory
    if os.path.isdir('subjectResponseFiles')==False:
        #create directory
        os.makedirs('subjectResponseFiles')
    nowTime=datetime.datetime.now()
    outFile='driftResponse%04d%02d%02d_%02d%02d.txt'%(nowTime.year,nowTime.month,nowTime.day,nowTime.hour,nowTime.minute)
    outFilePath=os.path.join('subjectResponseFiles',outFile)
    numpy.savetxt(outFilePath,findResp,fmt='%.0f')
    core.wait(2)
    winSub.close()
    if screenCount==2:
        winOp.close()
예제 #11
0
def makeRadialMatrix(matrixSize, center=(0.0, 0.0), radius=1.0):
    """DEPRECATED: please use psychopy.filters.makeRadialMatrix instead
    """
    from psychopy.visual import filters
    return filters.makeRadialMatrix(matrixSize, center, radius)