/lib/instruments.py
https://github.com/pruan/TestDepot · Python · 2725 lines · 2074 code · 375 blank · 276 comment · 304 complexity · e41fb248beb7871b14689746d524b862 MD5 · raw file
- #!/usr/bin/python
- # -*- coding: ascii -*-
- # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
- #
- # Copyright (C) 1999-2005 Stratalight Communications.
- #
- """
- Module where instrument objects are defined. These are persistent objects that
- can be stored in the Stratatest storage.
- """
- __all__ = ['InstrumentError', 'VISASyntaxError', 'GPIBInvalidCommand',
- 'VISAResource', 'GPIBResource', 'Bitfield', 'EventStatusEnableRegister',
- 'ServiceRequestEnableRegister', 'Block', 'Boolean', 'Identity', 'SCPIFloat',
- 'GpibInstrumentWrapper', 'Instrument', 'InstrumentChassis', 'InstrumentModule',
- 'InstrumentPort', 'DMM', 'RFSignalGenerator', 'Oscilloscope', 'HP53131A',
- 'FunctionGenerator', 'DCPower', 'SpectrumAnalyzer', 'OpticalSpectrumAnalyzer',
- 'PowerMeter', 'OpticalSignalGenerator', 'OpticalPowerAmp', 'OpticalPowerMeter',
- 'OpticalAttenuator', 'FIBERAMP', 'HP8163A', 'HP8163B', 'HP81635A', 'HP81635APort',
- 'HP81591A', 'HP81594B', 'HP8159xPort', 'MAP', 'OpticalAttenuator_JDSU',
- 'HP81570A', 'HP81570APort',
- 'HP81576A', 'HP81576APort',
- 'HP81663A', 'HP81689A', 'HP816xxAPort', 'HP81689APort', 'HP81663APort',
- 'HP86120C', 'HP8156A', 'HP34401A', 'HP86100A', 'HP34970A', 'HP33120A',
- 'HP6674A', 'HP81619A', 'HP81619APort', 'HP81633A', 'HP81633APort',
- 'HP83650L', 'AQ6317B', 'AQ6370',
- 'GP700', 'IA3',
- 'Graph', 'Marker', 'Modulation', 'plug_module',
- 'unplug_module', 'get_quantity', 'update_instruments', 'get_class',
- 'get_devices', 'clear_controller', 'KEOPSYSAMP']
- from copy import copy
- import sys
- from time import clock, sleep
- from netobjects import PersistentList, PersistentDict, PersistentData, MANDATORY, CONTAINER
- import scheduler
- import stratabuiltins # only needs to be imported, nothing more.
- import slstorage
- import pyvisa.visa as visa
- import pyvisa.vpp43 as vpp43
- import pyvisa.visa_exceptions as visa_exceptions
- import time
- import math
- from dataAnalysisLib import avg
- # instrument exceptions
- class InstrumentError(ValueError):
- pass
- class VISASyntaxError(InstrumentError):
- pass
- class GPIBInvalidCommand(InstrumentError):
- pass
- add_exception(InstrumentError)
- add_exception(VISASyntaxError)
- add_exception(GPIBInvalidCommand)
- # VISA objects
- class VISAResource(object):
- pass
- class GPIBResource(VISAResource):
- """GPIB[board]::primary address[::secondary address][::INSTR]"""
- def __init__(self, board=0, address=0, secondary=None):
- self.board = int(board)
- self.address = int(address)
- self.secondary = secondary
- def __repr__(self):
- return "%s(%r, %r, %r)" % (self.__class__.__name__, self.board, self.address, self.secondary)
- def __str__(self):
- if secondary is None:
- return "GPIB%s::%s::INSTR" % (self.board, self.address)
- else:
- return "GPIB%s::%s::%s::INSTR" % (self.board, self.address, self.secondary)
- def parse(self, text):
- parts = text.split("::")
- if len(parts) == 4:
- self.board, self.address, self.secondary = int(parts[0][4:]), int(parts[1]), int(parts[2])
- elif len(parts) in (2, 3):
- self.board, self.address, self.secondary = int(parts[0][4:]), int(parts[1]), None
- else:
- raise VISASyntaxError, "invalid GPIB resource: %s" % (text,)
- class Bitfield(object):
- "Mutable set of bits that also looks like an integer."
- _NAMES = {
- }
- def __init__(self, init_bits=0, numbits=32):
- self.bits = int(init_bits)
- if numbits < 1 or numbits > 32:
- raise ValueError, "bits must be 1:32"
- self._size = numbits
- def getbit(self, bit):
- return self.bits & (1 << bit)
- def setbit(self, bit):
- self.bits |= (1 << bit)
- def clearbit(self, bit):
- self.bits &= ~(1 << bit)
- def __str__(self):
- s = ["Bits set:"]
- names = self._NAMES
- for bit in range(self._size):
- if self.bits & 2**bit:
- name = names.get(bit)
- if name:
- s.append(name)
- else:
- s.append("Bit %d" % (bit,))
- return "\n".join(s)
- def __int__(self):
- return self.bits & ~(0xffffffff << self._size)
- def __getitem__(self, bit):
- return self.bits & (1 << bit)
- def __setitem__(self, bit, val):
- if bool(val):
- self.bits |= (1 << bit)
- else:
- self.bits &= ~(1 << bit)
-
- class EventStatusEnableRegister(Bitfield):
- _NAMES = {
- 7: "Power On",
- 6: "User Request",
- 5: "Command Error",
- 4: "Execution Error",
- 3: "Device dependent Error",
- 2: "Query Error",
- 1: "Request Control",
- 0: "Operation Complete",
- }
- def __init__(self, init_bits=0):
- super(EventStatusEnableRegister, self).__init__(init_bits, 8)
- class ServiceRequestEnableRegister(Bitfield):
- _NAMES = {
- 7: "Operation Status",
- 6: "Request Status",
- 5: "Event Status Byte",
- 4: "Message Available",
- 3: "Questionable Status",
- }
- def __init__(self, init_bits=0):
- super(ServiceRequestEnableRegister, self).__init__(init_bits, 8)
- class Block(object):
- def __init__(self, data):
- self.parse(data)
- def __str__(self):
- l = len(self.data)
- H = len(str(l))
- return "#%d%d%s" % (H, l, self.data)
- def parse(self, string):
- if string.startswith("#"):
- H = int(string[1])
- l = int(string[2:2+H])
- self.data = string[l+2:l]
- else:
- self.data = string
- class Boolean(object):
- def __init__(self, data):
- try:
- self.value = bool(int(data))
- except ValueError:
- if type(data) is str:
- data = data.lower()
- if data in ("on", "yes", "true", "enable", "ok"):
- self.value = True
- elif data in ("off", "no", "false", "disable", "notok"):
- self.value = False
- else:
- raise ValueError, "invalid value for Boolean: %s" % (data,)
- def __str__(self):
- return IF(self.value, "ON", "OFF")
- def __repr__(self):
- return "Boolean(%r)" % (self.value,)
- def __nonzero__(self):
- return self.value
- def __int__(self):
- return int(self.value)
- class Identity(object):
- """An equipment Identity. Returned from identify() instrument method."""
- def __init__(self, idtext=None):
- if idtext:
- idtext = idtext.strip()
- if idtext:
- self.parse(idtext)
- else:
- self.clear()
- else:
- self.clear()
- def clear(self):
- self.manufacturer = None
- self.model = None
- self.serial = None
- self.firmware = None
- def __str__(self):
- return """IDN: MFG: %s Model: %s Serial: %s Firmware: %s""" % (self.manufacturer, self.model, self.serial, self.firmware)
- # some equipment have five fields, most have four.
- def parse(self, text):
- commas = text.count(",")
- if commas > 3:
- self.manufacturer, model1, model2, self.serial, self.firmware = self._chop(text, 4)
- self.model = model1+model2
- elif commas > 2:
- self.manufacturer, self.model, self.serial, self.firmware = self._chop(text, 3)
- else:
- raise ValueError, "identity string appears invalid: %r" % (text,)
- def _chop(self, text, commas):
- return map(lambda s: s.replace(" ", ""), text.split(",",commas))
- # JDSU module ID is NOT standard IEEE
- class Identity_JDSU(object):
- """An equipment Identity. Returned from identify() instrument method."""
- def __init__(self, idtext=None):
- if idtext:
- idtext = idtext.strip()
- if idtext:
- #print "JDSU IDTEXT: %s" % idtext
- self.parse(idtext)
- else:
- self.clear()
- else:
- self.clear()
- def clear(self):
- self.manufacturer = None
- self.model = None
- self.serial = None
- self.firmware = None
- def __str__(self):
- return """IDN: MFG: %s Model: %s Serial: %s Firmware: %s""" % (self.manufacturer, self.model, self.serial, self.firmware)
- # some equipment have five fields, most have four.
- def parse(self, text):
- commas = text.count(",")
- if commas > 3:
- self.serial, self.model, model2, junk, self.firmware = self._chop(text, 4)
- self.manufacturer = 'JDSU'
- print " === model: %s" % self.model
- elif commas > 2:
- self.serial, self.model, self.firmware = self._chop(text, 3)
- self.manufacturer = 'JDSU'
- print "**** model: %s" % self.model
- else:
- raise ValueError, "identity string appears invalid: %r" % (text,)
- def _chop(self, text, commas):
- return map(lambda s: s.replace(" ", ""), text.split(",",commas))
-
- # a float with special values defined by SCPI
- class SCPIFloat(float):
- def __str__(self):
- if self == 9.9e37:
- return "INF"
- elif self == -9.9e37:
- return "NINF"
- elif self == 9.91e37:
- return "NaN"
- else:
- return float.__str__(self)
- ### constants and enumerations ###
- ### Some Instrument object attributes may be set to one of these values.
- DEFAULT = "DEF"
- MIN = "MIN"
- MAX = "MAX"
- ON = Enum(1, "ON")
- OFF = Enum(0, "OFF")
- SWEEP_STOP = Enum(0, "SWEEP_STOP")
- SWEEP_SINGLE = Enum(1, "SWEEP_SINGLE")
- SWEEP_CONTINUOUS = Enum(2, "SWEEP_CONTINUOUS") # same as REPEAT
- SWEEP_AUTO = Enum(3, "SWEEP_AUTO")
- SWEEP_SEGMENTMEASURE = Enum(4, "SWEEP_SEGMENTMEASURE")
- INF = SCPIFloat(9.9e37)
- NINF = SCPIFloat(-9.9e37)
- NaN = SCPIFloat(9.91e37)
- ## support for general modulation parameters ##
- # modulation types
- DC = NOMOD = Enum(0, "DC")
- AM = Enum(1, "AM")
- FM = Enum(2, "FM")
- PSK = Enum(3, "PSK")
- FSK = Enum(4, "FSK")
- # modulation subtypes
- SBSC = Enum(0, "SBSC") # FM subtype
- # modulation sources
- INT = Enum(0, "INT") # internal digital modulation
- INT1 = Enum(0, "INT1")
- INT2 = COHC = Enum(1, "INT2") # coherence control
- EXT = AEXT = Enum(2, "EXT") # external analog modulation
- DEXT = Enum(3, "DEXT") # external digital modulation
- WVLL = Enum(5, "WVLL") # wavelength locking
- BACK = Enum(6, "BACK") # backplane - external digital modulation using Input Trigger Connector
- # laser source selection
- LASER_EXTERNAL = Enum(0, "EXT")
- LASER_LOWER = Enum(1, "LOW")
- LASER_UPPER = Enum(2, "UPP")
- LASER_BOTH = Enum(3, "BOTH")
- # oscilloscope and spectrum analyzer control values
- PEAK = Enum(100, "PEAK")
- CENTER = Enum(101, "CENTER")
- REFERENCE = Enum(102, "REFERENCE")
- SCALE_WAVELENGTH = Enum(0, "SCALE_WAVELENGTH")
- SCALE_FREQUENCY = Enum(1, "SCALE_FREQUENCY")
- class GpibInstrumentWrapper(object):
- """Wrapper for VISA sessions that allows logging."""
- def __init__(self, inst, logfile):
- self._inst = inst
- self._logfile = logfile
- self._use_srq = False
- def __getattr__(self, key):
- return getattr(self._inst, key)
- def set_logfile(self, logfile):
- self._logfile = logfile
- def read(self):
- if self._use_srq:
- self.wait_for_srq()
- rv = self._inst.read()
- if self._logfile:
- self._logfile.write("VISA read: %s: %r\n" % (self._inst.resource_name, rv))
- return rv
- def write(self, text, wait=False):
- if self._logfile:
- self._logfile.write("VISA write: %s: %r\n" % (self._inst.resource_name, text))
- self._inst.write(text)
- if wait:
- cmd = "*OPC?"
- retries = 10
- while retries > 0:
- # do the command again
- self._inst.write(text)
- comp = int(self.ask(cmd))
- #print "comp: %s, retries: %s" % (comp, retries)
- if comp:
- break
- else:
- #print "resource: %s" % self._inst.resource_name
- self._inst.write(text)
- comp = int(self.ask(cmd))
- time.sleep(1)
- retries -= 1
- if not comp:
- raise InstrumentError, "Operation %r did not complete." % (text,)
- def ask(self, cmd):
- self._inst.write(cmd)
- if self._use_srq:
- self.wait_for_srq()
- rv = self._inst.read()
- if self._logfile:
- self._logfile.write("VISA ask: %s: %r -> %r\n" % (self._inst.resource_name, cmd, rv))
- return rv
- def _get_stb(self):
- return vpp43.read_stb(self._inst.vi)
- STB = property(_get_stb, None, None, "Status byte (STB)")
- def use_srq(self, flag=True):
- self._use_srq = bool(flag)
- srquse = property(lambda s: s._use_srq, use_srq, None, "SRQ line in use? Set to True to use SRQ line.")
- def wait_for_srq(self, timeout=250):
- vpp43.enable_event(self._inst.vi, vpp43.VI_EVENT_SERVICE_REQ, vpp43.VI_QUEUE)
- if timeout and not(0 <= timeout <= 4294967):
- raise ValueError, "timeout value is invalid"
- starting_time = clock()
- try:
- while True:
- if timeout is None:
- adjusted_timeout = vpp43.VI_TMO_INFINITE
- else:
- adjusted_timeout = max(0, int((starting_time + timeout - clock()) * 1000))
- event_type, context = vpp43.wait_on_event(self._inst.vi, vpp43.VI_EVENT_SERVICE_REQ, adjusted_timeout)
- vpp43.close(context)
- if vpp43.read_stb(self._inst.vi) & 0x40:
- break
- finally:
- vpp43.discard_events(self._inst.vi, vpp43.VI_EVENT_SERVICE_REQ, vpp43.VI_QUEUE)
- def get_SRE(self):
- res = self.ask("*SRE?")
- return ServiceRequestEnableRegister(int(res))
- def set_SRE(self, val):
- val = int(val) & 0xFF
- self.write("*SRE %d" % (val,))
- SRE = property(get_SRE, set_SRE, None, "SRE value")
- def get_ESE(self):
- res = self.ask("*ESE?")
- return EventStatusEnableRegister(int(res))
- def set_ESE(self, val):
- val = int(val) & 0xFF
- self.write("*ESE %d" % (val,))
- ESE = property(get_ESE, set_ESE)
- # abstract base class for instruments. Don't use this directly. This is a
- # persistent object that is also stored in the configuration.
- class Instrument(PersistentData):
- "A generic virtual instrument. It holds the base attributes."
- _ATTRS = {
- "name": (str, "unknown"),
- "manufacturer": (str, "unknown"),
- "modelNumber": (str, "unknown"),
- "serialNumber": (str, "unknown"),
- "firmware": (str, "unknown"),
- "password": (str, "1234"),
- "visa_resource": (str, ""), # e.g.'GPIB2::22'
- }
- def __str__(self):
- return "%s: %s %s (SN: %s)" % (self.name, self.manufacturer, self.modelNumber, self.serialNumber)
- def get_agent(self, logfile=None):
- """Returns a VISA Instrument instance to control the instrument."""
- try:
- return self._cache["_agent"]
- except KeyError:
- if self.visa_resource:
- a = scheduler.get_scheduler().timeout(visa.GpibInstrument, args=(self.visa_resource,))
- else:
- raise ValueError, "Instrument: visa_resource not set."
- a = GpibInstrumentWrapper(a, logfile or self._cache.get("_logfile"))
- self._cache["_agent"] = a
- self.initialize(a)
- return a
- def clear_agent(self):
- try:
- a = self._cache.pop("_agent")
- except KeyError:
- pass
- else:
- a.clear()
- a.close()
- # override if agent needs initialization after creation
- def initialize(self, agent):
- pass
- def set_logfile(self, lf):
- self._cache["_logfile"] = lf
- def clear_controller(self):
- self.clear_agent()
- clear_controller(self.visa_resource)
- def update(self):
- eqid = self.identify()
- self.manufacturer = eqid.manufacturer
- self.modelNumber = eqid.model
- self.serialNumber = eqid.serial
- self.firmware = eqid.firmware
- self.clear_agent()
- #print eqid
- def identify(self):
- return Identity(self.get_agent().ask("*IDN?"))
-
- def options(self):
- if self.name.startswith('MAP'):
- #print "Gettting GPIB address..."
- #cmd = "SYST:GPIB?"
- #print "CMD: %s" % cmd
- #print "GPIB: %s" % self.get_agent().ask(cmd)
- #cmd = "*IDN?"
- cmd = "SYST:LAY? 1"
- #cmd = ":SLOT1:IDN?"
- #cmd = "SYSTem:LAYout? 1"
- #cmd = "SYST:CARD:INFO? 1,1"
- #print "CMD: %s" % cmd
- raw = self.get_agent().ask(cmd)
- #print "raw: %s" % raw
-
- else:
- raw = self.get_agent().ask("*OPT?")
- print "RAW: %s" % raw
- return map(str.strip, raw.split(","))
- def test_result(self):
- res = self.get_agent().ask("*TST?")
- return int(res) # XXX
- def reset(self):
- self.get_agent().write("*RST")
- def clear_status(self):
- self.get_agent().write("*CLS")
- def wait(self):
- self.get_agent().write("*WAI")
-
- class InstrumentChassis(Instrument):
- """Instrument that is a chassis for holding other instrument modules."""
- _ATTRS = Instrument._ATTRS.copy()
- _ATTRS.update({
- "slots": (PersistentDict, CONTAINER), # slot maps to list index
- })
- SLOTBASE = 0
- # make the storage look like reality.
- def update(self):
- super(InstrumentChassis, self).update()
- for i, opt in enumerate(self.options()):
- if not opt:
- continue
- if (opt.endswith('BBS')) or (opt.endswith('EMP')) or (opt.endswith('UVL')):
- continue
- print "i: %s, opt: %s" % (i, opt)
- model = opt.split()[-1] # get rid of extraneous prefixes
- cls = get_class(model) # XXX true for all OPT? need spec...
- if cls is not None:
- #print "**** cls: %s" % cls
- inst = cls(visa_resource=self.visa_resource)
- try:
- plug_module(self, inst, i+self.SLOTBASE)
- except InstrumentError:
- unplug_module(self, i+self.SLOTBASE)
- plug_module(self, inst, i+self.SLOTBASE)
- inst.update()
- inst.name = "%s_%s" % (opt.strip(), inst.serialNumber)
- #print "xxx inst name: %s" % inst.name
- else:
- self.clear_agent()
- raise InstrumentError, "no instrument object defined for model: %s" % (model,)
- self.clear_agent()
- def plug_module(self, module, slot):
- return plug_module(self, module, slot)
- def unplug_module(self, module, slot):
- return unplug_module(self, module, slot)
- def is_empty(self, slot):
- "Indicate is given slot is empty or not."
- return bool(int(self.get_agent().ask(":SLOT%d:EMPT?" % (slot,))))
- def has_module(self, slot):
- "Indicate if a slot has something."
- return not self.is_empty()
- def get_slots(self):
- return self.slots.items()
- def get_modules(self, model=None):
- """Return a list of module with the given model name, or all modules if no model given."""
- if model is None:
- return self.slots.values()
- else:
- rv = []
- model = str(model)
- for slot, module in self.slots.items():
- if module.__class__.__name__.find(model) >= 0:
- rv.append(module)
- return rv
- def get_module(self, name):
- """Search for an installed module by model name. Returns module object,
- or None if not found."""
- if type(name) is int:
- return self.slots[name+self.SLOTBASE]
- for slot, module in self.slots.items():
- if module.__class__.__name__.find(name) >= 0:
- break
- else:
- return None # not found
- return module
- def __getitem__(self, name):
- mod = self.get_module(name)
- if mod:
- return mod
- else:
- raise KeyError, "module model name or index not found."
- class InstrumentModule(Instrument):
- """Instrument that is a module that fits into an InstrumentChassis."""
- _ATTRS = Instrument._ATTRS.copy()
- _ATTRS.update({
- "chassis": (InstrumentChassis, None), # parent object actually holding this module instance
- "slot": (int, 0), # slot
- })
- PORTBASE = 0
- def identify(self):
- if type(self) is IA3:
- #print "### Calling Identity_JDSU()..."
- self.name = 'IA3'
- return Identity_JDSU(self.get_agent().ask("SYST:CARD:INFO? 1,%s" %
- (self.slot,)), )
- else:
- #print "### Caling normal Identity()..."
- return Identity(self.get_agent().ask(":SLOT%d:IDN?" % (self.slot,)))
- def is_empty_head(self, head=0): # ack! I hope not!
- "Query if the port is is present."
- return int(self.get_agent().ask(":SLOT%d:HEAD%d:EMPT?" % (self.slot, head+self.PORTBASE)))
-
- def get_slot(self, slot=0):
- return self.slot
- def get_port(self, port=0):
- """Return a generic port. You probably want to override this in a subclass"""
- return self._get_port(InstrumentPort, port)
- def _get_master_port(self, portclass):
- if portclass.MASTER >= 0:
- return self._get_port(portclass, portclass.MASTER)
- else:
- return None
- def _get_port(self, portclass, port):
- #print "portclass: %s, port: %s" % (portclass, port)
- #print "portbase: %s" % self.PORTBASE
- if type (port) is int:
- return portclass(self, port+self.PORTBASE)
- elif type (port) is str and port.startswith("port"):
- port = int(port[4:])
- return portclass(self, port)
- else:
- raise ValueError, "invalid port number or name"
- def __getitem__(self, port):
- try:
- return self.get_port(port)
- except ValueError, err:
- raise KeyError, err
- def options(self):
- """Return connector options and instrument options"""
- return map(str.strip, self.get_agent().ask(":SLOT%d:OPT?" % (self.slot,)).split(","))
- # ports don't need to be stored and are non-persistent. they need an active session.
- class InstrumentPort(object):
- """Instrument that is a module that fits into an InstrumentChassis."""
- MASTER = -1 # some instruments have "master" ports that control settings for all ports.
- # a -1 value here means "no master". zero or greater indicates
- # the port number of the master.
- def __init__(self, module, port):
- self._agent = module.get_agent()
- self.slot = module.slot
- self.port = int(port)
- self.name = "%s.port%s" % (module.name, port)
- self.initialize()
- def __str__(self):
- return self.name
- def __del__(self):
- self.finalize()
- def is_master(self):
- if self.MASTER >= 0:
- return self.port == self.MASTER
- else:
- return True
- def initialize(self):
- pass
- def finalize(self):
- pass
- def identify(self):
- raw = self._agent.ask(":SLOT%d:HEAD%d:IDN?" % (self.slot,self.port)).strip()
- if raw:
- return Identity(raw)
- raw = self._agent.ask(":SLOT%d:IDN?" % (self.slot,)).strip()
- if raw:
- return Identity(raw)
- else:
- return Identity()
- def options(self):
- return self._agent.ask(":SLOT%d:HEAD%d:OPT?" % (self.slot,self.port))
- # virtually plug a module into a chassis...
- def plug_module(chassis, module, slot):
- #print "Calling plug...chassis: %s, module:%s, slot:%s" % (chassis, module, slot)
- if chassis.slots.has_key(slot):
- raise InstrumentError, "There's something in slot %s already." % (slot,)
- chassis.slots[slot] = module
- module.chassis = chassis
- module.slot = slot
- # unplug whatever is in slot from chassis object.
- def unplug_module(chassis, slot):
- module = chassis.slots.get(slot)
- if module:
- module.slot = -1
- del module.chassis
- del chassis.slots[slot]
- # classes for generic VISA equipment objects follow.
-
- class DMM(Instrument): # works with 34401A at least
- "A generic DMM object."
- def read_voltage(self, ac=False, range=20, resolution=0.001):
- a = self.get_agent()
- a.write(':MEASure:VOLTAGE:%s? %s,%s' % (IF(ac, "AC", "DC"), range, resolution))
- val = float(a.read())
- return PhysicalQuantity(round(val, 3), "V") # XXX fix round value
- def read_current(self, ac=False, range=1, resolution=0.001):
- a = self.get_agent()
- a.write(':MEASure:CURRENT:%s? %s,%s' % (IF(ac, "AC", "DC"), range, resolution))
- val = float(a.read())
- return PhysicalQuantity(round(val, 3), "A")
- class RFSignalGenerator(Instrument):
- "A generic RF signal generator."
- class Oscilloscope(Instrument):
- "A generic oscilloscope."
- class FunctionGenerator(Instrument):
- "A generic function generator."
- def _apply(self, function, frequency=DEFAULT, amplitude=DEFAULT, offset=DEFAULT):
- a = self.get_agent()
- return a.write("APPL:%s %s, %s, %s" % (function, frequency, amplitude, offset))
- def sinusoid(self, frequency=DEFAULT, amplitude=DEFAULT, offset=DEFAULT):
- return self._apply("SIN", frequency, amplitude, offset)
- def square(self, frequency=DEFAULT, amplitude=DEFAULT, offset=DEFAULT):
- return self._apply("SQU", frequency, amplitude, offset)
- def triangle(self, frequency=DEFAULT, amplitude=DEFAULT, offset=DEFAULT):
- return self._apply("TRI", frequency, amplitude, offset)
- def ramp(self, frequency=DEFAULT, amplitude=DEFAULT, offset=DEFAULT):
- return self._apply("RAMP", frequency, amplitude, offset)
- def noise(self, amplitude=DEFAULT, offset=DEFAULT):
- return self._apply("NOIS", DEFAULT, amplitude, offset)
- def DC(self, offset):
- return self._apply("DC", DEFAULT, DEFAULT, offset)
- def user(self, frequency=DEFAULT, amplitude=DEFAULT, offset=DEFAULT):
- return self._apply("USER", frequency, amplitude, offset)
- def output_load(self, imp):
- """output_load <impedence>
- Sets the output impedence to 50 ohms if impedenace is 50, open-circuit otherwise."""
- a = self.get_agent()
- if int(imp) != 50:
- imp = "INF"
- return a.write("OUT:LOAD %s" % (imp, ))
-
- def query(self):
- """Query the function generator and return:
- wave function, frequency, amplitude, dc offset, and output impedence."""
- a = self.get_agent()
- val = a.ask("APPLy?")[1:-1]
- imp = a.ask("OUT:LOAD?")
- fr, amp, offset = val.split(",")
- func, freq = fr.split()
- return func, float(freq), float(amp), float(offset), float(imp)
- class DCPower(Instrument):
- "A geneeric DC power supply."
- class SpectrumAnalyzer(Instrument):
- "A generic spectrum analyzer."
- class OpticalSpectrumAnalyzer(Instrument):
- "A generic optical spectrum analyzer."
- class PowerMeter(Instrument):
- "A generic power meter."
- class OpticalSignalGenerator(Instrument):
- "A generic optical signal generator."
- def initialize(self, agent):
- self.unlock()
-
- def is_locked(self):
- "Return state of laser lock."
- val = self.get_agent().ask(":LOCK?")
- return Boolean(val)
- def lock(self, tf=True, passwd=None):
- "Lock or unlock the laser functioning."
- tf = Boolean(tf)
- pw = passwd or self.password
- self.get_agent().write(":LOCK %s,%s" % (tf, pw[:4]))
- def unlock(self, passwd=None):
- self.lock(False, passwd)
-
- class OpticalPowerAmp(Instrument):
- "A generic optical power amplifier."
-
- class OpticalPowerMeter(Instrument):
- "A generic optical power meter (SCPI commands)."
- def initialize(self, agent):
- agent.write(":UNIT:POW dBm")
- class OpticalHeadInterface(Instrument):
- "A generic optical head interface"
- def initialize(self, agent):
- agent.write(":UNIT:POW dBm")
- class OpticalSwitch(Instrument):
- """A generic optical switch """
- class OpticalAttenuator(Instrument):
- "A generic optical attenuator"
- def _get_attenuation(self):
- raw = self.get_agent().ask(":INP:ATT?")
- return PhysicalQuantity(SCPIFloat(raw), "dB")
- def _set_attenuation(self, atten):
- atten = get_quantity(atten, "dB")
- self.get_agent().write(":INP:ATT %.2f" % (atten,), wait=True)
- #self.get_agent().write(":INP:ATT %.2f" % (atten,), wait=True)
- def _no_attenuation(self):
- self.get_agent().write(":INP:ATT MIN", wait=True)
- attenuation = property(_get_attenuation, _set_attenuation, _no_attenuation, "attenuation factor (dB)")
- def _get_max(self):
- raw = self.get_agent().ask(":INP:ATT? MAX")
- return PhysicalQuantity(SCPIFloat(raw), "dB")
- maximum_attenuation = property(_get_max, None, None, "Maximum possible attenuation.")
- def _get_min(self):
- raw = self.get_agent().ask(":INP:ATT? MIN")
- return PhysicalQuantity(SCPIFloat(raw), "dB")
- minimum_attenuation = property(_get_min, None, None, "Minimum possible attenuation.")
- def _get_wavelength(self):
- raw = self.get_agent().ask(":INP:WAV?") # in meters
- return PhysicalQuantity(SCPIFloat(raw), "m").inUnitsOf("nm")
- def _set_wavelength(self, wl):
- wl = get_quantity(wl, "nm")
- self.get_agent().write(":INP:WAV %s NM" % (wl._value,), wait=True)
- wavelength = property(_get_wavelength, _set_wavelength, None, "wavelengh in nM")
- def _get_output(self):
- return Boolean(self.get_agent().ask(":OUTP:STAT?"))
- def _set_output(self, flag):
- flag = Boolean(flag)
- self.get_agent().write(":OUTP:STAT %s" % (flag,), wait=True)
- output = property(_get_output, _set_output, None, "state of output shutter")
- state = output # alias
- def on(self):
- self._set_output(ON)
- def off(self):
- self._set_output(OFF)
- class OpticalAttenuator_JDSU(Instrument):
- "A generic optical attenuator"
-
- def _get_attenuation(self):
- addr_params = "%s,%s,%s" % (self.chassis_addr, self.slot_addr, self.device_addr)
- cmd = ":OUTP:ATT? %s" % (addr_params)
- raw = self.get_agent().ask("%s" % cmd)
- return PhysicalQuantity(SCPIFloat(raw), "dB")
-
- def _set_attenuation(self, atten):
- atten = get_quantity(atten, "dB")
- addr_params = "%s,%s,%s" % (self.chassis_addr, self.slot_addr, self.device_addr)
- cmd = ":OUTP:ATT %s,%.2f" % (addr_params, atten)
- print "att cmd: %s" % cmd
- self.get_agent().write("%s" % (cmd, ),)
- time.sleep(1) # JSDU voa need a time delay after set_attenuation
- def _no_attenuation(self):
- addr_params = "%s,%s,%s" % (self.chassis_addr, self.slot_addr, self.device_addr)
- cmd = ":OUTP:ATT %s,%.2f" % (addr_params, 0.0)
- self.get_agent().write(cmd, wait=True)
- attenuation = property(_get_attenuation, _set_attenuation, _no_attenuation, "attenuation factor (dB)")
- def _get_wavelength(self):
- addr_params = "%s,%s,%s" % (self.chassis_addr, self.slot_addr, self.device_addr)
- raw = self.get_agent().ask(":OUTP:WAV? %s" % addr_params) # in meters
- return PhysicalQuantity(SCPIFloat(raw), "m").inUnitsOf("nm")
- def _set_wavelength(self, wl):
- addr_params = "%s,%s,%s" % (self.chassis_addr, self.slot_addr, self.device_addr)
- wl = get_quantity(wl, "nm")
- cmd = ":OUTP:WAV %s,%s" % (addr_params,wl._value)
- self.get_agent().write("%s" % (cmd,), wait=True)
- wavelength = property(_get_wavelength, _set_wavelength, None, "wavelengh in nM")
- def _get_output(self):
- addr_params = "%s,%s,%s" % (self.chassis_addr, self.slot_addr, self.device_addr)
- cmd = ":OUTP:BBLock? %s" % addr_params
- return Boolean(self.get_agent().ask(cmd))
- def _set_output(self, state):
- addr_params = "%s,%s,%s" % (self.chassis_addr, self.slot_addr, self.device_addr)
- if state=='ON':
- cmd = ":OUTP:BBLock %s,0" % (addr_params)
- else:
- cmd = ":OUTP:BBLock %s,1" % (addr_params)
- self.get_agent().write(cmd, wait=True)
- output = property(_get_output, _set_output, None, "state of output shutter")
- state = output # alias
- def on(self):
- self._set_output(ON)
- def off(self):
- self._set_output(OFF)
- # specific instruments
- class FIBERAMP(OpticalPowerAmp):
- "A PHOTONETICS FIBERAMP BT1400 (EDFA)."
- def initialize(self, agent):
- agent.write("*SRE=17") # use SRQ line
- agent.use_srq()
- def _get_value(self, cmd):
- a = self.get_agent()
- try:
- raw = a.ask(cmd)
- except visa_exceptions.VisaIOError, err:
- if err.error_code == vpp43.VI_ERROR_TMO and a.STB == 3: # invalid command
- raise GPIBInvalidCommand, "%s: %s" % (self.visa_resource, cmd)
- else:
- raise
- if raw == "disabled":
- raise InstrumentError, "device is disabled"
- name, val = raw.split("=",1)
- return name, float(val)
- def _write(self, cmd):
- a = self.get_agent()
- a.write(cmd)
- a.wait_for_srq()
- def _get_current(self):
- name, val = self._get_value("I?")
- return PhysicalQuantity(val, "mA")
- def _set_current(self, mA):
- if str(mA).upper().startswith("MAX"):
- name, mA = self._get_value("ILIMIT?")
- else:
- mA = float(get_quantity(mA, "mA"))
- self._write("I=%0.1f" % (mA,))
- current = property(_get_current, _set_current, None, "constant current mode, current in mA")
- def _get_ilimit(self):
- name, mA = self._get_value("ILIMIT?")
- return PhysicalQuantity(mA, "mA")
- max_current = property(_get_ilimit)
- def _get_power(self):
- name, val = self._get_value("P?")
- return PhysicalQuantity(val, "mW")
- def _set_power(self, p):
- p = get_quantity(p, "mW")
- self._write("P=%0.f" % (p._value,))
- power = property(_get_power, _set_power, None, "constant power mode, power in mW")
- def enable(self):
- "Enable output"
- self._write("ENABLE")
- def disable(self):
- "Disable output"
- self._write("DISABLE")
- def _get_state(self):
- raw = self.get_agent().ask("P?")
- if raw == "disabled":
- return Boolean(0)
- else:
- return Boolean(1)
- def _set_state(self, state):
- state = Boolean(state)
- if state:
- self.enable()
- else:
- self.disable()
- state = property(_get_state, _set_state, None, "operating state")
- output = state # alias
- def is_locked(self):
- "Return state of interlock."
- val = self.get_agent().ask("INTERLOCK?")
- return Boolean(val)
- locked = property(is_locked)
- def _get_APC(self):
- val = self.get_agent().ask("APC?")
- return Boolean(val)
- def _set_APC(self, mode):
- mode = Boolean(mode)
- if mode: # true = APC on
- self._write("APCON")
- else:
- self._write("APCOFF")
- def _del_APC(self): # deleting APC is same as setting it off
- self._write("APCOFF")
- constant_power = property(_get_APC, _set_APC, _del_APC, "constant power (APC) mode control")
- def _get_temp(self):
- val = self.get_agent().ask("ERRORT?")
- return Boolean(val)
- temperature_error = property(_get_temp, None, None, "true if there is a Temperature Error condition.")
- def _get_ID(self):
- a = self.get_agent()
- raw = a.ask("*IDN?")
- #print "raw %s" %(raw,)
- return raw
- ID = property(_get_ID, None, None, "Instrument identification")
- class KEOPSYSAMP(OpticalPowerAmp):
- "A KEOPSYSAMP 18dBm FIBER AMPLIFIER (Model: OI-BT-C-18-sd-B-GP-FA)"
- def initialize(self, agent):
- agent.write("REM") # set to remote mode
- #agent.use_srq()
- def _get_value(self, cmd):
- a = self.get_agent()
- try:
- raw = a.ask(cmd)
- except visa_exceptions.VisaIOError, err:
- if err.error_code == vpp43.VI_ERROR_TMO and a.STB == 3: # invalid command
- raise GPIBInvalidCommand, "%s: %s" % (self.visa_resource, cmd)
- else:
- raise
- if raw == "disabled":
- raise InstrumentError, "device is disabled"
- name, val = raw.split("=",1)
- return name, float(val)
- def _write(self, cmd):
- a = self.get_agent()
- a.write(cmd)
- #a.wait_for_srq()
- def _get_current(self):
- name, val = self._get_value("RA1")
- print "name %s, val %s" %(name, val)
- return PhysicalQuantity(((val/4095) * 2.50)*1000, "mA") #Real value = (nnnn * full sclae) / (4095)
- def _set_current(self, mA):
- mA = float(get_quantity(mA, "mA"))
- mA = mA * 4095 / 2500
- self._write("SA1:%04d" % (mA,)) #Nearest integer(nnnn) = (real value * 4095) / fullscale
- sleep(2)
- current = property(_get_current, _set_current, None, "constant current mode, current in mA")
- def _get_power(self):
- name, val = self._get_value("RA1")
- print "name %s, val %s" %(name, val)
- return PhysicalQuantity(((val/4095) * 22.0), "dBm") #Real value = (nnnn * full sclae) / (4095)
- def _set_power(self, dbm):
- dbm = float(get_quantity(dbm, "dBm"))
- dbm = dbm * 4095 / 22.0
- self._write("SA1:%d" % (dbm,)) #Nearest integer(nnnn) = (real value * 4095) / fullscale
- power = property(_get_power, _set_power, None, "constant output power mode, power in dBm")
- def _get_ID(self):
- a = self.get_agent()
- raw = a.ask("ID")
- #print "raw %s" %(raw,)
- return raw
- ID = property(_get_ID, None, None, "Instrument identification")
- def _get_temp(self):
- name, val = self._get_value("RA2")
- print "name %s, val %s" %(name, val)
- return val
- temperature = property(_get_temp, None, None, "constant current mode, current in mA")
-
- def enable(self):
- "Enable output"
- self._write("K1")
- def disable(self):
- "Disable output"
- self._write("K0")
- def _set_state(self, state):
- state = Boolean(state)
- if state:
- self.enable()
- else:
- self.disable()
- state = property(_set_state, None, "operating state")
- output = state # alias
- def set_localmode(self):
- "Set to local mode"
- self._write("GTL")
- class MAP(InstrumentChassis):
- SLOTBASE = 1
-
- class HP8163A(InstrumentChassis):
- "A HEWLETT-PACKARD HP8163A optical measurement chassis"
- SLOTBASE = 1
- class HP8163B(InstrumentChassis):
- "A HP8163B just inherits HP8163A"
- SLOTBASE = 1
- class HP81635A(InstrumentModule, OpticalPowerMeter):
- "A HEWLETT-PACKARD HP81635A optical power module"
- PORTBASE = 1
- def get_port(self, port):
- return self._get_port(HP81635APort, port)
- class HP81635APort(InstrumentPort):
- """HP81635A dual power meter for HP8163A chassis"""
- MASTER = 1
- def initialize(self):
- self._currentunit = self._get_unit()
- if self._currentunit is None:
- raise InstrumentError, "could not initialize HP81635APort"
- def _set_unit(self, unit):
- assert unit in ("dBm", "DBM", "Watts", "W")
- self._agent.write(':SENSE%d:CHAN%d:POW:UNIT %s' % (self.slot, self.port, unit) )
- self._currentunit = self._get_unit()
- def _get_unit(self):
- val = int(self._agent.ask(':SENSE%d:CHAN%d:POW:UNIT?' % (self.slot, self.port) ))
- if val == 0:
- return "dBm"
- elif val == 1:
- return "W"
- unit = property(_get_unit, _set_unit, None, "Measurement unit: dBm or Watts")
- def _set_wavelength(self, wl):
- wl = get_quantity(wl, "m")
- self._agent.write(':SENSE%d:CHAN%d:POW:WAV %sM' % (self.slot,self.port, wl._value) )
- def _get_wavelength(self):
- val = self._agent.ask(':SENSE%d:CHAN%d:POW:WAV?' % (self.slot,self.port) )
- return PhysicalQuantity(SCPIFloat(val), "m")
- wavelength = property(_get_wavelength, _set_wavelength, None, "Wavelength in M")
- def _set_averaging(self, tm):
- tm = get_quantity(tm, "s")
- if self.is_master():
- self._agent.write(':SENSE%d:CHAN%d:POW:ATIM %sS' % (self.slot, self.port, tm._value))
- else:
- raise InstrumentError, "invalid operation on non-master port"
- def _get_averaging(self):
- val = self._agent.ask(':SENSE%d:CHAN%d:POW:ATIM?' % (self.slot,self.port))
- return PhysicalQuantity(SCPIFloat(val), "s")
- averaging_time = property(_get_averaging, _set_averaging, None, "Averaging time in S")
- def _set_continuous(self, state):
- if self.is_master():
- state = Boolean(state)
- self._agent.write(':INIT%d:CHAN%d:CONT %s' % (self.slot,self.port,state) )
- else:
- raise InstrumentError, "invalid operation on non-master port"
- def _get_continuous(self):
- return Boolean(self._agent.ask(':INIT%d:CHAN%d:CONT?' % (self.slot,self.port)))
- continuous = property(_get_continuous, _set_continuous, None, "continuous measurement mode?")
- def _get_power(self):
- val = self._agent.ask(':FETCH%d:CHAN%d:SCAL:POW?' % (self.slot,self.port) )
- return PhysicalQuantity(SCPIFloat(val), self._currentunit)
- power = property(_get_power, None, None, "Power in current units.")
- class HP81619A(InstrumentModule, OpticalHeadInterface):
- "A HEWLETT-PACKARD HP81635A optical power module"
- PORTBASE = 1
- def get_port(self, port):
- return self._get_port(HP81619APort, port)
-
- class HP81619APort(HP81635APort):
- "Same as a HP81635APort"
- pass
- class HP81633A(HP81635A):
- "Same as a HP81635A, except with only one port"
- pass
- class HP81633APort(HP81635APort):
- "Same as a HP81635APort"
- pass
- class HP81570A(InstrumentModule, OpticalAttenuator):
- "A HEWLETT-PACKARD HP81635A optical power module"
- PORTBASE = 1
- def get_port(self, port):
- return self._get_port(HP81570APort, port)
- class HP81570APort(HP81635APort):
- "Same as a HP81635APort"
- pass
- class HP81576A(InstrumentModule, OpticalAttenuator, OpticalPowerMeter):
- "A HEWLETT-PACKARD HP81635A optical power module"
- PORTBASE = 1
- def get_port(self, port):
- return self._get_port(HP81635APort, port)
- def _get_power(self):
- self._agent = self.get_agent()
- val = self._agent.ask(':FETCH%d:SCAL:POW?' % (self.slot,))
- #val = self._agent.ask(':FETCH%d:CHAN%d:SCAL:POW?' % (self.slot,self.port))
- return PhysicalQuantity(SCPIFloat(val), self._currentunit)
- power = property(_get_power, None, None, "Power in current units.")
-
- class HP81576APort(HP81635APort):
- "Same as a HP81635APort"
- pass
- class IA3(InstrumentModule, OpticalAttenuator_JDSU):
- _ATTRS = Instrument._ATTRS.copy()
- _ATTRS.update({
- "chassis_addr" : (str, "1"),
- "slot_addr" : (str, "1"),
- "device_addr" : (str, "1"), # slot maps to list index
- })
- pass
- class IA3Port(InstrumentPort):
- pass
- class OA(IA3):
- pass
- class OAPort(InstrumentPort):
- pass
-
- class HP81663A(InstrumentModule, OpticalSignalGenerator):
- "A HEWLETT-PACKARD HP81663A optical source"
- PORTBASE = 1
- def initialize(self, agent):
- self.unlock()
-
- def get_port(self, port=0):
- return self._get_port(HP81663APort, port)
- def _get_wavelength(self):
- from instrumentdata.HP81663A import HP81663_opt2wl
- modopt = self.options()[1]
- return PhysicalQuantity(HP81663_opt2wl[modopt], "nm")
- wavelength = property(_get_wavelength, None, None, "modules wavelength option")
- class HP81662A(HP81663A):
- pass
- class HP81591A(InstrumentModule, OpticalSwitch):# xxx:change type later
- """ Agilent HP 8159A 780 to 1350nm 2x1 Optical Switch """
- PORTBASE = 1
- def get_port(self, port=0):
- return self._get_port(HP8159xPort, port)
- class HP81591APort(InstrumentPort):
- """HP81591A/HP81591B dual power meter for HP8163A chassis"""
- MASTER = 1
- # signal routing functionalities
- def _get_switch_conf(self):
- """
- Queries the switch configuration of the instrument
- """
- # a = self._agent
- a = self.get_agent()
- cmd = ':ROUT%d:CHAN%d:CONF?' % (self.slot, 1)
- print "cmd: %s" % cmd
- val = a.ask(cmd)
- print "val: %s" % val
- return val
- def _get_switch_route(self, chan=1):
- """
- Queries the switch configuration of the instrument
- """
- a = self.get_agent()
- cmd = ':ROUT%d:CHAN%d:CONF:ROUT?' % (self.slot, chan)
- print "cmd: %s" % cmd
- val = a.ask(cmd)
- return val
- def _get_route_chan(self, m=1):
- """
- Queries the current channel route of the switch for a specific module
- and switch channel.
- n: the slot number of the switch module
- m: the switch channel within the selected switch module, default is 1
- """
- #a = self._agent
- a = self.get_agent()
- cmd = ':ROUT%d:CHAN%d?' % (self.slot, m)
- print "cmd: %s" % cmd
- #self.info("xxx", 1)
- val = a.ask(cmd)
- return val
- def _set_route_chan(self, chan='A', m=2):
- """
- Sets the channel route between two ports.
- format:
- :ROUTe[n]:[CHANnel[m]]<wsp><channel_list>
-
- n: the slot number of the switch module
- m: the switch channel within the selected switch module.
- e.g. for dual 1 x 2 module m = 1 for switch 1; m = 2 for switch 2
- the route between left and right ports.
- channel_list format: [A....Z],[1....n]
- """
- a = self.get_agent()
- chan_map = {1: 2, 2: 1}
-
- cmd = ':ROUT%d:CHAN%d %s,%d' % (self.slot, chan_map[m], chan, m)
- #print "cmd: %s" % cmd
- val = a.ask(cmd)
- return val
- def do_ask(self, cmd):
- a = self._agent
- #a = self.get_agent()
- #print "cmd: %s" % cmd
- val = a.ask(cmd)
- return val
- def do_write(self, cmd):
- a = self._agent
- #print "cmd: %s" % cmd
- val = a.write(cmd)
- #print "val: %s" % val
- return val
- def set_default_switch(self, chn=1):
- cmd = ":ROUT%d:CHAN%d A,%d" % (chn, chn, chn)
- return self.do_write(cmd)
- def set_switch_for_tx(self):
- cmd = ":ROUT1:CHAN1 A,2"
- return self.do_write(cmd)
-
- def get_route_config(self, chn=1):
- cmd = ":ROUT%d:CONF:rout?" % chn
- return self.do_ask(cmd)
- def get_port(self, port=0):
- return self._get_port(HP8159xPort, port)
- class HP81591B(InstrumentModule, OpticalSwitch):# xxx:change type later
- """ Agilent HP 8159A 780 to 1350nm 2x1 Optical Switch """
- PORTBASE = 1
- def get_port(self, port=0):
- return self._get_port(HP81591BPort, port)
- class HP81591BPort(InstrumentPort):
- """HP81591A/HP81591B dual power meter for HP8163A chassis"""
- MASTER = 1
- # signal routing functionalities
- def _get_switch_conf(self):
- """
- Queries the switch configuration of the instrument
- """
- a = self._agent
- # a = self.get_agent()
- cmd = ':ROUT%d:CHAN%d:CONF?' % (self.slot, 1)
- print "cmd: %s" % cmd
- val = a.ask(cmd)
- print "val: %s" % val
- return val
- def _get_switch_route(self, chan=1):
- """
- Queries the switch configuration of the instrument
- """
- a = self.get_agent()
- cmd = ':ROUT%d:CHAN%d:CONF:ROUT?' % (self.slot, chan)
- print "cmd: %s" % cmd
- val = a.ask(cmd)
- return val
- def _get_route_chan(self, m=1):
- """
- Queries the current channel route of the switch for a specific module
- and switch channel.
- n: the slot number of the switch module
- m: the switch channel within the selected switch module, default is 1
- """
- a = self._agent
- #a = self.get_agent()
- cmd = ':ROUT%d:CHAN%d?' % (self.slot, m)
- print "cmd: %s" % cmd
- #self.info("xxx", 1)
- val = a.ask(cmd)
- return val
- def _set_route_chan(self, chan='A', m=2):
- """
- Sets the channel route between two ports.
- format:
- :ROUTe[n]:[CHANnel[m]]<wsp><channel_list>
-
- n: the slot number of the switch module
- m: the switch channel within the selected switch module.
- e.g. for dual 1 x 2 module m = 1 for switch 1; m = 2 for switch 2
- the route between left and right ports.
- channel_list format: [A....Z],[1....n]
- """
- a = self.get_agent()
- chan_map = {1: 2, 2: 1}
-
- cmd = ':ROUT%d:CHAN%d %s,%d' % (self.slot, chan_map[m], chan, m)
- #print "cmd: %s" % cmd
- val = a.ask(cmd)
- return val
- def do_ask(self, cmd):
- a = self._agent
- #a = self.get_agent()
- #print "cmd: %s" % cmd
- val = a.ask(cmd)
- return val
- def do_write(self, cmd):
- a = self._agent
- #print "cmd: %s" % cmd
- val = a.write(cmd)
- #print "val: %s" % val
- return val
- def set_default_switch(self, chn=1):
- cmd = ":ROUT%d:CHAN%d A,%d" % (chn, chn, chn)
- return self.do_write(cmd)
- def set_switch_for_tx(self):
- cmd = ":ROUT1:CHAN1 A,2"
- return self.do_write(cmd)
-
- def get_route_config(self, chn=1):
- cmd = ":ROUT%d:CONF:rout?" % chn
- return self.do_ask(cmd)
- def get_port(self, port=0):
- return self._get_port(HP8159xPort, port)
- #class HP81591B(HP81591A):
- # pass
-
- class HP81594B(HP81591A):
- # XXX: should really rewrite this function later...
- PORTBASE = 1
-
- def get_port(self, port=0):
- return self._get_port(HP8159xPort, port)
-
- def set_default_switch(self):
- """
- set to A
- """
- cmd = "ROUT2:CHAN1 A,1;B,2.A,2;B,1"
- return self.do_write(cmd)
-
- def set_switch_for_tx(self):
- cmd = ":ROUT2:CHAN1 A,2;B,1.A,1;B,2"
- return self.do_write(cmd)
- #InstrumentModule, OpticalSwitch):# xxx:change type later
- #""" Agilent HP 81594B 780 to 1350nm 2x2 Optical Switch """
- #PORTBASE = 1
- #def get_port(self, port=0):
- # return self._get_port(HP8159xPort, port)
- class HP8159xPort(InstrumentPort):
- """HP81635A dual power meter for HP8163A chassis"""
- MASTER = 1
- def initialize(self):
- self._currentunit = self._get_unit()
- if self._currentunit is None:
- raise InstrumentError, "could not initialize HP8159xPort"
- def _set_unit(self, unit):
- assert unit in ("dBm", "DBM", "Watts", "W")
- self._agent.write(':SENSE%d:CHAN%d:POW:UNIT %s' % (self.slot, self.port, unit) )
- self._currentunit = self._get_unit()
- def _get_unit(self):
- val = int(self._agent.ask(':SENSE%d:CHAN%d:POW:UNIT?' % (self.slot, self.port) ))
- if val == 0:
- return "dBm"
- elif val == 1:
- return "W"
- unit = property(_get_unit, _set_unit, None, "Measurement unit: dBm or Watts")
- def _get_power(self):
- val = self._agent.ask(':FETCH%d:CHAN%d:SCAL:POW?' % (self.slot,self.port) )
- return PhysicalQuantity(SCPIFloat(val), self._currentunit)
- power = property(_get_power, None, None, "Power in current units.")
-
-
- class HP81689A(InstrumentModule, OpticalSignalGenerator):
- "A HEWLETT-PACKARD HP81689A optical source"
- PORTBASE = 1
- def get_port(self, port=0):
- return self._get_port(HP81689APort, port)
-
- class HP816xxAPort(InstrumentPort):
- """The HP81689A laser port.
- Attributes are:
- state - set laser state (on or off)
- lasersource - what laser (selected by wavelength) is to set or query.
- wavelength - set the wavelength to use (LASER_UPPER, LASER_LOWER, LASER_BOTH).
- modulation - set to a Modulation object to modulate the laser according to Modulation.
- power - the power level of the laser
- unit - the default unit for the power setting."""
- def initialize(self):
- self._currentunit = self._get_unit()
- self._lasersource = LASER_LOWER
- def _get_state(self):
- return Boolean(self._agent.ask(':OUTP%d:CHAN%d:STAT?' % (self.slot,self.port)))
- def _set_state(self, st):
- self._agent.write(':OUTP%d:CHAN%d:STAT %s' % (self.slot,self.port, st))
- # set the state to turn laser on or off
- state = property(_get_state, _set_state, None, "Power state of the laser")
- def on(self):
- """Turn laser source on (if it is not locked)."""
- self._set_state(ON)
- def off(self):
- """Turn laser source off."""
- self._set_state(OFF)
- def _get_lasersource(self):
- return self._lasersource
- def _set_lasersource(self, src):
- assert src in (LASER_LOWER, LASER_UPPER), "must set lasersource to LASER_LOWER or LASER_UPPER"
- self._lasersource = src
- lasersource = property(_get_lasersource, _set_lasersource, None, "The laser source on dual source lasers")
- def _get_modulation(self):
- return NotImplemented # XXX
- def _set_modulation(self, mod): # takes a Modulation object parameter
- if issubclass(type(mod), int):
- if mod == OFF:
- self._modulation_off(LASER_LOWER)
- self._modulation_off(LASER_UPPER)
- return
- elif mod == ON:
- return self._agent.write(":SOUR%d:CHAN%d:AM:STAT ON" % (self.slot, self.port)) # XXX
- else:
- raise ValueError, "need ON, OFF, or Modulation object."
- if mod.modtype == DC:
- self._modulation_off(mod.lasersource)
- else:
- self._agent.write(":SOUR%d:CHAN%d:%s:%s:FREQ%d %s" %
- (self.slot, self.port, mod.modtype, mod.source, mod.lasersource, mod.frequency))
- self._agent.write(":SOUR%d:CHAN%d:%s:STAT%d ON" %
- (self.slot, self.port, mod.modtype, mod.lasersource))
- def _modulation_off(self, lasersource):
- self._agent.write(":SOUR%d:CHAN%d:AM:STAT%d OFF" % (self.slot, self.port, lasersource))
- self._agent.write(":SOUR%d:CHAN%d:FM:STAT%d OFF" % (self.slot, self.port, lasersource))
- modulation = property(_get_modulation, _set_modulation, None, "modulation parameters (use Modulation)")
- _UNITMAP = {0:"dBm", 1:"W", 255:None}
- def _get_unit(self):
- val = int(self._agent.ask(':SOUR%d:CHAN%d:POW:UNIT?' % (self.slot, self.port) ))
- if val == 255:
- raise InstrumentError, "Bad unit value. invalid slot?"
- return self._UNITMAP[val]
- def _set_unit(self, unit):
- self._agent.write(':SOUR%d:CHAN%d:POW:UNIT %s' % (self.slot, self.port, unit) )
- self._currentunit = self._get_unit() # verify
- unit = property(_get_unit, _set_unit, None, "Laser power unit: dBm or Watts")
- def _get_power(self):
- val = self._agent.ask(':SOUR%d:CHAN%d:POW?' % (self.slot, self.port) )
- return PhysicalQuantity(SCPIFloat(val), self._currentunit)
- def _set_power(self, pwr):
- pwr = get_quantity(pwr, self._currentunit)
- self._agent.write(':SOUR%d:CHAN%d:POW %s' % (self.slot, self.port, pwr._value) )
- power = property(_get_power, _set_power, None, "Optical power in current unit for current lasersource.")
- class HP81689APort(HP816xxAPort):
- """Tunable laser source."""
- def _get_wavelength(self):
- val = self._agent.ask(":SOUR%d:CHAN%d:WAV:FIXED%d?" % (self.slot, self.port, self._lasersource))
- return PhysicalQuantity(SCPIFloat(val), "m")
- def _set_wavelength(self, wl):
- wl = get_quantity(wl, "m")
- self._agent.write(":SOUR%d:CHAN%d:WAV:FIXED%d %sM" % (self.slot, self.port, self._lasersource, wl._value))
- wavelength = property(_get_wavelength, _set_wavelength, None, "current laser source wavelength")
- class HP81663APort(HP816xxAPort):
- """Distributed Feedback (DFB) laser module, 20 mW."""
- _WAVMAP = {"UPP":LASER_UPPER, "LOW":LASER_LOWER, "BOTH":LASER_BOTH, "ERR":InstrumentError}
- def _get_wavelength(self):
- val = self._agent.ask(":SOUR%d:CHAN%d:POW:WAV?" % (self.slot, self.port))
- return self._WAVMAP[val.strip()]
- def _set_wavelength(self, wl):
- self._agent.write(":SOUR%d:CHAN%d:POW:WAV %s" % (self.slot, self.port, wl))
- self._lasersource = wl
- wavelength = property(_get_wavelength, _set_wavelength, None, "current laser source: LASER_UPPER or LASER_LOWER ")
- class HP86120C(OpticalPowerMeter):
- "A HEWLETT-PACKARD 86120C Multi-Wavelength Meter"
- def _get_array(self):
- a = self.get_agent()
- a.write(":INIT:CONT OFF")
- a.write(":CONF:ARR:POW MAX")
- a.write(":INIT:IMM")
- levels = a.ask(":FETC:ARR:POW?")
- wavelengths = a.ask(":FETC:ARR:POW:WAV?")
- # convert to lists
- levels = filter(None, levels.split(","))
- wavelengths = filter(None, wavelengths.split(","))
- # sanity checks...
- len_levels = int(levels[0]) ; len_wavelengths = int(wavelengths[0])
- assert len_levels == len_wavelengths
- levels.pop(0) ; wavelengths.pop(0)
- assert len_levels == len(levels) ; assert len_wavelengths == len(wavelengths)
- if len_levels > 0:
- return Graph(map(float, wavelengths), "m", map(float, levels), "dBm", "Wavemeter Readings")
- else:
- return None
- waveform = property(_get_array, None, None, "Waveform Graph.")
- measurements = waveform # alias
- class HP8156A(OpticalAttenuator):
- "A HEWLETT-PACKARD HP8156A optical attenuator"
- class HP34401A(DMM):
- """An HEWLETT-PACKARD 34401A"""
- class HP53131A(Instrument):
- """An HEWLETT-PACKARD HP53131A (Frequency Counter) """
- def read_freq(self):
- a = self.get_agent()
- # visa command
- cmd = ":MEASURE:FREQ?"
- print "executing cmd: %s" % cmd
- raw = self.get_agent().ask(cmd)
- freq = PQ(SCPIFloat(raw), "Hz")
- return freq
- class HP86100A(Instrument):
- """An HP86100A"""
- class HP6674A(Instrument):
- """An HP6674A Power Supply"""
- def power_on(self):
- a = self.get_agent()
- # visa command
- cmd = "OUTP ON"
- self.get_agent().write(cmd)
-
- def power_off(self):
- a = self.get_agent()
- cmd = "OUTP OFF"
- self.get_agent().write(cmd)
-
- def set_voltage(self, volts):
- """ program voltage level """
- a = self.get_agent()
- cmd = "VOLT %" % volts
- self.get_agent().write(cmd)
-
- def set_current(self, current):
- a = self.get_agent()
- cmd = "CURR %" % current
- self.get_agent().write(cmd)
-
- def show_voltage(self):
- cmd = "MEAS:VOLT?"
- self.get_agent().ask(cmd)
- def show_current(self):
- cmd = "MEAS:CURR?"
- self.get_agent().ask(cmd)
-
-
- class HP34970A(Instrument):
- """An HP34970A Data Acquisiton/Switch Unit, measure temperature, ac/dc volts, resistance, frequency or current"""
- _ATTRS = {
- "name": (str, "unknown"),
- "manufacturer": (str, "unknown"),
- "modelNumber": (str, "unknown"),
- "serialNumber": (str, "unknown"),
- "firmware": (str, "unknown"),
- "password": (str, "1234"),
- "visa_resource": (str, ""), # e.g.'GPIB2::22'
- "channel": (str, "101"),
- }
- def _get_temp(self, channel=''):
- if (channel):
- self.channel = channel
- cmd = ":MEASURE:TEMPERATURE? TCouple,T,(@%d)" % int(self.channel)
- raw = self.get_agent().ask(cmd)
- return PQ(SCPIFloat(raw), "degC")
- temperature = property(_get_temp)
- def get_temp(self, n=1):
- cmd = ":MEASURE:TEMPERATURE? TCouple,T,(@101"
- for i in range(102,101+n):
- cmd = cmd + ',%d' % (i)
- cmd = cmd + ')'
- tempList = []
- raw = self.get_agent().ask(cmd)
- for temp in raw.split(","):
- tempList.append(PQ(SCPIFloat(temp), "degC"))
- return tempList
- # Scan voltages for all the channels in the scanLst
- # by default the module is assumed to be plugged in slot 1
- def scan_voltages(self, scanLst, slot=1):
- voltDict = {}
- for chn in scanLst :
- voltDict[chn] = self.get_volt(chn,slot).value
- return voltDict
- # Read voltage for the given channel
- def get_volt(self, chn, slot=1):
- cmd = ":MEASURE:VOLTAGE:DC? (@"
- if(slot == 1):
- startChn = 100
- elif(slot == 2):
- startChn = 200
- else:
- startChn = 300
- chn = chn + startChn
- #print "reading DAQ channel: ", chn
- cmd = cmd + '%d' % (chn)
- cmd = cmd + ')'
- tmpLst = []
- raw = self.get_agent().ask(cmd)
- return (PQ(SCPIFloat(raw),"V"))
-
- class HP33120A(FunctionGenerator):
- """An HP HP33120A"""
- class HP83650L(RFSignalGenerator):
- """Synthesized Swept-CW Generator, 10 MHz to 50 GHz"""
- class AQ6317B(OpticalSpectrumAnalyzer):
- "An ANDO AQ6317B Optical Spectrum Analyzer"
- def initialize(self, agent):
- agent.write("SD0;BD0") # default data delimiters: SD = ',', and BD = CR+LF+EOI
- agent.write("RESCOR 1") # default to RESOLUTION CORRECT
- th2_threshold = 10.0
- print "Setting ENVT2 to %s" % th2_threshold
- agent.write("ENVT2 %s" % th2_threshold)
- def _do_sweep(self):
- a = self.get_agent()
- a.write("STP")
- a.write("SRMSK14") # srq on completed sweep
- a.write("SRQ1")
- a.srquse = True
- a.write("SGL")
- a.wait_for_srq()
- a.srquse = False
- a.write("SRQ0")
- def do_sweep(self):
- """perform a single sweep of the instrument."""
- self._do_sweep()
- _SWEEPMAP = enummap(SWEEP_STOP, SWEEP_SINGLE, SWEEP_CONTINUOUS, SWEEP_AUTO, SWEEP_SEGMENTMEASURE)
- def _get_sweep(self):
- val = self.get_agent().ask('SWEEP?').strip()
- return self._SWEEPMAP[int(val)]
- def _set_sweep(self, swp):
- if swp == SWEEP_STOP:
- self.get_agent().write("STP")
- elif swp == SWEEP_SINGLE:
- self.get_agent().write("SGL")
- elif swp == SWEEP_CONTINUOUS:
- self.get_agent().write("RPT")
- elif swp == SWEEP_AUTO:
- self.get_agent().write("AUTO")
- elif swp == SWEEP_SEGMENTMEASURE:
- self.get_agent().write("SMEAS")
- else:
- raise InstrumentError, "invalid sweep value"
- sweep = property(_get_sweep, _set_sweep, None, "the sweep setting: SWEEP_*")
- def _get_swi(self):
- val = self.get_agent().ask('SWPI?').strip()
- return PQ(int(val), "s")
- def _set_swi(self, val):
- val = get_quantity(val, "s")
- self.get_agent().write('SWPI%s' % (int(val),))
- def _del_swi(self): # deleting sweep interval is the same as setting to zero
- self.get_agent().write('SWPI0')
- sweepInterval = property(_get_swi, _set_swi, _del_swi, "sweep interval in seconds.")
- def _get_swpm(self):
- val = self.get_agent().ask('SWPM?').strip()
- return Boolean(val)
- def _set_swpm(self, val):
- val = Boolean(val)
- self.get_agent().write('SWPM%d' % (int(val),))
- def _del_swpm(self): # deleting sweep marker is the same as turning it off
- self.get_agent().write('SWPM0')
- sweepMarker = property(_get_swpm, _set_swpm, _del_swpm, "marker-to-marker sweep control")
- def _get_center(self):
- if self._get_xunit() == 0:
- raw = self.get_agent().ask('CTRWL?')
- try:
- return PQ(float(raw), "nm")
- except:
- return PQ(0.0, "nm")
- elif self._get_xunit() == 1:
- raw = self.get_agent().ask('CTRF?')
- try:
- return PQ(float(raw), "THz")
- except:
- return PQ(0.0, "THz")
- def _set_center(self, wl):
- if type(wl) is Enum and wl == PEAK:
- self.get_agent().write('CTR=P')
- return
- try:
- wl = get_quantity(wl, "nm")
- except TypeError:
- f = get_quantity(wl, "THz")
- self.get_agent().write('CTRF%3.3f' % (f,))
- else:
- self.get_agent().write('CTRWL%4.2f' % (wl,))
- centerWavelength = property(_get_center, _set_center, None, "center value: wavelength (nm), or PEAK")
- center = centerWavelength # alias
- def _get_start(self):
- if self._get_xunit() == 0:
- raw = self.get_agent().ask('STAWL?')
- return PQ(float(raw), "nm")
- elif self._get_xunit() == 1:
- raw = self.get_agent().ask('STAF?')
- return PQ(float(raw), "THz")
- def _set_start(self, wl):
- try:
- wl = get_quantity(wl, "nm")
- self.get_agent().write('STAWL%4.2f' % (wl,))
- except TypeError:
- f = get_quantity(wl, "THz")
- self.get_agent().write('STAF%3.3f' % (f,))
- startWavelength = property(_get_start, _set_start, None, "Sweep start wavelength")
- start = startWavelength
- def _get_stop(self):
- if self._get_xunit() == 0:
- raw = self.get_agent().ask('STPWL?')
- return PQ(float(raw), "nm")
- elif self._get_xunit() == 1:
- raw = self.get_agent().ask('STPF?')
- return PQ(float(raw), "THz")
- def _set_stop(self, wl):
- try:
- wl = get_quantity(wl, "nm")
- self.get_agent().write('STPWL%4.2f' % (wl,))
- except TypeError:
- f = get_quantity(wl, "THz")
- self.get_agent().write('STPF%3.3f' % (f,))
- stopWavelength = property(_get_stop, _set_stop, None, "Sweep stop wavelength")
- stop = stopWavelength
- def _get_RESCOR(self):
- stat = int(self.get_agent().ask('RESCOR?'))
- return stat
- def _set_RESCOR(self, state):
- self.get_agent().write("RESCOR %s" % state)
- self._cache["_rescor"] = int(self.get_agent().ask('RESCOR?'))
- rescor = property(_get_RESCOR, _set_RESCOR, None, "RESOLUNTION CORRECT: 0/1")
- def _get_X(self):
- xunt = int(self.get_agent().ask('XUNT?'))
- self._cache["_xunt"] = xunt
- if xunt == 0:
- return SCALE_WAVELENGTH
- elif xunt == 1:
- return SCALE_FREQUENCY
- def _set_X(self, scale):
- if scale not in (SCALE_WAVELENGTH , SCALE_FREQUENCY):
- raise InstrumentError, "invalid scale unit"
- self.get_agent().write('XUNT %d' % (scale,))
- self._cache["_xunt"] = int(self.get_agent().ask('XUNT?'))
- scaleX = property(_get_X, _set_X, None, "X scale units: SCALE_WAVELENGTH , SCALE_FREQUENCY")
- def _get_xunit(self):
- try:
- return self._cache["_xunt"]
- except KeyError:
- self._get_X()
- return self._cache["_xunt"]
- def _get_span(self):
- if self._get_xunit() == 0:
- raw = self.get_agent().ask('SPAN?')
- return PQ(float(raw), "nm")
- elif self._get_xunit() == 1:
- raw = self.get_agent().ask('SPANF?')
- return PQ(float(raw), "THz")
- def _set_span(self, span):
- try:
- span = get_quantity(span, "nm")
- assert float(span) <= 1200.0
- self.get_agent().write('SPAN%4.1f' % (span,))
- except TypeError:
- span = get_quantity(span, "THz")
- assert float(span) <= 350.0
- self.get_agent().write('SPANF%3.3f' % (span,))
- def _del_span(self, span):
- self.get_agent().write('SPAN0')
- span = property(_get_span, _set_span, _del_span, "scan span in nm")
- def _get_ref(self):
- raw = self.get_agent().ask('REFL?')
- if raw.startswith("PW"):
- return PQ(float(raw[2:]), "pW")
- elif raw.startswith("NW"):
- return PQ(float(raw[2:]), "nW")
- elif raw.startswith("UW"):
- return PQ(float(raw[2:]), "muW")
- elif raw.startswith("MW"):
- return PQ(float(raw[2:]), "mW")
- else:
- return PQ(float(raw), "dBm")
- def _set_ref(self, val):
- if type(val) is Enum and val == PEAK:
- self.get_agent().write('REF=P')
- return
- if type(val) is str:
- val = PhysicalQuantity(val)
- uname = val.unit.name()
- if uname == "dBm":
- self.get_agent().write('REFL%-4.1f' % (val,))
- elif uname == "pW":
- self.get_agent().write('REFLP%-4.1f' % (val,))
- elif uname == "nW":
- self.get_agent().write('REFLN%-4.1f' % (val,))
- elif uname == "muW":
- self.get_agent().write('REFLU%-4.1f' % (val,))
- elif uname == "mW":
- self.get_agent().write('REFLM%-4.1f' % (val,))
- else:
- raise ValueError, "invalid reference power"
- referenceLevel = property(_get_ref, _set_ref, None, "Reference level")
- reference = referenceLevel
- def _get_res(self):
- if self._get_xunit() == 0:
- raw = self.get_agent().ask('RESLN?')
- return PQ(float(raw), "nm")
- elif self._get_xunit() == 1:
- raw = self.get_agent().ask('RESLNF?')
- return PQ(float(raw), "GHz")
- def _set_res(self, res):
- if self._get_xunit() == 0:
- res = get_quantity(res, "nm")
- assert float(res) <= 2.0
- self.get_agent().write('RESLN%.2f' % (res._value,))
- elif self._get_xunit() == 1:
- res = get_quantity(res, "GHz")
- self.get_agent().write('RESLNF%.0f' % (res._value,))
- resolution = property(_get_res, _set_res, None, "resolution: 0.01 to 2.0 nm or 2 to 400 GHz")
- def _get_sampl(self):
- raw = self.get_agent().ask('SMPL?')
- return int(raw)
- def _set_sampl(self, val):
- val = int(val)
- assert val <= 200001 and val >= 11
- self.get_agent().write('SMPL%d' % (val,))
- def _del_sampl(self):
- self.get_agent().write('SMPL0')
- samplePoint = property(_get_sampl, _set_sampl, _del_sampl, "sampling point: 11 to 20001. delete to set auto")
- # markers and analysis
- def _set_lmarkerx(self, num, wl):
- wl = get_quantity(wl, "nm")
- self.get_agent().write("L%dMK%.3f" % (num, wl))
- def _get_lmarkerx(self, num):
- raw = self.get_agent().ask("L%dMK?" % (num,))
- if raw:
- return PhysicalQuantity(float(raw), "nm")
- else:
- return None
- linemarker1 = property(lambda s: s._get_lmarkerx(1),
- lambda s, v: s._set_lmarkerx(1, v), "Line marker 1 (left)")
- linemarker2 = property(lambda s: s._get_lmarkerx(2),
- lambda s, v: s._set_lmarkerx(2, v), "Line marker 2 (right)")
- def clear_linemarkers(self):
- self.get_agent().write("LMKCL")
- def _set_levmarkerx(self, num, dbm):
- dbm = get_quantity(dbm, "dBm")
- self.get_agent().write("L%dDBM%.2f" % (num, dbm))
- def _get_levmarkerx(self, num):
- raw = self.get_agent().ask("L%dMK?" % (num,))
- if raw:
- return PhysicalQuantity(float(raw), "dBm")
- else:
- return None
- levelmarker1 = property(lambda s: s._get_levmarkerx(3),
- lambda s, v: s._set_levmarkerx(3, v), "Level marker 1 (top)")
- levelmarker2 = property(lambda s: s._get_levmarkerx(4),
- lambda s, v: s._set_levmarkerx(4, v), "Level marker 2 (bottom)")
- def clear_markers(self):
- self.get_agent().write("MKCL")
- def _set_marker(self, wl):
- if type(wl) is Enum:
- if wl == CENTER:
- self.get_agent().write('CTR=M')
- elif wl == REFERENCE:
- self.get_agent().write('REF=M')
- return
- try:
- wl = get_quantity(wl, "nm")
- self.get_agent().write("WMKR%.3f" % (wl,))
- except TypeError:
- f = get_quantity(wl, "THz")
- self.get_agent().write("FMKR%.3f" % (f,))
- def _get_marker(self):
- raw = self.get_agent().ask("MKR?")
- if raw:
- rwl, rlev = raw.split(",", 1)
- xu = IF(self._get_xunit(), "THz", "nm")
- return PhysicalQuantity(float(rwl), xu), PhysicalQuantity(float(rlev), "dBm") # XXX level?
- else:
- return None, None
- marker = property(_get_marker, _set_marker, clear_markers, "Moving marker")
- # alternate method call interface for getting/setting markers by index number
- def set_marker(self, n, val):
- if n in (1,2):
- return self._set_lmarkerx(n, val)
- elif n in (3,4):
- return self._set_levmarkerx(n, val)
- def get_marker(self, n):
- if n in (1,2):
- return self._get_lmarkerx(n)
- elif n in (3,4):
- return self._get_levmarkerx(n)
- # using fixed markers
- def set_fixed_marker(self, n, wl=None):
- n = int(n)+4
- if wl is not None:
- self._set_marker(wl)
- self.get_agent().write("MKR%d" % (n,))
- def get_fixed_marker(self, n):
- n = int(n)+4
- raw = self.get_agent().ask("MKR?%d" % (n,))
- if raw:
- rwl, rlev = raw.split(",", 1)
- return (PhysicalQuantity(float(rwl), "nm"), PhysicalQuantity(float(rlev), "dBm"))
- else:
- return None
- def clear_fixed_marker(self, n):
- n = int(n)+4
- self.get_agent().write("MCLR%d" % (n,))
- def get_OSNR(self, wl=None):
- """Returns an OSNR of an individual channel."""
- if self._get_xunit() != 0:
- self.scaleX = SCALE_WAVELENGTH
- if wl is None:
- wl = self._get_center()
- else:
- self._set_center(wl)
- self._set_span("5.0 nm")
- self._set_res("1.0 nm")
- self._do_sweep()
- self.get_agent().write('CTR=P') # peak to center
- wl = self._get_center()
- self.set_fixed_marker(1, wl)
- self.set_fixed_marker(2, wl-PQ(1.5, "nm")) # XXX: 1.5 for DPSK
- self.set_fixed_marker(3, wl+PQ(1.5, "nm"))
- Ps = 10**(float(self.get_fixed_marker(1)[1])/10.0) # in mW
- nflow = 10.0**(float(self.get_fixed_marker(2)[1])/10.0) # in mW
- nfhi = 10.0**(float(self.get_fixed_marker(3)[1])/10.0) # in mW
- Pn = (nflow + nfhi)/2.0
- osnr = round((10.0*math.log10((Ps-Pn)/Pn) + 10.0), 3) #corr fact 10dB for 1.0nm res DPSK
- return PQ(osnr, "dB")
- OSNR = property(get_OSNR)
- def get_peak(self):
- # start peak search
- self.get_agent().write('PKSR')
- self.get_agent().write('CTR=P') # peak to center
- pwl = self._get_center()
- return pwl
- PEAK = property(get_peak)
- def get_avgOSNR(self, wllist):
- """Returns average and individual OSNR of multiple channels."""
- pwllist = []
- osnrdict = {}
- minwl = min(wllist)
- maxwl = max(wllist)
- cwl = avg(wllist)
- self._set_center(cwl)
- if self._get_xunit() != 0:
- self.scaleX = SCALE_WAVELENGTH
- if len(wllist) == 1: # for single wavelength
- self._set_span("5.0 nm")
- self._set_res("0.5 nm")
- self._do_sweep()
- self.get_agent().write('CTR=P') # peak to center
- pwl = self._get_center()
- pwllist.append(pwl)
- else: # for multiple wavelength
- span = (maxwl - minwl) + PQ(2.0, "nm") #adding margin of 2nm
- self._set_span(span)
- self._set_res("0.1 nm")
- self._do_sweep()
- self.get_agent().write('MKCL') # clear marker
- self.get_agent().write('PKSR') # start peak search
- self.set_fixed_marker(1, (minwl - PQ(0.5, "nm")))
- for wl in wllist:
- self.get_agent().write('NSRR') # next search
- pwl, plev = self.marker
- pwllist.append(pwl)
- self._set_res("0.5 nm")
- self._do_sweep()
- pwllist.sort()
- for wl, pwl in zip(wllist, pwllist):
- #print "wl %s, pwl %s" %(wl, pwl)
- self.set_fixed_marker(1, pwl)
- self.set_fixed_marker(2, pwl-PQ(0.75, "nm"))
- self.set_fixed_marker(3, pwl+PQ(0.75, "nm"))
- Ps = 10**(float(self.get_fixed_marker(1)[1])/10.0) # in mW
- nflow = 10.0**(float(self.get_fixed_marker(2)[1])/10.0) # in mW
- nfhi = 10.0**(float(self.get_fixed_marker(3)[1])/10.0) # in mW
- Pn = (nflow + nfhi)/2.0
- osnrdict[wl] = PQ(round((10.0*math.log10((Ps-Pn)/Pn) + 7.0), 3), "dB") #corr fact 7dB for 0.5nm res
- avgosnr = avg(osnrdict.values())
- return avgosnr, osnrdict
- def get_avgSigPwr(self, wllist):
- """Returns average and individual signal power of multiple channels."""
- pwllist = []
- plevdict = {}
- osnrdict = {}
- minwl = min(wllist)
- maxwl = max(wllist)
- cwl = avg(wllist)
- self._set_center(cwl)
- if self._get_xunit() != 0:
- self.scaleX = SCALE_WAVELENGTH
- if len(wllist) == 1: # for single wavelength
- self._set_span("5.0 nm")
- self._set_res("0.5 nm")
- self._do_sweep()
- self.get_agent().write('CTR=P') # peak to center
- pwl = self._get_center()
- pwllist.append(pwl)
- else: # for multiple wavelength
- span = (maxwl - minwl) + PQ(2.0, "nm") #adding margin of 2nm
- self._set_span(span)
- self._set_res("0.1 nm")
- self._do_sweep()
- self.get_agent().write('MKCL') # clear marker
- self.get_agent().write('PKSR') # start peak search
- self.referenceLevel = PEAK #set REFLEV to PEAK
- self.set_fixed_marker(1, (minwl - PQ(1.0, "nm")))
- for wl in wllist:
- self.get_agent().write('NSRR') # next search
- pwl, plev = self.marker
- plevdict[wl] = plev
- pwllist.append(pwl)
- self._set_res("0.5 nm")
- pwllist.sort()
- for wl, pwl in zip(wllist, pwllist):
- print "wl %s, pwl %s, plev %s" %(wl, pwl, plevdict[wl])
- avgplev = avg(plevdict.values())
- if len(wllist) == 1:
- return avgplev
- return avgplev, plevdict
- def get_spectralwidth(self, xunit=None, bw=None, wl=None):
- if self._get_xunit() != 0:
- self.scaleX = SCALE_WAVELENGTH
- if wl is None:
- wl = self.center
- else:
- self.center = wl
- self.span = "5.0 nm"
- self.resolution = "0.02 nm"
- if xunit is None:
- self.scaleX = SCALE_WAVELENGTH
- else:
- self.scaleX = SCALE_FREQUENCY
- self.sweep = SWEEP_SINGLE
- sleep(10)
- self.get_agent().write('SW0') #envelope
- if bw is None:
- self.get_agent().write('SWENV%.2f' %(3.0,)) # 3dB bandwidth
- else:
- self.get_agent().write('SWENV%.2f' %(float(bw),)) #
- sleep(2)
- raw = self.get_agent().ask("ANA?") # analysis functionality
- self.scaleX = SCALE_WAVELENGTH # default state
- self.sweep = SWEEP_CONTINUOUS
- if raw:
- rlist = raw.split(",")
- #print "rlist %s" %rlist
- wl, sw = rlist[0], rlist[1]
- #print "wl %s, bw %s" %(wl, sw)
- if xunit is None:
- unit = "nm"
- else:
- unit = xunit
- return PQ(float(wl), unit), PQ(float(sw), unit)
- else:
- return None
- spectralwidth = property(get_spectralwidth)
- # tracing operations...
- def _get_trc(self, abc, wl=None):
- if self._get_xunit() != 0:
- self.scaleX = SCALE_WAVELENGTH
- if wl is None:
- wl = self.center
- else:
- self.center = wl
- self.span = "2.5 nm"
- self.resolution = "0.01 nm"
- self.sweep = SWEEP_SINGLE
- sleep(10)
- levels = self.get_agent().ask("LDAT%s" % (abc,))
- wavelengths = self.get_agent().ask("WDAT%s" % (abc,))
- self.sweep = SWEEP_CONTINUOUS
- levels = levels.split(",")
- wavelengths = wavelengths.split(",")
- data = []
- for wl, level in zip(wavelengths, levels):
- data.append((float(wl), float(level)))
- # sanity checks...
- len_levels = int(levels[0]) ; len_wavelengths = int(wavelengths[0])
- assert len_levels == len_wavelengths
- levels.pop(0) ; wavelengths.pop(0)
- assert len_levels == len(levels)
- assert len_wavelengths == len(wavelengths)
- return Graph(map(float, wavelengths), "nm", map(float, levels), "dBm", "AQ6317B trace%s" % (abc,)), data
- traceA = property(lambda s: s._get_trc("A"), None, None, "trace A waveform Graph.")
- traceB = property(lambda s: s._get_trc("B"), None, None, "trace B waveform Graph.")
- traceC = property(lambda s: s._get_trc("C"), None, None, "trace C waveform Graph.")
- waveform = traceA # alias
- class AQ6370(AQ6317B):
- """ just inherit and hope for the best """
- pass
- class GP700(Instrument):#InstrumentChasiss):
- #class GP700(Instrument):
- """ dicon GP700 Optical SW """
- _SWITCHMAP = {
- -700 : 2,
- -50 : 3,
- 50 : 4,
- 700 : 5,
- 0 : 1,
- }
- _INVERSEMAP = dict(map(lambda t: (t[1], t[0]), _SWITCHMAP.items()))
- def _get_sys_conf(self):
- """
- Queries the switch configuration of the instrument, returns dictionary
- """
- dev = {}
- a = self.get_agent()
- cmd = 'SYST:CONF?'
- val = a.ask(cmd)
- devices = val.split(',')
- for device in devices:
- info = device.lstrip().split(' ')
- if len(info) == 1:
- dev[info[0]] = None
- elif len(info) == 2:
- dev[info[0]] = info[1]
- elif len(info) == 3:
- key = info[0][0] + info[0][2]
- dev[key] = info[1] + ' ' + info[2]
- else:
- dev[device[0]] = None
-
- return dev
- def _set_switch(self, sw_type, output, input=None):
- # first verify is the the host have the module type plugged in
- sys_config = self._get_sys_conf()
- assert sys_config.has_key(sw_type), "Invalid SW type"
- maxchan = sys_config[sw_type]
- if maxchan.startswith('MAX'):
- max_chan = int(maxchan.split('MAXCHAN')[1])
- if int(output) > max_chan:
- print "Output :%s setting is greater than max of %d" % (output,
- max_chan)
- return False
- cmd = "%s %s" % (sw_type, output)
- #print "Setting %s to output %s..." % (sw_type, output)
- a = self.get_agent()
- a.write(cmd)
- sw_status = a.ask("%s?" % sw_type)
- try:
- sw_state = sw_status.split(',')[0]
- except:
- sw_state = sw_status
- #print "switch %s is in state: %s" % (sw_type, sw_state)
- if eval(sw_state) == output:
- return True
- else:
- return False
- # P1 port1/2 S1/2/3):
- def set_switch(self, mod_type, output, sw_num=None):
- """
- generic switch interface
- mod_type: "M" or "P", follow by the slot number
- sw_num: The switch within the module
- output: The port to which the signal is routed.
- """
- if type(mod_type) is int:
- # for backward compatiblity this takes the form:
- # set_switch(6, 'cnt') mod_type is actually the switch number,
- # output is actually the state, 'byp' or 'cnt'
- if (output == 'cnt'):
- sw_pos = 0
- else:
- sw_pos = 1
- output = mod_type
- self._set_switch('M1', sw_pos)
- self._set_switch('M2', sw_pos)
- else:
- if mod_type.startswith('M'):
- # for M type module, setting the output is simple
- self._set_switch(mod_type, output)
- else: # a P type module.
- # step 1: get the current sw_val to write to.
- current_sw_val = int(self.get_switch(mod_type))
- # step 2: do math translate sw val
- new_sw_val = get_new_val(sw_num, output, current_sw_val)
- self._set_switch(mod_type, new_sw_val)
- def get_switch(self, sw_type):
- a = self.get_agent()
- return a.ask("%s?" % sw_type)
- def set_4x1_switch_output(self, p_num, input_num):
- """
- We make a 4x1 switch by using 3 2x1 switch. We impose that the switch
- must be configured as follow:
- 1 --\
- P2 }---\
- 2 --/ --\
- P1 }----
- 3 --\ --/
- P3 }---/
- 4 --/
- p_num is the name of the P-module within the DiCon chassis
- input_num is the input that the we want to connect to the output of the
- 4x1 switch (Px:1)
- """
- if (input_num % 4) == 1: #
- # do necessary setup to have output = input#1
- print "Input is SW #1"
- self.set_switch(p_num, 1, 1)
- self.set_switch(p_num, 1, 2)
- elif (input_num % 4) == 2:
- # do necessary setup to have output = input#2
- print "Input is SW #2"
- self.set_switch(p_num, 1, 1)
- self.set_switch(p_num, 2, 2)
- elif (input_num % 4) == 3:
- # do necessary setup to have output = input#3
- print "Input is SW #3"
- self.set_switch(p_num, 2, 1)
- self.set_switch(p_num, 1, 3)
- else: # input_num is 4
- print "Input is SW #4"
- self.set_switch(p_num, 2, 1)
- self.set_switch(p_num, 2, 3)
- dBox = property(lambda self: self)
-
- # dispersion mapping for Dicon M modules (8x1) to emulate in-house ProgCD
- """
- 2 : -700
- 3 : -50
- 4 : 50
- 5 : 700
- 1 : 0
- """
- def _get_dispersion(self):
- res = self.get_switch('M1')
- sw_pos = int(res.split(',')[0])
- dispersion = self._INVERSEMAP[sw_pos]
- return dispersion
- def _set_dispersion(self, disp):
- sw_pos = self._SWITCHMAP[disp]
- self._set_switch('M1', sw_pos)
- self._set_switch('M2', sw_pos)
- dispersion = property(_get_dispersion, _set_dispersion, None, "Dispersion value")
- # efficient storage of graphs with units. Iterator over datapoints, indexing
- # returns physcial values.
- class Graph(object):
- def __init__(self, xinit, xunit, yinit, yunit, title=None):
- import array
- self._xunit = xunit
- self._yunit = yunit
- self._x = array.array("d", xinit)
- self._y = array.array("d", yinit)
- self._i = 0
- self.title = title or self.__class__.__name__
- def __str__(self):
- return "%s with %d datapoints, X unit is %r, Y unit is %r )" \
- % (self.title, len(self._x), self._xunit, self._yunit)
- def plot(self, ui):
- winx, winy = ui.winsize
- ui.Print(self.title)
- miny = min(self._y)
- maxy = max(self._y)
- maxx = max(self._x)
- minx = min(self._x)
- ui.Print("X range (%s, %s), Y range (%s, %s)." % (minx, maxx, miny, maxy))
- sx = max(1, int(len(self._x)/(winy-3)))
- sy = (winx-9)/max(1, (maxy-miny))
- for i in range(0, len(self._x), sx):
- x = self._x[i]
- py = int((self._y[i]-miny)*sy)
- ui.Print("%04.2f:%s+" % (x, " "*py))
- ui.Print(" %04.2f%s%04.2f" % (miny, " "*(winx-22), maxy))
- def __getitem__(self, idx):
- return PQ(self._x[idx], self._xunit), PQ(self._y[idx], self._yunit)
- def __iter__(self):
- self._i = 0
- return self
- def __len__(self):
- return len(self._x)
- def next(self):
- try:
- x = self._x[self._i]
- y = self._y[self._i]
- except IndexError:
- raise StopIteration
- self._i += 1
- return x, y
- xunit = property(lambda s: s._xunit)
- yunit = property(lambda s: s._yunit)
- # convert a PhysicalQuantity (as object or string) to given unit value.
- def get_quantity(obj, unit):
- if type(obj) is str:
- obj = PhysicalQuantity(obj)
- return obj.inUnitsOf(unit)
- # Instrument control objects
- class Marker(object):
- """Generic marker for sweeping instruments."""
- def __init__(self, number, value=None):
- self.number = int(number)
- self.value = value
- def __str__(self):
- return "Marker %d: %s" % (self.number, self.value)
- def __int__(self):
- return self.number
- class Modulation(object):
- """Holds modulation parameters for general use. """
- def __init__(self, mtype, freq, amplitude=None, bandwidth=None, source=INT, lasersource=LASER_LOWER):
- self.modtype = mtype
- self.frequency = PhysicalQuantity(SCPIFloat(freq), "Hz")
- self.amplitude = amplitude
- self.bandwidth = bandwidth
- self.source = source
- self.lasersource = lasersource
- def __str__(self):
- if self.modtype == AM:
- return "Modulation: %s freq:%s amp:%s" % (self.modtype, self.frequency, self.amplitude)
- elif self.modtype == FM:
- return "Modulation: %s freq:%s bw:%s" % (self.modtype, self.frequency, self.bandwidth)
- else:
- return "Modulation: %s freq:%s amp:%s bw:%s" % (self.modtype, self.frequency, self.amplitude, self.bandwidth)
- class BitField(object):
- """
- This class allow user to mainipulate each bit field individually
- """
- def __init__(self,value=0):
- self._d = value
- def __getitem__(self, index):
- return (self._d >> index) & 1
- def __setitem__(self,index,value):
- value = (value&1L)<<index
- mask = (1L)<<index
- self._d = (self._d & ~mask) | value
- def __getslice__(self, start, end):
- mask = 2L**(end - start) -1
- return (self._d >> start) & mask
- def __setslice__(self, start, end, value):
- mask = 2L**(end - start) -1
- value = (value & mask) << start
- mask = mask << start
- self._d = (self._d & ~mask) | value
- return (self._d >> start) & mask
- def __int__(self):
- return self._d
- def get_new_val(sw_num, port, sw_val):
- k = BitField()
- h = BitField()
- k[0:3] = sw_val - 1
- h[0:3] = sw_val - 1
- bo = int(k)
- #h[sw_num-1] = port
- h[sw_num-1] = port - 1
- # new value
- new_sw_val = int(h) + 1
- #print "%d, %d, %d %d %d %d %d %d \t%d" % (port, sw_val, k[2], k[1],
- # k[0], h[2], h[1], h[0], bn)
- return new_sw_val
- # scans the VISA instrument list and updates the devstorage with Instrument objects.
- def update_instruments(devstorage, gpib_name=None, iostream=sys.stderr):
- #def update_instruments(devstorage, iostream=sys.stderr):
- rv = []
- insts = visa.get_instruments_list(False)
- if gpib_name is None:
- print "Scanning the entire GPIB network..."
- else:
- insts = filter(lambda names: names.startswith(gpib_name), insts)
- if len(insts) == 0:
- print "Can't find specified GPIB resource %s, scanning the entire GPIB network..." % gpib_name
- insts = visa.get_instruments_list(False)
- for addr in insts:
- try:
- iostream.write("Trying: %s\n" % (addr,)) ; iostream.flush()
- inst = visa.instrument(addr)
- inst.write("*IDN?")
- raw = inst.read()
- except visa_exceptions.VisaIOError:
- iostream.write("Warning: could not connect to %r.\n" % addr)
- continue
- if raw:
- try:
- [manufacturer, model, serial, firmware] = raw.split(",", 3)
- model = model.replace(" ", "")
- cls = get_class(model)
- if cls is None:
- iostream.write("Warning: No instrument object for model %r.\n" % model)
- continue
- #print "--- calling _add_inst() "
- name = _add_inst(devstorage, cls, addr, model, serial)
- if name:
- iostream.write("Added: %s\n" % (name,)) ; iostream.flush()
- rv.append(name)
- except ValueError:
- pass
- return rv
- def _add_inst(d, cls, name, model, serial):
- visa_resource = name
- rsrc = GPIBResource()
- rsrc.parse(name)
- name = "%s_gpib%s_%s" % (model, rsrc.board, rsrc.address)
- inst = cls(name=name)
- inst.visa_resource = visa_resource
- #print "updating inst: %s" % inst
- inst.update()
- #print "inst: %s" % inst.name
- print "updating devices..."
- if model == 'MAP':
- modules = inst.get_slots()
- for index in range(len(modules)):
- inst = modules[index][1]
- inst.slot_addr = modules[index][0]
- name = 'IA3_gpib%s_%s_slot%s' % (rsrc.board, rsrc.address, inst.slot_addr)
- if inst.modelNumber == 'MAPA+2370100FA':
- print 'Add %s' % name
- d[name] = inst
- else:
- namePort1 = "%s_port1" % name
- print 'Add %s' % namePort1
- d[namePort1] = inst
- newInst = copy(inst)
- newInst.device_addr = 2
- name = "%s_port2" % name
- print 'Add %s' % name
- d[name] = newInst
- else:
- d[name] = inst
- #print "***************"
- print d[name]
- #self.info("xxx", 1)
- return name
- # return an Instrument subclass for the model name. Return None if not found.
- def get_class(model):
- for clsname in __all__:
- if clsname.find(model) >= 0:
- return getattr(sys.modules[__name__], clsname)
- return None
- def get_devices():
- """Return available device types in a list. """
- return [ c for c in vars(sys.modules[__name__]).values() \
- if type(c) is type(object) \
- and issubclass(c, Instrument) \
- and not c.__name__.startswith("_")]
- def clear_controller(resource):
- rsrc = GPIBResource()
- rsrc.parse(resource)
- visa.Gpib(rsrc.board).send_ifc()
- def _test(argv):
- addr = 'GPIB13::19'
- inst = visa.instrument(addr)
- cmd = '*IDN?'
- val = inst.ask(cmd)
- #print "IDN: %s" % val
- inst.update()
- if __name__ == "__main__":
- _test(sys.argv)