def __init__(self, name, width=None, distance=None, gamma=None, notes=None, useBits=None, verbose=True, currentCalib={}, ): """ """ #make sure that all necessary settings have some value self.__type__ = 'psychoMonitor' self.name = name self.currentCalib = currentCalib self.currentCalibName = strFromDate(time.localtime()) self.calibs = {} self.calibNames = [] self._gammaInterpolator=None self._gammaInterpolator2=None self._loadAll() if len(self.calibNames)>0: self.setCurrent(-1) #will fetch previous vals if monitor exists else: self.newCalib() log.info(self.calibNames) #overide current monitor settings with the vals given if width: self.setWidth(width) if distance: self.setDistance(distance) if gamma: self.setGamma(gamma) if notes: self.setNotes(notes) if useBits!=None: self.setUseBits(useBits)
def updatePthFile(self, oldName, newName): """Searches site-packages for .pth files and replaces any instance of `oldName` with `newName`, where the names likely have the form PsychoPy-1.60.04 """ from distutils.sysconfig import get_python_lib siteDir = get_python_lib() pthFiles = glob.glob(os.path.join(siteDir, '*.pth')) enclosingSiteDir = os.path.split( siteDir )[0] #sometimes the site-packages dir isn't where the pth files are kept? pthFiles.extend(glob.glob(os.path.join(enclosingSiteDir, '*.pth'))) nUpdates = 0 #no paths updated info = "" for filename in pthFiles: lines = open(filename, 'r').readlines() needSave = False for lineN, line in enumerate(lines): if oldName in line: lines[lineN] = line.replace(oldName, newName) needSave = True if needSave: try: f = open(filename, 'w') f.writelines(lines) f.close() nUpdates += 1 log.info('Updated PsychoPy path in %s' % filename) except: info += 'Failed to update PsychoPy path in ', filename return -1, info return nUpdates, info
def updatePthFile(self, oldName, newName): """Searches site-packages for .pth files and replaces any instance of `oldName` with `newName`, where the names likely have the form PsychoPy-1.60.04 """ from distutils.sysconfig import get_python_lib siteDir=get_python_lib() pthFiles = glob.glob(os.path.join(siteDir, '*.pth')) enclosingSiteDir = os.path.split(siteDir)[0]#sometimes the site-packages dir isn't where the pth files are kept? pthFiles.extend(glob.glob(os.path.join(enclosingSiteDir, '*.pth'))) nUpdates = 0#no paths updated info="" for filename in pthFiles: lines = open(filename, 'r').readlines() needSave=False for lineN, line in enumerate(lines): if oldName in line: lines[lineN] = line.replace(oldName, newName) needSave=True if needSave: try: f = open(filename, 'w') f.writelines(lines) f.close() nUpdates+=1 log.info('Updated PsychoPy path in %s' %filename) except: info+='Failed to update PsychoPy path in ', filename return -1, info return nUpdates, info
def setCurrent(self, calibration=-1): """ Sets the current calibration for this monitor. Note that a single file can hold multiple calibrations each stored under a different key (the date it was taken) The argument is either a string (naming the calib) or an integer **eg**: ``myMon.setCurrent'mainCalib')`` fetches the calibration named mainCalib ``calibName = myMon.setCurrent(0)`` fetches the first calibration (alphabetically) for this monitor ``calibName = myMon.setCurrent(-1)`` fetches the last alphabetical calib for this monitor (this is default) If default names are used for calibs (ie date/time stamp) then this will import the most recent. """ #find the appropriate file #get desired calibration name if necess if type(calibration) in [str, unicode] and (calibration in self.calibNames): self.currentCalibName = calibration elif type(calibration)==int and calibration<=len(self.calibNames): self.currentCalibName = self.calibNames[calibration] else: print "No record of that calibration" return False self.currentCalib = self.calibs[self.currentCalibName] #do the import log.info("Loaded calibration from:%s" %self.currentCalibName) return self.currentCalibName
def doGammaFits(self, levels, lums): linMethod = self.currentMon.getLineariseMethod() if linMethod==4: log.info('Fitting gamma equation(%i) to luminance data' %linMethod) currentCal = numpy.ones([4,6],'f')*numpy.nan for gun in [0,1,2,3]: gamCalc = monitors.GammaCalculator(levels, lums[gun,:], eq=linMethod) currentCal[gun,0]=gamCalc.min#min currentCal[gun,1]=gamCalc.max#max currentCal[gun,2]=gamCalc.gamma#gamma currentCal[gun,3]=gamCalc.a#gamma currentCal[gun,4]=gamCalc.b#gamma currentCal[gun,5]=gamCalc.k#gamma else: currentCal = numpy.ones([4,3],'f')*numpy.nan log.info('Fitting gamma equation(%i) to luminance data' %linMethod) for gun in [0,1,2,3]: gamCalc = monitors.GammaCalculator(levels, lums[gun,:], eq=linMethod) currentCal[gun,0]=lums[gun,0]#min currentCal[gun,1]=lums[gun,-1]#max currentCal[gun,2]=gamCalc.gamma#gamma self.gammaGrid.setData(currentCal) self.currentMon.setGammaGrid(currentCal) self.unSavedMonitor=True
def doGammaFits(self, levels, lums): linMethod = self.currentMon.getLineariseMethod() currentCal = self.currentMon.currentCalib['gammaGrid'] if linMethod == 3: #create new interpolator functions for the monitor log.info('Creating linear interpolation for gamma') self.currentMon.lineariseLums(0.5, newInterpolators=True) for gun in [0, 1, 2, 3]: currentCal[gun, 0] = lums[gun, 0] #min currentCal[gun, 1] = lums[gun, -1] #max currentCal[gun, 2] = -1.0 #gamma makes no sense for this method else: log.info('Fitting gamma equation(%i) to luminance data' % linMethod) for gun in [0, 1, 2, 3]: gamCalc = monitors.GammaCalculator(levels, lums[gun, :], eq=linMethod) currentCal[gun, 0] = lums[gun, 0] #min currentCal[gun, 1] = lums[gun, -1] #max currentCal[gun, 2] = gamCalc.gammaVal #gamma self.gammaGrid.setData(currentCal) self.unSavedMonitor = True
def rush(value=True): """Raise the priority of the current thread/process Win32 and OS X only so far - on linux use os.nice(niceIncrement) Set with rush(True) or rush(False) Beware and don't take priority until after debugging your code and ensuring you have a way out (e.g. an escape sequence of keys within the display loop). Otherwise you could end up locked out and having to reboot! """ if importCtypesFailed: return False if value: bus = getBusFreq() extendedPolicy=_timeConstraintThreadPolicy() extendedPolicy.period=bus/160 #number of cycles in hz (make higher than frame rate) extendedPolicy.computation=bus/320#half of that period extendedPolicy.constrain= bus/640#max period that they should be carried out in extendedPolicy.preemptible=1 extendedPolicy=getThreadPolicy(getDefault=True, flavour=THREAD_TIME_CONSTRAINT_POLICY) err=cocoa.thread_policy_set(cocoa.mach_thread_self(), THREAD_TIME_CONSTRAINT_POLICY, ctypes.byref(extendedPolicy), #send the address of the struct THREAD_TIME_CONSTRAINT_POLICY_COUNT) if err!=KERN_SUCCESS: log.error('Failed to set darwin thread policy, with thread_policy_set') else: log.info('Successfully set darwin thread to realtime') else: #revert to default policy extendedPolicy=getThreadPolicy(getDefault=True, flavour=THREAD_STANDARD_POLICY) err=cocoa.thread_policy_set(cocoa.mach_thread_self(), THREAD_STANDARD_POLICY, ctypes.byref(extendedPolicy), #send the address of the struct THREAD_STANDARD_POLICY_COUNT) return True
def doGammaFits(self, levels, lums): linMethod = self.currentMon.getLineariseMethod() if linMethod == 4: log.info('Fitting gamma equation(%i) to luminance data' % linMethod) currentCal = numpy.ones([4, 6], 'f') * numpy.nan for gun in [0, 1, 2, 3]: gamCalc = monitors.GammaCalculator(levels, lums[gun, :], eq=linMethod) currentCal[gun, 0] = gamCalc.min #min currentCal[gun, 1] = gamCalc.max #max currentCal[gun, 2] = gamCalc.gamma #gamma currentCal[gun, 3] = gamCalc.a #gamma currentCal[gun, 4] = gamCalc.b #gamma currentCal[gun, 5] = gamCalc.k #gamma else: currentCal = numpy.ones([4, 3], 'f') * numpy.nan log.info('Fitting gamma equation(%i) to luminance data' % linMethod) for gun in [0, 1, 2, 3]: gamCalc = monitors.GammaCalculator(levels, lums[gun, :], eq=linMethod) currentCal[gun, 0] = lums[gun, 0] #min currentCal[gun, 1] = lums[gun, -1] #max currentCal[gun, 2] = gamCalc.gamma #gamma self.gammaGrid.setData(currentCal) self.currentMon.setGammaGrid(currentCal) self.unSavedMonitor = True
def __init__(self, port, verbose=None): if type(port) in [int, float]: self.portNumber = port #add one so that port 1=COM1 self.portString = 'COM%i' % self.portNumber #add one so that port 1=COM1 else: self.portString = port self.portNumber = None self.isOpen = 0 self.lastQual = 0 self.type = 'PR650' self.com = False self.OK = True #until we fail self.codes = { 'OK': '000\r\n', #this is returned after measure '18': 'Light Low', #these is returned at beginning of data '10': 'Light Low', '00': 'OK' } #try to open the port if sys.platform in ['darwin', 'win32' ] or sys.platform.startswith('linux'): try: self.com = serial.Serial(self.portString) except: self._error( "Couldn't connect to port %s. Is it being used by another program?" % self.portString) else: self._error("I don't know how to handle serial ports on %s" % sys.platform) #setup the params for PR650 comms if self.OK: self.com.setBaudrate(9600) self.com.setParity('N') #none self.com.setStopbits(1) try: self.com.open() self.isOpen = 1 except: self._error( "Opened serial port %s, but couldn't connect to PR650" % self.portString) if self.OK: log.info("Successfully opened %s" % self.portString) time.sleep(0.1) #wait while establish connection reply = self.sendMessage( 'b1\n') #turn on the backlight as feedback if reply != self.codes['OK']: self._error("PR650 isn't communicating") if self.OK: reply = self.sendMessage( 's01,,,,,,01,1' ) #set command to make sure using right units etc...
def makeMPEG(filename, images, codec='mpeg1video', codecParams=None, verbose=False): if not havePyMedia: log.error('pymedia (www.pymedia.org) needed to make mpeg movies') return 0 fw = open(filename, 'wb') t = time.time() #set bitrate if codec == 'mpeg1video': bitrate = 2700000 else: bitrate = 9800000 #set other params (or receive params dictionary) if codecParams == None: codecParams= { \ 'type': 0, 'gop_size': 12, 'frame_rate_base': 125, 'max_b_frames': 0, 'width': images[0].size[0], 'height': images[0].size[1], 'frame_rate': 3125, 'deinterlace': 0, 'bitrate': bitrate, 'id': vcodec.getCodecID( codec ) } log.info('Setting codec to ' + str(codecParams)) encoder = vcodec.Encoder(codecParams) for im in images: # Create VFrame imStr = im.tostring() bmpFrame = vcodec.VFrame(vcodec.formats.PIX_FMT_RGB24, im.size, (imStr, None, None)) yuvFrame = bmpFrame.convert(vcodec.formats.PIX_FMT_YUV420P, im.size) d = encoder.encode(yuvFrame) try: fw.write(d.data) #this is what works! except: fw.write(d) #this is what pymedia demo recommends else: log.info('%d frames written in %.2f secs' % (len(images), time.time() - t)) i = 0 fw.close()
def findPR650(ports=None): """DEPRECATED (as of v.1.60.01). Use :func:`psychopy.hardware.findPhotometer()` instead, which finds a wider range of devices """ log.error("DEPRECATED (as of v.1.60.01). Use psychopy.hardware.findPhotometer() instead, which "\ +"finds a wider range of devices") if ports==None: if sys.platform=='darwin': ports=[] #try some known entries in /dev/tty. used by keyspan ports.extend(glob.glob('/dev/tty.USA*'))#keyspan twin adapter is usually USA28X13P1.1 ports.extend(glob.glob('/dev/tty.Key*'))#some are Keyspan.1 or Keyserial.1 ports.extend(glob.glob('/dev/tty.modem*'))#some are Keyspan.1 or Keyserial.1 if len(ports)==0: log.error("couldn't find likely serial port in /dev/tty.* Check for \ serial port name manually, check drivers installed etc...") elif sys.platform=='win32': ports = range(11) elif type(ports) in [int,float]: ports=[ports] #so that we can iterate pr650=None log.info('scanning serial ports...\n\t') log.console.flush() for thisPort in ports: log.info(str(thisPort)); log.console.flush() pr650 = Photometer(port=thisPort, meterType="PR650", verbose=False) if pr650.OK: log.info(' ...OK\n'); log.console.flush() break else: pr650=None log.info('...Nope!\n\t'); log.console.flush() return pr650
def findPR650(ports=None): """DEPRECATED (as of v.1.60.01). Use :func:`psychopy.hardware.findPhotometer()` instead, which finds a wider range of devices """ log.error("DEPRECATED (as of v.1.60.01). Use psychopy.hardware.findPhotometer() instead, which "\ +"finds a wider range of devices") print 'here' if ports==None: if sys.platform=='darwin': ports=[] #try some known entries in /dev/tty. used by keyspan ports.extend(glob.glob('/dev/tty.USA*'))#keyspan twin adapter is usually USA28X13P1.1 ports.extend(glob.glob('/dev/tty.Key*'))#some are Keyspan.1 or Keyserial.1 ports.extend(glob.glob('/dev/tty.modem*'))#some are Keyspan.1 or Keyserial.1 if len(ports)==0: log.error("couldn't find likely serial port in /dev/tty.* Check for \ serial port name manually, check drivers installed etc...") elif sys.platform=='win32': ports = range(11) elif type(ports) in [int,float]: ports=[ports] #so that we can iterate pr650=None log.info('scanning serial ports...\n\t') log.console.flush() for thisPort in ports: log.info(str(thisPort)); log.console.flush() pr650 = Photometer(port=thisPort, meterType="PR650", verbose=False) if pr650.OK: log.info(' ...OK\n'); log.console.flush() break else: pr650=None log.info('...Nope!\n\t'); log.console.flush() return pr650
def __init__(self, port): self.type = None #get this from the device later self.com = False self.OK = True #until we fail if type(port) in [int, float]: self.portNumber = port #add one so that port 1=COM1 self.portString = 'COM%i' % self.portNumber #add one so that port 1=COM1 else: self.portString = port self.portNumber = None self.codes = { 'OK': '000\r\n', #this is returned after measure '18': 'Light Low', #these is returned at beginning of data '10': 'Light Low', '00': 'OK' } #try to open the port try: self.com = serial.Serial(self.portString) except: self._error( "Couldn't connect to port %s. Is it being used by another program?" % self.portString) #setup the params for PR650 comms if self.OK: self.com.setBaudrate(9600) self.com.setParity('N') #none self.com.setStopbits(1) try: self.com.close() #attempt to close if it's currently open self.com.open() self.isOpen = 1 except: self._error( "Found a device on serial port %s, but couldn't open that port" % self.portString) self.com.setTimeout( 0.5) #this should be large when making measurements self.startRemoteMode() self.type = self.getDeviceType() if self.type: log.info("Successfully opened %s on %s" % (self.type, self.portString)) else: self._error("PR655/PR670 isn't communicating")
def __init__(self, port, verbose=None): if type(port) in [int, float]: self.portNumber = port #add one so that port 1=COM1 self.portString = 'COM%i' %self.portNumber#add one so that port 1=COM1 else: self.portString = port self.portNumber=None self.isOpen=0 self.lastQual=0 self.type='PR650' self.com=False self.OK=True#until we fail self.codes={'OK':'000\r\n',#this is returned after measure '18':'Light Low',#these is returned at beginning of data '10':'Light Low', '00':'OK' } #try to open the port if sys.platform in ['darwin', 'win32'] or sys.platform.startswith('linux'): try:self.com = serial.Serial(self.portString) except: self._error("Couldn't connect to port %s. Is it being used by another program?" %self.portString) else: self._error("I don't know how to handle serial ports on %s" %sys.platform) #setup the params for PR650 comms if self.OK: self.com.setBaudrate(9600) self.com.setParity('N')#none self.com.setStopbits(1) try: self.com.open() self.isOpen=1 except: self._error("Opened serial port %s, but couldn't connect to PR650" %self.portString) if self.OK: log.info("Successfully opened %s" %self.portString) time.sleep(0.1) #wait while establish connection reply = self.sendMessage('b1\n') #turn on the backlight as feedback if reply != self.codes['OK']: self._error("PR650 isn't communicating") if self.OK: reply = self.sendMessage('s01,,,,,,01,1')#set command to make sure using right units etc...
def makeMPEG(filename, images, codec='mpeg1video', codecParams = None, verbose=False): if not havePyMedia: log.error('pymedia (www.pymedia.org) needed to make mpeg movies') return 0 fw= open( filename, 'wb' ) t= time.time() #set bitrate if codec== 'mpeg1video': bitrate= 2700000 else: bitrate= 9800000 #set other params (or receive params dictionary) if codecParams == None: codecParams= { \ 'type': 0, 'gop_size': 12, 'frame_rate_base': 125, 'max_b_frames': 0, 'width': images[0].size[0], 'height': images[0].size[1], 'frame_rate': 3125, 'deinterlace': 0, 'bitrate': bitrate, 'id': vcodec.getCodecID( codec ) } log.info('Setting codec to ' + str(codecParams)) encoder= vcodec.Encoder( codecParams ) for im in images: # Create VFrame imStr = im.tostring() bmpFrame= vcodec.VFrame( vcodec.formats.PIX_FMT_RGB24, im.size, (imStr,None,None)) yuvFrame= bmpFrame.convert( vcodec.formats.PIX_FMT_YUV420P, im.size ) d = encoder.encode( yuvFrame ) try: fw.write( d.data )#this is what works! except: fw.write( d )#this is what pymedia demo recommends else: log.info('%d frames written in %.2f secs' % ( len(images), time.time()- t)) i= 0 fw.close()
def rush(value=True): """Raise the priority of the current thread/process Win32 and OS X only so far - on linux use os.nice(niceIncrement) Set with rush(True) or rush(False) Beware and don't take priority until after debugging your code and ensuring you have a way out (e.g. an escape sequence of keys within the display loop). Otherwise you could end up locked out and having to reboot! """ if importCtypesFailed: return False if value: bus = getBusFreq() extendedPolicy = _timeConstraintThreadPolicy() extendedPolicy.period = bus / 160 #number of cycles in hz (make higher than frame rate) extendedPolicy.computation = bus / 320 #half of that period extendedPolicy.constrain = bus / 640 #max period that they should be carried out in extendedPolicy.preemptible = 1 extendedPolicy = getThreadPolicy(getDefault=True, flavour=THREAD_TIME_CONSTRAINT_POLICY) err = cocoa.thread_policy_set( cocoa.mach_thread_self(), THREAD_TIME_CONSTRAINT_POLICY, ctypes.byref(extendedPolicy), #send the address of the struct THREAD_TIME_CONSTRAINT_POLICY_COUNT) if err != KERN_SUCCESS: log.error( 'Failed to set darwin thread policy, with thread_policy_set') else: log.info('Successfully set darwin thread to realtime') else: #revert to default policy extendedPolicy = getThreadPolicy(getDefault=True, flavour=THREAD_STANDARD_POLICY) err = cocoa.thread_policy_set( cocoa.mach_thread_self(), THREAD_STANDARD_POLICY, ctypes.byref(extendedPolicy), #send the address of the struct THREAD_STANDARD_POLICY_COUNT) return True
def doGammaFits(self, levels, lums): linMethod = self.currentMon.getLineariseMethod() currentCal = self.currentMon.currentCalib['gammaGrid'] if linMethod == 3: #create new interpolator functions for the monitor log.info('Creating linear interpolation for gamma') self.currentMon.lineariseLums(0.5, newInterpolators=True) for gun in [0,1,2,3]: currentCal[gun,0]=lums[gun,0]#min currentCal[gun,1]=lums[gun,-1]#max currentCal[gun,2]=-1.0#gamma makes no sense for this method else: log.info('Fitting gamma equation(%i) to luminance data' %linMethod) for gun in [0,1,2,3]: gamCalc = monitors.GammaCalculator(levels, lums[gun,:], eq=linMethod) currentCal[gun,0]=lums[gun,0]#min currentCal[gun,1]=lums[gun,-1]#max currentCal[gun,2]=gamCalc.gammaVal#gamma self.gammaGrid.setData(currentCal) self.unSavedMonitor=True
def __init__(self, port): self.type = None#get this from the device later self.com=False self.OK=True#until we fail if type(port) in [int, float]: self.portNumber = port #add one so that port 1=COM1 self.portString = 'COM%i' %self.portNumber#add one so that port 1=COM1 else: self.portString = port self.portNumber=None self.codes={'OK':'000\r\n',#this is returned after measure '18':'Light Low',#these is returned at beginning of data '10':'Light Low', '00':'OK' } #try to open the port try: self.com = serial.Serial(self.portString) except: self._error("Couldn't connect to port %s. Is it being used by another program?" %self.portString) #setup the params for PR650 comms if self.OK: self.com.setBaudrate(9600) self.com.setParity('N')#none self.com.setStopbits(1) try: self.com.close()#attempt to close if it's currently open self.com.open() self.isOpen=1 except: self._error("Found a device on serial port %s, but couldn't open that port" %self.portString) self.com.setTimeout(0.1)#this should be large when making measurements self.startRemoteMode() self.type = self.getDeviceType() if self.type: log.info("Successfully opened %s on %s" %(self.type,self.portString)) else: self._error("PR655/PR670 isn't communicating")
def findPhotometer(ports=None, device=None): """Try to find a connected photometer/photospectrometer! PsychoPy will sweep a series of serial ports trying to open them. If a port successfully opens then it will try to issue a command to the device. If it responds with one of the expected values then it is assumed to be the appropriate device. :parameters: ports : a list of ports to search Each port can be a string (e.g. 'COM1', ''/dev/tty.Keyspan1.1') or a number (for win32 comports only). If none are provided then PsychoPy will sweep COM0-10 on win32 and search known likely port names on OS X and linux. device : string giving expected device (e.g. 'PR650', 'PR655', 'LS110'). If this is not given then an attempt will be made to find a device of any type, but this often fails :returns: * An object representing the first photometer found * None if the ports didn't yield a valid response * -1 if there were not even any valid ports (suggesting a driver not being installed) e.g.:: photom = findPhotometer(device='PR655') #sweeps ports 0 to 10 searching for a PR655 print photom.getLum() if hasattr(photom, 'getSpectrum'):#can retrieve spectrum (e.g. a PR650) print photom.getSpectrum() """ import minolta, pr if device.lower() in ['pr650']: photometers = [pr.PR650] elif device.lower() in ['pr655', 'pr670']: photometers = [pr.PR655] elif device.lower() in ['ls110', 'ls100']: photometers = [minolta.LS100] else: #try them all photometers = [pr.PR650, pr.PR655, minolta.LS100 ] #a list of photometer objects to test for #determine candidate ports if ports == None: if sys.platform == 'darwin': ports = [] #try some known entries in /dev/tty. used by keyspan ports.extend(glob.glob('/dev/tty.USA*') ) #keyspan twin adapter is usually USA28X13P1.1 ports.extend( glob.glob('/dev/tty.Key*')) #some are Keyspan.1 or Keyserial.1 ports.extend(glob.glob( '/dev/tty.modem*')) #some are Keyspan.1 or Keyserial.1 ports.extend(glob.glob('/dev/cu.usbmodem*')) #for PR650 if len(ports) == 0: log.error("PsychoPy couldn't find any likely serial port in /dev/tty.* or /dev/cs* Check for " \ +"serial port name manually, check drivers installed etc...") return None elif sys.platform.startswith('linux'): ports = glob.glob( '/dev/ttyACM?') #USB CDC devices (virtual serial ports) ports.extend( glob.glob('/dev/ttyS?') ) #genuine serial ports usually /dev/ttyS0 or /dev/ttyS1 elif sys.platform == 'win32': ports = range(11) elif type(ports) in [int, float]: ports = [ports] #so that we can iterate #go through each port in turn photom = None log.info('scanning serial ports...') log.flush() for thisPort in ports: log.info('...' + str(thisPort)) log.flush() for Photometer in photometers: photom = Photometer(port=thisPort) if photom.OK: log.info(' ...found a %s\n' % (photom.type)) log.flush() #we're now sure that this is the correct device and that it's configured #now increase the number of attempts made to communicate for temperamental devices! if hasattr(photom, 'setMaxAttempts'): photom.setMaxAttempts(10) return photom #we found one so stop looking else: if photom.com and photom.com.isOpen: log.info('closing port') photom.com.close() #If we got here we didn't find one log.info('...nope!\n\t') log.flush() return None
def __init__(self, port, maxAttempts=1): if not serial: raise ImportError('The module serial is needed to connect to photometers. ' +\ "On most systems this can be installed with\n\t easy_install pyserial") if type(port) in [int, float]: self.portNumber = port #add one so that port 1=COM1 self.portString = 'COM%i' %self.portNumber#add one so that port 1=COM1 else: self.portString = port self.portNumber=None self.isOpen=0 self.lastQual=0 self.lastLum=None self.type='LS100' self.com=False self.OK=True#until we fail self.maxAttempts=maxAttempts self.codes={ 'ER00\r\n':'Unknown command', 'ER01\r\n':'Setting error', 'ER11\r\n':'Memory value error', 'ER10\r\n':'Measuring range over', 'ER19\r\n':'Display range over', 'ER20\r\n':'EEPROM error (the photometer needs repair)', 'ER30\r\n':'Photometer battery exhausted',} #try to open the port if sys.platform in ['darwin', 'win32']: try:self.com = serial.Serial(self.portString) except: self._error("Couldn't connect to port %s. Is it being used by another program?" %self.portString) else: self._error("I don't know how to handle serial ports on %s" %sys.platform) #setup the params for PR650 comms if self.OK: self.com.close()#not sure why this helps but on win32 it does!! self.com.setByteSize(7)#this is a slightly odd characteristic of the Minolta LS100 self.com.setBaudrate(4800) self.com.setParity(serial.PARITY_EVEN)#none self.com.setStopbits(serial.STOPBITS_TWO) try: self.com.open() self.isOpen=1 except: self._error("Opened serial port %s, but couldn't connect to LS100" %self.portString) if self.OK:#we have an open com port. try to send a command for repN in range(self.maxAttempts): time.sleep(0.2) for n in range(10): reply = self.sendMessage('MDS,04')#set to use absolute measurements if reply[0:2] == 'OK': self.OK=True break elif reply not in self.codes.keys(): self.OK=False break#wasn't valid else: self.OK=False #false so far but keep trying if self.OK:# we have successfully sent and read a command log.info("Successfully opened %s" %self.portString)
def createLinearRamp(win, rampType=None): """Generate the Nx3 values for a linear gamma ramp on the current platform. This uses heuristics about known graphics cards to guess the 'rampType' if none is exlicitly given. Much of this work is ported from LoadIdentityClut.m, written by Mario Kleiner for the psychtoolbox rampType 0 : an 8-bit CLUT ranging 0:1 This is seems correct for most windows machines and older OS X systems Known to be used by: OSX 10.4.9 PPC with GeForceFX-5200 rampType 1 : an 8-bit CLUT ranging (1/256.0):1 For some reason a number of macs then had a CLUT that (erroneously?) started with 1/256 rather than 0 Known to be used by: OSX 10.4.9 with ATI Mobility Radeon X1600 OSX 10.5.8 with ATI Radeon HD-2600 maybe all ATI cards? rampType 2 : a 10-bit CLUT ranging 0:(1023/1024) A slightly odd 10-bit CLUT that doesn't quite finish on 1.0! Known to be used by: OSX 10.5.8 with Geforce-9200M (MacMini) OSX 10.5.8 with Geforce-8800 rampType 3 : a nasty, bug-fixing 10bit CLUT for crumby OS X drivers Craziest of them all for Snow leopard. Like rampType 2, except that the upper half of the table has 1/256.0 removed?!! Known to be used by: OSX 10.6.0 with NVidia Geforce-9200M """ if rampType == None: #try to determine rampType from heuristics #get sys info driver = gl_info.get_renderer() if sys.platform == 'darwin': isOSX = True osxVer = platform.mac_ver()[0] else: isOSX = False osxVer = None #try to deduce ramp type if isOSX: if 'NVIDIA' in driver: if ("10.5" < osxVer < "10.6"): #leopard nVidia cards don't finish at 1.0! rampType = 2 if ("10.6" < osxVer): #snow leopard cards are plain crazy! rampType = 3 else: #is ATI or unkown manufacturer, default to (1:256)/256 #this is certainly correct for radeon2600 on 10.5.8 and radeonX1600 on 10.4.9 rampType = 1 else: #for win32 and linux this is sensible, not clear about Vista and Windows7 rampType = 0 if rampType == 0: ramp = numpy.linspace(0.0, 1.0, num=256) elif rampType == 1: ramp = numpy.linspace(1 / 256.0, 1.0, num=256) elif rampType == 2: ramp = numpy.linspace(0, 1023.0 / 1024, num=1024) elif rampType == 3: ramp = numpy.linspace(0, 1023.0 / 1024, num=1024) ramp[512:] = ramp[512:] - 1 / 256.0 log.info('Using gamma ramp type: %i' % rampType) return ramp
dir=270, nDots=100, fieldShape='circle', fieldPos=(0.0, 0.0), fieldSize=1, dotLife=5, #number of frames for each dot to be drawn signalDots= 'same', #are the signal and noise dots 'different' or 'same' popns (see Scase et al) noiseDots= 'direction', #do the noise dots follow random- 'walk', 'direction', or 'position' speed=0.01, coherence=0.9) message = visual.TextStim(myWin, text='Hit Q to quit', pos=(0, -0.5)) trialClock = core.Clock() myWin.setRecordFrameIntervals() n = 0 while True: #quits after 20 secs n += 1 dotPatch.draw() message.draw() myWin.flip() #redraw the buffer for n in range(10): log.info('%i info' % n) #handle key presses each frame for key in event.getKeys(): if key in ['escape', 'q']: log.data('final fps = %.3f' % myWin.fps()) myWin.close() core.quit() event.clearEvents() #keep the event buffer from overflowing
def lineariseLums(self, desiredLums, newInterpolators=False, overrideGamma=None): """lums should be uncalibrated luminance values (e.g. a linear ramp) ranging 0:1""" linMethod = self.getLineariseMethod() desiredLums = numpy.asarray(desiredLums) output = desiredLums*0.0 #needs same size as input #gamma interpolation if linMethod==3: lumsPre = copy(self.getLumsPre()) if self._gammaInterpolator!=None and not newInterpolators: pass #we already have an interpolator elif lumsPre != None: log.info('Creating linear interpolation for gamma') #we can make an interpolator self._gammaInterpolator, self._gammaInterpolator2 =[],[] #each of these interpolators is a function! levelsPre = self.getLevelsPre()/255.0 for gun in range(4): lumsPre[gun,:] = (lumsPre[gun,:]-lumsPre[gun,0])/(lumsPre[gun,-1]-lumsPre[gun,0])#scale to 0:1 self._gammaInterpolator.append(interp1d(lumsPre[gun,:], levelsPre,kind='linear')) #interpFunc = Interpolation.InterpolatingFunction((lumsPre[gun,:],), levelsPre) #polyFunc = interpFunc.fitPolynomial(3) #print polyFunc.coeff #print polyFunc.derivative(0) #print polyFunc.derivative(0.5) #print polyFunc.derivative(1.0) #self._gammaInterpolator2.append( [polyFunc.coeff]) else: #no way to do this! Calibrate the monitor log.error("Can't do a gamma interpolation on your monitor without calibrating!") return desiredLums #then do the actual interpolations if len(desiredLums.shape)>1: for gun in range(3): output[:,gun] = self._gammaInterpolator[gun+1](desiredLums[:,gun])#gun+1 because we don't want luminance interpolator else:#just luminance output = self._gammaInterpolator[0](desiredLums) #use a fitted gamma equation (1 or 2) elif linMethod in [1,2]: #get the min,max lums gammaGrid = self.getGammaGrid() if gammaGrid!=None: #if we have info about min and max luminance then use it minLum = gammaGrid[1,0] maxLum = gammaGrid[1:4,1] if overrideGamma is not None: gamma=overrideGamma else: gamma = gammaGrid[1:4,2] maxLumWhite = gammaGrid[0,1] gammaWhite = gammaGrid[0,2] log.debug('using gamma grid'+str(gammaGrid)) else: #just do the calculation using gamma minLum=0 maxLumR, maxLumG, maxLumB, maxLumWhite= 1,1,1, 1 gamma = self.gamma gammaWhite = num.average(self.gamma) #get the inverse gamma if len(desiredLums.shape)>1: for gun in range(3): output[:,gun] = gammaInvFun(desiredLums[:,gun], minLum, maxLum[gun], gamma[gun],eq=linMethod) #print gamma else: output = gammaInvFun(desiredLums, minLum, maxLumWhite, gammaWhite,eq=linMethod) else: log.error("Don't know how to linearise with method %i" %linMethod) output = desiredLums #if DEBUG: print 'LUT:', output[0:10,1], '...' return output
from psychopy import log #create a log that gets replaced every run and stores all the details detailedLog = log.LogFile('complete.log', 'w', #'a' will append to previous file, 'w' will overwrite level=log.INFO) #set the level of the console log log.console.setLevel(log.WARNING) #set the level of the log at site-packages/psychopy/psychopy.log log.psychopyLog.setLevel(log.ERROR) log.warning('a shot across the bows') log.error('just a test error message') log.info('this will only get sent to the detailed log file')
def createLinearRamp(win, rampType=None): """Generate the Nx3 values for a linear gamma ramp on the current platform. This uses heuristics about known graphics cards to guess the 'rampType' if none is exlicitly given. Much of this work is ported from LoadIdentityClut.m, written by Mario Kleiner for the psychtoolbox rampType 0 : an 8-bit CLUT ranging 0:1 This is seems correct for most windows machines and older OS X systems Known to be used by: OSX 10.4.9 PPC with GeForceFX-5200 rampType 1 : an 8-bit CLUT ranging (1/256.0):1 For some reason a number of macs then had a CLUT that (erroneously?) started with 1/256 rather than 0 Known to be used by: OSX 10.4.9 with ATI Mobility Radeon X1600 OSX 10.5.8 with ATI Radeon HD-2600 maybe all ATI cards? rampType 2 : a 10-bit CLUT ranging 0:(1023/1024) A slightly odd 10-bit CLUT that doesn't quite finish on 1.0! Known to be used by: OSX 10.5.8 with Geforce-9200M (MacMini) OSX 10.5.8 with Geforce-8800 rampType 3 : a nasty, bug-fixing 10bit CLUT for crumby OS X drivers Craziest of them all for Snow leopard. Like rampType 2, except that the upper half of the table has 1/256.0 removed?!! Known to be used by: OSX 10.6.0 with NVidia Geforce-9200M """ if rampType==None: #try to determine rampType from heuristics #get sys info driver = pyglet.gl.gl_info.get_renderer() if sys.platform=='darwin': isOSX=True osxVer=platform.mac_ver()[0] else: isOSX=False osxVer=None #try to deduce ramp type if isOSX: if 'NVIDIA' in driver: if ("10.5"<osxVer<"10.6"):#leopard nVidia cards don't finish at 1.0! rampType=2 if ("10.6"<osxVer):#snow leopard cards are plain crazy! rampType=3 else: #is ATI or unkown manufacturer, default to (1:256)/256 #this is certainly correct for radeon2600 on 10.5.8 and radeonX1600 on 10.4.9 rampType=1 else:#for win32 and linux this is sensible, not clear about Vista and Windows7 rampType=0 if rampType==0: ramp = numpy.linspace(0.0, 1.0, num=256) elif rampType==1: ramp = numpy.linspace(1/256.0,1.0,num=256) elif rampType==2: ramp = numpy.linspace(0, 1023.0/1024,num=1024) elif rampType==3: ramp = numpy.linspace(0, 1023.0/1024,num=1024) ramp[512:] = ramp[512:]-1/256.0 log.info('Using gamma ramp type: %i' %rampType) return ramp
from psychopy import log #create a log that gets replaced every run and stores all the details detailedLog = log.LogFile( 'complete.log', 'w', #'a' will append to previous file, 'w' will overwrite level=log.INFO) #set the level of the console log log.console.setLevel(log.WARNING) #set the level of the log at site-packages/psychopy/psychopy.log log.psychopyLog.setLevel(log.ERROR) log.warning('a shot across the bows') log.error('just a test error message') log.info('this will only get sent to the detailed log file')
22: EXP 20:INFO 10:DEBUG So setting to DEBUG level will include all possible messages, setting to ERROR will include only the absolutely essential messages. """ globalClock = core.Clock()#if this isn't provided the log times will reflect secs since python started log.setDefaultClock(globalClock)#use this for log.console.setLevel(log.DEBUG)#set the console to receive nearly all messges logDat = log.LogFile('logLastRun.log', filemode='w',#if you set this to 'a' it will append instead of overwriting level=log.WARNING)#errors, data and warnings will be sent to this logfile #the following will go to any files with the appropriate minimum level set log.info('Something fairly unimportant') log.data('Something about our data. Data is likely very important!') log.warning('Handy while building your experiment - highlights possible flaws in code/design') log.error("You might have done something that PsychoPy can't handle! But hopefully this gives you some idea what.") #some things should be logged timestamped on the next video frame #For instance the time of a stimulus appearing is related to the flip: win = visual.Window([400,400]) for n in range(5): win.logOnFlip('frame %i occured' %n, level=log.EXP) if n in [2,4]: win.logOnFlip('an even frame occured', level=log.EXP) win.flip() #LogFiles can also simply receive direct input from the write() method #messages using write() will be sent immediately, and are often not
def findPhotometer(ports=None, device=None): """Try to find a connected photometer/photospectrometer! PsychoPy will sweep a series of serial ports trying to open them. If a port successfully opens then it will try to issue a command to the device. If it responds with one of the expected values then it is assumed to be the appropriate device. :parameters: ports : a list of ports to search Each port can be a string (e.g. 'COM1', ''/dev/tty.Keyspan1.1') or a number (for win32 comports only). If none are provided then PsychoPy will sweep COM0-10 on win32 and search known likely port names on OS X and linux. device : string giving expected device (e.g. 'PR650', 'PR655', 'LS110'). If this is not given then an attempt will be made to find a device of any type, but this often fails :returns: * An object representing the first photometer found * None if the ports didn't yield a valid response * -1 if there were not even any valid ports (suggesting a driver not being installed) e.g.:: photom = findPhotometer(device='PR655') #sweeps ports 0 to 10 searching for a PR655 print photom.getLum() if hasattr(photom, 'getSpectrum'):#can retrieve spectrum (e.g. a PR650) print photom.getSpectrum() """ import minolta, pr if device.lower() in ['pr650']: photometers=[pr.PR650] elif device.lower() in ['pr655', 'pr670']: photometers=[pr.PR655] elif device.lower() in ['ls110', 'ls100']: photometers=[minolta.LS100] else:#try them all photometers=[pr.PR650, pr.PR655, minolta.LS100]#a list of photometer objects to test for #determine candidate ports if ports==None: if sys.platform=='darwin': ports=[] #try some known entries in /dev/tty. used by keyspan ports.extend(glob.glob('/dev/tty.USA*'))#keyspan twin adapter is usually USA28X13P1.1 ports.extend(glob.glob('/dev/tty.Key*'))#some are Keyspan.1 or Keyserial.1 ports.extend(glob.glob('/dev/tty.modem*'))#some are Keyspan.1 or Keyserial.1 ports.extend(glob.glob('/dev/cu.usbmodem*'))#for PR650 if len(ports)==0: log.error("PsychoPy couldn't find any likely serial port in /dev/tty.* or /dev/cs* Check for " \ +"serial port name manually, check drivers installed etc...") return None elif sys.platform.startswith('linux'): ports = glob.glob('/dev/ttyACM?')#USB CDC devices (virtual serial ports) ports.extend(glob.glob('/dev/ttyS?'))#genuine serial ports usually /dev/ttyS0 or /dev/ttyS1 elif sys.platform=='win32': ports = range(11) elif type(ports) in [int,float]: ports=[ports] #so that we can iterate #go through each port in turn photom=None log.info('scanning serial ports...') log.flush() for thisPort in ports: log.info('...'+str(thisPort)); log.flush() for Photometer in photometers: photom = Photometer(port=thisPort) if photom.OK: log.info(' ...found a %s\n' %(photom.type)); log.flush() #we're now sure that this is the correct device and that it's configured #now increase the number of attempts made to communicate for temperamental devices! if hasattr(photom,'setMaxAttempts'):photom.setMaxAttempts(10) return photom#we found one so stop looking else: if photom.com and photom.com.isOpen: log.info('closing port') photom.com.close() #If we got here we didn't find one log.info('...nope!\n\t'); log.flush() return None
10:DEBUG So setting to DEBUG level will include all possible messages, setting to ERROR will include only the absolutely essential messages. """ globalClock = core.Clock( ) #if this isn't provided the log times will reflect secs since python started log.setDefaultClock(globalClock) #use this for log.console.setLevel(log.DEBUG) #set the console to receive nearly all messges logDat = log.LogFile( 'logLastRun.log', filemode='w', #if you set this to 'a' it will append instead of overwriting level=log.WARNING) #errors, data and warnings will be sent to this logfile #the following will go to any files with the appropriate minimum level set log.info('Something fairly unimportant') log.data('Something about our data. Data is likely very important!') log.warning( 'Handy while building your experiment - highlights possible flaws in code/design' ) log.error( "You might have done something that PsychoPy can't handle! But hopefully this gives you some idea what." ) #some things should be logged timestamped on the next video frame #For instance the time of a stimulus appearing is related to the flip: win = visual.Window([400, 400]) for n in range(5): win.logOnFlip('frame %i occured' % n, level=log.EXP) if n in [2, 4]: win.logOnFlip('an even frame occured', level=log.EXP)
def lineariseLums(self, desiredLums, newInterpolators=False, overrideGamma=None): """lums should be uncalibrated luminance values (e.g. a linear ramp) ranging 0:1""" linMethod = self.getLineariseMethod() desiredLums = numpy.asarray(desiredLums) output = desiredLums*0.0 #needs same size as input #gamma interpolation if linMethod==3: lumsPre = copy(self.getLumsPre()) if self._gammaInterpolator!=None and not newInterpolators: pass #we already have an interpolator elif lumsPre != None: log.info('Creating linear interpolation for gamma') #we can make an interpolator self._gammaInterpolator, self._gammaInterpolator2 =[],[] #each of these interpolators is a function! levelsPre = self.getLevelsPre()/255.0 for gun in range(4): lumsPre[gun,:] = (lumsPre[gun,:]-lumsPre[gun,0])/(lumsPre[gun,-1]-lumsPre[gun,0])#scale to 0:1 self._gammaInterpolator.append(interp1d(lumsPre[gun,:], levelsPre,kind='linear')) #interpFunc = Interpolation.InterpolatingFunction((lumsPre[gun,:],), levelsPre) #polyFunc = interpFunc.fitPolynomial(3) #print polyFunc.coeff #print polyFunc.derivative(0) #print polyFunc.derivative(0.5) #print polyFunc.derivative(1.0) #self._gammaInterpolator2.append( [polyFunc.coeff]) else: #no way to do this! Calibrate the monitor log.error("Can't do a gamma interpolation on your monitor without calibrating!") return desiredLums #then do the actual interpolations if len(desiredLums.shape)>1: for gun in range(3): output[:,gun] = self._gammaInterpolator[gun+1](desiredLums[:,gun])#gun+1 because we don't want luminance interpolator else:#just luminance output = self._gammaInterpolator[0](desiredLums) #use a fitted gamma equation (1 or 2) elif linMethod in [1,2,4]: #get the min,max lums gammaGrid = self.getGammaGrid() if gammaGrid!=None: #if we have info about min and max luminance then use it minLum = gammaGrid[1,0] maxLum = gammaGrid[1:4,1] b = gammaGrid[1:4,4] if overrideGamma is not None: gamma=overrideGamma else: gamma = gammaGrid[1:4,2] maxLumWhite = gammaGrid[0,1] gammaWhite = gammaGrid[0,2] log.debug('using gamma grid'+str(gammaGrid)) else: #just do the calculation using gamma minLum=0 maxLumR, maxLumG, maxLumB, maxLumWhite= 1,1,1, 1 gamma = self.gamma gammaWhite = num.average(self.gamma) #get the inverse gamma if len(desiredLums.shape)>1: for gun in range(3): output[:,gun] = gammaInvFun(desiredLums[:,gun], minLum, maxLum[gun], gamma[gun],eq=linMethod, b=b[gun]) #print gamma else: output = gammaInvFun(desiredLums, minLum, maxLumWhite, gammaWhite,eq=linMethod) else: log.error("Don't know how to linearise with method %i" %linMethod) output = desiredLums #if DEBUG: print 'LUT:', output[0:10,1], '...' return output
#create a window to draw in myWin =visual.Window((600,600), allowGUI=False, bitsMode=None, units='norm', winType='pyglet') #INITIALISE SOME STIMULI dotPatch =visual.DotStim(myWin, rgb=(1.0,1.0,1.0), dir=270, nDots=100, fieldShape='circle', fieldPos=(0.0,0.0),fieldSize=1, dotLife=5, #number of frames for each dot to be drawn signalDots='same', #are the signal and noise dots 'different' or 'same' popns (see Scase et al) noiseDots='direction', #do the noise dots follow random- 'walk', 'direction', or 'position' speed=0.01, coherence=0.9) message =visual.TextStim(myWin,text='Hit Q to quit', pos=(0,-0.5)) trialClock =core.Clock() myWin.setRecordFrameIntervals() n=0 while True:#quits after 20 secs n+=1 dotPatch.draw() message.draw() myWin.flip()#redraw the buffer for n in range(10): log.info('%i info' %n) #handle key presses each frame for key in event.getKeys(): if key in ['escape','q']: log.data('final fps = %.3f' % myWin.fps()) myWin.close() core.quit() event.clearEvents()#keep the event buffer from overflowing