Пример #1
0
    def __init__(self, name='Unnamed Host', hostname=None, **kwargs):
        if hostname is None:
            logger.warning("Hostname not set. isLive and list_resources not functional.")

        self.hostname = hostname
        self.name = name
        super().__init__(**kwargs)
Пример #2
0
    def isLive(self):
        """ Attempts VISA connection to instrument, and checks whether
            :meth:`~lightlab.equipment.visa_bases.visa_object.instrID`
            matches :data:`id_string`.

            Produces a warning if it is live but the id_string is wrong.

            Returns:
                (bool): True if "live", False otherwise.
        """
        try:
            driver = self.driver_object
            query_id = driver.instrID()
            logger.info("Found %s in %s.", self.name, self.address)
            if self.id_string is not None:
                if self.id_string == query_id:
                    logger.info("id_string of %s is accurate", self.name)
                    return True
                else:
                    logger.warning("%s: %s, expected %s", self.address,
                                   query_id, self.id_string)
                    return False
            else:
                logger.debug("Cannot authenticate %s in %s.",
                             self.name, self.address)
                return True
        except pyvisa.VisaIOError as err:
            logger.warning(err)
            return False
Пример #3
0
 def __init__(self, real_obj=None, virt_obj=None):
     '''
         Args:
             real_obj (Instrument): the real reference
             virt_obj (VirtualInstrument): the virtual reference
     '''
     self.real_obj = real_obj
     self.virt_obj = virt_obj
     if real_obj is not None and virt_obj is not None:
         violated = []
         allowed = real_obj.essentialMethods + \
             real_obj.essentialProperties + dir(VirtualInstrument)
         for attr in dir(type(virt_obj)):
             if attr not in allowed \
                     and '__' not in attr:
                 violated.append(attr)
         if len(violated) > 0:
             logger.warning('Virtual instrument ({}) violates '.format(
                 type(virt_obj).__name__) +
                            'interface of the real one ({})'.format(
                                type(real_obj).__name__))
             logger.warning('Got: ' + ', '.join(violated))  # pylint: disable=logging-not-lazy
             # logger.warning('Allowed: ' + ', '.join(filter(lambda x: '__' not in x, allowed)))
     self.synced = []
     super().__init__()
Пример #4
0
    def frequency(self, freq=None):
        ''' Frequency is in Hertz

            **Setting the frequency takes you out of sweep mode automatically**

            Args:
                freq (float): If None, only gets

            Returns:
                (float): center frequency
        '''
        if freq is not None:
            if freq > 40e9:
                logger.warning(
                    'Agilent N5183 ony goes up to 40GHz, given %s GHz.',
                    freq / 1e9)
                freq = 40e9
            if self.sweepEnable():
                logger.warning(
                    'Agilent N5183 was sweeping when you set frequency, moving to CW mode'
                )
            self.setConfigParam(
                'FREQ:CW',
                freq)  # Setting this automatically brings to CW mode
            # So we need to update this object's internal state too
            self.sweepEnable(False)
        return self.getConfigParam('FREQ:CW')
Пример #5
0
 def check_if_port_is_not_connected(connection, k1, v1):
     for k2, v2 in connection.items():
         if (k1, v1) == (k2, v2):
             logger.warning("Deleting existing connection %s.",
                            connection)
             return False
     return True
Пример #6
0
 def measVoltage(self):
     retStr = self.query('MEASURE:VOLT?')
     v = float(retStr.split(',')[0])  # first number is voltage always
     if v >= self.protectionVoltage:
         logger.warning('Keithley compliance voltage of %s reached',
                        self.protectionVoltage)
         logger.warning('You are sourcing %smW into the load.',
                        v * self._latestCurrentVal * 1e-3)
     return v
Пример #7
0
 def __init__(self, name='The laser source', address=None, useChans=None, **kwargs):
     kwargs['tempSess'] = kwargs.pop('tempSess', False)
     if 'dfbChans' in kwargs.keys():
         useChans = kwargs.pop('dfbChans')
     if useChans is None:
         logger.warning('No useChans specified for ILX_7900B_LS')
         useChans = list()
     VISAInstrumentDriver.__init__(self, name=name, address=address, **kwargs)
     MultiModuleConfigurable.__init__(self, useChans=useChans, configModule_klass=ILX_Module)
Пример #8
0
 def measCurrent(self):
     retStr = self.query('MEASURE:CURR?')
     i = float(retStr.split(',')[1])  # second number is current always
     if i >= self.protectionCurrent:
         logger.warning('Keithley compliance current of %s reached',
                        self.protectionCurrent)
         logger.warning('You are sourcing %smW into the load.',
                        i * self._latestVoltageVal * 1e-3)
     return i
Пример #9
0
    def updateConnections(self, *connections):
        """ Updates connections between instruments and devices.

        A connection is a tuple with a pair of one-entry dictionaries, as such:

        .. code-block:: python

            conn = ({instr1: port1}, {instr2: port2})

        The code assumes that there can only be one connection per port.
        This method performs the following action:

            1. verifies that `port` is one of `instr.ports`. Otherwise raises
                a ``RuntimeError``.
            2. deletes any connection in ``lab.connections`` that has
                either ``{instr1: port1}`` or ``{instr1: port1}``, and
                logs the deleted connection as a warning.
            3. adds new connection

        Args:
            connections (tuple(dict)): connection to update
        """

        # Verify if ports are valid, otherwise do nothing.
        for connection in connections:
            for k1, v1 in connection.items():
                if v1 not in k1.ports:
                    logger.error("Port '%s' is not in '%s: %s'", v1, k1,
                                 k1.ports)
                    raise RuntimeError("Port '{}' is not in '{}: {}'".format(
                        v1, k1, k1.ports))

        # Remove old conflicting connections
        def check_if_port_is_not_connected(connection, k1, v1):
            for k2, v2 in connection.items():
                if (k1, v1) == (k2, v2):
                    logger.warning("Deleting existing connection %s.",
                                   connection)
                    return False
            return True

        for connection in connections:
            for k1, v1 in connection.items():
                connectioncheck2 = lambda connection: check_if_port_is_not_connected(
                    connection, k1, v1)
                self.connections[:] = [
                    x for x in self.connections if connectioncheck2(x)
                ]

        # Add new connections
        for connection in connections:
            if connection not in self.connections:
                self.connections.append(connection)
            else:
                logger.warning("Connection already exists: %s", connection)
        return True
Пример #10
0
 def measCurrent(self):
     retStr = self.query_print(
         "{smuX}.measure.i()".format(smuX=self.smu_full_string))
     i = float(retStr)  # second number is current always
     if self.compliance:
         logger.warning('Keithley compliance current of %s reached',
                        self.protectionCurrent)
         logger.warning('You are sourcing %smW into the load.',
                        i * self._latestVoltageVal * 1e-3)
     return i
Пример #11
0
 def measVoltage(self):
     retStr = self.query_print(
         "{smuX}.measure.v()".format(smuX=self.smu_full_string))
     v = float(retStr)
     if self.compliance:
         logger.warning('Keithley compliance voltage of %s reached',
                        self.protectionVoltage)
         logger.warning('You are sourcing %smW into the load.',
                        v * self._latestCurrentVal * 1e-3)
     return v
Пример #12
0
    def driver_class(self):
        """ Class of the actual equipment driver
        (from :mod:`lightlab.equipment.lab_instruments`)

        This way the object knows how to instantiate a driver instance
        from the labstate.
        """
        if self._driver_class is None:
            logger.warning("Using default driver for %s.", self)
            return DefaultDriver
        else:
            return self._driver_class
Пример #13
0
 def isLive(self):
     ''' Pings the system and returns if it is alive.
     '''
     if self.hostname is not None:
         logger.debug("Pinging %s...", self.hostname)
         response = os.system("ping -c 1 {}".format(self.hostname))
         if response != 0:
             logger.warning("%s is not reachable via ping.", self)
         return response == 0
     else:
         logger.warning("Hostname not set. Unable to ping.")
         return False
Пример #14
0
    def __init__(self, useChans=None, **kwargs):
        if useChans is None:
            logger.warning('No useChans specified for MultichannelSource')
            useChans = list()
        self.useChans = useChans
        self.stateDict = dict([ch, 0] for ch in self.useChans)

        # Check that the requested channels are available to be blocked out
        if self.maxChannel is not None:
            if any(ch > self.maxChannel - 1 for ch in self.useChans):
                raise ChannelError(
                    'Requested channel is more than there are available')
        super().__init__(**kwargs)
Пример #15
0
    def removeInstrument(self, *instruments):
        r""" Disconnects the instrument from the host

        Args:
            \*instruments (Instrument): instruments

        Todo:
            Remove all connections
        """
        for instrument in instruments:
            if type(instrument) is str:
                logger.warning('Cannot remove by name string. Use the object')
            instrument.host = None
Пример #16
0
    def saveState(self, fname=None, save_backup=True):
        """ Saves the current lab, together with all its dependencies,
        to a JSON file.

        But first, it checks whether the file has the same hash as the
        previously loaded one. If file is not found, skip this check.

        If the labstate was created from scratch, save with ``_saveState()``.

        Args:
            fname (str or Path): file path to save
            save_backup (bool): saves a backup just in case, defaults to True.

        Raises:
            OSError: if there is any problem saving the file.
        """
        if fname is None:
            fname = self.filename
        try:
            loaded_lab = LabState.loadState(fname)
        except FileNotFoundError:
            logger.debug("File not found: %s. Saving for the first time.",
                         fname)
            self._saveState(fname, save_backup=False)
            return
        except JSONDecodeError:
            if os.stat(fname).st_size == 0:
                logger.warning("%s is empty. Saving for the first time.",
                               _filename)
                self._saveState(fname, save_backup=False)
                return
            else:
                raise

        if not self.__sha256__:
            logger.debug(
                "Attempting to compare fabricated labstate vs. preloaded one.")
            self.__sha256__ = self.__toJSON()["__sha256__"]
            logger.debug("self.__sha256__: %s", self.__sha256__)

        if loaded_lab == self:
            logger.debug("Detected no changes in labstate. Nothing to do.")
            return

        if loaded_lab.__sha256__ == self.__sha256__:
            self._saveState(fname, save_backup)
        else:
            logger.error(
                "%s's hash does not match with the one loaded in memory. Aborting save.",
                fname)
Пример #17
0
        def instrument_hooked(instrument=instrument, host=host, bench=bench):
            and_expr = True
            if host is not None:
                expr = (instrument in host)
                if not expr:
                    logger.warning("{} not in {} %s", (instrument, host))
                and_expr = and_expr and expr

            if bench is not None:
                expr = (instrument in bench)
                if not expr:
                    logger.warning("{} not in {} %s", (instrument, bench))
                and_expr = and_expr and expr
            return and_expr
Пример #18
0
    def insertDevice(self, device):
        """ Inserts device in labstate.

        Args:
            device (Device): device to insert.

        Raises:
            RuntimeError: Raised if duplicate names are found.
            TypeError: Raised if device is not of type :class:`~lightlab.laboratory.instruments.bases.Device`

        """
        self.devices.append(device)
        if device.bench and device.bench not in self.benches:
            logger.warning(f"Insterting *new* bench {device.bench.name}")
            self.benches.append(device.bench)
Пример #19
0
    def registerConnections(self, *connections):
        for connection in connections:
            if connection not in self.connections:
                self.connections.append(connection)
            else:
                logger.warning("Connection already exists: %s", connection)

            def connection_present(connection=connection,
                                   connections=self.lab.connections):
                if connection in connections:
                    return True
                else:
                    logger.error("Connection {} is not compatible with lab %s",
                                 connection)
                    return False

            self.validate_exprs.append(connection_present)
Пример #20
0
    def powers(self, newPowers):
        ''' Laser powers. Provides range check.

            Args:
                newPowers (list, np.ndarray): power in dBm
        '''
        for iCh, level in enumerate(newPowers):
            if level < self.powerRange[0]:
                logger.warning('Power out of range was constrained:\n' +
                               'Requested: {:.2f}dBm '.format(level) +
                               'Minimum: {:.2f}dBm.'.format(self.powerRange[0]))
                newPowers[iCh] = self.powerRange[0]
            if level > self.powerRange[1]:
                logger.warning('Power out of range was constrained:\n' +
                               'Requested: {:.2f}dBm '.format(level) +
                               'Maximum: {:.2f}dBm.'.format(self.powerRange[1]))
                newPowers[iCh] = self.powerRange[1]
        self.setConfigArray('LEVEL', newPowers)
Пример #21
0
    def insertInstrument(self, instrument):
        """ Inserts instrument in labstate.

        Args:
            instrument (Instrument): instrument
                to insert.
        Raises:
            RuntimeError: Raised if duplicate names are found.
            TypeError: Raised if instrument is not of type :class:`~lightlab.laboratory.instruments.bases.Instrument`

        """
        self.instruments.append(instrument)
        if instrument.bench and instrument.bench not in self.benches:
            logger.warning(f"Insterting *new* bench {instrument.bench.name}")
            self.benches.append(instrument.bench)
        if instrument.host and instrument.host not in self.hosts:
            logger.warning(f"Inserting *new* host {instrument.host.name}")
            self.hosts.append(instrument.host)
Пример #22
0
    def setPlotOptions(self, **kwargs):
        ''' Valid options for NdSweeper
                * plType
                * xKey
                * yKey
                * axArr
                * cmap-surf
                * cmap-curves

            Valid options for CommandControlSweeper
                * plType
        '''
        for k, v in kwargs.items():
            if k not in self.plotOptions.keys():
                logger.warning(k, '%s is not a valid plot option.')
                logger.warning('Valid ones are %s', self.plotOptions.keys())
            else:
                self.plotOptions[k] = v
        return self.plotOptions
Пример #23
0
def init_module(module):
    # do something that imports this module again
    empty_lab = False
    try:
        module.lab = module.LabState.loadState(_filename)
    except (OSError) as e:
        logger.error("%s: %s.", e.__class__.__name__, e)
        empty_lab = True
    except JSONDecodeError as e:
        if os.stat(_filename).st_size == 0:
            logger.warning("%s is empty.", _filename)
        else:
            logger.error("%s: %s is corrupted. %s.", e.__class__.__name__, _filename, e)
        empty_lab = True

    if empty_lab:
        logger.warning("Starting fresh new LabState(). "
                       "Save for the first time with lab._saveState()")
        module.lab = module.LabState()
Пример #24
0
    def wls(self, newWls):
        ''' Laser wavelengths. Provides range check.

            Args:
                newWls (list, np.ndarray): wavelengths in nanometers
        '''
        for iCh, wl in enumerate(newWls):
            wlRanges = self.wlRanges[iCh]
            if wl < wlRanges[0]:
                logger.warning('Wavelength out of range was constrained:\n' +
                               'Requested: {:.2f}nm '.format(wl) +
                               'Minimum: {:.2f}nm.'.format(wlRanges[0]))
                newWls[iCh] = wlRanges[0]
            if wl > wlRanges[1]:
                logger.warning('Wavelength out of range was constrained:\n' +
                               'Requested: {:.2f}nm '.format(wl) +
                               'Maximum: {:.2f}nm.'.format(wlRanges[1]))
                newWls[iCh] = wlRanges[1]
        self.setConfigArray('WAVE', newWls)
Пример #25
0
    def _triggerAcquire(self, timeout=None):
        ''' Sends a signal to the scope to wait for a trigger event.
            Waits until acquisition completes or timeout (in seconds).

            If timeout is very long, it will try a test first
        '''
        if timeout is None:
            timeout = self.timeout / 1e3
        if timeout > 60:
            logger.warning(f'Long timeout {timeout} specified, testing')
            old_avgCnt = self.timebaseConfig()['avgCnt']
            self.timebaseConfig(avgCnt=2)
            self._triggerAcquire(timeout=10)
            logger.warning('Test succeeded. Doing long average now')
            self.timebaseConfig(avgCnt=old_avgCnt)
        if self._clearBeforeAcquire:
            self.write('ACQUIRE:DATA:CLEAR')  # clear out average history
        self.write('ACQUIRE:STATE 1')  # activate the trigger listener
        # Bus and entire program stall until acquisition completes. Maximum of 30 seconds
        self.wait(int(timeout * 1e3))
Пример #26
0
 def enforceRange(cls, val, mode):
     ''' Returns clipped value. Raises RangeError
     '''
     bnds = [cls.baseUnit2val(vBnd, mode) for vBnd in cls.baseUnitBounds]
     enforcedValue = np.clip(val, *bnds)
     if enforcedValue != val:
         logger.warning(
             'Warning: value out of range was constrained.\n'
             'Requested %s.'
             'Allowed range is %s in %s s.', val, bnds, mode)
         if cls.exceptOnRangeError:
             if val < min(bnds):
                 violation_direction = 'low'
             elif val > max(bnds):
                 violation_direction = 'high'
             else:
                 violation_direction = None
             raise RangeError('Current sources requested out of range.',
                              violation_direction)
     return enforcedValue
Пример #27
0
    def _reparse(self, parseKeys=None):
        ''' Reprocess measured data into parsed data.
            If there is not enough data present, it does nothing.
            If the parser depends on

            Args:
                parseKeys (tuple, str, None): which parsers to recalculate. If None, does all.
                    Execution order depends on addParser calls, not parseKeys

            Returns:
                None
        '''
        if self.data is None:
            return
        if parseKeys is None:
            parseKeys = tuple(self.parse.keys())
        else:
            parseKeys = argFlatten(parseKeys, typs=tuple)

        for pk, pFun in self.parse.items(
        ):  # We're indexing this way to make sure parsing is done in the order of parse attribute, not the order of parseKeys
            if pk not in parseKeys:
                continue
            tempDataMat = np.zeros(self.swpShape)
            for index in np.ndindex(self.swpShape):
                dataOfPt = OrderedDict()
                for datKey, datVal in self.data.items():
                    if np.any(datVal.shape != self.swpShape):
                        logger.warning(
                            'Data member %s is wrong size for reparsing %s. Skipping.',
                            datKey, pk)
                    else:
                        dataOfPt[datKey] = datVal[index]
                try:
                    tempDataMat[index] = pFun(dataOfPt)
                except KeyError:
                    logger.warning(
                        'Parser %s depends on unpresent data. Skipping.', pk)
                    break
            else:
                self.data[pk] = tempDataMat
Пример #28
0
    def __getstate__(self):
        '''
        This method removes all variables in ``notPickled`` during
        serialization.
        '''
        state = super().__getstate__()
        allNotPickled = self.notPickled
        for base in type(self).mro():
            try:
                theirNotPickled = base.notPickled
                allNotPickled = allNotPickled.union(theirNotPickled)
            except AttributeError:
                pass

        keys_to_delete = set()
        for key, val in state.copy().items():
            if isinstance(key, str):

                # 1. explicit removals
                if key in allNotPickled:
                    keys_to_delete.add(key)

                # 2. hardware placeholders
                elif (val.__class__.__name__ == 'VISAObject'
                      or any(base.__name__ == 'VISAObject'
                             for base in val.__class__.mro())):
                    klassname = val.__class__.__name__
                    logger.warning('Not pickling %s = %s.', key, klassname)
                    state[key] = HardwareReference('Reference to a ' +
                                                   klassname)

                # 3. functions that are not available in modules - saves the code text
                elif jsonpickle.util.is_function(
                        val) and not jsonpickle.util.is_module_function(val):
                    state[key + '_dilled'] = dill.dumps(val)
                    keys_to_delete.add(key)

                # 4. double underscore attributes have already been removed
        for key in keys_to_delete:
            del state[key]
        return state
Пример #29
0
    def setMonitorOptions(self, **kwargs):
        ''' Valid options for NdSweeper
                * livePlot
                * plotEvery
                * stdoutPrint
                * runServer

            Valid options for CommandControlSweeper
                * livePlot
                * plotEvery
                * stdoutPrint
                * runServer
                * cmdCtrlPrint
        '''
        for k, v in kwargs.items():
            if k not in self.monitorOptions.keys():
                logger.warning(k, '%s is not a valid monitor option.')
                logger.warning('Valid ones are %s', self.monitorOptions.keys())
            else:
                self.monitorOptions[k] = v
        return self.monitorOptions
Пример #30
0
def interpInverse(xArrIn, yArrIn, startIndex, direction, threshVal):
    ''' Gives a float representing the interpolated x value that gives y=threshVal '''
    xArr = xArrIn.copy()
    yArr = yArrIn.copy()
    if direction == 'left':
        xArr = xArr[::-1]
        yArr = yArr[::-1]
        startIndex = len(xArr) - 1 - startIndex
    xArr = xArr[startIndex:]
    yArr = yArr[startIndex:]
    yArr = yArr - threshVal

    possibleRange = (np.min(yArrIn), np.max(yArrIn))
    # warnStr = 'Inversion requested y = {}, but {} of range is {}'
    if threshVal < possibleRange[0]:
        logger.warning('Inversion requested y = %s, but %s of range is %s',
                       threshVal, 'minimum', np.min(yArrIn))
        return xArr[-1]
    elif threshVal > possibleRange[1]:
        logger.warning('Inversion requested y = %s, but %s of range is %s',
                       threshVal, 'maximum', np.max(yArrIn))
        return xArr[0]

    fakeInvalidIndeces = np.zeros(len(yArr), dtype=bool)
    iHit, isValid = descend(yArr, fakeInvalidIndeces, startIndex=0, direction='right', threshVal=0)
    if not isValid:
        logger.warning('Did not descend across threshold. Returning minimum')
        return xArr[np.argmin(yArr)]
    elif iHit in [0]:
        return xArr[iHit]
    else:  # interpolate
        q = yArr[iHit - 1:iHit + 1][::-1]
        v = xArr[iHit - 1:iHit + 1][::-1]
        return np.interp(0, q, v)