def computeChaosPos(dir=0): if dir == -1: # left directionRange1 = [-180, -20] directionRange2 = [20, 180] elif dir == 1: # right directionRange1 = [-160, 0] directionRange2 = [0, 160] # Initial parameters dotsTheta = np.random.rand(nDots) * 360 # deg dotsRadius = (np.random.rand(nDots) ** 0.5) * fieldRadius # in deg dotsX, dotsY = pol2cart(dotsTheta, dotsRadius) # in deg XYpos = np.empty((nDots, 2, maxFrames)) for iFrame in range(maxFrames): # choose direction dir1 = np.random.rand(int(nDots / 2)) * (directionRange1[1] - directionRange1[0]) + directionRange1[0] dir2 = np.random.rand(int(nDots / 2)) * (directionRange2[1] - directionRange2[0]) + directionRange2[0] dirAll = np.hstack((dir1, dir2)) # update position dotsX, dotsY = dotsX + speedFrame * np.cos(dirAll), dotsY + speedFrame * np.sin(dirAll) # convert catesian to polar dotsTheta, dotsRadius = cart2pol(dotsX, dotsY) outFieldDots = (dotsRadius > fieldRadius) # judge dots outside if outFieldDots.any(): dotsRadius[outFieldDots] = np.random.rand(sum(outFieldDots)) * fieldRadius dotsTheta[outFieldDots] = np.random.rand(sum(outFieldDots)) * 360 # deg dotsX, dotsY = pol2cart(dotsTheta, dotsRadius) XYpos[:, 0, iFrame] = dotsX XYpos[:, 1, iFrame] = dotsY return XYpos
def get_flank_gap_pos(self, flank_orientation, flank_distance, num_flank, target_orientation, gap): pos = pol2cart(-flank_orientation + 90, 0.5 * self.target_diameter + 0.5 * self.flank_height, units='deg') pos = (pos[0] + self.eccentricity, pos[1]) return pos
def test_element_array(self): win = self.win if not win._haveShaders: pytest.skip( "ElementArray requires shaders, which aren't available") #using init thetas = numpy.arange(0, 360, 10) N = len(thetas) radii = numpy.linspace(0, 1.0, N) * self.scaleFactor x, y = pol2cart(theta=thetas, radius=radii) xys = numpy.array([x, y]).transpose() spiral = visual.ElementArrayStim(win, opacities=0, nElements=N, sizes=0.5 * self.scaleFactor, sfs=1.0, xys=xys, oris=-thetas) spiral.draw() #check that the update function is working by changing vals after first draw() call spiral.opacities = 1.0 spiral.sfs = 3.0 spiral.draw() str(spiral) #check that str(xxx) is working win.flip() spiral.draw() utils.compareScreenshot('elarray1_%s.png' % (self.contextName), win) win.flip()
def dots_update(dotsX, dotsY, frameCount, dotSpeed=dotSpeed, frameDeathAfter=np.inf): # convert to polar coordinates dotsTheta, dotsRadius = cart2pol(dotsX, dotsY) # update radius dotsRadius = (dotsRadius + dotSpeed) # decide which dots die lgcOutFieldDots = np.zeros(len(dotsTheta), dtype='bool') if dotSpeed > 0: # create lgc for elems where radius too large lgcOutFieldDots = (dotsRadius >= FieldSizeRadius) elif dotSpeed < 0: # create lgc for elems where radius too small lgcOutFieldDots = (dotsRadius <= innerBorder) # create logical for where frameCount too high lgcFrameDeath = (frameCount >= frameDeathAfter) # combine logicals lgcDeath = np.logical_or(lgcOutFieldDots, lgcFrameDeath) # replace dead dots dotsRadius[lgcDeath] = np.random.uniform(innerBorder, FieldSizeRadius, size=sum(lgcDeath)) dotsTheta[lgcDeath] = np.random.rand(sum(lgcDeath)) * 360 # convert dotsX, dotsY = pol2cart(dotsTheta, dotsRadius) # increase frameCount for every elements frameCount += 1 # set the counter for newborn dots to zero frameCount[lgcDeath] = 0 return dotsX, dotsY, frameCount
def get_target_gap_pos_rect2(self, flank_orientation, flank_distance, num_flank, target_orientation, gap): pos = pol2cart(-target_orientation + 90, 0.5 * self.target_diameter - 0.5 * self.line_width, units='deg') pos = (pos[0] + self.eccentricity, pos[1]) return pos
def dots_init(nDots): # specify the angle for each dot dotsTheta = np.random.rand(nDots) * 360 # specify the distance to the centre dotsRadius = (np.random.rand(nDots)**0.5) * FieldSizeRadius # convert dotsX, dotsY = pol2cart(dotsTheta, dotsRadius) return dotsX, dotsY
def dots_init(nDots): # specify the angle for each dot dotsTheta = np.random.rand(nDots) * 360 # specify the distance to the centre dotsRadius = (np.random.rand(nDots)**0.5) * FieldSizeRadius # convert dotsX, dotsY = pol2cart(dotsTheta, dotsRadius) # create array frameCount frameCount = np.random.uniform(0, dotLife, size=len(dotsX)).astype(int) return dotsX, dotsY, frameCount
def get_target_gap_pos(self, flank_orientation=0, flank_distance=0, num_flank=0, target_orientation=0, gap=0, offset=0): pos = pol2cart(-target_orientation + 90, 0.5 * self.target_diameter - 0.5 * self.line_width, units='deg') pos = (pos[0] + self.eccentricity, pos[1]) return pos
def dots_update_inward(dotsXin, dotsYin): # convert to polar coordinates dotsTheta, dotsRadius = cart2pol(dotsXin, dotsYin) # update radius dotsRadius = (dotsRadius - dotSpeed) # random radius where radius too large outFieldDots = (dotsRadius <= 0) dotsRadius[outFieldDots] = (np.random.rand(sum(outFieldDots))** 0.5) * FieldSizeRadius # convert dotsXin, dotsYin = pol2cart(dotsTheta, dotsRadius) return dotsXin, dotsYin
def dots_update_outward(dotsXout, dotsYout): # convert to polar coordinates dotsTheta, dotsRadius = cart2pol(dotsXout, dotsYout) #update radius dotsRadius = (dotsRadius + dotSpeed) #random radius where radius too large outFieldDots = (dotsRadius >= FieldSizeRadius) dotsRadius[outFieldDots] = np.random.rand( sum(outFieldDots)) * FieldSizeRadius # convert dotsXout, dotsYout = pol2cart(dotsTheta, dotsRadius) return dotsXout, dotsYout
def dots_update_lifetime(dotsX, dotsY, frameCount, dotSpeed=dotSpeed, frameDeathAfter=np.inf): # convert to polar coordinates dotsTheta, dotsRadius = cart2pol(dotsX, dotsY) # update radius dotsRadius = (dotsRadius + dotSpeed) # update frameCount frameCount += 1 # prepare array for dots that will die from falling out lgcOutFieldDots = np.zeros(len(dotsTheta), dtype='bool') # decide which dots fall out during expansion if dotSpeed > 0: # create lgc for elems where radius too large (expansion) lgcOutFieldDots = (dotsRadius >= FieldSizeRadius) # decide which dots fall out during contraction elif dotSpeed < 0: # create lgc for elems where radius too small (contraction) lgcOutFieldDots = (dotsRadius <= innerBorder) # decide which dots will die because they got too old lgcFrameDeath = (frameCount >= frameDeathAfter) # combine logicals from dots that died due to fell out and high age lgcDeath = np.logical_or(lgcOutFieldDots, lgcFrameDeath) radiOffset.append(dotsRadius[lgcDeath]) # calculate new radius for dots that died dotsRadius[lgcDeath] = np.sqrt( (np.square(FieldSizeRadius) - np.square(innerBorder)) * np.random.rand(sum(lgcDeath)) + np.square(innerBorder)) radiOnset.append(dotsRadius[lgcDeath]) # calculate new angle for all dots that died (from age or falling) dotsTheta[lgcDeath] = np.random.uniform(0, 360, sum(lgcDeath)) # reset the counter for newborn dots that died of high age frameCount[lgcFrameDeath] = 0 # reset the counter for newborn dots that died from falling out frameCount[lgcOutFieldDots] = np.random.uniform( 0, dotLife, size=sum(lgcOutFieldDots)).astype(int) radiDensity.append(dotsRadius) # convert from polar to Cartesian dotsX, dotsY = pol2cart(dotsTheta, dotsRadius) return dotsX, dotsY, frameCount
def replot_out_dots( radius, thetaRads, X, Y, params ): # Determine who's out of range if ( params['displayRegion'] == 'ring' ): outField = (radius >= params['outerRadiusUnits']) inField = (radius <= 0) out = outField + inField elif ( params['displayRegion'] == 'rect' ): gtMaxX = (X >= params['maxXunits']) ltMinX = (X <= params['minXunits']) gtMaxY = (Y >= params['maxYunits']) ltMinY = (Y >= params['minYunits']) outX = ( gtMaxX | ltMinX ) outY = ( gtMaxY | gtMaxY ) out = ( outX | outY ) else: print "Invalid displayRegion" if params['debugMode']: print 'Out= ' + str( sum( outField ) ) + '| In= ' + str( sum( inField ) )+ ' | MaxX = ' + str( numpy.max( X ) ) + ' | MinX = ' + str( numpy.min( X ) ) + ' | MinR = ' + str( numpy.min(radius) ) # Replot based on replotMode and moveMode if params['replotMode'] == 'wrap': if params['displayRegion'] == 'ring': if (params['moveMode'] == 'radial') or (params['moveMode'] == 'rotation') or (params['moveMode'] == 'random'): if out.any: radius = numpy.mod( radius, params['outerRadiusUnits'] ) X, Y = pol2cart( thetaRads, radius, units='rads' ) elif (params['moveMode'] == 'laminar'): if out.any: # mirror reverse X, Y coordinates X[ out ] = -1.0*X[out] Y[ out ] = -1.0*Y[out] thetaRads, radius = cart2pol( X, Y, units='rad' ) elif params['replotMode'] == 'replot-scaled-polar': if outField.any: radius[outField], thetaRads[outField], X[outField], Y[outField] = make_dots( sum( outField ), params, min=0., max = params['innerRadiusUnits'], distributionMode = 'scaled-polar' ) if inField.any: radius[inField], thetaRads[inField], X[inField], Y[inField] = make_dots( sum( inField ), params, min=params['outerRadiusUnits'], max=params['outerRadiusUnits']+params['dotSpeedUnits'], distributionMode = 'scaled-polar' ) elif params['replotMode'] == 'replot-radial': if out.any: radius[out], thetaRads[out], X[out], Y[out] = make_dots( sum( out ), params, min=0, max=params['outerRadiusUnits'], distributionMode = 'uniform-polar' ) elif params['replotMode'] == 'replot-rect': if out.any: radius[out], thetaRads[out], X[out], Y[out] = make_dots( sum( out ), params, min=params['xMinUnits'], max=params['xMaxUnits'], distributionMode='uniform-rect' ) # Convert changed X,Y to polar thetaRads, radius = cart2pol( X, Y, units='rad' ) # end if replotMode return radius, thetaRads, X, Y
def dots_init(nDots): # initialise angle for each dot as a uniform distribution dotsTheta = np.random.uniform(0, 360, nDots) # initialise radius for each dot # in order to get an overall uniform distribution, the radius must not be # picked from a uniform distribution, but as pdf_r = (2/R^2)*r dotsRadius = np.sqrt((np.square(FieldSizeRadius) - np.square(innerBorder)) * np.random.rand(nDots) + np.square(innerBorder)) # convert from polar to Cartesian dotsX, dotsY = pol2cart(dotsTheta, dotsRadius) # create array frameCount frameCount = np.random.uniform(0, dotLife, size=len(dotsX)).astype(int) return dotsX, dotsY, frameCount
def make_dots( nDots, params, min=-1, max=1, distributionMode='uniform-rect' ): if distributionMode == 'scaled-polar': # Adjusts for density change due to outward radial motion r = numpy.random.rand(nDots)**(0.5)*(max - min) + min th = numpy.random.rand(nDots)*(2*numpy.pi)-numpy.pi X, Y = pol2cart( th, r, units='rad' ) elif distributionMode == 'uniform-polar': r = numpy.random.rand(nDots)*(max - min) + min th = numpy.random.rand(nDots)*(2*numpy.pi)-numpy.pi X, Y = pol2cart( th, r, units='rad' ) elif distributionMode == 'fixed-circle': th = numpy.random.rand(nDots)*(2*numpy.pi)-numpy.pi r = numpy.ones(nDots)*.95 X, Y = pol2cart( th, r, units='rad' ) elif distributionMode == 'hybrid-uniform-rect-polar': # dots of uniform density in circular region X, Y = numpy.random.rand(nDots)*(max-min)+min, numpy.random.rand(nDots)*(max-min)+min th, r = cart2pol( X, Y, units = 'rad' ) outR = ( r >= params['outerRadiusUnits'] ) r[ outR ] = numpy.random.rand(sum(outR))*params['outerRadiusUnits'] X, Y = pol2cart( th, r, units='rad' ) else : # default is random in [-1,1] and [-1,1] in Cartesian coordinates X, Y = numpy.random.rand( nDots )*(max - min) + min, numpy.random.rand( nDots )*(max - min) + min th, r = cart2pol( X, Y, units = 'rad' ) return r, th, X, Y
def test_element_array(self): win = self.win if not win._haveShaders or utils._under_xvfb: pytest.skip("ElementArray requires shaders, which aren't available") #using init thetas = numpy.arange(0,360,10) N=len(thetas) radii = numpy.linspace(0,1.0,N)*self.scaleFactor x, y = pol2cart(theta=thetas, radius=radii) xys = numpy.array([x,y]).transpose() spiral = visual.ElementArrayStim(win, nElements=N,sizes=0.5*self.scaleFactor, sfs=3.0, xys=xys, oris=thetas) spiral.draw() win.flip() spiral.draw() utils.compareScreenshot('elarray1_%s.png' %(self.contextName), win) win.flip()
def update_cal_target(self): ''' make sure target stimuli is already memory when being used by draw_cal_target ''' if self.calTarget is 'picture': if self.pictureTargetFile is None: print( 'ERROR: Clibration target is None, please provide a picture' ) core.quit() else: self.calibTar = visual.ImageStim(self.display, self.pictureTargetFile, size=self.targetSize) elif self.calTarget is 'spiral': thetas = numpy.arange(0, 1440, 10) N = len(thetas) radii = numpy.linspace(0, 1.0, N) * self.targetSize x, y = pol2cart(theta=thetas, radius=radii) xys = numpy.array([x, y]).transpose() self.calibTar = visual.ElementArrayStim(self.display, nElements=N, sizes=self.targetSize, sfs=3.0, xys=xys, oris=-thetas) elif self.calTarget is 'movie': if self.movieTargetFile is None: print( 'ERROR: Clibration target is None, please provide a movie clip' ) core.quit() else: self.calibTar = visual.MovieStim3(self.display, self.movieTargetFile, loop=True, size=self.targetSize) else: #'use the default 'circle' self.calibTar = visual.Circle(self.display, radius=self.targetSize / 2, lineColor=self.foregroundColor, fillColor=self.backgroundColor, lineWidth=self.targetSize / 2.0, units='pix')
def test_element_array(self): win = self.win if not win._haveShaders: pytest.skip("ElementArray requires shaders, which aren't available") #using init thetas = numpy.arange(0,360,10) N=len(thetas) radii = numpy.linspace(0,1.0,N)*self.scaleFactor x, y = pol2cart(theta=thetas, radius=radii) xys = numpy.array([x,y]).transpose() spiral = visual.ElementArrayStim(win, opacities = 0, nElements=N,sizes=0.5*self.scaleFactor, sfs=1.0, xys=xys, oris=-thetas) spiral.draw() #check that the update function is working by changing vals after first draw() call spiral.opacities = 1.0 spiral.sfs = 3.0 spiral.draw() str(spiral) #check that str(xxx) is working win.flip() spiral.draw() utils.compareScreenshot('elarray1_%s.png' %(self.contextName), win) win.flip()
def move_dots( r, th, X, Y, params ): if params['moveMode'] == 'radial': # Coherent r[ params['cohIndex'] ] += params['dotSpeedUnits'] X[ params['cohIndex'] ], Y[ params['cohIndex'] ] = pol2cart(th[ params['cohIndex'] ], r[ params['cohIndex'] ], units='rad') # Incoherent if params['nDots'] > params['nCoherent']: inCohIndex = numpy.invert( params['cohIndex'] ) dTheta = numpy.random.rand(params['nDots']-params['nCoherent'])*numpy.pi*2.0 X[ inCohIndex ] += params['dotSpeedUnits']*numpy.cos( dTheta ) Y[ inCohIndex ] += params['dotSpeedUnits']*numpy.sin( dTheta ) th[ inCohIndex ], r[ inCohIndex ] = cart2pol( X[ inCohIndex ], Y[ inCohIndex ], units ='rad' ) # Normalize Cartesian and Polar coordinates # X, Y = pol2cart(th, r, units='rad') elif params['moveMode'] == 'rotation-eq-angle': # Coherent th[ params['cohIndex'] ] += params['dotSpeedUnits'] X[ params['cohIndex'] ], Y[ params['cohIndex'] ] = pol2cart(th[ params['cohIndex'] ], r[ params['cohIndex'] ], units='rad') # Incoherent if params['nDots'] > params['nCoherent']: inCohIndex = numpy.invert( params['cohIndex'] ) dTheta = numpy.random.rand(params['nDots']-params['nCoherent'])*numpy.pi*2.0 X[ inCohIndex ] += params['dotSpeedUnits']*numpy.cos( dTheta ) Y[ inCohIndex ] += params['dotSpeedUnits']*numpy.sin( dTheta ) th[ inCohIndex ], r[ inCohIndex ] = cart2pol( X[ inCohIndex ], Y[ inCohIndex ], units ='rad' ) elif params['moveMode'] == 'rotation-eq-spd': # Coherent X[ params['cohIndex'] ] += params['dotSpeedUnits']*numpy.sin( numpy.pi - th[ params['cohIndex'] ] ) Y[ params['cohIndex'] ] += params['dotSpeedUnits']*numpy.cos( numpy.pi - th[ params['cohIndex'] ] ) th[ params['cohIndex'] ], r[ params['cohIndex'] ] = cart2pol( X[ params['cohIndex'] ], Y[ params['cohIndex'] ], units ='rad' ) # Incoherent if params['nDots'] > params['nCoherent']: inCohIndex = numpy.invert( params['cohIndex'] ) dTheta = numpy.random.rand(params['nDots']-params['nCoherent'])*numpy.pi*2.0 X[ inCohIndex ] += params['dotSpeedUnits']*numpy.cos( dTheta ) Y[ inCohIndex ] += params['dotSpeedUnits']*numpy.sin( dTheta ) th[ inCohIndex ], r[ inCohIndex ] = cart2pol( X[ inCohIndex ], Y[ inCohIndex ], units ='rad' ) elif params['moveMode'] == 'laminar': # Coherent X[ params['cohIndex'] ] += params['dotSpeedUnits']*numpy.cos( params['laminarDirRads'] ) Y[ params['cohIndex'] ] += params['dotSpeedUnits']*numpy.sin( params['laminarDirRads'] ) th[ params['cohIndex'] ], r[ params['cohIndex'] ] = cart2pol( X[ params['cohIndex'] ], Y[ params['cohIndex'] ], units ='rad' ) # Incoherent if params['nDots'] > params['nCoherent']: inCohIndex = numpy.invert( params['cohIndex'] ) dTheta = numpy.random.rand(params['nDots']-params['nCoherent'])*numpy.pi*2.0 X[ inCohIndex ] += params['dotSpeedUnits']*numpy.cos( dTheta ) Y[ inCohIndex ] += params['dotSpeedUnits']*numpy.sin( dTheta ) th[ inCohIndex ], r[ inCohIndex ] = cart2pol( X[ inCohIndex ], Y[ inCohIndex ], units ='rad' ) elif params['moveMode'] == 'random': dTheta = numpy.random.rand(params['nDots'])*numpy.pi*2.0 X += params['dotSpeedUnits']*numpy.cos( dTheta ) Y += params['dotSpeedUnits']*numpy.sin( dTheta ) th, r = cart2pol( X, Y, units ='rad' ) # end if moveMode return r, th, X, Y
maxSpeed = 10 # The size of the field. Note that you also need to modify the `fieldSize` # keyword that is passed to `ElementArrayStim` below, due to (apparently) a bug # in PsychoPy fieldSize = 200 # The size of the dots dotSize = 2 # The number of frames nFrames = 1000 # Initial parameters dotsTheta = numpy.random.rand(nDots)*360 dotsRadius = (numpy.random.rand(nDots)**0.5)*200 speed = numpy.random.rand(nDots)*maxSpeed # Create the stimulus array dots = visual.ElementArrayStim(window_handle, elementTex=None, fieldShape='circle', elementMask='circle', nElements=nDots, sizes=dotSize, units='pix', fieldSize=10000) # Walk through each frame, update the dot positions and draw it for frameN in range(100): # update radius dotsRadius = (dotsRadius+speed) # random radius where radius too large outFieldDots = (dotsRadius>=fieldSize) dotsRadius[outFieldDots] = numpy.random.rand(sum(outFieldDots))*fieldSize dotsX, dotsY = pol2cart(dotsTheta,dotsRadius) dots.setXYs(numpy.array([dotsX, dotsY]).transpose()) dots.draw() window_handle.flip()
def dots_update_wrap(dotsX, dotsY, dotSpeed=dotSpeed): # convert to polar coordinates dotsTheta, dotsRadius = cart2pol(dotsX, dotsY) # update radius dotsRadius = (dotsRadius + dotSpeed) # prepare array for dots that will die from falling out lgcOutFieldDots = np.zeros(len(dotsTheta), dtype='bool') # decide which dots fall out during expansion if dotSpeed > 0: # create lgc for elems where radius too large (expansion) lgcOutFieldDots = (dotsRadius >= FieldSizeRadius) # how many dots should go in area A? numDotsAreaA = np.sum( np.random.choice(np.arange(2), p=[1 - pAexp, pAexp], size=np.sum(lgcOutFieldDots))) # get logical for area A lgcAdots = np.zeros(len(dotsTheta), dtype='bool') lgcAdots[np.where(lgcOutFieldDots)[0][:numDotsAreaA]] = True # calculate new radius for dots appearing in region A dotsRadius[lgcAdots] = innerBorder * np.sqrt( (np.square(alphaExp) - 1) * np.random.rand(sum(lgcAdots)) + 1) # get logical for area B lgcBdots = np.zeros(len(dotsTheta), dtype='bool') lgcBdots[np.where(lgcOutFieldDots)[0][numDotsAreaA:]] = True # calculate new radius for dots appearing in region B dotsRadius[lgcBdots] = np.sqrt( (np.square(FieldSizeRadius) - np.square(alphaExp) * np.square(innerBorder)) * np.random.rand(sum(lgcBdots)) + np.square(alphaExp) * np.square(innerBorder)) # decide which dots fall out during contraction elif dotSpeed < 0: # create lgc for elems where radius too small (contraction) lgcOutFieldDots = (dotsRadius <= innerBorder) # how many dots should go in area A? numDotsAreaA = np.sum( np.random.choice(np.arange(2), p=[1 - pAcontr, pAcontr], size=np.sum(lgcOutFieldDots))) # get logical for area A lgcAdots = np.zeros(len(dotsTheta), dtype='bool') lgcAdots[np.where(lgcOutFieldDots)[0][:numDotsAreaA]] = True # calculate new radius for dots appearing in region A dotsRadius[lgcAdots] = Scontr * np.sqrt( (np.square(alphaContr) - 1) * np.random.rand(sum(lgcAdots)) + 1) # get logical for area B lgcBdots = np.zeros(len(dotsTheta), dtype='bool') lgcBdots[np.where(lgcOutFieldDots)[0][numDotsAreaA:]] = True # calculate new radius for dots appearing in region B dotsRadius[lgcBdots] = np.sqrt( (np.square(Scontr) - np.square(innerBorder)) * np.random.rand(sum(lgcBdots)) + np.square(innerBorder)) # calculate new angle for all dots that died (from age or falling) dotsTheta[lgcOutFieldDots] = np.random.uniform(0, 360, sum(lgcOutFieldDots)) # convert from polar to Cartesian dotsX, dotsY = pol2cart(dotsTheta, dotsRadius) return dotsX, dotsY
def feedback_fn(block_n, condition, trial_n, trial_start, training=False): global training_score global bad_fb_onset_cnt surp = False # Check for responses if use_rtbox: (rts, btns) = rtbox.secs() else: responses = event.getKeys(keyList=[key], timeStamped=exp_clock) try: btns, rts = zip( *responses ) # unpack [(key1,time1),(key2,time2)] into (key1,key2) and (time1,time2) except ValueError: btns = [] rts = [] # Process responses if len(rts) > 0: if len(rts) > 1: # Warning if more than one button was pressed win.logOnFlip( 'WARNING!!! More than one response detected (taking first) on B{0}_T{1}: responses = {2}' .format(block_n, trial_n, rts), logging.WARNING) rt = rts[0] - trial_start # take only first response btn = btns[0] error = rt - interval_dur error_angle = error * angle_ratio if not training and trial_n in surprise_trials[ block_n]: # Surprise on if not in training and if in list of surprise trials target_zone.setColor('blue') resp_marker.setLineColor(None) outcome_str = 'SURPRISE!' sound_file = select_surp_sound() surp = True elif np.abs(error) < tolerances[condition]: # WIN target_zone.setColor('green') outcome_str = 'WIN!' sound_file = 'paradigm_sounds/{0}'.format(win_sound) win_flag = 0 else: # LOSS target_zone.setColor('red') outcome_str = 'LOSE!' sound_file = 'paradigm_sounds/{0}'.format(loss_sound) win_flag = 1 resp_marker.setStart( pol2cart(error_angle + 270, loop_radius - resp_marker_width / 2)) resp_marker.setEnd( pol2cart(error_angle + 270, loop_radius + resp_marker_width / 2)) else: # No response detected target_zone.setColor('red') outcome_str = 'None' rt = -1 resp_marker.setLineColor(None) sound_file = 'paradigm_sounds/{0}'.format(loss_sound) # no_response_time = exp_clock.getTime()-trial_start # # Not adjusting tolerance for this type of trial... outcome_sound = sound.Sound(value=sound_file, sampleRate=44100, blockSize=block_sz, secs=0.8, stereo=1) outcome_sound.setVolume(0.8) # Present feedback # preflip = exp_clock.getTime()-trial_start if paradigm_type == 'eeg': win.callOnFlip(port.setData, 2) sound_played = False else: win.callOnFlip(outcome_sound.play) sound_played = True for frameN in range( feedback_dur * 60 ): #assuming frame_rate is close enough it would round to 60 (this must be an int) if paradigm_type == 'ecog': trigger_rect.draw() target_zone_draw( ) # Using our defined target_zone_draw, not .draw to have correct visual. resp_marker.draw() # Wait until 1.5 frames before desired presentation time, then create fixed timing between this flip and sound/draw onsets if frameN == 0: # prewait = exp_clock.getTime()-trial_start # desired = interval_dur + feedback_delay - 0.5/frame_rate while exp_clock.getTime( ) < trial_start + interval_dur + feedback_delay - 0.5 / frame_rate: # Hard coded delay for EEG: if not sound_played and exp_clock.getTime( ) > trial_start + interval_dur + feedback_delay - 0.16: outcome_sound.play() sound_played = True core.wait(0.00002) win.flip() if frameN == 0: feedback_onset = exp_clock.getTime() - trial_start # if feedback_onset > 1.793 or feedback_onset < 1.792: # bad_fb_onset_cnt += 1 # print '{0} --> B{1}T{2} times:\n\tpreflip {3}\n\tprewait {4}\n\tdesired {5}\n\tfeedback = {6}'.format( # bad_fb_onset_cnt,block_n,trial_n,preflip,prewait,desired,feedback_onset) win.flip() if not surp and outcome_str != 'None': tolerances[condition] += tolerance_step[condition][ win_flag] # Update tolerances based on feedback. Needs to be here. if tolerances[condition] > tolerance_lim[ 0]: #!!! Won't work if moved to staircase. Would need new implementation. tolerances[condition] = tolerance_lim[0] elif tolerances[condition] < tolerance_lim[1]: tolerances[condition] = tolerance_lim[1] if training and trial_n >= n_fullvis: training_score[condition] += point_fn[win_flag] elif not training: points[block_n] += point_fn[win_flag] if training: win.logOnFlip( feedback_str.format('T', trial_n, outcome_str, rt, condition, tolerances[condition]), logging.DATA) win.logOnFlip( 'B{0}_T{1} responses/times = {2} / {3}'.format( 'T', trial_n, btns, rts), logging.DATA) win.logOnFlip( 'B{0}_T{1} SOUND = {2} feedback start: TIME = {3}'.format( 'T', trial_n, sound_file, feedback_onset), logging.DATA) else: win.logOnFlip( feedback_str.format(block_n, trial_n, outcome_str, rt, condition, tolerances[condition]), logging.DATA) win.logOnFlip( 'B{0}_T{1} responses/times = {2} / {3}'.format( block_n, trial_n, btns, rts), logging.DATA) win.logOnFlip( 'B{0}_T{1} SOUND = {2} feedback start: TIME = {3}'.format( block_n, trial_n, sound_file, feedback_onset), logging.DATA) resp_marker.setLineColor('black') target_zone.setColor('dimgrey') while exp_clock.getTime() < trial_start + trial_dur: for press in event.getKeys(keyList=['escape', 'q']): if press: clean_quit()
else: block_szs = [512, 512] sound_srate = 22050 stereo_val = 1 # Create a sound just so the stream gets initialized... tmp_sound = sound.Sound(value=tar_name, sampleRate=sound_srate, blockSize=block_szs[0], secs=stim_dur, stereo=stereo_val, volume=volumes[0]) #=================================================== # VISUAL STIMULI #=================================================== # "Light" Stimuli #--------------------------------------------------- circ_angles = np.linspace(-90,270,n_circ) #np.array([float(pos_ix)*(360/float(n_circ))-90 for pos_ix in range(n_circ)]) circ_radius = [loop_radius] * n_circ circ_X, circ_Y = pol2cart(circ_angles,circ_radius) circ_start = [circ_ix * (1/float(n_circ)) for circ_ix in range(n_circ)] # onset time of each light hidden_pos = [(circ_start[circ_xi] > (1-covered_portion)) for circ_xi in range(n_circ)] socket_colors = [(-1,-1,-1)] * n_circ # Sets black circles circ_colors = [(-1,-1,-1)] * (n_circ - sum(hidden_pos)) + [(0, 0, 0)] * sum(hidden_pos) # 13 black + 17 gray circles = visual.ElementArrayStim(win, nElements=n_circ, sizes=circ_size, xys = zip(circ_X, circ_Y), # Circle object inset ontop of sockets elementTex = None, elementMask = "circle", colors=circ_colors) sockets = visual.ElementArrayStim(win, nElements=n_circ,sizes=socket_size,xys = zip(circ_X, circ_Y), # "Sockets" providing outter black ring for circles. elementTex = None, elementMask = "circle", # always present behind circle stim colors=socket_colors) #--------------------------------------------------- # Target Zone
def draw_cal_target(self, x, y): '''Draw the calibration/validation & drift-check target''' self.clear_cal_display() xVis = (x - self.w / 2) yVis = (self.h / 2 - y) if self.calTarget is 'picture': if self.pictureTargetFile is None: print( 'ERROR: Clibration target is None, please provide a picture' ) core.quit() else: self.calibTar = visual.ImageStim(self.display, self.pictureTargetFile, size=self.targetSize) elif self.calTarget is 'spiral': thetas = numpy.arange(0, 1440, 10) N = len(thetas) radii = numpy.linspace(0, 1.0, N) * self.targetSize x, y = pol2cart(theta=thetas, radius=radii) xys = numpy.array([x, y]).transpose() self.calibTar = visual.ElementArrayStim(self.display, nElements=N, sizes=self.targetSize, sfs=3.0, xys=xys, oris=-thetas) elif self.calTarget is 'movie': if self.movieTargetFile is None: print( 'ERROR: Clibration target is None, please provide a movie clip' ) core.quit() else: self.calibTar = visual.MovieStim3(self.display, self.movieTargetFile, loop=True, size=self.targetSize) else: #'use the default 'circle' self.calibTar = visual.Circle(self.display, radius=self.targetSize / 2, lineColor=self.foregroundColor, fillColor=self.backgroundColor, lineWidth=self.targetSize / 2., units='pix') # update the target position if self.calTarget is 'spiral': self.calibTar.fieldPos = (xVis, yVis) else: self.calibTar.pos = (xVis, yVis) # handle the drawing if self.calTarget in ['movie', 'spiral']: self.animatedTarget = True # hand over drawing to get_input_key else: self.calibTar.draw() self.display.flip()
TargsQuad = CondsTargetQuadrants[cond][subCond-1] DistracQuad = CondsDistraQuadrants[cond][subCond-1] trialTargPos = [] targRadPos = np.empty(4) targRadPos[:] =np.nan switch = np.random.random()>0.5 for ii in range(nT): if (cond>3 and switch): ii = (nT-1) - ii qq = TargsQuad[ii] # target quadrant theta = np.random.choice(PossibleObjTheta[qq-1], replace=False) radixID = int(np.random.random()>0.5) targRadPos[qq-1] = radixID radix = PossibleObjRadix[radixID] x,y = coord.pol2cart(theta, radix, units='deg') trialTargPos.append((x,y)) if (TargetChangeID[tt]==-1) & (TrialChangeCondID[tt]<3): if (TrialChangeCondID[tt]==1) & (theta>90 and theta<270): TargetChangeID[tt]=ii elif (TrialChangeCondID[tt]==2) & (theta<90 or theta>270): TargetChangeID[tt]=ii trialDisPos = [] for ii in range(nD): qq = DistracQuad[ii] # target quadrant theta = np.random.choice(PossibleObjTheta[qq-1], replace=False) if targRadPos[qq-1]==1: radix = PossibleObjRadix[0] elif targRadPos[qq-1]==0:
def init_trial_stimuli(self): self.trial_stimuli = { # Fixation stimulus indicating start of the trial 'fixation': visual.ShapeStim(self.test_screen, units=None, lineWidth=4, pos=[0, 0], lineColor='white', closeShape=False, vertices=((0, -10), (0, 10), (0, 0), (-10, 0), (10, 0))), # Trial stimuli 'blanc1': visual.Circle(self.test_screen, units=None, radius=50, pos=pol2cart(15, 160, units='deg'), lineWidth=5, lineColor='white'), 'blanc2': visual.Circle(self.test_screen, units=None, radius=50, pos=pol2cart(-55, 160, units='deg'), lineWidth=5, lineColor='white'), 'blanc3': visual.Circle(self.test_screen, units=None, radius=50, pos=pol2cart(-125, 160, units='deg'), lineWidth=5, lineColor='white'), 'blanc4': visual.Circle(self.test_screen, units=None, radius=50, pos=pol2cart(-195, 160, units='deg'), lineWidth=5, lineColor='white'), 'stim1': visual.Circle(self.test_screen, units=None, radius=25, pos=pol2cart(15, 160, units='deg'), lineWidth=3, fillColor='white'), 'stim2': visual.Circle(self.test_screen, units=None, radius=25, pos=pol2cart(-55, 160, units='deg'), lineWidth=3, fillColor='white'), 'stim3': visual.Circle(self.test_screen, units=None, radius=25, pos=pol2cart(-125, 160, units='deg'), lineWidth=3, fillColor='white'), 'stim4': visual.Circle(self.test_screen, units=None, radius=25, pos=pol2cart(-195, 160, units='deg'), lineWidth=3, fillColor='white'), 'hint_1': visual.TextStim(self.test_screen, text='P', pos=pol2cart(15, 160, units='deg'), color='white', height=30), 'hint_2': visual.TextStim(self.test_screen, text='L', pos=pol2cart(-55, 160, units='deg'), color='white', height=30), 'hint_3': visual.TextStim(self.test_screen, text='D', pos=pol2cart(-125, 160, units='deg'), color='white', height=30), 'hint_4': visual.TextStim(self.test_screen, text='E', pos=pol2cart(-195, 160, units='deg'), color='white', height=30) }
def init_trial_stimuli(self): self.trial_stimuli = { # Fixation stimulus indicating start of the trial 'fixation': visual.ShapeStim(self.test_screen, units=None, lineWidth=4, pos=[0, 0], lineColor='white', closeShape=False, vertices=((0, -10), (0, 10), (0, 0), (-10, 0), (10, 0))), # Trial stimuli 'red': { 'solid': { 'circle': [ visual.Circle(self.test_screen, units=None, radius=40, pos=[-130, 0], lineWidth=6, lineColor=self.colors['red'], fillColor=self.colors['red'], lineColorSpace='rgb255', fillColorSpace='rgb255'), visual.Circle(self.test_screen, units=None, radius=40, pos=[130, 0], lineWidth=6, lineColor=self.colors['red'], fillColor=self.colors['red'], lineColorSpace='rgb255', fillColorSpace='rgb255') ], 'triangle': [ visual.ShapeStim(self.test_screen, units=None, pos=[-130, -0.33 * 40], lineWidth=6, closeShape=True, vertices=(pol2cart(90, 1.17 * 40, units='deg'), pol2cart(210, 1.17 * 40, units='deg'), pol2cart(330, 1.17 * 40, units='deg')), lineColor=self.colors['red'], fillColor=self.colors['red'], lineColorSpace='rgb255', fillColorSpace='rgb255'), visual.ShapeStim(self.test_screen, units=None, pos=[130, -0.33 * 40], lineWidth=6, closeShape=True, vertices=(pol2cart(90, 1.17 * 40, units='deg'), pol2cart(210, 1.17 * 40, units='deg'), pol2cart(330, 1.17 * 40, units='deg')), lineColor=self.colors['red'], fillColor=self.colors['red'], lineColorSpace='rgb255', fillColorSpace='rgb255') ] }, 'contour': { 'circle': [ visual.Circle(self.test_screen, units=None, radius=40, pos=[-130, 0], lineWidth=6, lineColor=self.colors['red'], fillColor=None, lineColorSpace='rgb255', fillColorSpace='rgb255'), visual.Circle(self.test_screen, units=None, radius=40, pos=[130, 0], lineWidth=6, lineColor=self.colors['red'], fillColor=None, lineColorSpace='rgb255', fillColorSpace='rgb255') ], 'triangle': [ visual.ShapeStim(self.test_screen, units=None, pos=[-130, -0.33 * 40], lineWidth=6, closeShape=True, vertices=(pol2cart(90, 1.17 * 40, units='deg'), pol2cart(210, 1.17 * 40, units='deg'), pol2cart(330, 1.17 * 40, units='deg')), lineColor=self.colors['red'], fillColor=None, lineColorSpace='rgb255', fillColorSpace='rgb255'), visual.ShapeStim(self.test_screen, units=None, pos=[130, -0.33 * 40], lineWidth=6, closeShape=True, vertices=(pol2cart(90, 1.17 * 40, units='deg'), pol2cart(210, 1.17 * 40, units='deg'), pol2cart(330, 1.17 * 40, units='deg')), lineColor=self.colors['red'], fillColor=None, lineColorSpace='rgb255', fillColorSpace='rgb255') ] } }, 'green': { 'solid': { 'circle': [ visual.Circle(self.test_screen, units=None, radius=40, pos=[-130, 0], lineWidth=6, lineColor=self.colors['green'], fillColor=self.colors['green'], lineColorSpace='rgb255', fillColorSpace='rgb255'), visual.Circle(self.test_screen, units=None, radius=40, pos=[130, 0], lineWidth=6, lineColor=self.colors['green'], fillColor=self.colors['green'], lineColorSpace='rgb255', fillColorSpace='rgb255') ], 'triangle': [ visual.ShapeStim(self.test_screen, units=None, pos=[-130, -0.33 * 40], lineWidth=6, closeShape=True, vertices=(pol2cart(90, 1.17 * 40, units='deg'), pol2cart(210, 1.17 * 40, units='deg'), pol2cart(330, 1.17 * 40, units='deg')), lineColor=self.colors['green'], fillColor=self.colors['green'], lineColorSpace='rgb255', fillColorSpace='rgb255'), visual.ShapeStim(self.test_screen, units=None, pos=[130, -0.33 * 40], lineWidth=6, closeShape=True, vertices=(pol2cart(90, 1.17 * 40, units='deg'), pol2cart(210, 1.17 * 40, units='deg'), pol2cart(330, 1.17 * 40, units='deg')), lineColor=self.colors['green'], fillColor=self.colors['green'], lineColorSpace='rgb255', fillColorSpace='rgb255') ] }, 'contour': { 'circle': [ visual.Circle(self.test_screen, units=None, radius=40, pos=[-130, 0], lineWidth=6, lineColor=self.colors['green'], fillColor=None, lineColorSpace='rgb255', fillColorSpace='rgb255'), visual.Circle(self.test_screen, units=None, radius=40, pos=[130, 0], lineWidth=6, lineColor=self.colors['green'], fillColor=None, lineColorSpace='rgb255', fillColorSpace='rgb255') ], 'triangle': [ visual.ShapeStim(self.test_screen, units=None, pos=[-130, -0.33 * 40], lineWidth=6, closeShape=True, vertices=(pol2cart(90, 1.17 * 40, units='deg'), pol2cart(210, 1.17 * 40, units='deg'), pol2cart(330, 1.17 * 40, units='deg')), lineColor=self.colors['green'], fillColor=None, lineColorSpace='rgb255', fillColorSpace='rgb255'), visual.ShapeStim(self.test_screen, units=None, pos=[130, -0.33 * 40], lineWidth=6, closeShape=True, vertices=(pol2cart(90, 1.17 * 40, units='deg'), pol2cart(210, 1.17 * 40, units='deg'), pol2cart(330, 1.17 * 40, units='deg')), lineColor=self.colors['green'], fillColor=None, lineColorSpace='rgb255', fillColorSpace='rgb255') ] } }, 'cue1': visual.TextStim(self.test_screen, text=u'ФОРМА'), 'cue2': visual.TextStim(self.test_screen, text=u'ЦВЕТ'), 'hint_D': visual.TextStim(self.test_screen, text=u'D <- одинаковые', height=25, pos=[-330, 0], color='white'), 'hint_L': visual.TextStim(self.test_screen, text=u'разные -> L', height=25, pos=[330, 0], color='white') }
dotSize = .0075 dotsTheta = numpy.random.rand(nDots) * 360 dotsRadius = (numpy.random.rand(nDots)**0.5) * 2 speed = numpy.random.rand(nDots) * maxSpeed win = visual.Window([800, 600], rgb=[-1, -1, -1]) dots = visual.ElementArrayStim(win, elementTex=None, elementMask='circle', nElements=nDots, sizes=dotSize) while True: #update radius dotsRadius = (dotsRadius + speed) #random radius where radius too large outFieldDots = (dotsRadius >= 2.0) dotsRadius[outFieldDots] = numpy.random.rand(sum(outFieldDots)) * 2.0 dotsX, dotsY = pol2cart(dotsTheta, dotsRadius) dotsX *= 0.75 #to account for wider aspect ratio dots.xys = numpy.array([dotsX, dotsY]).transpose() dots.draw() win.flip() # Exit on escape if event.getKeys(keyList=['escape', 'q']): break
def stimulus_chaos(direction): nDots = 50 # The maximum speed of the dots maxSpeed = 10 # 10 is degree, should switch to pixels # The size of the field. Note that you also need to modify the `fieldSize` # keyword that is passed to `ElementArrayStim` below, due to (apparently) a bug # in PsychoPy fieldSize = 200 # The size of the dots dotSize = 5 # The number of frames nFrames = 1000 # Initial parameters dotsTheta = np.random.rand(nDots) * 360 dotsRadius = (np.random.rand(nDots)**0.5) * fieldSize dotsX, dotsY = pol2cart(dotsTheta, dotsRadius) speed = maxSpeed if direction == 1: # left directionRange1 = [-180, -20] directionRange2 = [20, 180] elif direction == 2: # right directionRange1 = [-160, 0] directionRange2 = [0, 160] # Create the stimulus array dots = visual.ElementArrayStim(myWin, elementTex=None, fieldShape='circle', \ elementMask='circle', nElements=nDots, sizes=dotSize, units='pixels', \ fieldSize=500) # Walk through each frame, update the dot positions and draw it dir1 = np.random.rand(int(nDots / 2)) * ( directionRange1[1] - directionRange1[0]) + directionRange1[0] dir2 = np.random.rand(int(nDots / 2)) * ( directionRange2[1] - directionRange2[0]) + directionRange2[0] dir = np.hstack((dir1, dir2)) np.random.shuffle(dir) for frameN in range(5000): # draw random directions re = frameN % 10 while re == 0: dir1 = np.random.rand(int(nDots / 2)) * ( directionRange1[1] - directionRange1[0]) + directionRange1[0] dir2 = np.random.rand(int(nDots / 2)) * ( directionRange2[1] - directionRange2[0]) + directionRange2[0] dir = np.hstack((dir1, dir2)) # update position dotsX, dotsY = dotsX + speed * np.cos(dir), dotsY + speed * np.sin(dir) # convert catesian to polar dotsTheta, dotsRadius = cart2pol(dotsX, dotsY) # random radius where radius too large outFieldDots = (dotsRadius > fieldSize) dotsRadius[outFieldDots] = np.random.rand( sum(outFieldDots)) * fieldSize dotsX, dotsY = pol2cart(dotsTheta, dotsRadius) #坐标转换 dots.setXYs(np.array([dotsX, dotsY]).transpose()) dots.draw() myWin.flip()