Eager to get started? This page gives a good introduction to zhinst-qcodes. Follow Installation to install zhinst-qcodes first.


Before you can spin up zhinst-qcodes LabOne® needs to installed and running. For a complete reference see the dedicated user manual page for your instrument(s).

Before you continue make sure a LabOne® data server is running in your network and all of your devices are visible.

Session To The Data Server#

Zurich Instruments devices use a server-based connectivity methodology. Server-based means that all communication between the user and the instrument takes place via a computer program called a server, the Data Server. The Data Server recognizes available instruments and manages all communication between the instrument and the host computer on one side, and communication to all the connected clients on the other side. (see Architecture in the LabOne Programming Manual)

The entry point into zhinst-qcodes is therefor a API client session to a data server:

>>> from zhinst.qcodes import ZISession
>>> session = ZISession("localhost")

(if your data server runs on a remote computer (e.g. an MFLI directly) replace localhost with the correct address.)

The data server can be connected to one or multiple devices. By connecting, or accessing an already connected, device a new device object for that device is created by zhinst-qcodes.

>>> session.devices.visible()
['dev1234', 'dev5678']
>>> session.devices.connected()
>>> session.devices['dev1234']
<ZIBaseInstrument: zi_XXXX_dev1234>
>>> session.connect_device('dev5678')
<ZIBaseInstrument: zi_XXXX_dev5678>

The created device object holds all device specific nodes and depending on the device type also implements additional functionalities (e.g. exposes the zhinst.utils functions).

>>> device = session.devices['dev1234']
>>> device.demods[0].freq()

The drivers are based on zhinst-toolkit, a generic high level python driver for LabOne. Except for the node tree which in case for the zhinst-qcodes driver is implemented with the native QCoDeS Parameters, both driver behave the same. To be even more precise the zhinst-qcodes forwards all calls (functions, parameters …) to zhinst-toolkit and has no logic builtin what so ever.

For the device drivers this means that some device may have additional functionality provided by zhinst-toolkit. zhinst-qcodes forwards these functionalities. Please take a look at the examples in the zhinst-toolkit examples to see a list of all available functions. As already mentioned they can be used with the exact same syntax, which also is the case for all the examples from zhinst-toolkit (just replace the imports from zhinst-toolkit with zhinst-qcodes).

Easy Device Setup#

Since QCoDeS by design normally creates device objects directly zhinst-qcodes exposes helper classes for each instrument type that can be used to create a device object directly, without creating a session first. Note that these classes are just wrapper around the server-based connectivity methodology.

>>> from zhinst.qcodes import HDAWG
>>> device = HDAWG("DEV1234", "localhost", name="optional_qcodes_name")


If the instrument you are using does not have a dedicated helper class yet you can use the generic one ZIDevice.

Under the hood the helper class just creates a session, connects the device to it and returns the device class. It is therefore identical to:

>>> from zhinst.qcodes import ZISession
>>> session = ZISession("localhost")
>>> device = session.connect_device("DEV1234")

To avoid creating a new session to data server every time when using these helper classes, zhinst-qcodes by default only creates one session to a data server. Meaning if one connects two devices to e.g. localhost they will share the same session. For most use cases this is the desired behavior since it saves resources and avoids unintended edge cases. In the rare cases where you need to have a separate session for a device one can use the new_session flag. But it is preferred to work in such cases with the session directly and not use the helper classes, since it is simpler to understand and recreate.

Node Tree#

All settings and data in LabOne® are organized by the Data Server in a file-system-like hierarchical structure called the node tree. zhinst-qcodes implements the node tree in the by QCoDeS provided nested dictionary like structure. All leaf nodes are qcodes.instrument.parameter.Parameter nested in qcodes.instrument.baseInstrumentChannel s. Please refer to the QCoDeS Documentation for a detailed explanation of Parameter work in QCoDeS.

>>> session.debug.level()

So what did that code do?

  1. The session represents the session to the data server and therefor gives access to its nodes (/zi/* in the LabOne API).

  2. One of these nodes is zi/debug/level. zhinst-qcodes allows it to access that node by attributes.

  3. To get the current value of the node simply make a call operation.

Changing the value of a node can be done in a similar way. Simply add the value to the call operation.

>>> session.debug.level('warning')
>>> session.debug.level()

LabOne® modules#

In addition to the usual API commands available for instrument configuration and data retrieval the LabOne® API also provides a number of so-called modules: high-level interfaces that perform common tasks such as sweeping data or performing FFTs. (See the LabOne Programming Manual For a complete documentation of all modules available)

In zhinst-qcodes these modules can be accessed through the session. Similar to the devices each module can be controlled through a node tree. Some of the modules have toolkit specific functionalities (e.g. reading the acquired data automatically). To see an overview of the module specific functionalities take a look at the dedicated examples.


The underlying LabOne® module (zhinst.core object) can be accessed with the raw_module property

>>> daq_module = session.modules.daq
>>> daq_module.grid.mode()
>>> daq_module.raw_module
<zhinst.core.DataAcquisitionModule at 0x10edc5630>

Please take a look at the examples in the zhinst-toolkit examples to see some of the modules in action.