Device drivers
The device model, driver catalogue and custom driver development.
Quatm separates experiment logic from instrument communication. Every instrument is addressed through a logical name in device_db.py; the driver decides whether that name maps to a serial port, a VISA resource, a TCP socket, a USB device or a vendor DLL.
Access modes
| Mode | Behaviour | When to use |
|---|
local | Constructs a driver object | cameras, FPGA controllers, translation stages |
attr | Maps a channel to a Python attribute | DAC/TTL outputs |
generic_attr | Calls a named driver function | DDS tones, multi-channel settings |
All modes support simulation. In simulation the same experiment code runs against a dummy backend, which is essential for developing sequences without occupying the apparatus.
Driver categories
The bundled catalogue covers:
- Real-time control — ADwin, FPGA, timing and trigger distribution.
- Lasers and light — Toptica, Moglabs, Vescent, laser locks and shutters.
- Signal generation and RF — Spectrum AWGs, Rigol, Valon, DDS boards.
- Scientific cameras — Andor, FLIR/BlackFly, PCO and generic video sources.
- Motion and positioning — PI stages, Thorlabs, piezo mirrors.
- DAQ and power supplies — NI, MCC, Keysight, Keithley.
- Environmental monitoring — temperature controllers, magnetometers, wavemeters, vacuum gauges.
The catalogue and per-driver verification status are tracked in the repository (docs/DRIVER_VERIFICATION.md). A driver is considered verified only after it has been exercised on real hardware.
Writing a driver
A driver is a normal Python class with:
__init__ accepting the arguments declared in device_db.py;simulating handling for offline use;- explicit
close() releasing sockets, serial ports and vendor handles; - optional
check() / self-test hooks used by the Device Manager.
Place project-specific drivers under <project>/drivers/. They are imported before bundled drivers with the same suffix, so a laboratory can pin a local version without forking the framework.
Device health and leases
Opening a device acquires a cross-process lease, preventing two experiments from silently driving the same instrument. The Device Manager can probe instruments, verify drivers and report the current owner. Bus-level locking protects adapters that cannot be opened concurrently.
1 - Scientific cameras
Scientific camera and image acquisition drivers for 15 brands including Andor, Basler, Hamamatsu and FLIR.
Overview
Quatm provides a unified ICamera interface wrapper for 15 major scientific camera brands worldwide, covering EMCCD, sCMOS, high-speed CMOS and industrial cameras.
Andor series: iXon EMCCD / Zyla sCMOS / Shamrock spectrograph
Overview
Quatm provides two Andor camera drivers that deliver high-performance imaging control through the native SDKs:
| Driver class | SDK | Applicable models | Interface |
|---|
AndorSDK2Camera | atmcd32d.dll (SDK2) | iXon EMCCD, Luca, Clara | PCIe / USB |
AndorSDK3Camera | atcore.dll (SDK3) | Zyla, Neo, Marana (sCMOS) | USB3 / CameraLink |
ShamrockSpectrograph | ShamrockCIF.dll | SR-303i, SR-500i and other spectrographs | USB |
All classes inherit from the io.camera interface and support ROI, binning, exposure control and frame buffer management.
Andor SDK2 (EMCCD) AndorSDK2Camera
iXon EMCCD Andor SDK2 series
| Communication | DLL (atm32cd32) |
| Readout mode | EM/conventional |
| ADC frequency | 1/5/10 MHz |
| Pixel depth | 16-bit |
| Cooling | TEC (≤ -100°C) |
Suited to extremely low light levels (single atom/ion fluorescence), achieving single-photon sensitivity through electron multiplication (EM Gain).
Driver module:
AndorSDK2Camera
Initialization
from quatm.drivers.andor.AndorSDK2 import AndorSDK2Camera
# connect the first camera
cam = AndorSDK2Camera(cam_id=0)
# acquisition parameters
cam.setup_acquisition(
exposure=0.1, # exposure time (s)
em_gain=200, # EM gain (0-1000)
readout_rate="5MHz",# readout rate
pre_amp_gain=2, # pre-amplifier gain
hsspeed=0, # horizontal transfer rate
temperature=-70, # target temperature (°C)
)
# acquire a single frame
cam.start_acquisition(nframes=1)
image = cam.read_multiple_images(nframes=1)
Key parameters
| Parameter | Description | Typical range |
|---|
exposure | Exposure time per frame | 0.001 – 3600 s |
em_gain | Electron multiplication gain | 0 – 1000 (linear or real gain mode) |
readout_rate | ADC readout frequency | 1MHz / 5MHz / 10MHz |
temperature | Target sensor temperature | -60 to -100°C (depends on cooler) |
pre_amp_gain | Preamplifier gain | 1× – 4× |
Andor SDK3 (sCMOS) AndorSDK3Camera
Zyla / Neo sCMOS Andor SDK3 series
| Communication | DLL (atcore) |
| Sensor | sCMOS |
| Interface | USB3 / CameraLink |
| Pixel depth | 12/16-bit |
| Frame rate | up to 100 fps (full resolution) |
Suited to fast sequence imaging and applications requiring a large field of view. Exposure, ROI and triggering are configured through the GenAPI property model.
Driver module:
AndorSDK3Camera
Initialization
from quatm.drivers.andor.AndorSDK3 import AndorSDK3Camera
cam = AndorSDK3Camera(cam_id=0)
cam.setup_acquisition(
exposure=0.05,
pixel_format="Mono16",
trigger_mode="Internal",
)
Andor Shamrock spectrograph ShamrockSpectrograph
Controls grating selection, centre wavelength and slit width:
from quatm.drivers.andor.Shamrock import ShamrockSpectrograph
spec = ShamrockSpectrograph(idx=0)
spec.set_wavelength(780.24) # centre wavelength (nm)
spec.set_grating(2) # select grating
spec.set_slit_width(50, port=1) # entrance slit (µm)
Device configuration
"emccd": {
"type": "local",
"module": "drivers.andor.AndorSDK2",
"class": "AndorSDK2Camera",
"arguments": {"cam_id": 0},
}
Calibration note
EMCCD gain must be calibrated for quantitative fluorescence measurements. Excessive gain introduces clock-induced charge (CIC) noise and non-linearity. We recommend establishing a gain–signal curve using fluorescent beads or a calibrated light source.
FLIR / Teledyne / Blackfly S / Grasshopper3
Overview
Quatm wraps the Spinnaker SDK in the TeledyneSpinnakerCamera class, supporting all GenICam/GenAPI-compatible FLIR/Teledyne USB3/GigE cameras.
Blackfly S / Grasshopper3 FLIR Spinnaker series
| Communication | Spinnaker SDK |
| Interface | USB3 / GigE |
| Pixel formats | Mono8/16, Bayer |
| Trigger | hardware/software |
| Frame rate | depends on model |
For general laboratory imaging: MOT monitoring, alignment beam imaging and equipment status monitoring.
Driver module:
TeledyneSpinnakerCamera
Initialization
from quatm.drivers.teledyne.spinnaker import TeledyneSpinnakerCamera
# list all available cameras
cam_list = TeledyneSpinnakerCamera.list_cameras()
# connect a camera by serial or index
cam = TeledyneSpinnakerCamera(cam_id="serial_xxx")
# or use an index
cam = TeledyneSpinnakerCamera(cam_id=0)
# configure and start acquisition
cam.setup_acquisition(
exposure=0.02, # 20 ms exposure
pixel_format="Mono8",
width=1920, height=1200,
offset_x=0, offset_y=0,
)
Key methods
| Method | Description |
|---|
list_cameras() | Enumerate all Spinnaker cameras in the system |
setup_acquisition(**kwargs) | Configure ROI, exposure, pixel format, etc. |
start_acquisition(nframes) | Start acquisition of the specified number of frames |
read_multiple_images(nframes) | Read the acquired images |
get_device_info() | Get the camera serial number, model and firmware version |
Common property operations
Camera parameters are read and written directly by GenAPI node name:
# Set gain
cam.set_attribute("Gain", 10.0)
# Enable auto exposure
cam.set_attribute("ExposureAuto", "Continuous")
# Get sensor temperature
temp = cam.get_attribute("DeviceTemperature")
Device configuration
"monitor_cam": {
"type": "local",
"module": "drivers.teledyne.spinnaker",
"class": "TeledyneSpinnakerCamera",
"arguments": {"cam_id": 0},
}
Multi-camera synchronization
The Spinnaker SDK supports hardware-triggered synchronization of multiple cameras. Setting TriggerMode = On and TriggerSource = Line0 enables nanosecond-level synchronized exposure through an external TTL signal.stop(): Stop capturing images.
quatm.drivers.blackfly.bfly.Camserver(name, serial)
class quatm.drivers.blackfly.bfly.Camserver(object):
def __init__(self, name, serial):
pass
def generateImageIndex(self):
pass
def run(self):
pass
def sendimage(self, im):
pass
def updateBusInfo(self):
pass
generateImageIndex(): In the current measurement, count the images. If the next run has started (either task, repetition or run changes), reset the counter (imgindex).
run(): Run loop running forever. Sends images from the camera to the imagestream and initiates reconfiguration of the camera in case properties have changed.
sendimage(im): Send Blackfly camera image via the imagestream. The image is converted to numpy array, additional information like binning, timestamp, etc., is added to a dictionary and both are sent to the imagestream.
- Args:
im - Blackfly image object. - Returns:
None
updateBusInfo(): Detect cameras on the bus and update info in properties if new camera has been found.
quatm.drivers.blackfly.bfly.pc2
class quatm.drivers.blackfly.bfly.pc2(object):
pass
- Dummy class in case driver is not installed.
Function:
Thorlabs TSI / uc480 scientific cameras
TLCamera ThorlabsTLCamera
TSI series Thorlabs scientific camera
| Communication | TLCamera SDK |
| Interface | USB3 |
| Sensor | sCMOS / CCD |
| Support | ROI, binning |
For high-frame-rate scientific imaging with SDK-level control.
Driver module:
ThorlabsTLCamera
from quatm.drivers.thorlabs.TLCamera import ThorlabsTLCamera
cam = ThorlabsTLCamera(serial="12345678")
cam.setup_acquisition(exposure=0.01, width=1024, height=768)
Basler — Pylon SDK series
Basler ace / dart Pylon SDK series
| Communication | Pylon SDK (GenICam) |
| Interface | USB3 / GigE |
| Sensor | CMOS |
| Pixel formats | Mono8/16, Bayer |
| Features | ROI, Binning, hardware trigger |
Industrial CMOS cameras, suited to routine laboratory imaging tasks such as MOT fluorescence monitoring and alignment beam imaging.
Driver module:
BaslerPylonCamera
from quatm.drivers.Basler.pylon import BaslerPylonCamera
# Enumerate all cameras
cams = BaslerPylonCamera.list_cameras()
cam = BaslerPylonCamera(cam_id=cams[0])
cam.setup_acquisition(exposure=0.02)
cam.start_acquisition(nframes=1)
Hamamatsu ORCA series sCMOS
ORCA-Fusion / ORCA-Flash4.0 Hamamatsu DCAM
| Communication | DCAM SDK (DLL) |
| Sensor | sCMOS |
| Pixels | 2048×2048 (Fusion) |
| Frame rate | up to 100 fps |
| Readout noise | < 1.6 e⁻ |
Ultra-low-noise sCMOS, suited to quantitative single atom/single ion fluorescence imaging.
Driver module:
DCAMCamera
from quatm.drivers.DCAM.DCAM import DCAMCamera
cam = DCAMCamera(idx=0)
cam.setup_acquisition(exposure=0.1, pixel_format="Mono16")
Photometrics Prime / Evolve series
Prime BSI / Evolve EMCCD Photometrics PVCAM
| Communication | PVCAM SDK (DLL) |
| Sensor | back-illuminated sCMOS / EMCCD |
| Interface | PCIe / USB3 |
| Pixel depth | 16-bit |
Back-illuminated sCMOS offers high quantum efficiency; EMCCD models provide single-photon sensitivity.
Driver module:
PVCAMCamera
from quatm.drivers.Photometrics.pvcam import PVCAMCamera
cam = PVCAMCamera(cam_name="Prime_BSI_95B")
cam.setup_acquisition(exposure=0.05)
Princeton Instruments PIXIS / ProEM
PIXIS / ProEM / IsoPlane Princeton PICam
| Communication | PICam SDK (DLL) |
| Sensor | CCD / EMCCD |
| Cooling | liquid nitrogen / TEC |
| Interface | PCIe / USB |
Spectroscopy-grade CCD/EMCCD cameras, commonly used together with Acton/IsoPlane spectrographs.
Driver module:
PicamCamera
from quatm.drivers.PrincetonInstruments.picam import PicamCamera
cam = PicamCamera(cam_id=0)
cam.setup_acquisition(exposure=1.0) # long-exposure spectrum acquisition
PCO edge / dimax high-speed cameras
edge / dimax / pco.panda PCO SC2
| Communication | SC2 SDK (DLL) |
| Interface | CameraLink HS / USB3 / GigE |
| Frame rate | up to several thousand fps |
| Sensor | sCMOS / high-speed CMOS |
Suited to fast dynamical processes: MOT loading dynamics and real-time observation of ion crystal reordering.
Driver module:
PCOSC2Camera
from quatm.drivers.PCO.SC2 import PCOSC2Camera
cam = PCOSC2Camera(interface="USB 3.0")
cam.setup_acquisition(exposure=0.001) # 1 ms high-speed acquisition
Allied Vision Alvium / Mako
Alvium / Mako / Bonito Allied Vision Vimba X
| Communication | VimbaX SDK (GenICam) |
| Interface | USB3 / GigE / CameraLink |
| Sensor | CMOS |
Compact industrial cameras, suited to space-constrained optical path integration.
Driver module:
AlliedVisionVimbaXCamera
from quatm.drivers.AlliedVision.VimbaX import AlliedVisionVimbaXCamera
cam = AlliedVisionVimbaXCamera(cam_id=0)
IDS uEye+ / Ensenso
uEye+ / Ensenso 3D IDS peak
| Communication | IDS peak SDK |
| Interface | USB3 / GigE |
| Sensor | CMOS |
General-purpose USB/GigE cameras, including the Ensenso 3D stereo camera.
Driver module:
GenericIDSPeakCamera
from quatm.drivers.IDS.peak import GenericIDSPeakCamera
cam = GenericIDSPeakCamera(cam_id=0)
Generic configuration pattern
All cameras are registered in device_db.py with type: "local":
"imaging_cam": {
"type": "local",
"module": "drivers.Basler.pylon",
"class": "BaslerPylonCamera",
"arguments": {"cam_id": 0},
}
Frame grabbers
For cameras with a Camera Link interface, Quatm also ships drivers for NI IMAQ, BitFlow and Silicon Software frame grabbers. They are used in the same way as camera drivers: all frame grabbers likewise inherit the io.camera interface.2 - Signal sources and RF
Drivers for frequency synthesizers and RF instruments: Valon 5009, DDS AD9959, Agilent, Rigol.
Overview
Quatm supports a broad range of RF instruments, from general-purpose function generators to vector network analyzers, covering frequency synthesis, arbitrary waveforms and S-parameter measurement.
Valon 5009 dual-channel microwave frequency synthesizer
Overview
The Valon 5009 is a dual-channel frequency synthesizer (23.5 MHz – 6 GHz) controlled over a serial port. Quatm wraps it in valon, which sets the frequency and power of the two outputs independently.
Valon 5009 Dual RF Synthesizer
| Communication | serial (RS232) |
| Frequency range | 23.5 MHz – 6 GHz |
| Channels | 2 |
| Output power | -30 ~ +10 dBm |
| Frequency resolution | 0.1 Hz |
Widely used in ion trap experiments to drive microwave transitions (such as the Ba⁺ 9.9 GHz hyperfine transition) or as an AOM drive source.
Driver module:
valon
Initialization
from quatm.drivers.valon.valon_quatm import valon
# Connect to Valon (default /dev/ttyUSB0)
valon = valon(port="/dev/ttyUSB0")
# Set channel 1 frequency to 500 MHz
valon.set_frequency(freq=500e6, source=1)
# Set channel 2 frequency to 9.925 GHz (external frequency multiplier required)
valon.set_frequency(freq=9.925e9, source=2)
# Send raw command
valon.sendRaw("LOCK 1 ON\r\n")
Key methods
| Method | Description |
|---|
set_frequency(freq, source) | Set the output frequency of channel 1 or 2 (Hz) |
sendCommand(source, command, value) | Send a formatted SCPI command |
sendRaw(cmd) | Send a raw string command |
Serial communication
Underneath, the Valon driver communicates through VSerialPort (a serial.Serial subclass). Typical parameters:
# serial parameters (driver defaults)
port = "/dev/ttyUSB0"
baudrate = 115200
timeout = 0.1
Use the Valon 5009 to drive the 9.925 GHz hyperfine transition and measure Rabi oscillations by scanning the frequency.
Key parameters
| Start frequency | 9.924 GHz |
| Stop frequency | 9.926 GHz |
| Step | 10 kHz |
| Repetitions per point | 100 |
# experiment snippet: frequency scan
import numpy as np
frequencies = np.arange(9.924e9, 9.926e9, 10e3)
for f in frequencies:
valon.set_frequency(freq=f, source=2)
# ... run the probe sequence ...
Reference: See ion trap experiments → quantum state detection
Frequency accuracy
The internal reference stability of the Valon 5009 is limited. For high-precision spectroscopy or quantum control experiments we recommend:
- an external 10 MHz rubidium clock reference
- or real-time monitoring of the output frequency with a HighFinesse wavemeter / spectrum analyzer
class quatm.drivers.valon.valon_prog.Valon_Standalone(name='Valon')
Bases: object
Standalone driver for the Valon frequency generator. Commands can be sent via the Commandhub and are processed in parallel to the experiment, thereby the experiment is not delayed by the Valon.
function quatm.drivers.valon.valon_prog.run()
DDS AD9959 four-channel direct digital synthesis
Overview
The AD9959 driver wraps the AD9959 evaluation board and controls four independent DDS channels over the SPI bus, providing precise frequency, amplitude and phase control.
AD9959 evaluation board 4-channel DDS
| Communication | SPI |
| Channels | 4 |
| Frequency resolution | 32-bit (0.12 Hz @ 500 MHz clock) |
| Phase resolution | 14-bit |
| Amplitude control | 10-bit DAC |
Widely used in cold atom/ion experiments for AOM driving, sideband generation and coherent manipulation.
Driver module:
AD9959
Initialization
from quatm.drivers.dds import AD9959
dds = AD9959()
# Configure channel 0 — cooling-light AOM
dds.set_frequency(0, 80e6) # 80 MHz
dds.set_amplitude(0, 0.5) # 50% amplitude
dds.set_phase(0, 0) # 0° phase
# configure channel 1 — repump AOM (+0.1 MHz offset)
dds.set_frequency(1, 80.1e6)
dds.set_amplitude(1, 0.3)
Key methods
| Method | Description |
|---|
set_frequency(ch, freq_hz) | Set the channel frequency (Hz) |
set_amplitude(ch, amp) | Set the channel amplitude (0–1 fraction) |
set_phase(ch, phase_deg) | Set the channel phase (°) |
update_all() | Update all channels at once |
Synchronized update
The AD9959 supports a synchronized update mode: first call the set_* methods for the four channels individually (buffered), then call update_all() to write everything to the hardware at once. This guarantees phase consistency between channels, which is essential for experiments such as sideband cooling that rely on precise phase relations.Device configuration
"aom_dds": {
"type": "local",
"module": "drivers.DDS",
"class": "AD9959",
}
Typical applications
| Application | Configuration |
|---|
| AOM drive | Single channel, fixed frequency |
| Raman transitions | Two channels, difference-frequency locking |
| Trap drive | Multi-channel phase control |
| Sideband cooling | Frequency modulation |
Alternative driver
An alternative AD9959 board driver with a serial (AT command) interface is also available:
from quatm.drivers.dds.alibaba import AD9959Board
Rigol DG1020Z two-channel function generator
DG1020Z
DG1020Z Rigol function generator
| Communication | VISA (USB/LAN) |
| Channels | 2 |
| Frequency range | 1 µHz – 25 MHz |
| Amplitude | 1 mVpp – 10 Vpp |
| Sampling rate | 200 MSa/s |
Used to generate AOM/EOM drive signals, modulation waveforms and custom arbitrary waveforms.
Driver module:
RigolDG1020Z
from quatm.drivers.AWG.specific import RigolDG1020Z
fg = RigolDG1020Z(addr="USB0::...")
fg.set_frequency(80e6)
fg.set_amplitude(1.0) # 1.0 Vpp
fg.enable_output(channel=1, enable=True)
fg.set_function(channel=1, function="SIN")
Other Rigol devices
DP1116A programmable DC power supply
DP1116A Rigol DC power supply
| Communication | VISA |
| Output | 16V/10A or 32V/5A |
| Channels | 1 |
| Resolution | 1 mV / 1 mA |
Used for coil current control, laser diode driving and circuit board supply.
Driver module:
DP1116A
from quatm.drivers.rigol.power_supply import DP1116A
ps = DP1116A(addr="USB0::0x1AB1::0x0E11::DP1A123456789::INSTR")
ps.set_voltage(12.0) # 12V
dc.set_current(0.5) # 500 mA current limit
ps.enable_output(True)
Oscilloscopes
Rigol DS series oscilloscopes are compatible with the Tektronix SCPI command set and are controlled through the ITektronixScope driver:
from quatm.drivers.tektronix.base import ITektronixScope
scope = ITektronixScope(addr="USB0::0x1AB1::0x04CE::DS123456789::INSTR", nchannels=4)
scope.set_timebase(scale=1e-6) # 1 µs/div
scope.set_vertical(channel=1, scale=0.5) # 0.5 V/div
waveform = scope.acquire(channel=1)
33500B / 33220A / 33250A Agilent/Keysight
| Communication | VISA (USB/LAN/GPIB) |
| Channels | 1–2 |
| Frequency | up to 120 MHz (33500B) |
| Resolution | 14-bit |
| Sampling rate | 250 MSa/s |
| Waveforms | sine/square/ramp/pulse/noise/ARB |
A laboratory standard signal source for AOM driving, modulation signals and reference clock generation.
Driver module:
Agilent33500 / Agilent33220A
from quatm.drivers.awg.specific import Agilent33500
awg = Agilent33500(addr="USB0::0x0957::0x2C07::MY52801234::INSTR")
# Configure an 80 MHz sine wave
awg.set_function(channel=1, function="SIN")
awg.set_frequency(80e6)
awg.set_amplitude(1.0) # 1 Vpp
awg.enable_output(channel=1, enable=True)
# Burst mode — generate N cycles, then stop automatically
awg.enable_burst(channel=1, ncycles=100)
Supported models
| Driver class | Applicable models |
|---|
Agilent33500 | 33500B, 33510B, 33520B, 33522B |
Agilent33220A | 33220A, 33250A |
RigolDG1000 | DG1022, DG1032 |
RigolDG1020Z | DG1022Z, DG1032Z |
Instek AFG2000 / AFG2225 dual channel
AFG-2225 / AFG-2100 Instek
| Communication | VISA |
| Channels | 1 (AFG2000) / 2 (AFG2225) |
| Frequency | up to 25 MHz |
| Sampling rate | 200 MSa/s |
A cost-effective two-channel arbitrary waveform generator.
Driver module:
InstekAFG2225 / InstekAFG2000
from quatm.drivers.awg.specific import InstekAFG2225
awg = InstekAFG2225(addr="USB0::...")
awg.set_frequency(10e6)
awg.set_amplitude(2.0)
awg.enable_output(channel=1, enable=True)
awg.enable_output(channel=2, enable=True)
AFG1022 / AFG1062 Tektronix
| Communication | VISA |
| Channels | 2 |
| Frequency | up to 60 MHz (AFG1062) |
| Sampling rate | 300 MSa/s |
| Arbitrary waveform | 64 MB memory |
A high-performance two-channel AWG with support for large custom waveforms.
Driver module:
TektronixAFG1000
from quatm.drivers.awg.specific import TektronixAFG1000
awg = TektronixAFG1000(addr="USB0::...")
awg.set_function(channel=1, function="ARB")
# Load a custom waveform...
Tektronix DPO/MSO series oscilloscopes
DPO2000 / MSO4000 series Tektronix oscilloscope
| Communication | VISA |
| Bandwidth | 100 MHz – 1 GHz |
| Channels | 2–4 |
| Sampling rate | up to 5 GS/s |
Automates waveform acquisition and parameter measurement over SCPI. Frequently used for experiment debugging and pulse sequence verification.
Driver module:
ITektronixScope
from quatm.drivers.tektronix.base import ITektronixScope
scope = ITektronixScope(
addr="USB0::0x0699::0x0401::C012345::INSTR",
nchannels=4
)
# Configure trigger
scope.set_trigger(source=1, level=0.5, slope="POS")
scope.set_timebase(scale=1e-6) # 1 µs/div
scope.set_vertical(channel=1, scale=0.1) # 0.1 V/div
# Acquire waveform
waveform = scope.acquire(channel=1)
Agilent E5071C vector network analyzer
E5071C Agilent VNA
| Communication | VISA |
| Frequency | 9 kHz – 20 GHz |
| Ports | 2–4 |
| Functions | S-parameters, impedance, Smith chart |
Used for RF component characterization: S-parameter measurement of filters, amplifiers, antennas and transmission lines.
Driver module:
AgilentE5071C
from quatm.drivers.Agilent.vna import AgilentE5071C
vna = AgilentE5071C(addr="TCPIP::192.168.1.100::INSTR")
vna.set_frequency_range(start=1e6, stop=1e9, points=1001)
vna.set_if_bandwidth(100) # 100 Hz IFBW
vna.set_averaging(count=10)
# Read S21 parameters
freq, s21 = vna.read_S_parameters(parameter="S21")
PicoVNA portable vector network analyzer
PicoVNA Pico Technology
| Communication | TCP/SCPI (port 5025) |
| Frequency | 300 kHz – 8.5 GHz |
| Ports | 2 |
| Dynamic range | 100 dB
|
A compact USB-controlled VNA, well suited to desktop RF debugging in the laboratory.
Driver module:
PicoVNA
from quatm.drivers.PicoTech.vna_scpi import PicoVNA
vna = PicoVNA(addr="localhost") # or IP address
vna.set_frequency_range(start=10e6, stop=500e6)
s_params = vna.read_S_parameters(parameter="S21")
Generic SCPI device configuration
"function_gen": {
"type": "local",
"module": "drivers.awg.specific",
"class": "Agilent33500",
"arguments": {"addr": "USB0::..."},
}
3 - Lasers and optics
Drivers for lasers and optical measurement: Cobolt, Toptica, Sirah Matisse, M² Solstis, HighFinesse wavemeters.
Overview
Quatm supports diode lasers, pump lasers, tunable ring lasers and optical measurement instruments. Laser-type devices are controlled over serial ports; SCPI instruments inherit the standard interface.
Hubner Cobolt MLD / DPL single-frequency lasers
Cobolt 06-01 series Hubner Cobolt
| Communication | serial (115200 baud) |
| Wavelength | 405/445/488/515/532/561/594/633/660/780/1064 nm |
| Power | 25–300 mW |
| Modulation | analog + digital TTL (up to 5 MHz) |
Compact DPSS/diode lasers for ion/atom cooling light, repump light and fluorescence excitation.
Driver module:
Cobolt
from quatm.drivers.Hubner.Cobolt import Cobolt
laser = Cobolt(conn="/dev/ttyUSB0")
# Turn on the laser
laser.set_autostart(True)
laser.set_power(50e-3) # 50 mW
# Digital modulation (TTL)
laser.set_digital_modulation(True)
laser.set_modulation_power(100e-3) # High power during modulation
# Read operating parameters
hours = laser.get_operating_hours()
temp = laser.get_base_temperature()
Toptica iBeam smart diode lasers
iBeam series Toptica
| Communication | serial (115200 baud) |
| Wavelength | 375–1550 nm |
Smart laser heads with a built-in controller, supporting automatic current/power calibration and status diagnostics.
Driver module:
TopticaIBeam
from quatm.drivers.Toptica.ibeam import TopticaIBeam
laser = TopticaIBeam(conn="/dev/ttyUSB0")
laser.set_power(channel=0, power=10e-3)
laser.enable(channel=0, enable=True)
Laser Quantum Finesse pump laser
Finesse Laser Quantum
| Communication | serial (19200 baud) |
| Power | 4–16 W (532 nm) |
| Noise | < 0.1% RMS |
| Application | Ti:sapphire/dye laser pumping |
An ultra-low-noise continuous-wave DPSS laser used to pump tunable ring lasers such as the Sirah Matisse.
Driver module:
Finesse
from quatm.drivers.LaserQuantum.base import Finesse
pump = Finesse(conn="/dev/ttyUSB0")
pump.set_power(10.0) # 10 W
pump.enable(True)
actual_power = pump.get_power()
Lighthouse Photonics Sprout G
Sprout G Lighthouse Photonics
| Communication | serial (19200 baud) |
| Wavelength | 532 nm |
| Power | 6–18 W |
| Noise | < 0.2% RMS |
A high-power 532 nm solid-state pump laser for Ti:sapphire lasers and optical dipole traps.
Driver module:
SproutG
from quatm.drivers.LighthousePhotonics.base import SproutG
sprout = SproutG(conn="/dev/ttyUSB0")
sprout.set_power(15.0)
sprout.enable(True)
Sirah Matisse tunable ring laser
Matisse Sirah Lasertechnik
| Communication | VISA or TCP/IP |
| Wavelength range | visible–near-infrared (depends on dye/Ti:sapphire) |
| Linewidth | < 50 kHz (locked) |
| Tuning elements | birefringent filter + thin/thick etalon + piezo |
A precision tunable ring laser system.
MatisseTuner coordinates the laser with a HighFinesse wavemeter to provide automatic wavelength tuning and stitched scans.
Driver module:
SirahMatisse / MatisseTuner
from quatm.drivers.Sirah.Matisse import SirahMatisse
matisse = SirahMatisse(addr="TCPIP::192.168.1.10::INSTR")
# Set wavelength
matisse.set_birefringent_filter(wavelength=780.24) # nm
matisse.set_thin_etalon(wavelength=780.24)
matisse.set_thick_etalon(wavelength=780.24)
# Piezo scan
matisse.set_piezo_voltage(50.0) # 0–100 V
# Automatic tuning (requires a wavemeter)
from quatm.drivers.Sirah.tuner import MatisseTuner
tuner = MatisseTuner(laser=matisse, wavemeter=wlm)
tuner.tune_to(wavelength=780.24) # Auto-search and lock
tuner.scan(start=780.20, stop=780.30, speed=0.01) # nm/s
M² Solstis narrow-linewidth tunable laser
Solstis M² Lasers
| Communication | TCP/IP JSON + WebSocket |
| Wavelength range | 700–1000 nm (Ti:sapphire) |
| Linewidth | < 50 kHz |
| Functions | etalon lock, cavity reference lock, wavemeter feedback |
A fully digital tunable laser system, completely remotely controllable through a TCP/IP JSON interface. It supports a WebSocket real-time status stream.
Driver module:
Solstis (ICE Bloc)
from quatm.drivers.M2.solstis import Solstis
solstis = Solstis(addr="192.168.1.20", port=8080)
# Wavelength tuning
solstis.set_wavelength(780.24)
# Etalon lock
solstis.lock_etalon()
# Terahertz scan (with the EMM module)
solstis.set_terahertz_scan(start_freq=0, stop_freq=100e9)
Optical power meters & wavemeters
Ophir Vega laser power/energy meter
Vega Ophir
| Communication | serial |
| Heads | thermopile/photodiode/pyroelectric |
| Power | µW – kW |
| Energy | µJ – J |
A versatile laser measurement instrument supporting continuous-wave power and pulsed energy measurement.
Driver module:
VegaPowerMeter
from quatm.drivers.Ophir.base import VegaPowerMeter
pm = VegaPowerMeter(conn="/dev/ttyUSB0")
power = pm.get_power()
HighFinesse WS6/WS7 precision wavemeters
WS6 / WS7 HighFinesse
| Communication | native wlmData.dll |
| Accuracy | 2–200 MHz (depends on model) |
| Channels | 1–8 |
| Measurement rate | up to 500 Hz |
| Wavelength range | 350–1120 nm |
Fizeau interferometer wavemeters for precision laser frequency measurement and feedback control. Multi-channel models can monitor the frequencies of several lasers simultaneously.
Driver module:
WLM
from quatm.drivers.HighFinesse.wlm import WLM
wlm = WLM(version=7, dll_path="C:\\wlm\\wlmData.dll")
# Read the current frequency of channel 1
freq = wlm.get_frequency(channel=1) # THz
wavelength = wlm.get_wavelength(channel=1) # nm
# Exposure control (auto-adapts to light intensity)
wlm.set_exposure(channel=1, mode="auto")
Matisse automatic tuning
The combination of a HighFinesse wavemeter and a Sirah Matisse is the archetypal laser frequency feedback control system in Quatm. The MatisseTuner driver coordinates the two to provide closed-loop automatic tuning and wide-range mode-hop-free scanning.
Thorlabs optical power meters PM100 / PM400
PM100 / PM400 series Thorlabs power meter
| Communication | VISA (USB) |
| Supported heads | photodiode/thermopile/pyroelectric |
| Wavelength range | depends on head |
| Power range | nW – W level |
Communicates with Thorlabs power meter heads over SCPI commands and supports a variety of sensor head types.
Driver module:
GenericPM
from quatm.drivers.Thorlabs.misc import GenericPM
pm = GenericPM(addr="USB0::0x1313::0x8078::P1234567::INSTR")
pm.set_wavelength(780.0) # 780 nm calibration
power = pm.get_power() # Current power (W)
4 - Motion and positioning
Drivers for precision motion and positioning: PI piezo nanopositioners, Attocube, Newport Picomotor, Thorlabs APT.
Overview
Quatm supports a wide range of motion platforms, from piezo nanopositioning to long-travel stepper motors, behind a unified IMultiaxisStage interface.
Physik Instrumente (PI) piezo nanopositioning
Overview
GenericPIController wraps serial communication with PI general-purpose controllers and controls a variety of PI piezo positioning platforms through the ASCII command set.
PI piezo controller E-xxx series
| Communication | serial (RS232) |
| Protocol | PI ASCII command set |
| Axes | depends on controller model |
| Accuracy | sub-nanometre |
Typical applications include fine focusing of high-NA objectives, automatic fibre coupling alignment, interferometer beam path adjustment and control of the beam waist position of optical dipole traps.
Driver module:
GenericPIController
Initialization
from quatm.drivers.PhysikInstrumente.base import GenericPIController
# serial connection
stage = GenericPIController(conn="/dev/ttyUSB0")
# home
stage.home(axis=0)
# absolute positioning (µm)
stage.move_to(axis=0, position=50.0)
# Relative move
stage.move_by(axis=1, delta=10.0)
# query current position
pos = stage.get_position(axis=0)
Key methods
| Method | Description |
|---|
home(axis) | Home the specified axis |
move_to(axis, position) | Absolute positioning (µm) |
move_by(axis, delta) | Relative move (µm) |
get_position(axis) | Query the current position |
stop(axis) | Emergency stop |
Device configuration
"objective_z": {
"type": "local",
"module": "drivers.PhysikInstrumente.base",
"class": "GenericPIController",
"arguments": {"conn": "/dev/ttyUSB0"},
}
Usage example
# In the Experiment class
self.pi_stage = self.get_device("pi_stage")
# Move to the target position (µm)
self.pi_stage.move_absolute(x=50.0, y=25.0, z=10.0)
# Relative move
self.pi_stage.move_relative(dx=1.0, dy=0.0, dz=0.0)
Note: piezo translation stages have a limited travel range, and exceeding it triggers hardware protection. Consult the device manual to confirm the maximum travel before use.
Thorlabs APT/Kinesis translation stages
KDC101 / K10CR1 series
KDC101 / K10CR1 / filter wheel Thorlabs APT/Kinesis
| Communication | serial (FTDI) |
| Protocol | APT (binary) |
| Applicable devices | DC servo motors, stepper motors, filter wheels, shutters |
A unified wrapper for Thorlabs APT protocol devices.
Driver module:
BasicKinesisDevice
from quatm.drivers.Thorlabs.kinesis import BasicKinesisDevice
stage = BasicKinesisDevice(conn="27200001")
stage.home()
stage.move_to(position=25.0) # mm
Elliptec piezoelectric resonant motors
ELLx series Thorlabs Elliptec
| Communication | serial (9600 baud) |
| Travel | depends on slider |
| Accuracy | µm level |
Compact piezoelectric resonant motors, suited to space-constrained optical mounts.
Driver module:
ElliptecMotor
from quatm.drivers.Thorlabs.elliptec import ElliptecMotor
motor = ElliptecMotor(conn="/dev/ttyUSB0", addrs=[0])
motor.move_to(axis=0, position=10.0)
Motorized filter wheels FW102/FW212
from quatm.drivers.Thorlabs.serial import FW
fw = FW(conn="/dev/ttyUSB0")
fw.set_position(position=2) # switch to filter position 2
KDC101 motorized translation stage
Control Thorlabs KDC101/T-Cube series motorized translation stages through the .NET SDK.
from quatm.drivers.thorlabs.kdc101 import KDC101
stage = KDC101("26001234") # Serial number
stage.home() # Home
stage.move_absolute(10.0) # Move to 10.0 mm
pos = stage.get_position() # Read current position
| Function | Description |
|---|
| Homing | Automatically seek the limit switch |
| Absolute move | Move to the specified position (mm) |
| Relative move | Move relative to the current position |
| Position readout | Read the current position in real time |
Attocube ANC300 / ANC350 nanopositioning
ANC300 Attocube
| Communication | TCP/IP (port 7230) |
| Axes | up to 7 |
| Travel | mm range |
| Accuracy | nm range |
| Suitable for | cryogenic / vacuum |
A modular nanopositioning controller, remotely controlled over TCP/IP. It is widely used for precise positioning of objectives and samples inside cryostats.
Driver module:
ANC300
from quatm.drivers.Attocube.anc300 import ANC300
anc = ANC300(conn=("192.168.1.30", 7230))
# home
anc.home(axis=0)
# Nanometer-level step
anc.move_by(axis=0, delta=0.1) # 100 nm
# Continuous scan mode
anc.set_continuous_mode(axis=1, enable=True)
anc.set_continuous_speed(axis=1, speed=100.0) # nm/s
ANC350 Attocube (USB)
| Communication | USB HID (PyUSB) |
| Axes | up to 3 |
| Control | direct USB connection |
USB variant, suited to desktop applications.
Driver module:
ANC350
from quatm.drivers.Attocube.anc350 import ANC350
anc = ANC350(conn=0) # First USB device
anc.move_to(axis=0, position=50.0)
Newport Picomotor 8742 4-axis controller
Picomotor 8742 Newport
| Communication | USB (PyUSB) or TCP/IP Telnet (port 23) |
| Axes | 4 |
| Step size | < 30 nm |
| Vacuum compatible | optional |
A piezoelectric inertial motor controller supporting direct USB or network control. Vacuum-compatible models can be used directly for adjusting optical elements inside a vacuum chamber.
Driver module:
Picomotor8742
from quatm.drivers.Newport.picomotor import Picomotor8742
# USB connection
pico = Picomotor8742(conn=0)
# Or TCP/IP
pico = Picomotor8742(conn="192.168.1.40", multiaddr=(0, 1))
pico.move_to(axis=0, position=5.0) # mm
pico.home(axis=0)
SmarAct MCS2 / SCU3D high-precision positioning
MCS2 SmarAct
| Communication | native MCS2 SDK |
| Axes | up to 18 |
| Accuracy | nm range |
| Speed | up to 20 mm/s |
| Vacuum/cryogenic | optional modules |
A modular high-precision positioning system supporting coordinated multi-axis motion and complex trajectories.
Driver module:
MCS2
from quatm.drivers.SmarAct.MCS2 import MCS2
mcs = MCS2(locator="usb:sn:12345678")
mcs.move_to(axis=0, position=10.0) # mm
mcs.get_position(axis=0)
SCU3D SmarAct 3-axis
| Communication | SCU3DControl SDK |
| Axes | 3 |
An integrated 3-axis controller for confined spaces.
Driver module:
SCU3D
from quatm.drivers.SmarAct.scu3d import SCU3D
scu = SCU3D(idx=0)
scu.move_to(axis=1, position=25.0)
Standa 8SMC stepper motor controllers
8SMC4 / 8SMC5 Standa
| Communication | serial (115200 baud) |
| Axes | 1–4 |
| Step resolution | depends on motor/lead screw |
| Application | long-travel translation stages, rotation stages |
An economical stepper motor controller, suited to long-travel coarse positioning on optical tables.
Driver module:
Standa8SMC
from quatm.drivers.standa.base import Standa8SMC
stage = Standa8SMC(conn="/dev/ttyUSB0")
stage.move_to(position=50.0) # mm
stage.home()
Performax Arcus Technology
| Communication | USB (DLL) or RS485 serial |
| Axes | up to 4 |
| Features | acceleration/deceleration profiles, limit detection |
A high-performance stepper motor controller providing smooth S-curve acceleration and deceleration.
Driver module:
GenericPerformaxStage
from quatm.drivers.arcus.performax import GenericPerformaxStage
stage = GenericPerformaxStage(idx=0, conn="USB")
stage.move_to(axis=0, position=100.0)
stage.set_acceleration(axis=0, accel=50.0) # mm/s²
Trinamic TMCM-1110 integrated stepper motor
TMCM-1110 Trinamic
| Communication | serial (9600 baud, TMCL protocol) |
| Features | StallGuard stall detection, CoolStep energy saving |
An integrated stepper motor module with a built-in controller and driver. Suited to simple rotation/translation tasks and beam path shutters.
Driver module:
TMCM1110
from quatm.drivers.trinamic.base import TMCM1110
motor = TMCM1110(conn="/dev/ttyUSB0")
motor.move_to(position=180.0) # Rotation (°)
motor.set_velocity(500.0) # °/s
"objective_z": {
"type": "local",
"module": "drivers.Attocube.anc300",
"class": "ANC300",
"arguments": {"conn": ("192.168.1.30", 7230)},
}
Multi-axis coordination
All io.multiaxisstage drivers support independent axis mapping. The muxaxis tool can combine physical axes into a logical coordinate system, enabling advanced features such as tilt correction and coordinate transformation.5 - DAQ and power supplies
Data acquisition and electrical measurement drivers: NI DAQ, Rigol/EA power supplies, Keithley/Voltcraft multimeters, oscilloscopes.
Overview
Data acquisition and power equipment form the infrastructure of experiment automation. Quatm provides a unified NI-DAQmx wrapper together with SCPI/Modbus instrument drivers.
Rigol DP1116A programmable DC power supply
DP1116A Rigol DC power supply
| Communication | VISA |
| Output | 16V/10A or 32V/5A |
| Channels | 1 |
| Resolution | 1 mV / 1 mA |
Used for coil current control, laser diode driving and circuit board supply.
Driver module:
DP1116A
from quatm.drivers.rigol.power_supply import DP1116A
ps = DP1116A(addr="USB0::0x1AB1::0x0E11::DP1A123456789::INSTR")
ps.set_voltage(12.0) # 12V
dc.set_current(0.5) # 500 mA current limit
ps.enable_output(True)
Rigol DP932 programmable DC power supply
Provides programmable DC power for a wide range of laboratory equipment.
from quatm.drivers.rigol.dp932 import RigolDP932
psu = RigolDP932("USB0::...")
psu.set_voltage(1, 5.0) # Channel 1: 5.0 V
psu.set_current(1, 1.0) # Channel 1: 1.0 A current limit
psu.output_on(1)
NI-SWITCH matrix/multiplexer switches
PXI-25xx / SCXI-11xx series NI-SWITCH
| Communication | NI-SWITCH API |
| Topology | matrix/multiplexer/general-purpose |
| Channels | depends on module |
| Switching speed | ms range |
| Maximum voltage | 300 V (depends on module) |
NI switch modules are controlled through the
niswitch Python API. They are suited to signal routing, multiplexed calibration and coil polarity reversal in experiments.
Driver module:
ni_switch
from quatm.drivers.NI.ni_switch import NISwitch
sw = NISwitch(resource_name="PXI1Slot2")
sw.connect(channel1="ch0", channel2="com0")
sw.disconnect(channel1="ch0", channel2="com0")
all_relays = sw.get_relay_count()
PXIe-657x / PXIe-655x series NI-Digital
| Communication | NI-Digital Pattern API |
| Channels | 32–128 |
| Rate | up to 200 MHz |
| Voltage | 1.2–5.5 V (programmable) |
| Features | pattern generation/acquisition, PMU parametric measurement |
NI digital waveform instruments are controlled through the
nidigital Python API. They generate and acquire high-speed digital waveforms for custom TTL timing protocols and chip-level digital testing.
Driver module:
ni_digital
from quatm.drivers.NI.ni_digital import NIDigital
dig = NIDigital(resource_name="PXI1Slot3")
dig.configure_voltage_levels(voltage=3.3)
pattern = [0b10101010] * 100 # 100-cycle digital waveform
dig.burst_pattern(pattern, frequency=10e6)
NI-DAQmx multifunction data acquisition
PCIe-63xx / USB-63xx / PXI series NI DAQ
| Communication | NI-DAQmx |
| Analog input | 16-bit, up to 2 MS/s |
| Analog output | 16-bit |
| Digital I/O | TTL, up to 10 MHz |
| Counters | 2–4 channels |
General-purpose multifunction DAQ cards for analog signal recording, timed digital I/O and photon counting.
Driver module:
NIDAQ
from quatm.drivers.NI.daq import NIDAQ
daq = NIDAQ(
dev_name="Dev1",
rate=100_000, # 100 kS/s
buffer_size=10_000,
)
# Analog input (continuous acquisition)
daq.configure_ai(channels=["ai0", "ai1"], voltage_range=(-10, 10))
daq.start_ai()
data = daq.read_ai(samples=1000)
# Analog output
daq.configure_ao(channels=["ao0"], voltage_range=(0, 5))
daq.write_ao(channel="ao0", voltage=3.3)
# Digital I/O
daq.configure_di(lines=["port0/line0"])
daq.configure_do(lines=["port0/line1"])
daq.write_do(line="port0/line1", value=True)
# Counters (photon counting / frequency measurement)
daq.configure_counter(
counter="ctr0",
mode="edge_count",
source="PFI0",
)
counts = daq.read_counter("ctr0")
Conrad relay board controller
Relay Board Conrad
| Communication | serial (19200 baud, binary protocol) |
| Channels | 8 relays per board, daisy-chainable |
| Contacts | AC/DC switching |
An economical multi-channel relay controller suited to coarse switching: magnetic trap coil polarity reversal, device power switching and laser shutter control.
Driver module:
RelayBoard
from quatm.drivers.Conrad.base import RelayBoard
# Single board
rb = RelayBoard(conn="/dev/ttyUSB0", start_addr=0)
rb.set_relay(relay=0, state=True) # Close relay 1
rb.set_relay(relay=3, state=False) # Open relay 4
# Byte write (controls 8 channels at once)
rb.write_byte(0b10101010)
Elektro Automatik PS2000B high-power supply
PS2000B series Elektro Automatik
| Communication | serial (115200 baud) |
| Power | 640 W – 15 kW (depends on model) |
| Voltage | up to 1500 V |
| Current | up to 510 A |
| Modes | constant voltage/current/power |
High-power programmable DC supply for driving large currents in magnetic trap coils and for Feshbach resonance field coils.
Driver module:
PS2000B
from quatm.drivers.ElektroAutomatik.base import PS2000B
ps = PS2000B(conn="/dev/ttyUSB0", remote_mode=True)
# Constant-current mode — magnetic field coil
ps.set_current(50.0) # 50 A
ps.set_voltage_limit(20.0) # 20 V voltage limit
ps.enable_output(True)
# Read actual values
actual_v = ps.get_voltage()
actual_i = ps.get_current()
Keithley 2110 benchtop digital multimeter
2110 Keithley
| Communication | VISA (USB/LAN) |
| Functions | DCV/ACV/DCI/ACI/resistance/capacitance/frequency/temperature |
| Accuracy | 5½ digits |
| Sampling rate | up to 50 kS/s |
A precision benchtop multimeter for electrical characterization and sensor calibration.
Driver module:
Keithley2110
from quatm.drivers.Keithley.multimeter import Keithley2110
dmm = Keithley2110(addr="USB0::0x05E6::0x2110::1234567::INSTR")
# DC voltage measurement
voltage = dmm.measure_voltage(range="10V")
# 4-wire resistance measurement
resistance = dmm.measure_resistance_4wire(range="100Ω")
# Temperature (thermocouple)
temp = dmm.measure_temperature(tc_type="K")
Voltcraft VC7055 two-channel benchtop multimeter
VC7055 Voltcraft
| Communication | serial (115200 baud, SCPI) |
| Channels | 2 |
| Functions | DCV/ACV/DCI/ACI/resistance/frequency/capacitance |
| Bluetooth | optional (VC7055BT) |
A two-channel benchtop multimeter; the BT variant with built-in Bluetooth supports wireless data acquisition.
Driver module:
VC7055
from quatm.drivers.Voltcraft.multimeter import VC7055
dmm = VC7055(addr="/dev/ttyUSB0")
# Simultaneous two-channel measurement
v1 = dmm.measure_voltage(channel=1)
v2 = dmm.measure_voltage(channel=2)
Device configuration
"daq": {
"type": "local",
"module": "drivers.NI.daq",
"class": "NIDAQ",
"arguments": {"dev_name": "Dev1", "rate": 100_000},
},
"coil_ps": {
"type": "local",
"module": "drivers.ElektroAutomatik.base",
"class": "PS2000B",
"arguments": {"conn": "/dev/ttyUSB0", "remote_mode": True},
},
"dmm": {
"type": "local",
"module": "drivers.Keithley.multimeter",
"class": "Keithley2110",
"arguments": {"addr": "USB0::..."},
},
6 - Environmental monitoring
Drivers for temperature, vacuum and cryogenic monitoring: Lakeshore, Cryocon, Pfeiffer, Leybold.
Overview
Laboratory environmental monitoring underpins the stability of quantum experiments. Quatm ships drivers for temperature, vacuum and cryogenic level monitoring with real-time data logging and anomaly alerts.
Lakeshore 218 temperature monitor
218 Lakeshore
| Communication | serial (9600 baud, 7E1) |
| Channels | 8 |
| Sensors | diode (Si/GaAs), platinum resistance (Pt100/1000), Cernox, RuO₂ |
| Temperature | 1.4 K – 1500 K (depends on sensor) |
The standard temperature monitor for cryogenic physics experiments. The eight channels are configured independently and support diode and resistance thermometers as well as Cernox thin-film resistors.
Driver module:
Lakeshore218
from quatm.drivers.Lakeshore.base import Lakeshore218
ls = Lakeshore218(conn="/dev/ttyUSB0")
# Configure channel 1 as a silicon diode
ls.set_sensor_type(channel=1, sensor_type="DT-670")
# Read temperature
temp = ls.get_temperature(channel=1) # Kelvin
all_temps = ls.get_all_temperatures() # All 8 channels
# Read raw sensor values (voltage/resistance)
raw = ls.get_reading(channel=1)
Cryocon 12C / 14C / 18C temperature controllers
12C / 14C / 18C Cryocon
| Communication | serial (9600 baud) |
| Channels | 2–4 (depends on model) |
| Supported sensors | diode/Pt/Cernox |
Cryogenic temperature controllers with PID heater output for precise temperature stabilization.
Driver module:
Cryocon1x
from quatm.drivers.Cryocon.base import Cryocon1x
cryo = Cryocon1x(conn="/dev/ttyUSB0", nchannels=4)
# Read channel 1 temperature
temp = cryo.get_temperature(channel=1)
# PID setpoint
cryo.set_setpoint(channel=1, temperature=4.2) # 4.2 K
cryo.set_heater_range(channel=1, range="low")
cryo.enable_heater(channel=1, enable=True)
Lumel RE72 · Omron E5_C temperature controllers
RE72 / E5_C Lumel / Omron
| Communication | RS485 Modbus RTU |
| Features | PID autotuning, ramp/soak programs |
| Application | optical table temperature stabilization, laser crystal temperature control |
Industrial-grade PID temperature controllers communicating over the Modbus RTU protocol. Commonly used for laser crystal temperature control and optical table environmental temperature control.
Driver module:
LumelRE72Controller / OmronE5xCController
from quatm.drivers.Lumel.base import LumelRE72Controller
from quatm.drivers.Omron.base import OmronE5xCController
# Lumel RE72
lumel = LumelRE72Controller(conn="/dev/ttyUSB1", daddr=1)
temp = lumel.get_temperature()
lumel.set_setpoint(25.0)
# Omron E5_C
omron = OmronE5xCController(conn="/dev/ttyUSB1", daddr=2)
omron.set_setpoint(30.0)
omron.enable_heater(True)
Pfeiffer TPG2xx high-vacuum gauges
TPG2xx series Pfeiffer Vacuum
| Communication | serial (9600 baud) |
| Channels | 2 |
| Supported gauges | Pirani / Cold Cathode / combination gauge |
| Range | atmospheric pressure – 10⁻¹⁰ mbar |
A compact two-channel vacuum gauge controller supporting both rough vacuum (Pirani) and ultra-high vacuum (cold cathode) gauge heads.
Driver module:
TPG2xx
from quatm.drivers.Pfeiffer.base import TPG2xx
tpg = TPG2xx(conn="/dev/ttyUSB0")
# Read both pressure channels
p1 = tpg.get_pressure(channel=1) # mbar
p2 = tpg.get_pressure(channel=2)
# Gauge type identification
gauge_type = tpg.get_gauge_type(channel=1)
Leybold ITR wide-range vacuum gauges
ITR series Leybold
| Communication | serial (9600 baud, binary protocol) |
| Range | atmospheric pressure – 5×10⁻¹⁰ mbar |
| Output | continuous pressure data stream |
Wide-range Pirani/cold cathode combination vacuum gauges that actively push pressure data.
Driver module:
GenericITR
from quatm.drivers.Leybold.base import GenericITR
itr = GenericITR(conn="/dev/ttyUSB0")
pressure = itr.get_pressure() # mbar
Agilent XGS-600 multi-channel vacuum controller
XGS-600 Agilent
| Communication | serial (RS485) |
| Channels | up to 6 gauge heads |
| Gauge types | Hot Filament / Cold Cathode / Pirani / Convection |
A multi-gauge controller for large vacuum systems, addressed over RS485 in a daisy chain.
Driver module:
XGS600
from quatm.drivers.Agilent.pressure import XGS600
xgs = XGS600(conn="/dev/ttyUSB0", addr=1)
# Read all channel pressures
pressures = xgs.get_all_pressures()
p1 = xgs.get_pressure(channel=1)
Cryogenic level monitoring
Cryomagnetics LM500 liquid helium/nitrogen level meter
LM500 / LM510 Cryomagnetics
| Communication | serial (9600 baud) |
| Functions | He/N₂ level, temperature, sample chamber temperature |
| Channels | 1–2 level + 4 temperature |
The standard instrument for monitoring levels in superconducting magnet dewars. It monitors liquid helium/nitrogen levels and the sample chamber temperature simultaneously.
Driver module:
LM500
from quatm.drivers.Cryomagnetics.base import LM500
lm = LM500(conn="/dev/ttyUSB0")
helium_level = lm.get_helium_level() # %
nitrogen_level = lm.get_nitrogen_level() # %
sample_temp = lm.get_temperature()
American Magnetics 1700 level monitor
1700 American Magnetics
| Communication | serial or TCP/IP (port 7180) |
| Functions | He / N₂ level, relay control |
A level monitor supporting both serial and network interfaces.
Driver module:
AM1700
from quatm.drivers.AmericanMagnetics.base import AM1700
am = AM1700(conn="192.168.1.50") # TCP/IP
# Or serial port: am = AM1700(conn="/dev/ttyUSB0")
level = am.get_helium_level()
Generic environmental monitoring configuration
"chamber_pressure": {
"type": "local",
"module": "drivers.Pfeiffer.base",
"class": "TPG2xx",
"arguments": {"conn": "/dev/ttyUSB0"},
},
"cryo_temp": {
"type": "local",
"module": "drivers.Lakeshore.base",
"class": "Lakeshore218",
"arguments": {"conn": "/dev/ttyUSB1"},
},
Automated monitoring
Together with Quatm’s DataStreamMonitor and UpdatingPlot components, vacuum, temperature and level data can be visualized in real time, and threshold alerts can be configured to pause the experiment automatically.7 - Experiment control and others
Drivers for FPGA controllers and auxiliary devices such as ADwin, NI-FPGA and Red Pitaya, covering the full spectrum of experiment control requirements from nanosecond real-time timing to general-purpose switching logic.
Overview
FPGA controllers and auxiliary devices are an essential part of experiment automation: from nanosecond real-time timing to relay switching, Quatm provides a unified control interface. ADwin, NI-FPGA, Red Pitaya and several other brands are currently supported.
ADwin
Overview
ADwin is a family of real-time controllers from Jaeger Computergesteuerte Messtechnik, based on an FPGA/DSP architecture, that executes real-time tasks independently of the PC operating system.
ADwin Gold II / Pro II
| Communication | PCI / USB |
| Processor | DSP + FPGA |
| Timing precision | nanosecond level |
| Analog input | 16-bit |
| Digital I/O | TTL (5V) |
| Memory | 32 MB DRAM |
It runs real-time processes compiled from ADbasic and communicates with Quatm through shared memory or register reads and writes. Typical applications include laser cooling timing, MOT magnetic field switching and photon counting acquisition.
Driver module:
ADwin
How it works
PC (Quatm) ADwin (real-time)
┌──────────┐ PCI/USB ┌──────────────┐
│ experiment│ ←──────────→ │ ADbasic proc │
│ .py │ Par/Data │ ns timing+acq│
└──────────┘ └──────────────┘
Quatm experiment scripts read and write parameters and data arrays through the ADwin driver, interacting with the ADbasic process running on the ADwin. The timing-critical parts execute on the ADwin hardware, while the Python side handles parameter setting and result readout.
Initialization
from quatm.drivers.fpga import ADwin
# Connect to ADwin (PCI bus)
adw = ADwin(device_number=1)
# Load and start the ADbasic process
adw.load_process("experiment_sequence.TB1")
adw.start_process()
# Set experiment parameters
adw.set_par(1, 100_000) # Par_1 = 100 µs cooling time
adw.set_par(2, 50) # Par_2 = 50 cycles
adw.set_par(3, 10_000) # Par_3 = 10 ms detection time
# Start one experiment sequence (triggered by an event in ADbasic)
adw.trigger()
# Read acquired data
photons = adw.get_data(1, data_length=1000) # Read photon counts from Data_1
Key methods
| Method | Description |
|---|
load_process(binary_path) | Load an ADbasic-compiled binary process |
start_process() | Start the loaded process |
stop_process() | Stop the running process |
set_par(index, value) | Write an integer parameter (1–80) |
set_fpar(index, value) | Write a floating-point parameter (1–80) |
get_par(index) | Read an integer parameter |
get_data(index, data_length) | Read a data array (1–200) |
set_data(index, values) | Write a data array |
trigger() | Send a software trigger event |
Typical ADbasic process structure
' ADbasic code snippet — experiment timing
Init:
Par_1 = 100000 ' Cooling time (µs)
Par_2 = 50 ' Number of cycles
Event:
For i = 1 To Par_2
P2_DAC(1, 5000) ' Set AOM power
P2_DAC(2, 800) ' Set magnetic field
' ... wait, acquire, switch ...
Next i
Device configuration
"fpga": {
"type": "local",
"module": "quatm.drivers.fpga",
"class": "ADwin",
"arguments": {"device_number": 1},
}
Development and debugging
During development, experiment logic can be tested with the FPGADummy simulator (no hardware required). The simulator exposes the same API but performs no actual hardware operations, which makes it suitable for developing and validating experiment scripts on an office computer.Exception:
quatm.drivers.fpga.client module
Class:
quatm.drivers.fpga.units module
NI-FPGA LabVIEW FPGA modular instruments
PXIe-78xxR / PCIe-78xxR series NI-FPGA
| Communication | NI-FPGA Interface Python API |
| FPGA | Xilinx Kintex/Virtex |
| Digital I/O | up to 1 Gb/s |
| Analog I/O | up to 3.2 GS/s |
| Programming | LabVIEW FPGA + Python runtime control |
Controls LabVIEW FPGA bitstreams at runtime through the
nifpga Python API. Suited to custom digital signal processing requiring very high throughput and deterministic timing.
Driver module:
ni_fpga
from quatm.drivers.NI.ni_fpga import NIFPGA
fpga = NIFPGA(resource_name="RIO0", bitfile="custom_logic.lvbitx")
fpga.run()
fpga.write_control("pulse_width", 100) # ns
fpga.write_control("trigger_delay", 50)
fpga.read_indicator("photon_count")
Comparison with ADwin
| Feature | ADwin | NI-FPGA |
|---|
| Programming language | ADbasic (BASIC-like) | LabVIEW FPGA (graphical) |
| Python control | Parameter/data array read-write | Control/indicator read-write |
| Suitable for | Nanosecond timing, photon counting | High-speed DSP, custom protocols |
| Hardware ecosystem | Standalone controller | Integrated in the NI PXI platform |
Conrad relay board
Relay Board Conrad
| Communication | serial (19200 baud) |
| Channels | 8 relays per board |
| Support | daisy-chain expansion |
An economical multi-channel relay controller, suited to magnetic trap coil polarity switching, device power switching and laser shutter control.
Driver module:
RelayBoard
from quatm.drivers.Conrad.base import RelayBoard
rb = RelayBoard(conn="/dev/ttyUSB0", start_addr=0)
rb.set_relay(relay=0, state=True)
rb.set_relay(relay=3, state=False)
rb.write_byte(0b10101010)
Development and debugging
During development, experiment logic can be tested with the FPGADummy simulator, without connecting real hardware.