Esempio n. 1
0
    def _connect(self) -> None:
        """Connects the device to the data server.

        Instantiates the device controller from :mod:`zhinst-toolkit`, sets up 
        the data server and connects the device the data server. This method is 
        called from `__init__` of the :class:`BaseInstrument` class.

        """
        self._controller = tk.HDAWG(
            self._name,
            self._serial,
            interface=self._interface,
            host=self._host,
            port=self._port,
            api=self._api,
        )
        self._controller.setup()
        self._controller.connect_device(nodetree=False)
        self.connect_message()
        self._get_nodetree_dict()
        # initialize ChannelList of AWGs
        channel_list = ChannelList(self, "awgs", AWG)
        for i in range(4):
            channel_list.append(AWG(f"awg-{i}", i, self, self._controller))
        channel_list.lock()
        self.add_submodule("awgs", channel_list)
Esempio n. 2
0
    def __init__(
        self,
        name: str = 'mdac',
        num_channels: int = 10,
        **kwargs):

        """
        Create a dummy instrument that can be used for testing

        Args:
            name: name for the instrument
            gates: list of names that is used to create parameters for
                            the instrument
        """
        super().__init__(name, **kwargs)

        # make gates
        channels = ChannelList(self, "channels", MockDACChannel)
        for n in range(num_channels):
            num = str(n + 1).zfill(2)
            chan_name = f"ch{num}"
            channel = MockDACChannel(parent=self, name=chan_name, num=num)
            channels.append(channel)
            self.add_submodule(chan_name, channel)
        self.add_submodule("channels", channels)
Esempio n. 3
0
 def _init_readout_channels(self):
     # init submodules for ReadoutChannels
     channel_list = ChannelList(self, "channels", Channel)
     for i in range(10):
         channel_list.append(Channel(f"ch-{i}", i, self, self._controller))
     channel_list.lock()
     self.add_submodule("channels", channel_list)
Esempio n. 4
0
 def _init_awg_channels(self):
     # initialize ChannelList of AWGs
     channel_list = ChannelList(self, "awgs", AWG)
     for i in range(4):
         channel_list.append(AWG(f"awg-{i}", i, self, self._controller))
     channel_list.lock()
     self.add_submodule("awgs", channel_list)
Esempio n. 5
0
    def __init__(self, name, **kwargs):
        super().__init__(name, **kwargs)

        channels = ChannelList(self, "TempSensors", DummyChannel, snapshotable=False)
        for chan_name in ('A', 'B', 'C', 'D', 'E', 'F'):
            channel = DummyChannel(self, f'Chan{chan_name}', chan_name)
            channels.append(channel)
            self.add_submodule(chan_name, channel)
        self.add_submodule("channels", channels)
Esempio n. 6
0
 def _init_qachannels(self):
     # init submodules for QAChannels
     num_qachannels = self._controller.num_qachannels()
     channel_list = ChannelList(self, "qachannels", QAChannel)
     for i in range(num_qachannels):
         channel_list.append(
             QAChannel(f"qachannel-{i}", i, self, self._controller))
     channel_list.lock()
     self.add_submodule("qachannels", channel_list)
Esempio n. 7
0
    def __init__(self, name, address, silent=False, **kwargs):
        """
        Args:
            name (string): The name of the instrument used internally
                by QCoDeS. Must be unique.
            address (string): The VISA resource name.
            silent (Optional[bool]): If True, no connect message is printed.
        """

        warnings.warn(
            "This driver is old and will be removed "
            "from QCoDeS soon. Please use the "
            "WaveformGenerator_33XXX from the file "
            "instrument_drivers/Keysight/KeysightAgilent_33XXX"
            " instead.", UserWarning)

        super().__init__(name, address, **kwargs)

        channels = ChannelList(self,
                               "Channels",
                               KeysightChannel,
                               snapshotable=False)
        for i in range(1, 3):
            channel = KeysightChannel(self, 'ch{}'.format(i), i)
            channels.append(channel)
        channels.lock()
        self.add_submodule('channels', channels)

        self.add_parameter('sync_source',
                           label='Source of sync function',
                           set_cmd='OUTPut:SYNC:SOURce {}',
                           get_cmd='OUTPut:SYNC:SOURce?',
                           val_mapping={
                               1: 'CH1',
                               2: 'CH2'
                           },
                           vals=vals.Enum(1, 2))

        self.add_parameter('sync_output',
                           label='Sync output state',
                           set_cmd='OUTPut:SYNC {}',
                           get_cmd='OUTPut:SYNC?',
                           val_mapping={
                               'ON': 1,
                               'OFF': 0
                           },
                           vals=vals.Enum('ON', 'OFF'))

        self.add_function('force_trigger', call_cmd='*TRG')

        self.add_function('sync_channel_phases', call_cmd='PHAS:SYNC')

        if not silent:
            self.connect_message()
Esempio n. 8
0
 def _init_integrations(self):
     # init submodules for Integration Units
     num_integrations = self._readout.device.num_integrations_per_qachannel(
     )
     channel_list = ChannelList(self, "integrations", Integration)
     for i in range(num_integrations):
         channel_list.append(
             Integration(f"integration-{i}", i, self, self._readout))
     channel_list.lock()
     self.add_submodule("integrations", channel_list)
     self._readout._init_integrations()
Esempio n. 9
0
    def __init__(self, name, DACChannelClass: Type[DACChannelInterface]):
        assert issubclass(DACChannelClass, DACChannelInterface)
        super().__init__(name)

        channels = ChannelList(self,
                               "Channels",
                               DACChannelClass,
                               snapshotable=False)
        for chan_id in range(0, 64):
            chan_name = f"nt channel {chan_id}"
            channel = DACChannelClass(self, chan_name, chan_id)
            channels.append(channel)
            self.add_submodule(chan_name, channel)
        self.add_submodule("nt_channels", channels)
Esempio n. 10
0
def test_channel_tuple_snapshot_enabled(empty_instrument):

    channels = ChannelList(empty_instrument,
                           "ListElem",
                           DummyChannel,
                           snapshotable=True)
    for chan_name in ("A", "B", "C", "D", "E", "F"):
        channel = DummyChannel(empty_instrument, f"Chan{chan_name}", chan_name)
        channels.append(channel)
    empty_instrument.add_submodule("channels", channels)

    snapshot = empty_instrument.channels.snapshot()
    assert snapshot["snapshotable"] is True
    assert len(snapshot.keys()) == 3
    assert "channels" in snapshot.keys()
Esempio n. 11
0
    def __init__(self, name, address, **kwargs):
        super().__init__(name, address, 5, '\r\n', **kwargs)

        # configure the port
        if 'ASRL' not in address:
            self.visa_handle.baud_rate = 38400  # USB has no baud rate parameter
        self.visa_handle.stop_bits = pyvisa.constants.StopBits.one
        self.visa_handle.parity = pyvisa.constants.Parity.none
        self.visa_handle.read_termination = '\r\n'
        self.parameters.pop('IDN')  # Get rid of this parameter

        # for security check the ID from the device
        self.idn = self.ask("ver")
        log.debug("Main version:", self.idn)
        if not self.idn.startswith("attocube ANC300"):
            raise RuntimeError("Invalid device ID found: " + str(self.idn))

        # Now request all serial numbers of the axis modules. The first 6 chars are the id
        # of the module type. This will be used to enable special parameters.
        # Instantiate the axis channels only for available axis
        axischannels = ChannelList(self,
                                   "Anc300Channels",
                                   Anc300Axis,
                                   snapshotable=False)
        for ax in range(1, 7 + 1):
            try:
                tmp = self.ask('getser {}'.format(ax))
                name = 'axis{}'.format(ax)
                axischan = Anc300Axis(self, name, ax, tmp[:6])
                axischannels.append(axischan)
                self.add_submodule(name, axischan)
            except:
                pass
        axischannels.lock()
        self.add_submodule('axis_channels', axischannels)

        # instantiate the trigger channels even if they could not be tested
        triggerchannels = ChannelList(self,
                                      "Anc300Trigger",
                                      Anc300TriggerOut,
                                      snapshotable=False)
        for ax in [1, 2, 3]:
            name = 'trigger{}'.format(ax)
            trigchan = Anc300TriggerOut(self, name, ax)
            triggerchannels.append(trigchan)
            self.add_submodule(name, trigchan)
        triggerchannels.lock()
        self.add_submodule('trigger_channels', triggerchannels)
Esempio n. 12
0
def _make_dci_with_list():
    for i in range(10):
        pass

    dci = Instrument(name="dciwl")
    channels = ChannelList(dci, "ListElem", DummyChannel, snapshotable=False)
    for chan_name in ("A", "B", "C", "D", "E", "F"):
        channel = DummyChannel(dci, f"Chan{chan_name}", chan_name)
        channels.append(channel)
        dci.add_submodule(chan_name, channel)
    dci.add_submodule("channels", channels)

    try:
        yield dci
    finally:
        dci.close()
Esempio n. 13
0
    def __init__(self, name, channel_names=None, **kwargs):
        super().__init__(name, **kwargs)

        channels = ChannelList(self,
                               "TempSensors",
                               DummyChannel,
                               snapshotable=False)

        if channel_names is None:
            channel_ids = ("A", "B", "C", "D", "E", "F")
            channel_names = tuple(f"Chan{chan_name}"
                                  for chan_name in channel_ids)
        else:
            channel_ids = channel_names
        for chan_name, chan_id in zip(channel_names, channel_ids):
            channel = DummyChannel(self, chan_name, chan_id)
            channels.append(channel)
            self.add_submodule(chan_id, channel)
        self.add_submodule("channels", channels.to_channel_tuple())
Esempio n. 14
0
    def __init__(self, name, address, port=23):
        super().__init__(name, address, port)
        self.flush_connection()

        channels = ChannelList(self, "Channels", MC_channel,
                               snapshotable=False)

        _chanlist = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
        _max_channel_number = int(self.IDN()['model'][3])
        _chanlist = _chanlist[0:_max_channel_number]

        for c in _chanlist:
            channel = MC_channel(self, f'channel_{c}', c)
            channels.append(channel)
            self.add_submodule(f'channel_{c}', channel)
        channels.lock()
        self.add_submodule('channels', channels)

        self.connect_message()
Esempio n. 15
0
    def __init__(self, name: str, address: str, port: int = 23):
        super().__init__(name, address, port)
        self.flush_connection()

        channels = ChannelList(self,
                               "Channels",
                               MC_channel,
                               snapshotable=False)

        _chanlist = ['a', 'b']
        _max_channel_number = int(self.IDN()['model'][3])
        _chanlist = _chanlist[0:_max_channel_number]

        for c in _chanlist:
            channel = MC_channel(self, f'channel_{c}', c)
            channels.append(channel)
            self.add_submodule(f"channel_{c}", channel)
        self.add_submodule("channels", channels.to_channel_tuple())

        self.connect_message()
Esempio n. 16
0
    def _add_submodules_recursively(self, parent, treedict: Dict) -> None:
        """
        Recursively add submodules (ZINodes) for each node in the ZI node tree.
        At the leaves create a parameter. Create a ChannelList as submodules
        whenever a node is enumerated, e.g. 'dev8030/sigouts/*/on'.
        
        Arguments:
            parent (InstrumentChannel): parent QCoDeS object, either 
                Instrument(-Channel) or ZINode
            treedict (dict): dictionary specifying the (sub-)tree of the ZI 
                node hirarchy

        """
        for key, value in treedict.items():
            if all(isinstance(k, int) for k in value.keys()):
                # if enumerated node
                if "Node" in list(value.values())[0].keys():
                    # if at leave, don't create ChannelList but parameter with "{key}{i}"
                    for k in value.keys():
                        self._add_parameter_from_dict(parent, f"{key}{k}",
                                                      value[k])
                else:
                    # else, create ChannelList to hold all enumerated ZINodes
                    channel_list = ChannelList(parent, key, ZINode)
                    for k in value.keys():
                        ch_name = f"{key}{k}"
                        ch = ZINode(parent, ch_name)
                        channel_list.append(ch)
                        self._add_submodules_recursively(ch, treedict[key][k])
                    channel_list.lock()
                    parent.add_submodule(key, channel_list)
            else:
                # if not enumerated ZINode
                if "Node" in value.keys():
                    # if at leave add a parameter to the node
                    self._add_parameter_from_dict(parent, key, value)
                else:
                    # if not at leave, create ZINode as submodule
                    module = ZINode(parent, key)
                    parent.add_submodule(key, module)
                    self._add_submodules_recursively(module, treedict[key])
Esempio n. 17
0
    def add_channels(self):
        channels = ChannelList(
            self, "Channels", self.CHANNEL_CLASS, snapshotable=False)

        _chanlist = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
        self._deprecated_attributes = {
            f'channel_{k}': k
            for k in _chanlist
        }

        _max_channel_number = self.get_number_of_channels()
        _chanlist = _chanlist[0:_max_channel_number]

        for c in _chanlist:
            channel = self.CHANNEL_CLASS(self, f'channel_{c}', c)
            channels.append(channel)
            attribute_name = f'channel_{c}'
            self.add_submodule(attribute_name, channel)
            self.add_submodule(c, channel)
            self._deprecated_attributes[attribute_name] = c
        channels.lock()
        self.add_submodule('channels', channels)
Esempio n. 18
0
    def __init__(self, name: str, library: ANC350v3Lib, inst_no: int = 0):
        super().__init__(name)

        if isinstance(library, ANC350v4Lib):
            self._version_no = 4
        elif isinstance(library, ANC350v3Lib):
            self._version_no = 3
        else:
            raise NotImplementedError(
                "Only version 3 and 4 of ANC350's driver-DLL are currently "
                "supported")

        self._lib = library
        self._device_no = inst_no
        self._device_handle = self._lib.connect(inst_no)

        axischannels = ChannelList(self, "Anc350Axis", Anc350Axis)
        for nr, axis in enumerate(['x', 'y', 'z']):
            axis_name = f"{axis}_axis"
            axischannel = Anc350Axis(parent=self, name=axis_name, axis=nr)
            axischannels.append(axischannel)
            self.add_submodule(axis_name, axischannel)
        axischannels.lock()
        self.add_submodule("axis_channels", axischannels)
Esempio n. 19
0
    def _connect(self) -> None:
        """Connects the device to the data server.

        Instantiates the device controller from :mod:`zhinst-toolkit`, sets up 
        the data server and connects the device the data server. This method is 
        called from `__init__` of the :class:`BaseInstrument` class.

        """
        self._controller = tk.UHFQA(
            self._name,
            self._serial,
            interface=self._interface,
            host=self._host,
            port=self._port,
            api=self._api,
        )
        self._controller.setup()
        self._controller.connect_device(nodetree=False)
        self.connect_message()
        self._get_nodetree_dict()
        # init submodules for ReadoutChannels and AWG
        channel_list = ChannelList(self, "channels", Channel)
        for i in range(10):
            channel_list.append(Channel(f"ch-{i}", i, self, self._controller))
        channel_list.lock()
        self.add_submodule("channels", channel_list)
        self.add_submodule("awg", AWG("awg", self, self._controller))
        # add custom parameters as QCoDeS parameters
        self.add_parameter(
            "crosstalk_matrix",
            docstring=
            "The 10x10 crosstalk suppression matrix that multiplies the 10 signal paths. Can be set only partially.",
            get_cmd=self._controller.crosstalk_matrix,
            set_cmd=self._controller.crosstalk_matrix,
            label="Crosstalk Matrix",
        )
        sources = [
            "Crosstalk",
            "Integration",
            "Threshold",
            "Crosstalk Correlation",
            "Threshold Correlation",
            "Rotation",
        ]
        self.add_parameter(
            "result_source",
            docstring=
            f"The signal source for QA Results. Has to be one of {sources}.",
            get_cmd=self._controller.result_source,
            set_cmd=self._controller.result_source,
            label="Result Source",
            vals=vals.Enum(*sources),
        )
        self.add_parameter(
            "integration_time",
            docstring=
            "The integration time used for demodulation in seconds. Can be up to 2.27 us when using weighted integration and up to 50 us in spectroscopy mode.",
            get_cmd=self._controller.integration_time,
            set_cmd=self._controller.integration_time,
            label="Integration Time",
            vals=vals.Numbers(0, 50e-6),
        )
        self.add_parameter(
            "averaging_mode",
            docstring=self._controller.averaging_mode._description,
            get_cmd=self._controller.averaging_mode,
            set_cmd=self._controller.averaging_mode,
            label="Averaging Mode",
            vals=vals.Enum("Cyclic", "Sequential"),
        )
Esempio n. 20
0
    def __init__(self,
                 name,
                 model,
                 chassis,
                 slot,
                 channel_idxs: List[int] = None,
                 triggers=8,
                 **kwargs):
        super().__init__(name, model, chassis, slot, triggers, **kwargs)

        if channel_idxs is None:
            channel_idxs = model_channel_idxs[self.model]
        self.channel_idxs = channel_idxs

        # Create instance of keysight SD_AOU class
        self.awg = logclass(keysightSD1.SD_AOU)()

        # Create an instance of keysight SD_Wave class
        self.wave = logclass(keysightSD1.SD_Wave)()

        # Open the device using the specified chassis and slot number
        self.initialize(chassis=chassis, slot=slot)

        self.add_parameter('clock_output',
                           val_mapping={
                               'off': 0,
                               'on': 1
                           },
                           set_function=self.awg.clockIOconfig,
                           docstring="Turn clock connector output on or off.")

        self.add_parameter(
            'trigger_io',
            label='trigger io',
            get_function=self.awg.triggerIOread,
            set_function=self.awg.triggerIOwrite,
            docstring='The trigger input value, 0 (OFF) or 1 (ON)',
            vals=vals.Enum(0, 1))

        self.add_parameter('trigger_direction',
                           label=f'trigger direction',
                           val_mapping={
                               'in': 1,
                               'out': 0
                           },
                           set_function=self.awg.triggerIOconfig,
                           docstring='Determines if trig i/o should be used '
                           'as a trigger input or trigger output.')

        self.add_parameter('clock_frequency',
                           label='clock frequency',
                           unit='Hz',
                           get_function=self.awg.clockGetFrequency,
                           set_function=self.awg.clockSetFrequency,
                           docstring='The real hardware clock frequency in Hz',
                           vals=vals.Numbers(100e6, 500e6))

        self.add_parameter(
            'clock_sync_frequency',
            label='clock sync frequency',
            unit='Hz',
            get_function=self.awg.clockGetSyncFrequency,
            docstring='The frequency of the internal CLKsync in Hz')

        channels = ChannelList(self, name='channels', chan_type=AWGChannel)
        for ch in self.channel_idxs:
            channel = AWGChannel(self, name=f'ch{ch}', id=ch)
            setattr(self, f'ch{ch}', channel)
            channels.append(channel)
        self.add_submodule('channels', channels)
Esempio n. 21
0
    def __init__(self,
                 name,
                 address,
                 num_chans=48,
                 update_currents=True,
                 **kwargs):
        """
        Instantiates the instrument.

        Args:
            name (str): The instrument name used by qcodes
            address (str): The VISA name of the resource
            num_chans (int): Number of channels to assign. Default: 48
            update_currents (bool): Whether to query all channels for their
                current current value on startup. Default: True.

        Returns:
            QDac object
        """
        super().__init__(name, address, **kwargs)
        self._output_n_lines = 50
        handle = self.visa_handle
        self._get_status_performed = False
        # This is the baud rate on power-up. It can be changed later but
        # you must start out with this value.
        handle.baud_rate = 480600
        handle.parity = visa.constants.Parity(0)
        handle.data_bits = 8
        self.set_terminator('\n')
        # TODO: do we want a method for write termination too?
        handle.write_termination = '\n'
        # TODO: do we need a query delay for robust operation?
        self._write_response = ''

        if self._get_firmware_version() < 0.170202:
            raise RuntimeError('''
                               Obsolete QDAC Software version detected.
                               QCoDeS only supports version 0.170202 or newer.
                               Contact [email protected] for an update.
                               ''')

        self.num_chans = num_chans

        # Assigned slopes. Entries will eventually be [chan, slope]
        self._slopes = []
        # Function generators (used in _set_voltage)
        self._fgs = set(range(1, 9))
        self._assigned_fgs = {}  # {chan: fg}
        # Sync channels
        self._syncoutputs = []  # Entries: [chan, syncchannel]

        self.chan_range = range(1, 1 + self.num_chans)
        self.channel_validator = vals.Ints(1, self.num_chans)

        channels = ChannelList(self,
                               "Channels",
                               QDacChannel,
                               snapshotable=False,
                               multichan_paramclass=QDacMultiChannelParameter)

        for i in self.chan_range:
            channel = QDacChannel(self, f'chan{i:02}', i)
            channels.append(channel)
            # Should raise valueerror if name is invalid (silently fails now)
            self.add_submodule(f'ch{i:02}', channel)
        channels.lock()
        self.add_submodule('channels', channels)

        for board in range(6):
            for sensor in range(3):
                label = f'Board {board}, Temperature {sensor}'
                self.add_parameter(name=f'temp{board}_{sensor}',
                                   label=label,
                                   unit='C',
                                   get_cmd=f'tem {board} {sensor}',
                                   get_parser=self._num_verbose)

        self.add_parameter(name='cal',
                           set_cmd='cal {}',
                           vals=self.channel_validator)
        # TO-DO: maybe it's too dangerous to have this settable.
        # And perhaps ON is a better verbose mode default?
        self.add_parameter(name='verbose',
                           set_cmd='ver {}',
                           val_mapping={
                               True: 1,
                               False: 0
                           })

        self.add_parameter(name='fast_voltage_set',
                           label='fast voltage set',
                           get_cmd=None,
                           set_cmd=None,
                           vals=vals.Bool(),
                           initial_value=False,
                           docstring=""""Deprecated with no functionality""")
        # Initialise the instrument, all channels DC (unbind func. generators)
        for chan in self.chan_range:
            # Note: this call does NOT change the voltage on the channel
            self.write(f'wav {chan} 0 1 0')

        self.verbose.set(False)
        self.connect_message()
        log.info('[*] Querying all channels for voltages and currents...')
        self._update_cache(readcurrents=update_currents)
        self._update_currents = update_currents
        log.info('[+] Done')
Esempio n. 22
0
    def __init__(self,
                 name: str,
                 address: str,
                 timeout: float = 20,
                 **kwargs: Any):
        """
        Initialises the DS4000.

        Args:
            name: Name of the instrument used by QCoDeS
            address: Instrument address as used by VISA
            timeout: visa timeout, in secs. long default (180)
                to accommodate large waveforms
        """

        # Init VisaInstrument. device_clear MUST NOT be issued, otherwise communications hangs
        # due a bug in firmware
        super().__init__(name,
                         address,
                         device_clear=False,
                         timeout=timeout,
                         **kwargs)
        self.connect_message()

        self._check_firmware_version()

        # functions
        self.add_function('run',
                          call_cmd=':RUN',
                          docstring='Start acquisition')
        self.add_function('stop',
                          call_cmd=':STOP',
                          docstring='Stop acquisition')
        self.add_function('single',
                          call_cmd=':SINGle',
                          docstring='Single trace acquisition')
        self.add_function('force_trigger',
                          call_cmd='TFORce',
                          docstring='Force trigger event')
        self.add_function("auto_scale",
                          call_cmd=":AUToscale",
                          docstring="Perform autoscale")

        # general parameters
        self.add_parameter('trigger_type',
                           label='Type of the trigger',
                           get_cmd=':TRIGger:MODE?',
                           set_cmd=':TRIGger:MODE {}',
                           vals=vals.Enum('EDGE', 'PULS', 'RUNT', 'NEDG',
                                          'SLOP', 'VID', 'PATT', 'RS232',
                                          'IIC', 'SPI', 'CAN', 'FLEX', 'USB'))
        self.add_parameter('trigger_mode',
                           label='Mode of the trigger',
                           get_cmd=':TRIGger:SWEep?',
                           set_cmd=':TRIGger:SWEep {}',
                           vals=vals.Enum('AUTO', 'NORM', 'SING'))
        self.add_parameter("time_base",
                           label="Horizontal time base",
                           get_cmd=":TIMebase:MAIN:SCALe?",
                           set_cmd=":TIMebase:MAIN:SCALe {}",
                           get_parser=float,
                           unit="s/div")
        self.add_parameter("sample_point_count",
                           label="Number of the waveform points",
                           get_cmd=":WAVeform:POINts?",
                           set_cmd=":WAVeform:POINts {}",
                           get_parser=int,
                           vals=Ints(min_value=1))
        self.add_parameter("enable_auto_scale",
                           label="Enable or disable autoscale",
                           get_cmd=":SYSTem:AUToscale?",
                           set_cmd=":SYSTem:AUToscale {}",
                           get_parser=bool,
                           vals=Bool())

        channels = ChannelList(self,
                               "Channels",
                               RigolDS4000Channel,
                               snapshotable=False)

        for channel_number in range(1, 5):
            channel = RigolDS4000Channel(self, f"ch{channel_number}",
                                         channel_number)
            channels.append(channel)

        channels.lock()
        self.add_submodule('channels', channels)
Esempio n. 23
0
    def __init__(self,
                 name: str,
                 address: str,
                 max_frequency: float,
                 reset: bool = False,
                 **kwargs: Any):
        super().__init__(name, address, terminator='\n', **kwargs)
        self._max_frequency = max_frequency
        # Reference commands
        self.add_parameter(name='frequency',
                           label='Frequency',
                           unit='Hz',
                           get_cmd='FREQ?',
                           set_cmd='FREQ {}',
                           get_parser=float,
                           vals=Numbers(min_value=1e-3,
                                        max_value=self._max_frequency))
        self.add_parameter(name='sine_outdc',
                           label='Sine out dc level',
                           unit='V',
                           get_cmd='SOFF?',
                           set_cmd='SOFF {}',
                           get_parser=float,
                           vals=Numbers(min_value=-5, max_value=5))
        self.add_parameter(name='amplitude',
                           label='Amplitude',
                           unit='V',
                           get_cmd='SLVL?',
                           set_cmd='SLVL {}',
                           get_parser=float,
                           vals=Numbers(min_value=0, max_value=2))
        self.add_parameter(name='harmonic',
                           label='Harmonic',
                           get_cmd='HARM?',
                           get_parser=int,
                           set_cmd='HARM {:d}',
                           vals=Ints(min_value=1, max_value=99))
        self.add_parameter(name='phase',
                           label='Phase',
                           unit='deg',
                           get_cmd='PHAS?',
                           set_cmd='PHAS {}',
                           get_parser=float,
                           vals=Numbers(min_value=-3.6e5, max_value=3.6e5))
        # Signal commands
        self.add_parameter(name='sensitivity',
                           label='Sensitivity',
                           get_cmd='SCAL?',
                           set_cmd='SCAL {:d}',
                           get_parser=self._get_sensitivity,
                           set_parser=self._set_sensitivity)
        self.add_parameter(name='filter_slope',
                           label='Filter slope',
                           unit='dB/oct',
                           get_cmd='OFSL?',
                           set_cmd='OFSL {}',
                           val_mapping={
                               6: 0,
                               12: 1,
                               18: 2,
                               24: 3
                           })
        self.add_parameter(name='sync_filter',
                           label='Sync filter',
                           get_cmd='SYNC?',
                           set_cmd='SYNC {}',
                           val_mapping={
                               'OFF': 0,
                               'ON': 1
                           })
        self.add_parameter(name='noise_bandwidth',
                           label='Noise bandwidth',
                           unit='Hz',
                           get_cmd='ENBW?',
                           get_parser=float)
        self.add_parameter(name='signal_strength',
                           label='Signal strength indicator',
                           get_cmd='ILVL?',
                           get_parser=int)
        self.add_parameter(name='signal_input',
                           label='Signal input',
                           get_cmd='IVMD?',
                           get_parser=self._get_input_config,
                           set_cmd='IVMD {}',
                           set_parser=self._set_input_config,
                           vals=Enum(*self._INPUT_SIGNAL_TO_N.keys()))
        self.add_parameter(name='input_range',
                           label='Input range',
                           unit='V',
                           get_cmd='IRNG?',
                           set_cmd='IRNG {}',
                           val_mapping={
                               1: 0,
                               300e-3: 1,
                               100e-3: 2,
                               30e-3: 3,
                               10e-3: 4
                           })
        self.add_parameter(name='input_config',
                           label='Input configuration',
                           get_cmd='ISRC?',
                           set_cmd='ISRC {}',
                           val_mapping={
                               'a': 0,
                               'a-b': 1
                           })
        self.add_parameter(name='input_shield',
                           label='Input shield',
                           get_cmd='IGND?',
                           set_cmd='IGND {}',
                           val_mapping={
                               'float': 0,
                               'ground': 1
                           })
        self.add_parameter(name='input_gain',
                           label='Input gain',
                           unit='ohm',
                           get_cmd='ICUR?',
                           set_cmd='ICUR {}',
                           val_mapping={
                               1e6: 0,
                               100e6: 1
                           })
        self.add_parameter(name='adv_filter',
                           label='Advanced filter',
                           get_cmd='ADVFILT?',
                           set_cmd='ADVFILT {}',
                           val_mapping={
                               'OFF': 0,
                               'ON': 1
                           })
        self.add_parameter(name='input_coupling',
                           label='Input coupling',
                           get_cmd='ICPL?',
                           set_cmd='ICPL {}',
                           val_mapping={
                               'ac': 0,
                               'dc': 1
                           })
        self.add_parameter(name='time_constant',
                           label='Time constant',
                           unit='s',
                           get_cmd='OFLT?',
                           set_cmd='OFLT {}',
                           val_mapping={
                               1e-6: 0,
                               3e-6: 1,
                               10e-6: 2,
                               30e-6: 3,
                               100e-6: 4,
                               300e-6: 5,
                               1e-3: 6,
                               3e-3: 7,
                               10e-3: 8,
                               30e-3: 9,
                               100e-3: 10,
                               300e-3: 11,
                               1: 12,
                               3: 13,
                               10: 14,
                               30: 15,
                               100: 16,
                               300: 17,
                               1e3: 18,
                               3e3: 19,
                               10e3: 20,
                               30e3: 21
                           })

        self.add_parameter(
            name="external_reference_trigger",
            label="External reference trigger mode",
            get_cmd="RTRG?",
            set_cmd="RTRG {}",
            val_mapping={
                "SIN": 0,
                "POS": 1,
                "POSTTL": 1,
                "NEG": 2,
                "NEGTTL": 2,
            },
            docstring="The triggering mode for synchronization of the "
            "internal reference signal with the externally provided "
            "one")

        self.add_parameter(name="reference_source",
                           label="Reference source",
                           get_cmd="RSRC?",
                           set_cmd="RSRC {}",
                           val_mapping={
                               "INT": 0,
                               "EXT": 1,
                               "DUAL": 2,
                               "CHOP": 3
                           },
                           docstring="The source of the reference signal")

        self.add_parameter(
            name="external_reference_trigger_input_resistance",
            label="External reference trigger input resistance",
            get_cmd="REFZ?",
            set_cmd="REFZ {}",
            val_mapping={
                "50": 0,
                "50OHMS": 0,
                0: 0,
                "1M": 1,
                "1MEG": 1,
                1: 1,
            },
            docstring="Input resistance of the input for the external "
            "reference signal")

        # Auto functions
        self.add_function('auto_range', call_cmd='ARNG')
        self.add_function('auto_scale', call_cmd='ASCL')
        self.add_function('auto_phase', call_cmd='APHS')

        # Data transfer
        # first 4 parameters from a list of 16 below.
        self.add_parameter('X',
                           label='In-phase Magnitude',
                           get_cmd='OUTP? 0',
                           get_parser=float,
                           unit='V')
        self.add_parameter('Y',
                           label='Out-phase Magnitude',
                           get_cmd='OUTP? 1',
                           get_parser=float,
                           unit='V')
        self.add_parameter('R',
                           label='Magnitude',
                           get_cmd='OUTP? 2',
                           get_parser=float,
                           unit='V')
        self.add_parameter('P',
                           label='Phase',
                           get_cmd='OUTP? 3',
                           get_parser=float,
                           unit='deg')

        # CH1/CH2 Output Commands
        self.add_parameter('X_offset',
                           label='X offset ',
                           unit='%',
                           get_cmd='COFP? 0',
                           set_cmd='COFP 0, {}',
                           get_parser=float,
                           vals=Numbers(min_value=-999.99, max_value=999.99))
        self.add_parameter('Y_offset',
                           label='Y offset',
                           unit='%',
                           get_cmd='COFP? 1',
                           set_cmd='COFP 1, {}',
                           get_parser=float,
                           vals=Numbers(min_value=-999.99, max_value=999.99))
        self.add_parameter('R_offset',
                           label='R offset',
                           unit='%',
                           get_cmd='COFP? 2',
                           set_cmd='COFP 2, {}',
                           get_parser=float,
                           vals=Numbers(min_value=-999.99, max_value=999.99))
        self.add_parameter('X_expand',
                           label='X expand multiplier',
                           get_cmd='CEXP? 0',
                           set_cmd='CEXP 0, {}',
                           val_mapping={
                               'OFF': '0',
                               'X10': '1',
                               'X100': '2'
                           })
        self.add_parameter('Y_expand',
                           label='Y expand multiplier',
                           get_cmd='CEXP? 1',
                           set_cmd='CEXP 1, {}',
                           val_mapping={
                               'OFF': 0,
                               'X10': 1,
                               'X100': 2
                           })
        self.add_parameter('R_expand',
                           label='R expand multiplier',
                           get_cmd='CEXP? 2',
                           set_cmd='CEXP 2, {}',
                           val_mapping={
                               'OFF': 0,
                               'X10': 1,
                               'X100': 2
                           })

        # Aux input/output
        for i in [0, 1, 2, 3]:
            self.add_parameter(f'aux_in{i}',
                               label=f'Aux input {i}',
                               get_cmd=f'OAUX? {i}',
                               get_parser=float,
                               unit='V')
            self.add_parameter(f'aux_out{i}',
                               label=f'Aux output {i}',
                               get_cmd=f'AUXV? {i}',
                               get_parser=float,
                               set_cmd=f'AUXV {i}, {{}}',
                               unit='V')

        # Data channels:
        # 'DAT1' (green), 'DAT2' (blue), 'DAT3' (yellow), 'DAT4' (orange)
        data_channels = ChannelList(self,
                                    "data_channels",
                                    SR86xDataChannel,
                                    snapshotable=False)
        for num, color in zip(range(self._N_DATA_CHANNELS),
                              ('green', 'blue', 'yellow', 'orange')):
            cmd_id = f"{num}"
            cmd_id_name = f"DAT{num + 1}"
            ch_name = f"data_channel_{num + 1}"

            data_channel = SR86xDataChannel(self, ch_name, cmd_id, cmd_id_name,
                                            color)

            data_channels.append(data_channel)
            self.add_submodule(ch_name, data_channel)

        data_channels.lock()
        self.add_submodule("data_channels", data_channels)

        # Interface
        self.add_function('reset', call_cmd='*RST')

        self.add_function('disable_front_panel', call_cmd='OVRM 0')
        self.add_function('enable_front_panel', call_cmd='OVRM 1')

        buffer = SR86xBuffer(self, f"{self.name}_buffer")
        self.add_submodule("buffer", buffer)

        self.input_config()
        self.connect_message()
Esempio n. 24
0
    def __init__(
        self,
        name: str,
        address: str,
        timeout: float = 20,
        channels: int = 4,
        silence_pyvisapy_warning: bool = False,
        **kwargs: Any,
    ):
        """
        Initialises the oscilloscope.

        Args:
            name: Name of the instrument used by QCoDeS
            address: Instrument address as used by VISA
            timeout: Visa timeout, in secs.
            channels: The number of channels on the scope.
            silence_pyvisapy_warning: Don't warn about pyvisa-py at startup
        """
        super().__init__(name,
                         address,
                         timeout=timeout,
                         terminator="\n",
                         **kwargs)
        self.connect_message()

        # Check if we are using pyvisa-py as our visa lib and warn users that
        # this may cause long digitize operations to fail
        if (self.visa_handle.visalib.library_path == "py"
                and not silence_pyvisapy_warning):
            self.log.warning(
                "Timeout not handled correctly in pyvisa_py. This may cause"
                " long acquisitions to fail. Either use ni/keysight visalib"
                " or set timeout to longer than longest expected acquisition"
                " time.")

        # switch the response header off else none of our parameters will work
        self.write(":SYSTem:HEADer OFF")

        # Then set up the data format used to retrieve waveforms
        self.write(":WAVEFORM:FORMAT WORD")
        self.write(":WAVEFORM:BYTEORDER LSBFirst")
        self.write(":WAVEFORM:STREAMING ON")

        # Query the oscilloscope parameters
        # Set sample rate, bandwidth and memory depth limits
        self._query_capabilities()
        # Number of channels can't be queried on most older scopes. Use a parameter
        # for now.
        self.no_channels = channels

        # Run state
        self.run_mode = Parameter(
            name="run_mode",
            instrument=self,
            label="run mode",
            get_cmd=":RST?",
            vals=vals.Enum("RUN", "STOP", "SING"),
        )

        # Timing Parameters
        self.timebase_range = Parameter(
            name="timebase_range",
            instrument=self,
            label="Range of the time axis",
            unit="s",
            get_cmd=":TIM:RANG?",
            set_cmd=":TIM:RANG {}",
            vals=vals.Numbers(5e-12, 20),
            get_parser=float,
        )
        self.timebase_position = Parameter(
            name="timebase_position",
            instrument=self,
            label="Offset of the time axis",
            unit="s",
            get_cmd=":TIM:POS?",
            set_cmd=":TIM:POS {}",
            vals=vals.Numbers(),
            get_parser=float,
        )
        self.timebase_roll_enabled = Parameter(
            name="timebase_roll_enabled",
            instrument=self,
            label="Is rolling mode enabled",
            get_cmd=":TIM:ROLL:ENABLE?",
            set_cmd=":TIM:ROLL:ENABLE {}",
            val_mapping={
                True: 1,
                False: 0
            },
        )

        # Trigger
        self.trigger_mode = Parameter(
            name="trigger_mode",
            instrument=self,
            label="Trigger mode",
            get_cmd=":TRIG:MODE?",
        )
        self.trigger_sweep = Parameter(
            name="trigger_sweep",
            instrument=self,
            label="Trigger sweep mode",
            get_cmd=":TRIG:SWE?",
            set_cmd=":TRIG:SWE {}",
            vals=vals.Enum("AUTO", "TRIG"),
        )
        self.trigger_state = Parameter(
            name="trigger_state",
            instrument=self,
            label="Trigger state",
            get_cmd=":AST?",
            vals=vals.Enum("ARM", "TRIG", "ATRIG", "ADONE"),
            snapshot_value=False,
        )

        # Edge trigger parameters
        # Note that for now we only support parameterized edge triggers - this may
        # be something worth expanding.
        # To set trigger level, use the "trigger_level" parameter in each channel
        self.trigger_edge_source = Parameter(
            name="trigger_edge_source",
            instrument=self,
            label="Source channel for the edge trigger",
            get_cmd=":TRIGger:EDGE:SOURce?",
            set_cmd=":TRIGger:EDGE:SOURce {}",
            vals=vals.Enum(*([f"CHAN{i}" for i in range(1, 4 + 1)] +
                             [f"DIG{i}"
                              for i in range(16 + 1)] + ["AUX", "LINE"])),
        )
        self.trigger_edge_slope = Parameter(
            name="trigger_edge_slope",
            instrument=self,
            label="slope of the edge trigger",
            get_cmd=":TRIGger:EDGE:SLOPe?",
            set_cmd=":TRIGger:EDGE:SLOPe {}",
            vals=vals.Enum("POS", "POSITIVE", "NEG", "NEGATIVE", "EITH"),
        )
        self.trigger_level_aux = Parameter(
            name="trigger_level_aux",
            instrument=self,
            label="Tirgger level AUX",
            unit="V",
            get_cmd=":TRIGger:LEVel? AUX",
            set_cmd=":TRIGger:LEVel AUX,{}",
            get_parser=float,
            vals=vals.Numbers(),
        )

        # Aquisition
        # If sample points, rate and timebase_scale are set in an
        # incomensurate way, the scope only displays part of the waveform
        self.acquire_points = Parameter(
            name="acquire_points",
            instrument=self,
            label="sample points",
            get_cmd=":ACQ:POIN?",
            set_cmd=":ACQ:POIN {}",
            get_parser=int,
            vals=vals.Numbers(min_value=self.min_pts, max_value=self.max_pts),
        )
        self.sample_rate = Parameter(
            name="sample_rate",
            instrument=self,
            label="sample rate",
            get_cmd=":ACQ:SRAT?",
            set_cmd=":ACQ:SRAT {}",
            unit="Hz",
            get_parser=float,
            vals=vals.Numbers(min_value=self.min_srat,
                              max_value=self.max_srat),
        )
        # Note: newer scopes allow a per-channel bandwidth. This is not implemented yet.
        self.bandwidth = Parameter(
            name="bandwidth",
            instrument=self,
            label="bandwidth",
            get_cmd=":ACQ:BAND?",
            set_cmd=":ACQ:BAND {}",
            unit="Hz",
            get_parser=float,
            vals=vals.Numbers(min_value=self.min_bw, max_value=self.max_bw),
        )
        self.acquire_interpolate = Parameter(
            name="acquire_interpolate",
            instrument=self,
            get_cmd=":ACQ:INTerpolate?",
            set_cmd=":ACQuire:INTerpolate {}",
            vals=vals.Enum(0, 1, "INT1", "INT2", "INT4", "INT8", "INT16",
                           "INT32"),
        )
        self.acquire_mode = Parameter(
            name="acquire_mode",
            instrument=self,
            label="Acquisition mode",
            get_cmd="ACQuire:MODE?",
            set_cmd="ACQuire:MODE {}",
            vals=vals.Enum(
                "ETIMe",
                "RTIMe",
                "PDETect",
                "HRESolution",
                "SEGMented",
                "SEGPdetect",
                "SEGHres",
            ),
        )
        self.average = Parameter(
            name="average",
            instrument=self,
            label="Averages",
            get_cmd=self._get_avg,
            set_cmd=self._set_avg,
            vals=vals.Ints(min_value=1, max_value=10486575),
        )

        # Automatically digitize before acquiring a trace
        self.auto_digitize: Parameter = Parameter(
            name="auto_digitize",
            instrument=self,
            label="Auto digitize",
            set_cmd=None,
            get_cmd=None,
            val_mapping=create_on_off_val_mapping(),
            docstring=(
                "Digitize before each waveform download. "
                "If you need to acquire from multiple channels simultaneously "
                "or you wish to acquire with the scope running freely, "
                "set this value to False."),
            initial_value=True,
        )
        self.cache_setpoints: Parameter = Parameter(
            name="cache_setpoints",
            instrument=self,
            label="Cache setpoints",
            set_cmd=None,
            get_cmd=None,
            val_mapping=create_on_off_val_mapping(),
            docstring=
            ("Cache setpoints. If false, the preamble is queried before each"
             " acquisition, which may add latency to measurements. If you"
             " are taking repeated measurements, set this to True and update"
             " setpoints manually by calling `instr.chX.update_setpoints()`."),
            initial_value=False,
        )

        # Channels
        _channels = ChannelList(self,
                                "channels",
                                InfiniiumChannel,
                                snapshotable=False)
        for i in range(1, self.no_channels + 1):
            channel = InfiniiumChannel(self, f"chan{i}", i)
            _channels.append(channel)
            self.add_submodule(f"ch{i}", channel)
        self.add_submodule("channels", _channels.to_channel_tuple())

        # Functions
        _functions = ChannelList(self,
                                 "functions",
                                 InfiniiumFunction,
                                 snapshotable=False)
        for i in range(1, 16 + 1):
            function = InfiniiumFunction(self, f"func{i}", i)
            _functions.append(function)
            self.add_submodule(f"func{i}", function)
        # Have to call channel list "funcs" here as functions is a
        # reserved name in Instrument.
        self.add_submodule("funcs", _functions.to_channel_tuple())

        # Submodules
        meassubsys = UnboundMeasurement(self, "measure")
        self.add_submodule("measure", meassubsys)
Esempio n. 25
0
    def __init__(self,
                 name: str,
                 address: str,
                 num_channels: int,
                 timeout: float = 10,
                 **kwargs) -> None:
        """
        Args:
            name: The name used internally by QCoDeS in the DataSet
            address: The VISA resource name of the instrument
            timeout: The VISA timeout time (in seconds)
            num_channels: Number of channels on the AWG
        """

        self.num_channels = num_channels

        super().__init__(name,
                         address,
                         timeout=timeout,
                         terminator='\n',
                         **kwargs)

        # The 'model' value begins with 'AWG'
        self.model = self.IDN()['model'][3:]

        if self.model not in ['70001A', '70002A', '5208']:
            raise ValueError('Unknown model type: {}. Are you using '
                             'the right driver for your instrument?'
                             ''.format(self.model))

        self.add_parameter('current_directory',
                           label='Current file system directory',
                           set_cmd='MMEMory:CDIRectory "{}"',
                           get_cmd='MMEMory:CDIRectory?',
                           vals=vals.Strings())

        self.add_parameter('mode',
                           label='Instrument operation mode',
                           set_cmd='INSTrument:MODE {}',
                           get_cmd='INSTrument:MODE?',
                           vals=vals.Enum('AWG', 'FGEN'))

        ##################################################
        # Clock parameters

        self.add_parameter('sample_rate',
                           label='Clock sample rate',
                           set_cmd='CLOCk:SRATe {}',
                           get_cmd='CLOCk:SRATe?',
                           unit='Sa/s',
                           get_parser=float,
                           vals=SRValidator(self))

        self.add_parameter('clock_source',
                           label='Clock source',
                           set_cmd='CLOCk:SOURce {}',
                           get_cmd='CLOCk:SOURce?',
                           val_mapping={
                               'Internal': 'INT',
                               'Internal, 10 MHZ ref.': 'EFIX',
                               'Internal, variable ref.': 'EVAR',
                               'External': 'EXT'
                           })

        self.add_parameter('clock_external_frequency',
                           label='External clock frequency',
                           set_cmd='CLOCk:ECLock:FREQuency {}',
                           get_cmd='CLOCk:ECLock:FREQuency?',
                           get_parser=float,
                           unit='Hz',
                           vals=vals.Numbers(6.25e9, 12.5e9))

        # We deem 2 channels too few for a channel list
        if self.num_channels > 2:
            chanlist = ChannelList(self,
                                   'Channels',
                                   AWGChannel,
                                   snapshotable=False)

        for ch_num in range(1, num_channels + 1):
            ch_name = 'ch{}'.format(ch_num)
            channel = AWGChannel(self, ch_name, ch_num)
            self.add_submodule(ch_name, channel)
            if self.num_channels > 2:
                chanlist.append(channel)

        if self.num_channels > 2:
            chanlist.lock()
            self.add_submodule('channels', chanlist)

        # Folder on the AWG where to files are uplaoded by default
        self.wfmxFileFolder = "\\Users\\OEM\\Documents"
        self.seqxFileFolder = "\\Users\\OEM\Documents"

        self.current_directory(self.wfmxFileFolder)

        self.connect_message()
Esempio n. 26
0
    def __init__(self, name, address, silent=False, **kwargs):
        """
        Args:
            name (string): The name of the instrument used internally
                by QCoDeS. Must be unique.
            address (string): The VISA resource name.
            silent (Optional[bool]): If True, no connect message is printed.
        """

        super().__init__(name, address, **kwargs)

        def errorparser(rawmssg):
            """
            Parses the error message.

            Args:
                rawmssg (str): The raw return value of 'SYSTem:ERRor?'

            Returns:
                tuple (int, str): The error code and the error message.
            """
            code = int(rawmssg.split(',')[0])
            mssg = rawmssg.split(',')[1].strip().replace('"', '')

            return code, mssg

        channels = ChannelList(self,
                               "Channels",
                               KeysightChannel,
                               snapshotable=False)
        for i in range(1, 3):
            channel = KeysightChannel(self, 'ch{}'.format(i), i)
            channels.append(channel)
        channels.lock()
        self.add_submodule('channels', channels)

        self.add_parameter('sync_source',
                           label='Source of sync function',
                           set_cmd='OUTPut:SYNC:SOURce {}',
                           get_cmd='OUTPut:SYNC:SOURce?',
                           val_mapping={
                               1: 'CH1',
                               2: 'CH2'
                           },
                           vals=vals.Enum(1, 2))

        self.add_parameter('sync_output',
                           label='Sync output state',
                           set_cmd='OUTPut:SYNC {}',
                           get_cmd='OUTPut:SYNC?',
                           val_mapping={
                               'ON': 1,
                               'OFF': 0
                           },
                           vals=vals.Enum('ON', 'OFF'))

        self.add_parameter('error',
                           label='Error message',
                           get_cmd='SYSTem:ERRor?',
                           get_parser=errorparser)

        self.add_function('force_trigger', call_cmd='*TRG')

        self.add_function('sync_channel_phases', call_cmd='PHAS:SYNC')

        if not silent:
            self.connect_message()
class PulseBlasterDDS(Instrument):
    """
    This is the qcodes driver for the SpinCore PulseBlasterDDS-II-300
    """

    # pb_start_programming options
    TX_PHASE_REGS = 2
    RX_PHASE_REGS = 3
    # COS_PHASE_REGS = 4 # RadioProcessor boards ONLY
    # SIN_PHASE_REGS = 5 # RadioProcessor boards ONLY

    # pb_write_register options
    BASE_ADDR = 0x40000
    FLAG_STATES = BASE_ADDR + 0x8
    START_LOCATION = BASE_ADDR + 0x7

    # pb_dds_load options
    DEVICE_DDS = 0x099000
    DEVICE_SHAPE = 0x099001

    N_CHANNELS = 2
    N_FREQ_REGS = 16
    N_PHASE_REGS = 8
    N_AMPLITUDE_REGS = 4

    DEFAULT_DDS_INST = (0, 0, 0, 0, 0)

    PROGRAM_INSTRUCTIONS_MAP = {
        'CONTINUE': 0,  #inst_data=Not used
        'STOP': 1,  #inst_data=Not used
        'LOOP': 2,  #inst_data=Number of desired loops
        'END_LOOP': 3,  #inst_data=Address of instruction originating loop
        'JSR': 4,  #inst_data=Address of first instruction in subroutine
        'RTS': 5,  #inst_data=Not Used
        'BRANCH': 6,  #inst_data=Address of instruction to branch to
        'LONG_DELAY': 7,  #inst_data=Number of desired repetitions
        'WAIT': 8
    }  #inst_data=Not used

    def __init__(self, name, board_number=0, initialize=True, **kwargs):
        """
        Initialize the pulseblaster DDS

        Args:
            name: Name of instrument 
            **kwargs: Additional keyword arguments passed to Instrument
        """
        super().__init__(name, **kwargs)

        # Create an empty list of lists of instructions [[], [], ...]
        self.instructions = [[] for _ in range(self.N_CHANNELS)]

        ########################################################################
        ###                              Parameters                          ###
        ########################################################################
        self.add_parameter('core_clock',
                           label='Core clock',
                           set_cmd=self.set_core_clock,
                           vals=Numbers(),
                           docstring='The core clock of the PulseBlasterDDS')

        self.add_parameter('board_number',
                           set_cmd=None,
                           initial_value=board_number)

        self.output_channels = ChannelList(self,
                                           name='output_channels',
                                           chan_type=InstrumentChannel)

        for ch_idx in range(self.N_CHANNELS):
            ch_name = f'ch{ch_idx+1}'
            output_channel = InstrumentChannel(self, ch_name)
            output_channel.idx = ch_idx
            self.output_channels.append(output_channel)

            output_channel.add_parameter(
                'frequencies',
                label=f'{ch_name} frequency',
                unit='Hz',
                # set_cmd=partial(self.set_frequencies, ch_idx),
                set_cmd=None,
                vals=Lists(Numbers()))
            output_channel.add_parameter(
                'phases',
                label=f'{ch_name} phase',
                unit='deg',
                # set_cmd=partial(self.set_phases, ch_idx),
                set_cmd=None,
                vals=Lists(Numbers()))
            output_channel.add_parameter(
                'amplitudes',
                label=f'{ch_name} amplitude',
                unit='V',
                # set_cmd=partial(self.set_amplitudes, ch_idx),
                set_cmd=None,
                vals=Lists(Numbers()))

        self.add_parameter('instruction_sequence',
                           set_cmd=None,
                           initial_value=[],
                           vals=Lists(),
                           snapshot_value=False)

        # Initialize the DDS
        self.setup(initialize=initialize)

    ###########################################################################
    ###                         DDS Board commands                          ###
    ###########################################################################
    # Just wrapped from spinapi.py #

    @staticmethod
    def get_error():
        """ Print library error as UTF-8 encoded string. """
        return str(api.pb_get_error())

    @staticmethod
    @error_parse
    def get_version():
        """ Return the current version of the spinapi library being used. """
        return api.pb_get_version()

    @staticmethod
    @error_parse
    def count_boards():
        """ Print the number of boards detected in the system. """
        return api.pb_count_boards()

    @staticmethod
    @error_parse
    def initialize():
        """Initialize currently selected board."""
        return api.pb_init()

    @staticmethod
    @error_parse
    def set_debug(debug):
        """ Enables logging to a log.txt file in the current directory """
        return api.pb_set_debug(debug)

    @staticmethod
    @error_parse
    def select_board(board_number):
        """ Select a specific board number """
        return api.pb_select_board(board_number)

    @staticmethod
    @error_parse
    def set_defaults():
        """ Set board defaults. Must be called before using any other board 
        functions."""
        return api.pb_set_defaults()

    def set_core_clock(self, clock):
        """ Sets the core clock reference value

        Note: This does not change anything in the device, it just provides 
        the library with the value given
        """
        self.select_board(self.board_number())
        api.pb_core_clock(clock)

    @staticmethod
    @error_parse
    def write_register(address, value):
        """ Write to one of two core registers in the DDS

        Args:
            address (int) : the address of the register
            value   (int) : the value to be written to the register
        """
        return api.pb_write_register(address, value)

    ###########################################################################
    ###                        DDS Control commands                         ###
    ###########################################################################

    def setup(self, initialize=False):
        """
        Sets up the DDS
        Args:
            initialize (Bool): Initialize the DDS (should only be done once 
                at the start). False by default 

        """
        assert self.count_boards() > 0, "PB Error: Can't find board"
        self.select_board(self.board_number())
        if initialize:
            self.initialize()

    @error_parse
    def start(self):
        self.setup(initialize=False)

        # Reprogram instruction sequence as it may have been overwritten by stop
        self.program_instruction_sequence(self.instruction_sequence())
        self.reset()

        # This api function does not seem to do much
        return api.pb_start()

    @error_parse
    def reset(self):
        self.select_board(self.board_number())
        return api.pb_reset()

    @error_parse
    def stop(self):
        self.setup(initialize=False)

        # Must overwrite the sequence (api.pb_stop does not work)
        stop_instruction = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'stop', 0, 20000)
        self.program_instruction_sequence([stop_instruction])
        self.reset()

        # This api function does not seem to do much, might be due to
        # firmware (see manual)
        return api.pb_stop()

    @error_parse
    def close(self):
        self.select_board(self.board_number())
        return api.pb_close()

    def add_instruction(self, inst, channel):
        self.instructions[channel].append(inst)

    @error_parse
    def start_programming(self, mode):
        """ Start a programming sequence 

        Args:
            mode    (int) : one of (PULSE_PROGRAM, FREQ_REGS, etc.)
        """
        self.select_board(self.board_number())
        return api.pb_start_programming(mode)

    @error_parse
    def instruction_sine_pulse(self, freq0, phase0, amp0, dds_en0,
                               phase_reset0, freq1, phase1, amp1, dds_en1,
                               phase_reset1, flags, inst, inst_data, length):
        """ During start_programming(PULSE_PROGRAM) 
            add an unshaped sine pulse to program

        Args:
            inst  (tuple) : a tuple to program the board, must be of form:
            
                            (int freq0, int phase0, int amp0, int dds_en0, 
                             int phase_reset0, int freq1, int phase1, 
                             int amp1, int dds_en1, int phase_reset1, int flags,
                             int inst, int inst_data, double length)
                             
                             dds_en should be api.TX_ENABLE or api.TX_DISABLE 
        """
        length = round(length * api.s)

        if isinstance(inst, str):
            inst = self.PROGRAM_INSTRUCTIONS_MAP[inst.upper()]

        self.select_board(self.board_number())
        return api.pb_inst_dds2(freq0, phase0, amp0, dds_en0, phase_reset0,
                                freq1, phase1, amp1, dds_en1, phase_reset1,
                                flags, inst, inst_data, length)

    @error_parse
    def instruction_shaped_sine_pulse(self, *inst):
        """ During start_programming(PULSE_PROGRAM) 
            add a shaped pulse to program, if desired

        Args:
            inst  (tuple) : a tuple to program the board in the
                            (FREQ0, PHASE0, ...)
        """
        inst = inst[:-1] + (round(inst[-1] * api.s), )
        self.select_board(self.board_number())
        return api.pb_inst_dds2_shape(*inst)

    @error_parse
    def dds_load(self, data, device):
        """ Load a 1024 point waveform into one of two devices

        Args:
            data  (list) : a 1024 point waveform. Each point ranges
                           from -1.0 to 1.0
            device (int) : Either DEVICE_DDS (the default shape for all output)
                               or DEVICE_SHAPE (an alternative shape register)
        """
        self.select_board(self.board_number())
        return api.pb_dds_load(device)

    @error_parse
    def stop_programming(self):
        """ End a programming sequence """
        self.select_board(self.board_number())
        return api.pb_stop_programming()

    @error_parse
    def select_dds(self, channel):
        self.select_board(self.board_number())
        return api.pb_select_dds(channel)

    def program_instruction_sequence(self, instruction_sequence):
        """ An all-in-one method to send a sequence of instructions to the board

        Args:
            instruction_sequence (list) : a list of instructions to program
                                    the board
                                    the instructions should be tuples i.e.
                                    (FREQ0, PHASE0, ...)
        """
        self.start_programming(api.PULSE_PROGRAM)
        for instruction in instruction_sequence:
            self.instruction_sine_pulse(*instruction)
        self.stop_programming()

    @error_parse
    def set_shape_defaults(self, channel):
        """ Resets the shape for the specified channel

        Args:
            channel      (int) : Either DDS0 (0) or DDS1 (1)
        """
        self.select_dds(channel)
        return api.pb_set_shape_defaults()

    def load_waveform(self, data, device, channel):
        """ Loads a waveform onto the DDS

        Args:
            data         (arr) : an array of 1024 points representing a single 
                                 period of the waveform. Points range between 
                                 -1.0 and 1.0
            device       (int) : Either DEVICE_DDS or DEVICE_SHAPE
            channel      (int) : Either DDS0 (0) or DDS1 (1)
        """
        self.select_dds(channel)
        return self.dds_load(data, device)

    @error_parse
    def set_envelope_freq(self, freq, channel, register):
        """ Sets the frequency for an envelope register

        Args:
            freq       (float) : the frequency in Hz for the envelope register
            register     (int) : the register number
            channel      (int) : Either DDS0 (0) or DDS1 (1)
        """
        # Scale the frequency to Hertz, as the underlying api assumes MHz
        freq *= api.Hz
        self.select_dds(channel)
        return api.pb_dds_set_envelope_freq(freq, register)

    ###########################################################################
    ###                  Set/Get commands for parameters                    ###
    ###########################################################################

    def set_frequencies(self, channel, frequencies):
        """ Sets the DDS frequency for the specified channel and register

        Args:
            frequency (list(double)): the frequency in Hz for a channel register
            channel      (int) : Either DDS0 (0) or DDS1 (1)
        """
        # Scale the frequency to Hertz, as the underlying api assumes MHz

        frequencies = np.array(frequencies) * api.Hz

        # Update channel frequencies
        self.select_dds(channel)
        self.start_programming(api.FREQ_REGS)
        for frequency in frequencies:
            error_parse(api.pb_set_freq)(frequency)
        self.stop_programming()

    def set_phases(self, channel, phases):
        """ Sets the DDS phase for the specified channel and register

        Args:
            phases (list(double)): List of phases for a channel register
            channel        (int) : Either DDS0 (0) or DDS1 (1)
        """
        self.select_dds(channel)
        self.start_programming(self.TX_PHASE_REGS)
        for phase in phases:
            error_parse(api.pb_set_phase)(phase)
        self.stop_programming()

    def set_amplitudes(self, channel, amplitudes):
        """ Sets the DDS amplitude for the specified channel and register

        Args:
            channel (int) : Either DDS0 (0) or DDS1 (1)
            amplitudes (list(double)): Register amplitudes in Volt for a 
                channel 
        """
        self.select_dds(channel)
        # Amplitudes does not need to start programming
        for register, amplitude in enumerate(amplitudes):
            # Looking at the DDS output, an amplitude of 1 apparently
            # corresponds to 0.6V output. This further decreases if the
            # frequency is below 1 MHz,  but above 1MHz it is fairly constant.
            amplitude /= 0.6
            error_parse(api.pb_set_amp)(amplitude, register)
Esempio n. 28
0
    def __init__(self, name, address, update_currents=False, **kwargs):
        """
        Instantiates the instrument.

        Args:
            name (str): The instrument name used by qcodes
            address (str): The VISA name of the resource
            update_currents (bool): Whether to query all channels for their
                current sensor value on startup, which takes about 0.5 sec
                per channel. Default: False.

        Returns:
            QDac object
        """

        super().__init__(name, address, **kwargs)
        handle = self.visa_handle
        self._get_status_performed = False

        # Communication setup + firmware check
        handle.baud_rate = 480600
        handle.parity = visa.constants.Parity(0)
        handle.data_bits = 8
        self.set_terminator('\n')
        handle.write_termination = '\n'
        self._write_response = ''
        firmware_version = self._get_firmware_version()
        if firmware_version < 1.07:
            LOG.warning(f"Firmware version: {firmware_version}")
            raise RuntimeError('''
                No QDevil QDAC detected or the firmware version is obsolete.
                This driver only supports version 1.07 or newer. Please
                contact [email protected] for a firmware update.
                ''')

        # Initialse basic information and internal book keeping
        self.num_chans = self._get_number_of_channels()
        num_boards = int(self.num_chans / 8)
        self._output_n_lines = self.num_chans + 2
        self._chan_range = range(1, 1 + self.num_chans)
        self.channel_validator = vals.Ints(1, self.num_chans)
        self._reset_bookkeeping()

        # Add channels (and channel parameters)
        channels = ChannelList(self,
                               "Channels",
                               QDacChannel,
                               snapshotable=False,
                               multichan_paramclass=QDacMultiChannelParameter)

        for i in self._chan_range:
            channel = QDacChannel(self, f'chan{i:02}', i)
            channels.append(channel)
            self.add_submodule(f'ch{i:02}', channel)
        channels.lock()
        self.add_submodule('channels', channels)

        # Updatechannel  sync port validator according to number of boards
        self._num_syns = max(num_boards - 1, 1)
        for chan in self._chan_range:
            self.channels[chan - 1].sync.vals = vals.Ints(0, self._num_syns)

        # Add non-channel parameters
        for board in range(num_boards):
            for sensor in range(3):
                label = f'Board {board}, Temperature {sensor}'
                self.add_parameter(name=f'temp{board}_{sensor}',
                                   label=label,
                                   unit='C',
                                   get_cmd=f'tem {board} {sensor}',
                                   get_parser=self._num_verbose)

        self.add_parameter(name='cal',
                           set_cmd='cal {}',
                           vals=vals.Ints(0, self.num_chans))

        self.add_parameter(name='mode_force',
                           label='Mode force',
                           get_cmd=None,
                           set_cmd=None,
                           vals=vals.Bool(),
                           initial_value=False)

        # Due to a firmware bug in 1.07 voltage ranges are always reported
        # vebosely. So for future compatibility we set verbose True
        self.write('ver 1')
        self._update_voltage_ranges()
        # The driver require verbose mode off except for the above command
        self.write('ver 0')
        self._verbose = False  # Just so that the code can check the state
        self.connect_message()
        LOG.info('[*] Querying all channels for voltages and currents...')
        self._update_cache(update_currents=update_currents)
        self._update_currents = update_currents
        self._load_state()
        LOG.info('[+] Done')
Esempio n. 29
0
    def __init__(self,name:str,
                      address:str,
                      num_chans:int=16,
                      init_start:bool=False,
                      synchronous_enable:bool=True,
                      synchronous_delay:float=1,
                      synchronous_threshold:float=1e-5,
                      **kwargs: Any) -> None:
        """
        Instantiate the instrument.

        Args:
            name: The instrument name used by qcodes
            address: The VISA name of the resource
            num_chans: Number of channels to assign. Default: 16
            init_start: If true set all channels to 0V, 1.2V range and switch
                then on.
            synchronous_enable: If true, block the communication until the set voltage
                is reached. The communication is block through a simple while loop
                with a waiting time "synchronous_delay" at each iteration until the
                set voltage and the measured voltage difference is below
                "synchronous_threshold".
            synchronous_delay: Time between to voltage measurement in second.
            synchronous_threshold: Threshold to unblock communication in volt.

        Returns:
            ITest object
        """
        super().__init__(name, address=address,
                               terminator='\n',
                               device_clear=False,
                               **kwargs)

        self.idn = self.get_idn()
        self.num_chans = num_chans
        self.chan_range = range(1,self.num_chans+1)

        # Create the channels
        channels = ChannelList(parent=self,
                               name='Channels',
                               chan_type=iTestChannel,
                               multichan_paramclass=iTestMultiChannelParameter)

        for i in self.chan_range:

            channel = iTestChannel(self, name='chan{:02}'.format(i),
                                         chan_num=i)
            channel.synchronous_enable(synchronous_enable)
            channel.synchronous_delay(synchronous_delay)
            channel.synchronous_threshold(synchronous_threshold)
            channels.append(channel)
            self.add_submodule('ch{:02}'.format(i),channel)

        channels.lock()
        self.add_submodule('channels',channels)

        if init_start:
            for channel in self.channels:
                channel.v.set(0)
                channel.v_range(1.2)
                channel.start()

        self.connect_message()
Esempio n. 30
0
    def __init__(self, name, address, timeout=2, **kwargs):
        """
        Initialises the Rigol DS1000
        
        Args:
            name (str) of the instrument
            address (string) Visa address for the instrument
            timeout (float) visa timeout
        """
        super().__init__(name, address, device_clear=False, timeout=timeout, **kwargs)
        self.connect_message()

        # functions
        self.add_function('run',
                          call_cmd=':RUN',
                          docstring='Start acquisition')
        self.add_function('stop',
                          call_cmd=':STOP',
                          docstring='Stop acquisition')
        self.add_function('single',
                          call_cmd=':SINGle',
                          docstring='Single trace acquisition')
        self.add_function('force_trigger',
                          call_cmd='TFORce',
                          docstring='Force trigger event')

        #acquire mode parameters
        self.add_parameter("acquire_type",
                label='type of aquire being used by oscilloscope',
                get_cmd=':ACQ:TYPE?',
                set_cmd='ACQ:TYPE {}',
                vals=vals.Enum('NORMAL', 'AVERAGE', 'PEAKDETECT'))
        self.add_parameter("acquire_mode",
                label="mode of aquisition being used by oscillioscope",
                get_cmd=':ACQ:MODE?',
                set_cmd=':ACQ:MODE {}',
                vals = vals.Enum('RTIM', 'ETIM')
                )
        self.add_parameter("acquire_averages",
                label="the average number in averages mode",
                get_cmd=':ACQ:AVER?',
                set_cmd=':ACQ:AVER {}',
                vals=vals.Enum('2', '4', '8', '16', '32', '64', '128', '256'))
        #note to self: aquire sampling rate parameters to go under channel class
        self.add_parameter("acquire_mem_depth",
                label='depth of memory being used by oscilloscope',
                get_cmd=':ACQ:MEMDepth?',
                set_cmd=':ACQ:MEMDepth {}',
                vals = vals.Enum('LONG', 'NORM'))

        #display parameters
        self.add_parameter("display_type",
                label='display type between samples, either vector or dot',
                get_cmd=':DISP:TYPE?',
                set_cmd=':DISP:TYPE {}',
                vals = vals.Enum('VECT', 'DOTS'))
        self.add_parameter("display_grid",
                label='controls/queries if the oscilloscope display has a grid',
                get_cmd=':DISP:GRID?',
                set_cmd=':DISP:GRID {}',
                vals = vals.Enum('FULL', 'HALF', 'NONE'))
        self.add_parameter("display_persist",
                label="controls/queries if the waveform record point persists or refreshes",
                get_cmd=':DISP:PERS?',
                set_cmd=':DiSP:PERS {}',
                vals = vals.Enum('ON', 'OFF'))
        self.add_parameter("display_mnud",
                label="timing for menus hiding automatically",
                get_cmd=':DISP:MNUD?',
                set_cmd=':DISP:MNUD {}',
                vals = vals.Enum('1', '2', '5', '10', '20', 'Infinite')
                )
        self.add_parameter("display_mnus",
                label="status of the menus",
                get_cmd=':DISP:MNUS?',
                set_cmd=':DISP:MNUS {}',
                vals = vals.Enum('ON', 'OFF'))
        #note to self - add display clear parameter
        self.add_parameter("display_brightness",
                label="set and get the brightness of the grid for the oscilloscope",
                get_cmd=':DISP:BRIG?',
                set_cmd=':DISP:BRIG {}',
                get_parser=int,
                vals=vals.Ints(0,32))
        self.add_parameter("display_intensity",
                label="set the brightness of the waveform",
                get_cmd=':DISP:INT?',
                set_cmd=':DISP:INT {}',
                get_parser=int,
                vals=vals.Ints(0,32))

        # Channel parameters
        channels = ChannelList(self, "Channels", RigolDS1000Channel, snapshotable=False)

        for channel_number in [1, 2]:
            channel = RigolDS1000Channel(self, "ch{}".format(channel_number), channel_number)
            channels.append(channel)

        for channel_number in ['MATH', 'FFT']:
            channel = RigolDS1000Channel(self, "ch_{}".format(channel_number), channel_number)
            channels.append(channel)

        channels.lock()
        self.add_submodule('channels', channels)

        #timebase parameters
        self.add_parameter("time_base_mode",
                label="the scan mode of the horizontal time base",
                get_cmd=":TIM:MODE?",
                set_cmd=":TIM:MODE {}",
                vals = vals.Enum('MAIN', 'DEL'))
        #note to self, decide how to deal with timebase offset parameter.
        self.add_parameter("time_base_offset",
                label="controls the main and delayed mode offset",
                get_cmd=":TIM:OFFS?",
                set_cmd=":TIM:OFFS {}",
                get_parser=float,
                unit="s")
        
        self.add_parameter("time_base_scale",
                label="the scale of the horizontal time base",
                get_cmd=":TIM:SCAL?",
                set_cmd=":TIM:SCAL {}",
                get_parser=float,
                unit="s/div")
        self.add_parameter("time_base_format",
                label="the format of the time base",
                get_cmd=":TIM:FORM?",
                set_cmd=":TIM:FORM {}",
                vals=vals.Enum('X-Y', 'Y-T', 'SCANNING')
                )
        #trigger commands
        self.add_parameter("trigger_mode",
                label="sets and queries the trigger mode",
                get_cmd=":TRIG:MODE?",
                set_cmd=":TRIG:MODE {}",
                vals = vals.Enum('EDGE', 'PULSE', 'VIDEO', 'SLOPE',
                    'PATTERN','DURATION', 'ALTERNATION')
                )
        self.add_parameter("trigger_source",
                label="sets and queries the trigger source",
                get_cmd = ":TRIG:{}:SOUR?".format(self.trigger_mode()),
                set_cmd = ":TRIG:{}:SOUR {}".format(self.trigger_mode(), "{}")
                #get_cmd = self.source_get_cmd,
                #set_cmd = self.source_set_cmd,
                )
        self.add_parameter("trigger_level",
                label="sets and queries the trigger level",
                get_cmd=":TRIG:{}:LEV?".format(self.trigger_mode()),
                set_cmd=":TRIG:{}:LEV {}".format(self.trigger_mode(), "{}"),
                #get_cmd = self.level_get_cmd,
                get_parser = float,
                #set_cmd = self.level_set_cmd,
                unit = "V"
                #vals = vals.permissiveInts(-6*#vertical scale, 6*#vertical scale())
                )
        self.add_parameter("trigger_sweep",
                label="sets and queries the trigger sweep",
                get_cmd =":TRIG:{}:SWE?".format(self.trigger_mode()),
                set_cmd =":TRIG:{}:SWE {}".format(self.trigger_mode(), "{}"),
                #get_cmd = self.sweep_get_cmd,
                #set_cmd = self.sweep_set_cmd,
                vals = vals.Enum("AUTO","NORM","SING")
                )
        self.add_parameter("trigger_coupling",
                label="sets and queries the coupling",
                get_cmd = ":TRIG:{}:COUP?".format(self.trigger_mode()),
                set_cmd = ":TRIG:{}:COUP {}".format(self.trigger_mode(), "{}"),
                vals = vals.Enum("DC","AC","HF","LF")
                )
        self.add_parameter("trigger_holdoff",
                label="sets and queries the trigger holdoff",
                get_cmd = ":TRIG:HOLD?",
                set_cmd = ":TRIG:HOLD {}",
                get_parser = float,
                unit = 's'
               )

        # Waveform
        self.add_parameter("waveform_points_mode",
                   label="Number of the waveform points",
                   get_cmd=":WAVEFORM:POINTS:MODE?",
                   set_cmd=":WAVEFORM:POINTS:MODE {}",
                   vals = vals.Enum("NORM","MAX","RAW"),
                   get_parser=str,
                  )