def run(self): """Run the node in a loop, reconnecting after connection loss.""" log = logging.getLogger('labrad.node') while True: print 'Connecting to {}:{}...'.format(self.host, self.port) try: p = yield protocol.connect(self.host, self.port, self.tls_mode) yield p.authenticate(self.password) node = NodeServer(self.nodename, self.host, self.port, self.password) yield node.startup(p) except Exception: log.error('Node failed to start', exc_info=True) else: try: yield node.onShutdown() except Exception: log.error('Error during node shutdown', exc_info=True) ## hack: manually clear the internal message dispatcher dispatcher.connections.clear() dispatcher.senders.clear() dispatcher._boundMethods.clear() yield util.wakeupCall(0) print 'Will try to reconnect in {} seconds...'.format(self.reconnectDelay) yield util.wakeupCall(self.reconnectDelay)
def startTakingTemps(self, addrs): # if no chans, refresh once a second # if one chan, measure once a second # if more than one chan, switch, wait, measure, ... chanList = self.allDeviceChans[addrs].keys() chanList.remove('context') chanList.remove('currentChanIndex') chanList.remove('deviceAddresses') # If no chans, refresh if len( chanList ) < 1: callLater(MIN_REFRESH_RATE['s'],self.startTakingTemps,addrs) return # If chan index is out of range, reset to 0 if self.allDeviceChans[addrs]['currentChanIndex'] >= len(chanList): self.allDeviceChans[addrs]['currentChanIndex'] = 0 # Switch channel -> wait time const -> measure temp. index = self.allDeviceChans[addrs]['currentChanIndex'] chan = chanList[index] ctx = self.allDeviceChans[addrs]['context'] deviceAddresses = self.allDeviceChans[addrs]['deviceAddresses'] MP = self.client[deviceAddresses[1][0]] ACB = self.client[deviceAddresses[0][0]] yield MP.channel(chan, context=ctx) yield ACB.set_curve(chan, context=ctx) t = yield ACB.get_time_constant(context=ctx) timeout = max(MIN_REFRESH_RATE['s'], TIME_CONSTANT_MULTIPLIER * t['s']) * units.s if len(chanList) > 1: yield util.wakeupCall(timeout['s']) else: yield util.wakeupCall(MIN_REFRESH_RATE['s']) temp = yield ACB.get_ruox_temperature(context=ctx) self.allDeviceChans[addrs][chan] = temp self.allDeviceChans[addrs]['currentChanIndex'] += 1 callLater(0.1,self.startTakingTemps,addrs)
def run(self): """Run the node in a loop, reconnecting after connection loss.""" log = logging.getLogger('labrad.node') while True: print('Connecting to {}:{}...'.format(self.host, self.port)) try: p = yield protocol.connect(self.host, self.port, self.tls_mode, self.username, self.password) node = NodeServer(self.nodename, self.host, self.port, p.credential) yield node.startup(p) except Exception: log.error('Node failed to start', exc_info=True) else: try: yield node.onShutdown() except Exception: log.error('Error during node shutdown', exc_info=True) ## hack: manually clear the internal message dispatcher dispatcher.connections.clear() dispatcher.senders.clear() dispatcher._boundMethods.clear() yield util.wakeupCall(0) print('Will try to reconnect in {} seconds...'.format(self.reconnectDelay)) yield util.wakeupCall(self.reconnectDelay)
def startTakingTemps(self, addrs): # if no chans, refresh once a second # if one chan, measure once a second # if more than one chan, switch, wait, measure, ... chanList = self.allDeviceChans[addrs].keys() chanList.remove('context') chanList.remove('currentChanIndex') chanList.remove('deviceAddresses') # If no chans, refresh if len(chanList) < 1: callLater(MIN_REFRESH_RATE['s'], self.startTakingTemps, addrs) return # If chan index is out of range, reset to 0 if self.allDeviceChans[addrs]['currentChanIndex'] >= len(chanList): self.allDeviceChans[addrs]['currentChanIndex'] = 0 # Switch channel -> wait time const -> measure temp. index = self.allDeviceChans[addrs]['currentChanIndex'] chan = chanList[index] ctx = self.allDeviceChans[addrs]['context'] deviceAddresses = self.allDeviceChans[addrs]['deviceAddresses'] MP = self.client[deviceAddresses[1][0]] ACB = self.client[deviceAddresses[0][0]] yield MP.channel(chan, context=ctx) yield ACB.set_curve(chan, context=ctx) t = yield ACB.get_time_constant(context=ctx) timeout = max(MIN_REFRESH_RATE['s'], TIME_CONSTANT_MULTIPLIER * t['s']) * units.s if len(chanList) > 1: yield util.wakeupCall(timeout['s']) else: yield util.wakeupCall(MIN_REFRESH_RATE['s']) temp = yield ACB.get_ruox_temperature(context=ctx) self.allDeviceChans[addrs][chan] = temp self.allDeviceChans[addrs]['currentChanIndex'] += 1 callLater(0.1, self.startTakingTemps, addrs)
def waitForSettling(self, minSettle=Value(0.0,'s')): t = time.time() while 1: done = yield self.doneSettling() if done: yield util.wakeupCall(max(0.0, minSettle['s'] - (time.time() - t))) returnValue(None) #Return None because returnValue needs an argument else: print 'Device waiting for settling. Will check again in %d seconds' %self.SETTLING_TIME['s'] yield util.wakeupCall(self.SETTLING_TIME['s'])
def waitForSettling(self, minSettle=T.Value(0,'s')): yield self.write("*CLS") yield self.write("UNST 0") # wait for 1 / (5 * bandwidth) span = yield self.query("FSPN? 0") time = 0.2 / float(span) yield util.wakeupCall(max(time, minSettle['s'])) done = yield self.doneSettling() while not done: yield util.wakeupCall(self.SETTLING_TIME['s']) done = yield self.doneSettling() returnValue(None)
def startTakingTemps(self,c): while True: chans = c['chans'].keys() if len(chans) < 1: yield util.wakeupCall( MIN_REFRESH_RATE['s'] ) # to not take up too many resources if no channels are selected # switch channel -> wait time const -> measure temp for chan in chans: yield c['MP'].channel(chan) yield c['ACB'].set_curve(chan) t = yield c['ACB'].get_time_constant() timeout = max(MIN_REFRESH_RATE['s'], 2*t['s'])*units.s yield util.wakeupCall( timeout['s'] ) c['chans'][chan] = yield c['ACB'].get_ruox_temperature()
def freq_sweep_phase(self, c, log=False): """Initiate a frequency sweep. If log is False (the default), this will perform a linear sweep. If log is True, the sweep will be logarithmic. """ dev = self.selectedDevice(c) resp = yield dev.query('SENS:FREQ:STAR?; STOP?') fstar, fstop = [float(f) for f in resp.split(';')] sweepType = 'LOG' if log else 'LIN' sweeptime, npoints = yield self.startSweep(dev, sweepType) if sweeptime > 1: sweeptime *= self.sweepFactor(c) yield util.wakeupCall(2*sweeptime) #needs factor of 2 since it runs both forward and backward if log: ## hack: should use numpy.logspace, but it seems to be broken ## for now, this works instead. lim1, lim2 = numpy.log10(fstar), numpy.log10(fstop) freq = 10**numpy.linspace(lim1, lim2, npoints) else: freq = numpy.linspace(fstar, fstop, npoints) # wait for sweep to finish phase = yield self.getSweepDataPhase(dev, c['meas']) returnValue((freq, phase))
def startService(self): """Connect to labrad in a loop, reconnecting after connection loss.""" self.running = True while self.running: self.report('Connecting...') try: dv = DataVaultMultiHead(self.host, self.port, self.password, self.hub, self.session_store) self.stop_func = yield self.start(dv) self.report('Connected') self.connected = True except Exception: self.report('Data Vault failed to start') traceback.print_exc() else: try: yield dv.onShutdown() except Exception: self.report('Disconnected with error') traceback.print_exc() else: self.report('Disconnected') self.hub.disconnect(dv) self.connected = False if self.running: self.report('Will reconnect in {} seconds...'.format( self.reconnectDelay)) yield util.wakeupCall(self.reconnectDelay)
def multi_trace(self, c, cstar=1, cend=2): """Returns the y-values of the current traces from the sampling scope in a tuple. (offset, timestep, 2-D array of traces) """ dev = self.selectedDevice(c) if cstar < 1 or cstar > 8: raise Exception('cstar out of range') if cend < 1 or cend > 8: raise Exception('cend out of range') if cstar > cend: raise Exception('must have cend >= cstar') yield dev.write('COND TYP:AVG') while True: if int((yield dev.query('COND? REMA'))[18:]) == 0: break yield util.wakeupCall(2) resp = yield dev.query('ENC WAV:BIN;BYT. LSB;OUT TRA%dTOTRA%d;WAV?' % (cstar, cend), bytes=20000L) splits = resp.split(";WFMPRE") traces = [] ofs = 0 incr = 0 for trace in splits: ofs, incr, vals = _parseBinaryData(trace) traces.append(vals) #ofs1, incr1, vals1 = _parseBinaryData(t1) #ofs2, incr2, vals2 = _parseBinaryData(t2) #traces = np.vstack((vals1, vals2)) returnValue((ofs, incr, traces))
def masterReset(self, switch, commands): for command in commands: reschan = commands[command] yield self.write(reschan) yield self.resetPulse() yield util.wakeupCall(2) self.state[switch] = '0'
def freq_sweep(self, c, log=False): """Initiate a frequency sweep. If log is False (the default), this will perform a linear sweep. If log is True, the sweep will be logarithmic. """ print 'starting' dev = self.selectedDevice(c) resp = yield dev.query('SENS:FREQ:STAR?; STOP?') fstar, fstop = [float(f) for f in resp.split(';')] print 'fstar = ',fstar print 'fstop = ',fstop print resp.split(";") sweepType = 'LOG' if log else 'LIN' sweeptime, npoints = yield self.startSweep(dev, sweepType) if sweeptime > 1: sweeptime *= self.sweepFactor(c) print "sweeptime = ", sweeptime yield util.wakeupCall(sweeptime) if log: # hack: should use numpy.logspace, but it seems to be broken # for now, this works instead. lim1, lim2 = numpy.log10(fstar), numpy.log10(fstop) freq = 10**numpy.linspace(lim1, lim2, npoints) else: freq = numpy.linspace(fstar, fstop, npoints) # wait for sweep to finish sparams = yield self.getSweepData(dev, c['meas']) returnValue((freq*units.Hz, sparams))
def initServer(self): """This method loads default settings from the registry, sets up instruments, and sets up listeners for GPIB device connect/disconnect messages.""" DeviceServer.initServer(self) try: yield self.client.registry.cd(self.ADRSettingsPath) self.file_path = yield self.client.registry.get('Log Path') except Exception as e: self.logMessage( '{Saving log failed. Check that AFS is working.} ' ) yield self.loadDefaults() yield util.wakeupCall( 3 ) # on the round ADR, the HP DMM takes forever to initialize. This prevents it from going on before it is ready. yield self.initializeInstruments() # subscribe to messages # the server ones are not used right now, but at some point they could be connect_func = lambda c, (s, payload): self.gpib_device_connect(*payload) disconnect_func = lambda c, (s, payload): self.gpib_device_disconnect(*payload) serv_conn_func = lambda c, (s, payload): self.serversChanged(*payload) serv_disconn_func = lambda c, (s, payload): self.serversChanged(*payload) mgr = self.client.manager self._cxn.addListener(connect_func, source=mgr.ID, ID=10) self._cxn.addListener(disconnect_func, source=mgr.ID, ID=11) self._cxn.addListener(serv_conn_func, source=mgr.ID, ID=12) self._cxn.addListener(serv_disconn_func, source=mgr.ID, ID=13) yield mgr.subscribe_to_named_message('GPIB Device Connect', 10, True) yield mgr.subscribe_to_named_message('GPIB Device Disconnect', 11, True) yield mgr.subscribe_to_named_message('Server Connect', 12, True) yield mgr.subscribe_to_named_message('Server Disconnect', 13, True) self.updateState()
def measure(self, c, count=0, wait=Value(0.5, "s")): """ returns the values from the measure function of the scope. if count >0, wait until scope has >= count stats before returning, waiting _wait_ time between calls. Note that the measurement must be set manually on the scope for this to work. """ dev = self.selectedDevice(c) yield dev.write(":MEAS:STAT ON") def parse(s): s = s.split(",") d = [] while s: d += [[s[0]] + [float(x) for x in s[1:7]]] s = s[7:] return d d = [] while True: d = yield dev.query(":MEAS:RES?") d = parse(d) counts = [x[-1] for x in d] if min(counts) >= count: break yield util.wakeupCall(wait["s"]) returnValue(d)
def kill(self, finished=None): """Kill the server process.""" if not self.started: return try: servers = self.client.servers if hasattr(self, 'shutdownMode') and self.name in servers: mode, ID = self.shutdownMode if mode == 'message': # try to shutdown by sending a message servers[self.name].sendMessage(ID) elif mode == 'setting': # try to shutdown by calling a setting try: yield servers[self.name][ID]() except: pass yield util.wakeupCall(self.shutdownTimeout) # hack to let us know that we did indeed finish killing the server if finished is not None: if finished[0]: return # if we're not dead yet, kill with a vengeance if self.started: self.proc.signalProcess('KILL') except Exception: logging.error('Error while trying to kill server process for "%s":' % self.name, exc_info=True)
def freq_sweep_phase(self, c, log=False): """Initiate a frequency sweep. If log is False (the default), this will perform a linear sweep. If log is True, the sweep will be logarithmic. """ dev = self.selectedDevice(c) resp = yield dev.query('SENS:FREQ:STAR?; STOP?') fstar, fstop = [float(f) for f in resp.split(';')] sweepType = 'LOG' if log else 'LIN' sweeptime, npoints = yield self.startSweep(dev, sweepType) if sweeptime > 1: sweeptime *= self.sweepFactor(c) # needs factor of 2 since it runs both forward and backward yield util.wakeupCall(2 * sweeptime) if log: ## hack: should use numpy.logspace, but it seems to be broken ## for now, this works instead. lim1, lim2 = numpy.log10(fstar), numpy.log10(fstop) freq = 10**numpy.linspace(lim1, lim2, npoints) else: freq = numpy.linspace(fstar, fstop, npoints) # wait for sweep to finish phase = yield self.getSweepDataPhase(dev, c['meas']) returnValue((freq, phase))
def freq_sweep(self, c, log=False): """Initiate a frequency sweep. If log is False (the default), this will perform a linear sweep. If log is True, the sweep will be logarithmic. """ print 'starting' dev = self.selectedDevice(c) resp = yield dev.query('SENS:FREQ:STAR?; STOP?') fstar, fstop = [float(f) for f in resp.split(';')] print 'fstar = ', fstar print 'fstop = ', fstop print resp.split(";") sweepType = 'LOG' if log else 'LIN' sweeptime, npoints = yield self.startSweep(dev, sweepType) if sweeptime > 1: sweeptime *= self.sweepFactor(c) print "sweeptime = ", sweeptime yield util.wakeupCall(sweeptime) if log: # hack: should use numpy.logspace, but it seems to be broken # for now, this works instead. lim1, lim2 = numpy.log10(fstar), numpy.log10(fstop) freq = 10**numpy.linspace(lim1, lim2, npoints) else: freq = numpy.linspace(fstar, fstop, npoints) # wait for sweep to finish sparams = yield self.getSweepData(dev, c['meas']) returnValue((freq * units.Hz, sparams))
def readLoop(self): cxn = self.client while self.alive: for s in self.queries: yield cxn.refresh() rslt = yield cxn[s['server']][s['setting']]() s['last'] = str(rslt[0]), datetime.now() yield util.wakeupCall(self.delayTime)
def startRefreshLoop(self): while self.keepRefreshing:# & 'IBCL' in self.client.servers: try: yield self.refresh_devices() except: import traceback print "An error occured while refreshing devices:" traceback.print_exc() if self.keepRefreshing: yield util.wakeupCall(self.refreshInterval)
def startRefreshLoop(self): while self.keepRefreshing: # & 'IBCL' in self.client.servers: try: yield self.refresh_devices() except: import traceback print "An error occured while refreshing devices:" traceback.print_exc() if self.keepRefreshing: yield util.wakeupCall(self.refreshInterval)
def _magUp(self): """ The magging up method, as per the HPD Manual, involves increasing the voltage in steps of MAG_UP_dV volts every cycle of the loop. This cycle happens once every STEP_LENGTH seconds, nominally 1s (since the voltage monitor reads once a second). Each cycle, the voltage across the magnet is read to get the backEMF. If it is greater than the MAGNET_VOLTAGE_LIMIT, the voltage will not be raised until the next cycle for which the backEMF < MAGNET_VOLTAGE_LIMIT. """ instruments = self.instruments settings = self.ADRSettings if self.state['maggingUp']: self.logMessage('Already magging up.') return if self.state['regulating']: self.logMessage('Currently in PID control loop regulation.' ' Please wait until finished.') return if self.state['T_3K']['K'] > settings['magnet_max_temp']: self.logMessage('Temperature too high to mag up.') return deviceNames = ['Power Supply','Magnet Voltage Monitor'] deviceStatus = [instruments[name].connected for name in deviceNames] if False in deviceStatus: message = ('Cannot mag up: At least one of the essential ' 'devices is not connected. Connections: %s' %str([deviceNames[i]+':'+str(deviceStatus[i]) for i in range(len(deviceNames))])) self.logMessage(message, alert=True) return self.client.manager.send_named_message('MagUp Started', 'start') self.logMessage('Beginning to mag up to ' + str(settings['current_limit']) + ' A.') self.state['maggingUp'] = True while self.state['maggingUp']: startTime = datetime.datetime.utcnow() dI = self.state['PSCurrent'] - self.lastState['PSCurrent'] dt = deltaT( self.state['datetime'] - self.lastState['datetime'] ) if dt == 0: dt = 0.0000000001 #to prevent divide by zero error if self.state['PSCurrent']['A'] < settings['current_limit']: if self.state['magnetV']['V'] < settings['magnet_voltage_limit'] and \ abs(dI['A']/dt) < settings['dIdt_magup_limit'] and \ self.state['T_FAA']['K'] < settings['magnet_max_temp']: newVoltage = self.state['PSVoltage'] + settings['magup_dV']*units.V if newVoltage['V'] < settings['voltage_limit']: instruments['Power Supply'].voltage(newVoltage) #set new voltage else: instruments['Power Supply'].voltage(settings['voltage_limit']*units.V) cycleLength = deltaT(datetime.datetime.utcnow() - startTime) yield util.wakeupCall( max(0,settings['step_length']-cycleLength) ) else: self.logMessage( 'Finished magging up. %s reached.'%str(self.state['PSCurrent']) ) self.state['maggingUp'] = False self.client.manager.send_named_message('MagUp Stopped', 'done')
def readLoop(self, idx=0): while self.alive: # read only one specific channel if self.onlyChannel > 0: chan = self.onlyChannel yield util.wakeupCall(self.settleTime['s']) r = yield self.query('RDGR? %d' % chan) self.readings[chan] = float(r)*Ohm, datetime.now() # scan over channels else: if len(self.readOrder) > 0: chan = self.readOrder[idx] else: yield util.wakeupCall(self.settleTime['s']) continue yield self.selectChannel(chan) yield util.wakeupCall(self.settleTime['s']) r = yield self.query('RDGR? %d' % chan) self.readings[chan] = float(r)*Ohm, datetime.now() idx = (idx + 1) % len(self.readOrder)
def waitForAveraging(self): waited = 0 while 1: done = yield self.doneAveraging() if done: returnValue(None) #Return None because returnValue needs an argument else: waited+=1 print 'Device waiting for averaging to complete.' print 'Will check again in %d seconds' %self.AVERAGING_TIME['s'] print 'This is wait number: %d' %waited yield util.wakeupCall(self.AVERAGING_TIME['s'])
def device_connection_changed(self, device, server, channel, isConnected): print '%s connected: %s' % (device, isConnected) # if instrument added, initialize instrument. if it is removed, # mark it as disconnected. for instName in self.instruments.keys(): instAddress = self.ADRSettings[instName][1] if server in instAddress and channel in instAddress: if isConnected == False: self.instruments[instName].connected = False else: yield util.wakeupCall(0.5) # to give the instrument # server time to register the device self.connectDevice(instName)
def readLoop(self): cxn = self.client while self.alive: yield cxn.refresh() for s in self.queries: server = s['server'] setting = s['setting'] try: rslt = yield cxn[server][setting]() s['last'] = str(rslt[0]), datetime.now() except Exception: pass yield util.wakeupCall(self.delayTime)
def setThirdSwitchChannel(self, channel, commands): """change the channel set on the third switch""" chan = str(channel) if self.state[2] != chan and chan != '0': if self.state[2] != '0': reschan = commands[self.state[2]] yield self.write(reschan) yield self.resetPulse() yield util.wakeupCall(1) setchan = commands[chan] yield self.write(setchan) yield self.setPulse() yield util.wakeupCall(1) self.state[2] = chan if self.state[2] != chan and chan == '0': reschan = commands[self.state[2]] yield self.write(reschan) yield self.resetPulse() self.state[2] = chan returnValue(chan)
def device_connection_changed(self, device, server, channel, isConnected): print '%s connected: %s'%(device, isConnected) # if instrument added, initialize instrument. if it is removed, # mark it as disconnected. for instName in self.instruments.keys(): instAddress = self.ADRSettings[instName][1] if server in instAddress and channel in instAddress: if isConnected == False: self.instruments[instName].connected = False else: yield util.wakeupCall(0.5) # to give the instrument # server time to register the device self.connectDevice(instName)
def setThirdSwitchChannel(self, channel, commands): """change the channel set on the third switch""" chan = str(channel) if self.state[2]!=chan and chan!='0': if self.state[2]!='0': reschan = commands[self.state[2]] yield self.write(reschan) yield self.resetPulse() yield util.wakeupCall(1) setchan = commands[chan] yield self.write(setchan) yield self.setPulse() yield util.wakeupCall(1) self.state[2] = chan if self.state[2]!=chan and chan=='0': reschan = commands[self.state[2]] yield self.write(reschan) yield self.resetPulse() self.state[2] = chan returnValue(chan)
def run(self): """Run the node in a loop, reconnecting after connection loss.""" log = logging.getLogger('labrad.node') while True: print('Connecting to {}:{}...'.format(self.host, self.port)) try: p = yield protocol.connect(self.host, self.port, self.tls_mode, self.username, self.password) node = NodeServer(self.nodename, self.host, self.port, p.credential) yield node.startup(p) except Exception: log.error('Node failed to start', exc_info=True) else: try: yield node.onShutdown() except Exception: log.error('Error during node shutdown', exc_info=True) yield util.wakeupCall(0) print('Will try to reconnect in {} seconds...'.format(self.reconnectDelay)) yield util.wakeupCall(self.reconnectDelay)
def freq_sweep_save(self, c, name='untitled'): """Initiate a frequency sweep. The data will be saved to the data vault in the current directory for this context. Note that the default directory in the data vault is the root directory, so you should cd before trying to save. """ dev = self.selectedDevice(c) resp = yield dev.query('SENS:FREQ:STAR?; STOP?') fstar, fstop = [float(f) for f in resp.split(';')] sweeptime, npoints = yield self.startSweep(dev, 'LIN') if sweeptime > 1: sweeptime *= self.sweepFactor(c) yield util.wakeupCall(sweeptime) sparams = yield self.getSweepData(dev, c['meas']) freq = util.linspace(fstar, fstop, npoints) freq = [T.Value(f, 'Hz') for f in freq] for s in sparams: for i, cplx in enumerate(s): s[i] = T.Complex(cplx) f = numpy.array(freq) s = 20 * numpy.log10(abs(numpy.array(sparams))) phases = numpy.angle(numpy.array(sparams)) data = numpy.vstack((f, s, phases)).T data = data.astype('float64') dv = self.client.data_vault power = yield self.power(c) bw = yield self.bandwidth(c) independents = ['frequency [Hz]'] dependents = [(Sij, 'log mag', 'dB') for Sij in c['meas']] + [(Sij, 'phase', 'dB') for Sij in c['meas']] p = dv.packet() p.new(name, independents, dependents) p.add(data) p.add_comment('Autosaved by PNA server.') p.add_parameter('power', power) p.add_parameter('bandwidth', bw) yield p.send(context=c.ID) returnValue(data)
def power_sweep_phase(self, c): """Initiate a power sweep.""" dev = self.selectedDevice(c) resp = yield dev.query('SOUR:POW:STAR?; STOP?') pstar, pstop = [float(p) for p in resp.split(';')] sweeptime, npoints = yield self.startSweep(dev, 'POW') if sweeptime > 1: sweeptime *= self.sweepFactor(c) yield util.wakeupCall(sweeptime) power = util.linspace(pstar, pstop, npoints) power = [T.Value(p, 'dBm') for p in power] phase = yield self.getSweepDataPhase(dev, c['meas']) returnValue((power, phase))
def freq_sweep_save(self, c, name='untitled'): """Initiate a frequency sweep. The data will be saved to the data vault in the current directory for this context. Note that the default directory in the data vault is the root directory, so you should cd before trying to save. """ dev = self.selectedDevice(c) resp = yield dev.query('SENS:FREQ:STAR?; STOP?') fstar, fstop = [float(f) for f in resp.split(';')] sweeptime, npoints = yield self.startSweep(dev, 'LIN') if sweeptime > 1: sweeptime *= self.sweepFactor(c) yield util.wakeupCall(sweeptime) sparams = yield self.getSweepData(dev, c['meas']) freq = util.linspace(fstar, fstop, npoints) freq = [T.Value(f, 'Hz') for f in freq] for s in sparams: for i, cplx in enumerate(s): s[i] = T.Complex(cplx) f = numpy.array(freq) s = 20*numpy.log10(abs(numpy.array(sparams))) phases = numpy.angle(numpy.array(sparams)) data = numpy.vstack((f, s, phases)).T data = data.astype('float64') dv = self.client.data_vault power = yield self.power(c) bw = yield self.bandwidth(c) independents = ['frequency [Hz]'] dependents = [(Sij, 'log mag', 'dB') for Sij in c['meas']]+[(Sij, 'phase', 'dB') for Sij in c['meas']] p = dv.packet() p.new(name, independents, dependents) p.add(data) p.add_comment('Autosaved by PNA server.') p.add_parameter('power', power) p.add_parameter('bandwidth', bw) yield p.send(context=c.ID) returnValue(data)
def get_averaged_trace(self, c, data=1): dev = self.selectedDevice(c) self.switch_average(c, setting='OFF') averaging = True self.switch_average(c, setting='ON') yield dev.write('*CLS') yield dev.write('*ESE 1') yield dev.write(':INIT:IMM') yield dev.write('*OPC') while averaging: result = yield dev.query('*STB?') if int(result) & (1 << 5): averaging = False yield util.wakeupCall(1) trace = yield self.get_trace(c, data=data) self.switch_average(c, setting='OFF') returnValue(trace)
def get_averaged_trace(self, c, data=1): dev = self.selectedDevice(c) self.switch_average(c, setting = 'OFF') averaging = True self.switch_average(c, setting = 'ON') yield dev.write('*CLS') yield dev.write('*ESE 1') yield dev.write(':INIT:IMM') yield dev.write('*OPC') while averaging: result = yield dev.query('*STB?') if int(result)&(1<<5): averaging = False yield util.wakeupCall(1) trace = yield self.get_trace(c, data = data) self.switch_average(c, setting = 'OFF') returnValue(trace)
def power_sweep(self, c): """Initiate a power sweep.""" dev = self.selectedDevice(c) resp = yield dev.query('SOUR:POW:STAR?; STOP?') pstar, pstop = [float(p) for p in resp.split(';')] sweeptime, npoints = yield self.startSweep(dev, 'POW') if sweeptime > 1: sweeptime *= self.sweepFactor(c) yield util.wakeupCall(sweeptime) sparams = yield self.getSweepData(dev, c['meas']) power = util.linspace(pstar, pstop, npoints) power = [T.Value(p, 'dBm') for p in power] for s in sparams: for i, c in enumerate(s): s[i] = T.Complex(c) returnValue((power, sparams))
def get_trace(self, c, trace=1): """Returns the y-values of the current trace from the sampling scope. First element: offset time Second element: time step Third to last element: trace """ dev = self.selectedDevice(c) if trace < 1 or trace > 3: raise NotConnectedError() yield dev.write('COND TYP:AVG') while True: if int((yield dev.query('COND? REMA'))[18:]) == 0: break yield util.wakeupCall(2) resp = yield dev.query(__QUERY__ % trace, bytes=20000L) ofs, incr, vals = _parseBinaryData(resp) returnValue([T.Value(v, 'V') for v in np.hstack(([ofs, incr], vals))])
def request_handler(self, source, context, flat_records): """Handle an incoming request. If this is a new context, we create a context object and a lock to ensure that requests in this context are serialized. Then, we serve the request. """ # create a new context if needed c = self.contexts.get(context, None) if c is None: c = self.contexts[context] = Context() yield c.acquire() # make sure we're the first in line c.data = yield self._dispatch(self.newContext, context) yield self._dispatch(self.initContext, c.data) else: yield c.acquire( ) # wait for previous requests in this context to finish if self.prioritizeWrites: # yield here so that pending writes will be sent in preference to processing # new requests. This can help in cases where server settings do long-running # computations that block, though we are still limited fundamentally by # the completely single-threaded way twisted operates yield util.wakeupCall(0.0) response = [] try: yield self._dispatch(self.startRequest, c.data, source) for ID, flat_data in flat_records: c.check() # make sure this context hasn't expired try: setting = self.settings[ID] result = yield self._dispatch(setting.handleRequest, self, c.data, flat_data) response.append((ID, result, setting.returns)) except Exception as e: response.append((ID, self._getTraceback(e))) break c.check() # make sure this context hasn't expired finally: reactor.callLater(0, c.release) returnValue(response)
def cw_measurement(self, c): """Initiate a continuous wave measurement. """ dev = self.selectedDevice(c) resp = yield dev.query('SENS:FREQ:STAR?; STOP?') fstar, fstop = [float(f) for f in resp.split(';')] sweeptime, npoints = yield self.startSweep(dev, 'CW') if sweeptime > 1: sweeptime *= self.sweepFactor(c) print sweeptime yield util.wakeupCall(sweeptime) time = numpy.linspace(fstar, fstop, npoints) # wait for sweep to finish sparams = yield self.getSweepData(dev, c['meas']) returnValue((numpy.append(time, sweeptime), sparams))
def request_handler(self, source, context, flat_records): """Handle an incoming request. If this is a new context, we create a context object and a lock to ensure that requests in this context are serialized. Then, we serve the request. """ # create a new context if needed c = self.contexts.get(context, None) if c is None: c = self.contexts[context] = Context() yield c.acquire() # make sure we're the first in line c.data = yield self._dispatch(self.newContext, context) yield self._dispatch(self.initContext, c.data) else: yield c.acquire() # wait for previous requests in this context to finish if self.prioritizeWrites: # yield here so that pending writes will be sent in preference to processing # new requests. This can help in cases where server settings do long-running # computations that block, though we are still limited fundamentally by # the completely single-threaded way twisted operates yield util.wakeupCall(0.0) response = [] try: yield self._dispatch(self.startRequest, c.data, source) for ID, flat_data in flat_records: c.check() # make sure this context hasn't expired try: setting = self.settings[ID] result = yield self._dispatch(setting.handleRequest, self, c.data, flat_data) response.append((ID, result, setting.returns)) except Exception as e: response.append((ID, self._getTraceback(e))) break c.check() # make sure this context hasn't expired finally: reactor.callLater(0, c.release) returnValue(response)
def takeData(self): self.startDataTaking.configure(text='Stop', command=self.stopTakingData) self.takingData = True start = -1*self.startV.get() stop = -1*self.stopV.get() print 'taking data', start, stop for v in numpy.arange(start,stop,-(self.stopV.get()-self.startV.get())/max(self.nPoints.get(),1)): if self.takingData == False: break self.voltageSource.voltage(v) Vout = v#&&& self.graph.set_xdata(numpy.append(self.graph.get_xdata(),v)) self.graph.set_ydata(numpy.append(self.graph.get_ydata(),Vout)) if self.toolbar._active == 'HOME' or self.toolbar._active == None: self.ax.set_xlim(stop,start) self.ax.relim() self.ax.autoscale(axis='y') #draw self.canvas.draw() yield util.wakeupCall( 1 ) self.startDataTaking.configure(text='Go!', command=self.takeData) self.takingData = False print 'finished'
def measure(self, c, count=0, wait=Value(0.5, 's')): ''' returns the values from the measure function of the scope. if count >0, wait until scope has >= count stats before returning, waiting _wait_ time between calls. Note that the measurement must be set manually on the scope for this to work. ''' dev = self.selectedDevice(c) yield dev.write(":MEAS:STAT ON") def parse(s): s = s.split(',') d = [] while s: d += [[s[0]] + [float(x) for x in s[1:7]]] s = s[7:] return d d = [] while True: d = yield dev.query(":MEAS:RES?") d = parse(d) counts = [x[-1] for x in d] if min(counts) >= count: break yield util.wakeupCall(wait['s']) returnValue(d)
def _regulate(self, temp): """ This function starts a PID loop to control the temperature. The basics of it is that a new voltage V+dV is proposed. dV is then limited as necessary, and the new voltage is set. As with magging up, regulate runs a cycle at approximately once per second. """ print 'REG TEMP', temp self.state['regulationTemp'] = temp self.logMessage('Setting regulation temperature to %f K.' % temp) if self.state['maggingUp'] == True: self.logMessage( 'Currently magging up. Please wait until finished.') return deviceNames = [ 'Power Supply', 'Diode Temperature Monitor', 'Ruox Temperature Monitor', 'Magnet Voltage Monitor' ] deviceStatus = [ self.instruments[name].connected for name in deviceNames ] if False in deviceStatus: message = ('Cannot regulate: At least one of the essential ' 'devices is not connected. Connections: %s' % str([ deviceNames[i] + ':' + str(deviceStatus[i]) for i in range(len(deviceNames)) ])) self.logMessage(message, alert=True) return self.factory.sendMessageToAll( {'isRegulating': self.state['regulating']}) self.client.manager.send_named_message('Regulation Started', 'start') self.logMessage('Starting regulation to ' + str(self.state['regulationTemp']) + ' K from ' + str(self.state['PSCurrent']) + '.') self.state['regulating'] = True print 'beginning regulation' print 'V\tbackEMF\tdV/dT\tdV' while self.state['regulating']: startTime = datetime.datetime.utcnow() dI = self.state['PSCurrent'] - self.lastState['PSCurrent'] if numpy.isnan(self.state['T_FAA']['K']): self.logMessage('FAA temperature is not valid. ' 'Regulation cannot continue.') self._cancelRegulate() # propose new voltage T_target = float(self.state['regulationTemp']) * units.K dT = deltaT(self.state['datetime'] - self.lastState['datetime']) if dT == 0: dT = 0.001 #to prevent divide by zero error self.state['PID_cumulativeError'] += (T_target['K'] - self.state['T_FAA']['K']) self.state['PID_cumulativeError'] = \ min(self.state['PID_cumulativeError'], self.ADRSettings['PID_MaxI'],key=abs) # so we dont just build this up during the mag down. dV = ( self.ADRSettings['PID_KP']*(T_target['K']-self.state['T_FAA']['K']) \ + self.ADRSettings['PID_KI']*self.state['PID_cumulativeError'] \ + self.ADRSettings['PID_KD']*(self.lastState['T_FAA']['K'] \ - self.state['T_FAA']['K'])/dT )*units.V # hard current limit if self.state[ 'PSCurrent'] > self.ADRSettings['current_limit'] * units.A: if dV > 0 * units.V: dV = 0 * units.V # hard voltage limit if self.state['PSVoltage'] + dV > self.ADRSettings[ 'voltage_limit'] * units.V: dV = self.ADRSettings['voltage_limit'] * units.V - self.state[ 'PSVoltage'] # steady state limit if dV['V'] < 0: dV = max(dV, self.state['magnetV'] - \ self.ADRSettings['magnet_voltage_limit']*units.V) if dV['V'] > 0: dV = 0 * units.V if dV['V'] > 0: dV = min( dV, self.ADRSettings['magnet_voltage_limit'] * units.V - self.state['magnetV']) if dV['V'] < 0: dV = 0 * units.V # limit by hard voltage increase limit # print str(dV/dT)+'\t', if abs(dV / dT) > self.ADRSettings['dVdT_limit'] * units.V: dV = self.ADRSettings['dVdT_limit'] * dT * (dV / abs(dV)) * units.V # limit by hard current increase limit if abs(dI / dT) > self.ADRSettings['dIdt_regulate_limit'] * units.A: dV = 0 * units.V # will voltage go negative? if self.state['PSVoltage'] + dV <= 0 * units.V: self.instruments['Power Supply'].voltage(0 * units.V) dV = 0 * units.V # is current 0? if so, end regulation # if dV > 0, don't end regulation because we are increasing current # 0.02 amps is pretty arebitrary, but the PS seemed to stay at 0.018A # at 0.02V (the lowest it went) if self.state['PSCurrent']['A'] < 0.03 and dV['V'] <= 0: runCycleAgain = False else: runCycleAgain = True # print str(dV) self.instruments['Power Supply'].voltage(self.state['PSVoltage'] + dV) cycleTime = deltaT(datetime.datetime.utcnow() - startTime) if runCycleAgain: yield util.wakeupCall( max(0, self.ADRSettings['step_length'] - cycleTime)) else: self.logMessage( 'Regulation has completed. Mag up and try again.') self.state['regulating'] = False self.factory.sendMessageToAll( {'isRegulating': self.state['regulating']}) self.client.manager.send_named_message('Regulation Stopped', 'done')
def _magUp(self): """ The magging up method, as per the HPD Manual, involves increasing the voltage in steps of MAG_UP_dV volts every cycle of the loop. This cycle happens once every STEP_LENGTH seconds, nominally 1s (since the voltage monitor reads once a second). Each cycle, the voltage across the magnet is read to get the backEMF. If it is greater than the MAGNET_VOLTAGE_LIMIT, the voltage will not be raised until the next cycle for which the backEMF < MAGNET_VOLTAGE_LIMIT. """ instruments = self.instruments settings = self.ADRSettings if self.state['maggingUp']: self.logMessage('Already magging up.') return if self.state['regulating']: self.logMessage('Currently in PID control loop regulation.' ' Please wait until finished.') return if self.state['T_3K']['K'] > settings['magnet_max_temp']: self.logMessage('Temperature too high to mag up.') return deviceNames = ['Power Supply', 'Magnet Voltage Monitor'] deviceStatus = [instruments[name].connected for name in deviceNames] if False in deviceStatus: message = ('Cannot mag up: At least one of the essential ' 'devices is not connected. Connections: %s' % str([ deviceNames[i] + ':' + str(deviceStatus[i]) for i in range(len(deviceNames)) ])) self.logMessage(message, alert=True) return self.state['maggingUp'] = True self.factory.sendMessageToAll({'isMaggingUp': self.state['maggingUp']}) self.client.manager.send_named_message('MagUp Started', 'start') self.logMessage('Beginning to mag up to ' + str(settings['current_limit']) + ' A.') while self.state['maggingUp']: startTime = datetime.datetime.utcnow() dI = self.state['PSCurrent'] - self.lastState['PSCurrent'] dt = deltaT(self.state['datetime'] - self.lastState['datetime']) if dt == 0: dt = 0.0000000001 #to prevent divide by zero error if self.state['PSCurrent']['A'] < settings['current_limit']: if self.state['magnetV']['V'] < settings['magnet_voltage_limit'] and \ abs(dI['A']/dt) < settings['dIdt_magup_limit'] and \ self.state['T_FAA']['K'] < settings['magnet_max_temp']: newVoltage = self.state[ 'PSVoltage'] + settings['magup_dV'] * units.V if newVoltage['V'] < settings['voltage_limit']: instruments['Power Supply'].voltage( newVoltage) #set new voltage else: instruments['Power Supply'].voltage( settings['voltage_limit'] * units.V) cycleLength = deltaT(datetime.datetime.utcnow() - startTime) yield util.wakeupCall( max(0, settings['step_length'] - cycleLength)) else: self.logMessage('Finished magging up. %s reached.' % str(self.state['PSCurrent'])) self.state['maggingUp'] = False self.factory.sendMessageToAll( {'isMaggingUp': self.state['maggingUp']}) self.client.manager.send_named_message('MagUp Stopped', 'done')
def updateState(self): """ This takes care of the real time reading of the instruments. It starts immediately upon starting the program, and never stops. """ nan = numpy.nan instruments = self.instruments while self.alive: cycleStartTime = datetime.datetime.utcnow() self.lastState = self.state.copy() # datetime, cycle self.state['datetime'] = datetime.datetime.utcnow() self.state['cycle'] += 1 # compressor self.state['CompressorStatus'] = None if hasattr(instruments['Compressor'],'connected') \ and instruments['Compressor'].connected: try: self.state['CompressorStatus'] = yield instruments[ 'Compressor'].status() except Exception as e: print 'could not read compressor status', str(e) # diode temps try: temps = yield instruments[ 'Diode Temperature Monitor'].get_diode_temperatures() self.state['T_60K'], self.state['T_3K'] = temps except Exception as e: self.state['T_60K'], self.state[ 'T_3K'] = nan * units.K, nan * units.K try: lastState = instruments[ 'Diode Temperature Monitor'].connected instruments['Diode Temperature Monitor'].connected = False if lastState != False: self._refreshInstruments() except AttributeError: pass # in case instrument didn't initialize properly and is None # ruox temps try: temps = yield instruments[ 'Ruox Temperature Monitor'].get_ruox_temperature() # if there are two returned temps, maps them to GGG and FAA. # if only one is returned, assumes it is for the FAA try: FAAChan = self.ADRSettings['FAA MP Chan'] GGGChan = self.ADRSettings['GGG MP Chan'] self.state['T_GGG'] = dict(temps)[GGGChan] self.state['T_FAA'] = dict(temps)[FAAChan] except: self.state['T_GGG'], self.state[ 'T_FAA'] = nan * units.K, temps except Exception as e: self.state['T_GGG'], self.state[ 'T_FAA'] = nan * units.K, nan * units.K try: lastState = instruments[ 'Ruox Temperature Monitor'].connected instruments['Ruox Temperature Monitor'].connected = False if lastState != False: self._refreshInstruments() except AttributeError: pass # in case instrument didn't initialize properly and is None if self.state['T_GGG']['K'] == 20.0: self.state['T_GGG'] = nan * units.K if self.state['T_FAA']['K'] == 45.0: self.state['T_FAA'] = nan * units.K # voltage across magnet try: self.state['magnetV'] = yield instruments[ 'Magnet Voltage Monitor'].get_magnet_voltage() except Exception as e: self.state['magnetV'] = nan * units.V try: lastState = instruments['Magnet Voltage Monitor'].connected instruments['Magnet Voltage Monitor'].connected = False if lastState != False: self._refreshInstruments() except AttributeError: pass # in case instrument didn't initialize properly and is None # PS current, voltage try: self.state['PSCurrent'] = yield instruments[ 'Power Supply'].current() self.state['PSVoltage'] = yield instruments[ 'Power Supply'].voltage() # except LRError as e: # if 'VisaIOError' in e.msg: # self.state['PSCurrent'] = nan*units.A # self.state['PSVoltage'] = nan*units.V # try: # lastState = instruments['Power Supply'].connected # instruments['Power Supply'].connected = False # if lastState != False: # self._refreshInstruments() # except AttributeError: # pass # in case instrument didn't initialize properly and is None # else: # print str(e) except Exception as e: self.state['PSCurrent'] = nan * units.A self.state['PSVoltage'] = nan * units.V try: lastState = instruments['Power Supply'].connected instruments['Power Supply'].connected = False if lastState != False: self._refreshInstruments() except AttributeError: pass # in case instrument didn't initialize properly and is None # pressure try: pressures = yield instruments['Pressure Guage'].get_pressures() pressure = pressures[0]['torr'] * units.torr except Exception as e: pressure = numpy.nan * units.torr self.state['Pressure'] = pressure # update relevant files try: newTemps = [ numpy.float16(self.state[t]['K']) for t in ['T_60K', 'T_3K', 'T_GGG', 'T_FAA'] ] timestamp = deltaT(self.state['datetime'] - datetime.datetime(1970, 1, 1)) self.tempDataChest.addData([[timestamp] + newTemps]) except Exception as e: self.logMessage('Temperature recording failed: %s.\n%s' % (str(e), str([[timestamp] + newTemps]))) cycleLength = deltaT(datetime.datetime.utcnow() - cycleStartTime) self.factory.sendMessageToAll({ 'temps': { 'timeStamps': [(self.state['datetime'] - datetime.datetime(1970, 1, 1)).total_seconds()], 't60K': [self.state['T_60K']['K']], 't03K': [self.state['T_3K']['K']], 'tGGG': [self.state['T_GGG']['K']], 'tFAA': [self.state['T_FAA']['K']] }, 'instruments': { name: { 'server': status[0], 'connected': status[1] } for (name, status) in self.getInstrumentState('bla') }, 'compressorOn': self.state['CompressorStatus'], 'pressure': self.state['Pressure']['torr'], 'isMaggingUp': self.state['maggingUp'], 'isRegulating': self.state['regulating'], 'backEMF': self.state['magnetV']['V'], 'PSCurrent': self.state['PSCurrent']['A'], 'PSVoltage': self.state['PSVoltage']['V'] }) self.client.manager.send_named_message('State Changed', 'state changed') yield util.wakeupCall( max(0, self.ADRSettings['step_length'] - cycleLength))
def stage(i): print 'starting:', (ID, k) yield wakeupCall(DELAYS[i % len(DELAYS)], (ID, i)) print 'finished:', (ID, k)
def exc_in_inlinecallback(self, c, data): """Raises an exception in an inlineCallback.""" self.log('Exception from an inlineCallback.') yield util.wakeupCall(c['delay'][s]) raise Exception('Raised in inlineCallback.')
def delayed_echo(self, c, data): """Echo a packet after a specified delay.""" yield util.wakeupCall(c['delay'][s]) returnValue(data)