def updateparams(self, i): """Updates stimulus parameters, given sweep table index i""" if i == None: # do a blank sweep self.tsp.on = False # turn off the movie, leave all other parameters unchanged self.postval = C.MAXPOSTABLEINT # posted to DT port to indicate a blank sweep self.nvsyncs = sec2intvsync(self.blanksweeps.sec) # this many vsyncs for this sweep self.npostvsyncs = 0 # this many post-sweep vsyncs for this sweep, blank sweeps have no post-sweep delay else: # not a blank sweep self.tsp.on = True # ensure texture stimulus is on self.postval = i # sweep table index will be posted to DT port self.nvsyncs = sec2intvsync(self.st.sweepSec[i]) # this many vsyncs for this sweep self.npostvsyncs = sec2intvsync(self.st.postsweepSec[i]) # this many post-sweep vsyncs for this sweep # Update texture frame = self.frames[self.st.framei[i]] # get the frame for this sweep #frame = self[self.st.framei[i]] # get the frame for this sweep if self.st.invert[i]: frame = 255 - frame # give the frame inverted polarity self.to.put_sub_image(frame, data_format=gl.GL_LUMINANCE, data_type=gl.GL_UNSIGNED_BYTE) # Update texturestimulus self.tsp.angle = self.static.orioff + self.st.ori[i] self.tsp.position = self.xorig+deg2pix(self.st.xposDeg[i]), self.yorig+deg2pix(self.st.yposDeg[i]) # Update background parameters self.bgp.color = self.st.bgbrightness[i], self.st.bgbrightness[i], self.st.bgbrightness[i], 1.0 # Update fixationspot self.fsp.on = bool(self.st.fixationspotDeg[i]) self.fsp.size = deg2pix(self.st.fixationspotDeg[i]), deg2pix(self.st.fixationspotDeg[i])
def updateparams(self, i): """Updates stimulus parameters, given sweep table index i""" if i == None: # do a blank sweep self.tp.on = False # turn off the target, leave all other parameters unchanged self.postval = C.MAXPOSTABLEINT # posted to DT port to indicate a blank sweep self.nvsyncs = sec2intvsync(self.blanksweeps.sec) # this many vsyncs for this sweep self.npostvsyncs = 0 # this many post-sweep vsyncs for this sweep, blank sweeps have no post-sweep delay else: # not a blank sweep self.tp.on = True # ensure stimulus is on self.postval = i # sweep table index will be posted to DT port self.nvsyncs = sec2intvsync(self.st.sweepSec[i]) # this many vsyncs for this sweep self.npostvsyncs = sec2intvsync(self.st.postsweepSec[i]) # this many post-sweep vsyncs for this sweep # Update target position ori = self.static.orioff + self.st.ori[i] theta = ori / 180 * pi dxi = self.st.xi[i] - self.xi0 # destination index - origin index dyi = self.st.yi[i] - self.yi0 sintheta = math.sin(theta) costheta = math.cos(theta) dx = dxi*self.barWidth*costheta - dyi*self.barHeight*sintheta # see SparseNoise.png for the trigonometry dy = dxi*self.barWidth*sintheta + dyi*self.barHeight*costheta x = self.xorig + deg2pix(self.st.xposDeg[i]) + dx y = self.yorig + deg2pix(self.st.yposDeg[i]) + dy self.tp.position = (x, y) # Update non-positional target parameters self.tp.orientation = ori self.tp.color = self.st.brightness[i], self.st.brightness[i], self.st.brightness[i], 1.0 self.tp.anti_aliasing = self.st.antialiase[i] # Update background parameters self.bgp.color = self.st.bgbrightness[i], self.st.bgbrightness[i], self.st.bgbrightness[i], 1.0
def updateparams(self, i): """Updates stimulus parameters, given sweep table index i""" if i == None: # do a blank sweep self.tp.on = False # turn off the target, leave all other parameters unchanged self.postval = C.MAXPOSTABLEINT # posted to DT port to indicate a blank sweep self.nvsyncs = sec2intvsync(self.blanksweeps.sec) # this many vsyncs for this sweep self.npostvsyncs = 0 # this many post-sweep vsyncs for this sweep, blank sweeps have no post-sweep delay else: # not a blank sweep self.tp.on = True # ensure stimulus is on self.postval = i # sweep table index will be posted to DT port self.nvsyncs = sec2intvsync(self.st.sweepSec[i]) # this many vsyncs for this sweep self.npostvsyncs = sec2intvsync(self.st.postsweepSec[i]) # this many post-sweep vsyncs for this sweep # Generate position as a f'n of vsynci for this sweep, even if speedDegSec is 0 distance = degSec2pixVsync(self.st.speedDegSec[i]) * self.nvsyncs # total distance to travel on this sweep direction = self.static.orioff + self.st.ori[i] + 90 # direction to travel on this sweep, always |_ to current ori xdistance = distance * math.cos(direction / 180 * math.pi) ydistance = distance * math.sin(direction / 180 * math.pi) xstep = xdistance / self.nvsyncs # pix to travel per vsync ystep = ydistance / self.nvsyncs x0 = self.xorig - xdistance / 2 y0 = self.yorig - ydistance / 2 self.x = x0 + xstep * np.arange(self.nvsyncs) + deg2pix(self.st.xposDeg[i]) # deg2pix returns 0 if deg is None self.y = y0 + ystep * np.arange(self.nvsyncs) + deg2pix(self.st.yposDeg[i]) # Update non-positional target parameters self.tp.orientation = self.static.orioff + self.st.ori[i] self.tp.size = deg2pix(self.st.widthDeg[i]), deg2pix(self.st.heightDeg[i]) self.tp.color = self.st.rbrightness[i], self.st.gbrightness[i], self.st.bbrightness[i], 1.0 self.tp.anti_aliasing = self.st.antialiase[i] # Update background parameters self.bgp.color = self.st.bgbrightness[i], self.st.bgbrightness[i], self.st.bgbrightness[i], 1.0
def calcduration(self): """Calculates how long this Experiment should take, in sec""" i = self.sweeptable.i # convert all times to vsyncs, add 'em up, then convert back. This takes into account discretization from sec to vsync try: blanksweepvsyncs = sec2intvsync(self.blanksweeps.sec) * list(i).count(None) except AttributeError: # blanksweeps are None, None has no .sec attrib blanksweepvsyncs = 0 notblank = np.int32(i[np.not_equal(i, None)]) # sweep table indices that aren't blank sweeps, i was an object array due to Nones in it nvsyncs = sec2intvsync(self.static.preexpSec) + \ np.asarray([ sec2intvsync(sweeptime) for sweeptime in self.st.sweepSec[notblank] ]).sum() + \ np.asarray([ sec2intvsync(postsweeptime) for postsweeptime in self.st.postsweepSec[notblank] ]).sum() + \ blanksweepvsyncs + \ sec2intvsync(self.static.postexpSec) return vsync2sec(nvsyncs)
def __init__(self, script, params): self.script = script.replace("\\", C.SLASH).replace( ".pyc", ".py" ) # Experiment script file name, with stuff cleaned up self.script = os.path.splitdrive(self.script)[-1] # strip the drive name from the start self.params = params self.params.check() for paramname, paramval in params.items(): setattr(self, paramname, paramval) # bind all parameter names to self if not self.flash: # DW self.flashSec = 0 self.flashvsyncs = sec2intvsync(self.flashSec) eye = dc.get("Eye", "open") # Init signals self.squarelock, self.brightenText = False, False self.UP, self.DOWN, self.LEFT, self.RIGHT = False, False, False, False self.PLUS, self.MINUS = False, False self.BRRIGHT, self.BRLEFT = False, False self.LEFTBUTTON, self.RIGHTBUTTON, self.SCROLL = False, False, False self.eyei = C.EYESTATES.index(eye) # Init Colors DW self.lastbrightness = self.brightness self.black = 0.0 self.white = 1.0
def updateparams(self, i): """Updates stimulus parameters, given sweep table index i""" if i == None: # do a blank sweep self.gp.on = False # turn off the grating, leave all other parameters unchanged self.postval = C.MAXPOSTABLEINT # posted to DT port to indicate a blank sweep self.nvsyncs = sec2intvsync(self.blanksweeps.sec) # this many vsyncs for this sweep self.npostvsyncs = 0 # this many post-sweep vsyncs for this sweep, blank sweeps have no post-sweep delay else: # not a blank sweep self.gp.on = True # ensure grating is on self.postval = i # sweep table index will be posted to DT port self.nvsyncs = sec2intvsync(self.st.sweepSec[i]) # this many vsyncs for this sweep self.npostvsyncs = sec2intvsync(self.st.postsweepSec[i]) # this many post-sweep vsyncs for this sweep """Generate phase as a f'n of vsynci for this sweep sine grating eq'n used by VE: luminance(x) = 0.5*contrast*sin(2*pi*sfreqCycDeg*x + phaseRad) + ml ...where x is the position in deg along the axis of the sinusoid, and phaseRad = phaseDeg/180*pi. Motion in time is achieved by changing phaseDeg over time. phaseDeg inits to phase0""" sfreq = cycDeg2cycPix(self.st.sfreqCycDeg[i]) # convert it just once, reuse it for this sweep """phaseoffset is req'd to make phase0 the initial phase at the centre of the grating, instead of at the edge of the grating as VE does. Take the distance from the centre to the edge along the axis of the sinusoid (which in this case is the height), multiply by spatial freq to get numcycles between centre and edge, multiply by 360 deg per cycle to get req'd phaseoffset. THE EXTRA 180 DEG IS NECESSARY FOR SOME REASON, DON'T REALLY UNDERSTAND WHY, BUT IT WORKS!!!""" phaseoffset = self.height / 2 * sfreq * 360 + 180 phasestep = cycSec2cycVsync(self.st.tfreqCycSec[i]) * 360 # delta cycles per vsync, in degrees of sinusoid self.phase = -self.st.phase0[i] - phaseoffset - phasestep * np.arange(self.nvsyncs) # array of phases for this sweep. -ve makes the grating move in +ve direction along sinusoidal axis, see sin eq'n above # Update grating stimulus self.gp.position = self.xorig+deg2pix(self.st.xposDeg[i]), self.yorig+deg2pix(self.st.yposDeg[i]) self.gp.orientation = self.static.orioff + self.st.ori[i] + 90 # VE defines grating ori as direction of motion of grating, but we want it to be the orientation of the grating elements, so add 90 deg (this also makes grating ori def'n correspond to bar ori def'n). This means that width and height have to be swapped (done at creation of grating) if self.masks: self.gp.mask = self.masks[self.st.diameterDeg[i]] self.gp.spatial_freq = sfreq self.gp.pedestal = self.st.ml[i] if self.st.contrastreverse[i]: contraststep = cycSec2cycVsync(self.st.cfreqCycSec[i])*self.st.contrast[i]*2 self.contrast =self.st.contrast[i]*np.sin(contraststep * np.arange(self.nvsyncs)) else: self.gp.contrast = self.st.contrast[i] # Update background parameters self.bgp.color = self.st.bgbrightness[i], self.st.bgbrightness[i], self.st.bgbrightness[i], 1.0
def __init__(self, script, params): self.script = script.replace('\\', C.SLASH).replace('.pyc', '.py') # Experiment script file name, with stuff cleaned up self.script = os.path.splitdrive(self.script)[-1] # strip the drive name from the start self.params = params self.params.check() for paramname, paramval in params.items(): setattr(self, paramname, paramval) # bind all parameter names to self self.flashvsyncs = sec2intvsync(self.flashSec) eye = dc.get('Eye', 'open') # Init signals self.squarelock, self.brightenText = False, False self.UP, self.DOWN, self.LEFT, self.RIGHT = False, False, False, False self.PLUS, self.MINUS, self.BRLEFT, self.BRRIGHT = False, False, False, False self.LEFTBUTTON, self.RIGHTBUTTON, self.SCROLL = False, False, False self.eyei = C.EYESTATES.index(eye) #Set up initial terrain self.brightness = self.terrain.color self.ori = self.terrain.orientation self.laps = [] #Set up initial gratings self.gratingWidth = I.SCREENWIDTH*2 self.gratingHeight = I.SCREENHEIGHT*2 self.ml = 0.5 self.snapDeg = 18 #set up encoder self.encoder.start() time.sleep(0.2) #give NIDAQ chance to take a buffer of data self.encDeg = self.encoder.getDegrees() self.lastDx = 0 if self.encoder.getVin() < 1: print 'Encoder not connected or powered on.' #set up reward self.reward.start() self.framescorrect = 0 self.rewards = [] #set up session clock self.sc = SessionClock() #set up logs self.posx = [] self.dx = [] self.terrainlog = []
def get_brightness(self): """Get target brightness""" if self.PLUS: self.brightness += self.brightnessstep elif self.MINUS: self.brightness -= self.brightnessstep self.brightness = max(self.brightness, 0) # keep it >= 0 self.brightness = min(self.brightness, 1) # keep it <= 1 """Set flash speed""" # DW AIBS if self.BRRIGHT: self.flashSec += self.flashSecStep elif self.BRLEFT: self.flashSec -= self.flashSecStep self.flashSec = max(self.flashSec, 0) if self.flashSec == 0: self.flash = False self.tp.on = True # toggle it self.tipp.on = True else: self.flash = True self.flashvsyncs = sec2intvsync(self.flashSec) self.flashvsyncs = intround( self.flashvsyncs / self.nscreens ) # normalize by number of screens to flip in each loop in main()
def run(self): """Run the experiment""" # Check it first self.check() info('Running Experiment script: %s' % self.script) # Build the SweepTable and the Header self.build() self.setgamma(self.static.gamma) # Init OpenGL graphics screen self.screen = ve.Core.get_default_screen() # Create VisionEgg stimuli objects, defined by each specific subclass of Experiment self.createstimuli() # Create a VisionEgg Viewport self.viewport = ve.Core.Viewport(screen=self.screen, stimuli=self.stimuli) self.initbackgroundcolor() self.fix1stsweeplag() # 1st sweep lag hacks # Create the VsyncTimer self.vsynctimer = Core.VsyncTimer() # Prepare IODAQ try: self.dOut = DigitalOutput('Dev1') # device should be read from a config file self.dOut.StartTask() self.ni = True except: self.ni = False print "NIDAQ could not be initialized! No frame/sweep data will be output." self.sweepBit = 0 self.frameBit = 1 # Events (quit/pause etc) self.quit = False # init quit signal self.pause = False # init pause signal self.paused = False # remembers whether this experiment has been paused self.nvsyncsdisplayed = 0 # nvsyncs seen by Surf # time-critical stuff starts here self.sync2vsync(nswaps=2) # sync up to vsync signal, ensures that all following swap_buffers+glFlush call pairs return on the vsync self.startdatetime = datetime.datetime.now() self.starttime = time.clock() # precision timestamp # Do pre-experiment delay self.staticscreen(nvsyncs=sec2intvsync(self.static.preexpSec)) # Run the main stimulus loop, defined by each specific subclass of Experiment self.main() # Do post-experiment delay self.staticscreen(nvsyncs=sec2intvsync(self.static.postexpSec)) self.stoptime = time.clock() # precision timestamp self.stopdatetime = datetime.datetime.now() # time-critical stuff ends here if self.ni: self.dOut.WriteBit(self.sweepBit, 0) #ensure sweep bit is low self.dOut.WriteBit(self.frameBit, 0) #ensure frame bit is low self.dOut.ClearTask() #clear NIDAQ # Close OpenGL graphics screen (necessary when running from Python interpreter) self.screen.close() # Print messages to VisionEgg log and to screen info(self.vsynctimer.pprint()) info('%d vsyncs displayed, %d sweeps completed' % (self.nvsyncsdisplayed, self.ii)) info('Experiment duration: %s expected, %s actual' % (isotime(self.sec, 6), isotime(self.stoptime-self.starttime, 6))) if self.paused: warning('dimstim was paused at some point') if self.quit: warning('dimstim was interrupted before completion') else: info('dimstim completed successfully\n') printf2log('SWEEP ORDER: \n' + str(self.sweeptable.i.tolist()) + '\n') printf2log('SWEEP TABLE: \n' + self.sweeptable._pprint(None) + '\n') printf2log('\n' + '-'*80 + '\n') # add minuses to end of log to space it out between sessions # Log relevent objects to file. self.logmeta()
def run(self): """Run the experiment""" # Check it first self.check() info('Running Experiment script: %s' % self.script) # Build the SweepTable and the Header self.build() self.setgamma(self.static.gamma) # Init OpenGL graphics screen self.screen = ve.Core.get_default_screen() # Create VisionEgg stimuli objects, defined by each specific subclass of Experiment self.createstimuli() # Create a VisionEgg Viewport self.viewport = ve.Core.Viewport(screen=self.screen, stimuli=self.stimuli) self.initbackgroundcolor() self.fix1stsweeplag() # 1st sweep lag hacks # Create the VsyncTimer self.vsynctimer = Core.VsyncTimer() self.quit = False # init quit signal self.pause = False # init pause signal self.paused = False # remembers whether this experiment has been paused self.nvsyncsdisplayed = 0 # nvsyncs seen by Surf # time-critical stuff starts here self.sync2vsync(nswaps=2) # sync up to vsync signal, ensures that all following swap_buffers+glFlush call pairs return on the vsync self.startdatetime = datetime.datetime.now() self.starttime = time.clock() # precision timestamp # Do pre-experiment delay self.staticscreen(nvsyncs=sec2intvsync(self.static.preexpSec)) # Run the main stimulus loop, defined by each specific subclass of Experiment self.main() # Do post-experiment delay self.staticscreen(nvsyncs=sec2intvsync(self.static.postexpSec)) self.stoptime = time.clock() # precision timestamp self.stopdatetime = datetime.datetime.now() # time-critical stuff ends here # Close OpenGL graphics screen (necessary when running from Python interpreter) self.screen.close() # Print messages to VisionEgg log and to screen info(self.vsynctimer.pprint()) info('%d vsyncs displayed, %d sweeps completed' % (self.nvsyncsdisplayed, self.ii)) info('Experiment duration: %s expected, %s actual' % (isotime(self.sec, 6), isotime(self.stoptime-self.starttime, 6))) print "Logging Data..." self.logmeta() print "Logging Completed."