This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

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

ModeBehaviourWhen to use
localConstructs a driver objectcameras, FPGA controllers, translation stages
attrMaps a channel to a Python attributeDAC/TTL outputs
generic_attrCalls a named driver functionDDS 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 classSDKApplicable modelsInterface
AndorSDK2Cameraatmcd32d.dll (SDK2)iXon EMCCD, Luca, ClaraPCIe / USB
AndorSDK3Cameraatcore.dll (SDK3)Zyla, Neo, Marana (sCMOS)USB3 / CameraLink
ShamrockSpectrographShamrockCIF.dllSR-303i, SR-500i and other spectrographsUSB

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
CommunicationDLL (atm32cd32)
Readout modeEM/conventional
ADC frequency1/5/10 MHz
Pixel depth16-bit
CoolingTEC (≤ -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

ParameterDescriptionTypical range
exposureExposure time per frame0.001 – 3600 s
em_gainElectron multiplication gain0 – 1000 (linear or real gain mode)
readout_rateADC readout frequency1MHz / 5MHz / 10MHz
temperatureTarget sensor temperature-60 to -100°C (depends on cooler)
pre_amp_gainPreamplifier gain1× – 4×

Andor SDK3 (sCMOS) AndorSDK3Camera

Zyla / Neo sCMOS Andor SDK3 series
CommunicationDLL (atcore)
SensorsCMOS
InterfaceUSB3 / CameraLink
Pixel depth12/16-bit
Frame rateup 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},
}

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
CommunicationSpinnaker SDK
InterfaceUSB3 / GigE
Pixel formatsMono8/16, Bayer
Triggerhardware/software
Frame ratedepends 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

MethodDescription
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},
}
  • 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:

  • quatm.drivers.blackfly.bfly.run(name)

    def quatm.drivers.blackfly.bfly.run(name):
        pass
    
    • Initialize a Camserver and run it.

Thorlabs TSI / uc480 scientific cameras

TLCamera ThorlabsTLCamera

TSI series Thorlabs scientific camera
CommunicationTLCamera SDK
InterfaceUSB3
SensorsCMOS / CCD
SupportROI, 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
CommunicationPylon SDK (GenICam)
InterfaceUSB3 / GigE
SensorCMOS
Pixel formatsMono8/16, Bayer
FeaturesROI, 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
CommunicationDCAM SDK (DLL)
SensorsCMOS
Pixels2048×2048 (Fusion)
Frame rateup 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
CommunicationPVCAM SDK (DLL)
Sensorback-illuminated sCMOS / EMCCD
InterfacePCIe / USB3
Pixel depth16-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
CommunicationPICam SDK (DLL)
SensorCCD / EMCCD
Coolingliquid nitrogen / TEC
InterfacePCIe / 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
CommunicationSC2 SDK (DLL)
InterfaceCameraLink HS / USB3 / GigE
Frame rateup to several thousand fps
SensorsCMOS / 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
CommunicationVimbaX SDK (GenICam)
InterfaceUSB3 / GigE / CameraLink
SensorCMOS
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
CommunicationIDS peak SDK
InterfaceUSB3 / GigE
SensorCMOS
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},
}

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
Communicationserial (RS232)
Frequency range23.5 MHz – 6 GHz
Channels2
Output power-30 ~ +10 dBm
Frequency resolution0.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

MethodDescription
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
Ba⁺ microwave transition scan Ba⁺

Use the Valon 5009 to drive the 9.925 GHz hyperfine transition and measure Rabi oscillations by scanning the frequency.

Key parameters
Start frequency9.924 GHz
Stop frequency9.926 GHz
Step10 kHz
Repetitions per point100
# 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 ...

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.

    • run()
  • 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
CommunicationSPI
Channels4
Frequency resolution32-bit (0.12 Hz @ 500 MHz clock)
Phase resolution14-bit
Amplitude control10-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

MethodDescription
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

Device configuration

"aom_dds": {
    "type": "local",
    "module": "drivers.DDS",
    "class": "AD9959",
}

Typical applications

ApplicationConfiguration
AOM driveSingle channel, fixed frequency
Raman transitionsTwo channels, difference-frequency locking
Trap driveMulti-channel phase control
Sideband coolingFrequency 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
CommunicationVISA (USB/LAN)
Channels2
Frequency range1 µHz – 25 MHz
Amplitude1 mVpp – 10 Vpp
Sampling rate200 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
CommunicationVISA
Output16V/10A or 32V/5A
Channels1
Resolution1 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)

Agilent / Keysight 33500 series arbitrary waveform generators

33500B / 33220A / 33250A Agilent/Keysight
CommunicationVISA (USB/LAN/GPIB)
Channels1–2
Frequencyup to 120 MHz (33500B)
Resolution14-bit
Sampling rate250 MSa/s
Waveformssine/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 classApplicable models
Agilent3350033500B, 33510B, 33520B, 33522B
Agilent33220A33220A, 33250A
RigolDG1000DG1022, DG1032
RigolDG1020ZDG1022Z, DG1032Z

Instek AFG2000 / AFG2225 dual channel

AFG-2225 / AFG-2100 Instek
CommunicationVISA
Channels1 (AFG2000) / 2 (AFG2225)
Frequencyup to 25 MHz
Sampling rate200 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)

Tektronix AFG1000 arbitrary waveform generator

AFG1022 / AFG1062 Tektronix
CommunicationVISA
Channels2
Frequencyup to 60 MHz (AFG1062)
Sampling rate300 MSa/s
Arbitrary waveform64 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
CommunicationVISA
Bandwidth100 MHz – 1 GHz
Channels2–4
Sampling rateup 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
CommunicationVISA
Frequency9 kHz – 20 GHz
Ports2–4
FunctionsS-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
CommunicationTCP/SCPI (port 5025)
Frequency300 kHz – 8.5 GHz
Ports2
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
Communicationserial (115200 baud)
Wavelength405/445/488/515/532/561/594/633/660/780/1064 nm
Power25–300 mW
Modulationanalog + 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
Communicationserial (115200 baud)
Wavelength375–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
Communicationserial (19200 baud)
Power4–16 W (532 nm)
Noise< 0.1% RMS
ApplicationTi: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
Communicationserial (19200 baud)
Wavelength532 nm
Power6–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
CommunicationVISA or TCP/IP
Wavelength rangevisible–near-infrared (depends on dye/Ti:sapphire)
Linewidth< 50 kHz (locked)
Tuning elementsbirefringent 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
CommunicationTCP/IP JSON + WebSocket
Wavelength range700–1000 nm (Ti:sapphire)
Linewidth< 50 kHz
Functionsetalon 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
Communicationserial
Headsthermopile/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
Communicationnative wlmData.dll
Accuracy2–200 MHz (depends on model)
Channels1–8
Measurement rateup to 500 Hz
Wavelength range350–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")

Thorlabs optical power meters PM100 / PM400

PM100 / PM400 series Thorlabs power meter
CommunicationVISA (USB)
Supported headsphotodiode/thermopile/pyroelectric
Wavelength rangedepends on head
Power rangenW – 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
Communicationserial (RS232)
ProtocolPI ASCII command set
Axesdepends on controller model
Accuracysub-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

MethodDescription
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
Communicationserial (FTDI)
ProtocolAPT (binary)
Applicable devicesDC 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
Communicationserial (9600 baud)
Traveldepends 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
FunctionDescription
HomingAutomatically seek the limit switch
Absolute moveMove to the specified position (mm)
Relative moveMove relative to the current position
Position readoutRead the current position in real time

Attocube ANC300 / ANC350 nanopositioning

ANC300 Attocube
CommunicationTCP/IP (port 7230)
Axesup to 7
Travelmm range
Accuracynm range
Suitable forcryogenic / 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)
CommunicationUSB HID (PyUSB)
Axesup to 3
Controldirect 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
CommunicationUSB (PyUSB) or TCP/IP Telnet (port 23)
Axes4
Step size< 30 nm
Vacuum compatibleoptional
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
Communicationnative MCS2 SDK
Axesup to 18
Accuracynm range
Speedup to 20 mm/s
Vacuum/cryogenicoptional 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
CommunicationSCU3DControl SDK
Axes3
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
Communicationserial (115200 baud)
Axes1–4
Step resolutiondepends on motor/lead screw
Applicationlong-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()

Arcus Performax multi-axis stepper control

Performax Arcus Technology
CommunicationUSB (DLL) or RS485 serial
Axesup to 4
Featuresacceleration/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
Communicationserial (9600 baud, TMCL protocol)
FeaturesStallGuard 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

Generic motion platform configuration

"objective_z": {
    "type": "local",
    "module": "drivers.Attocube.anc300",
    "class": "ANC300",
    "arguments": {"conn": ("192.168.1.30", 7230)},
}

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
CommunicationVISA
Output16V/10A or 32V/5A
Channels1
Resolution1 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
CommunicationNI-SWITCH API
Topologymatrix/multiplexer/general-purpose
Channelsdepends on module
Switching speedms range
Maximum voltage300 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()

NI-Digital digital waveform generator/analyzer

PXIe-657x / PXIe-655x series NI-Digital
CommunicationNI-Digital Pattern API
Channels32–128
Rateup to 200 MHz
Voltage1.2–5.5 V (programmable)
Featurespattern 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
CommunicationNI-DAQmx
Analog input16-bit, up to 2 MS/s
Analog output16-bit
Digital I/OTTL, up to 10 MHz
Counters2–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
Communicationserial (19200 baud, binary protocol)
Channels8 relays per board, daisy-chainable
ContactsAC/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
Communicationserial (115200 baud)
Power640 W – 15 kW (depends on model)
Voltageup to 1500 V
Currentup to 510 A
Modesconstant 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
CommunicationVISA (USB/LAN)
FunctionsDCV/ACV/DCI/ACI/resistance/capacitance/frequency/temperature
Accuracy5½ digits
Sampling rateup 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
Communicationserial (115200 baud, SCPI)
Channels2
FunctionsDCV/ACV/DCI/ACI/resistance/frequency/capacitance
Bluetoothoptional (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
Communicationserial (9600 baud, 7E1)
Channels8
Sensorsdiode (Si/GaAs), platinum resistance (Pt100/1000), Cernox, RuO₂
Temperature1.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
Communicationserial (9600 baud)
Channels2–4 (depends on model)
Supported sensorsdiode/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
CommunicationRS485 Modbus RTU
FeaturesPID autotuning, ramp/soak programs
Applicationoptical 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
Communicationserial (9600 baud)
Channels2
Supported gaugesPirani / Cold Cathode / combination gauge
Rangeatmospheric 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
Communicationserial (9600 baud, binary protocol)
Rangeatmospheric pressure – 5×10⁻¹⁰ mbar
Outputcontinuous 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
Communicationserial (RS485)
Channelsup to 6 gauge heads
Gauge typesHot 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
Communicationserial (9600 baud)
FunctionsHe/N₂ level, temperature, sample chamber temperature
Channels1–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
Communicationserial or TCP/IP (port 7180)
FunctionsHe / 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"},
},

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
CommunicationPCI / USB
ProcessorDSP + FPGA
Timing precisionnanosecond level
Analog input16-bit
Digital I/OTTL (5V)
Memory32 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

MethodDescription
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},
}

Exception:

  • quatm.drivers.fpga.adwin.AdWinDriverError(message)

    class quatm.drivers.fpga.adwin.AdWinDriverError(Exception):
        pass
    

quatm.drivers.fpga.client module

Class:

  • quatm.drivers.fpga.client.AdWinClient(experiment, simulating=None)

    class quatm.drivers.fpga.client.AdWinClient(object):
        def filter_cmdlist(self, combinetime=1e-08):
            pass
    
        def push(self, time, command, value, combinetime=1e-09):
            pass
    
        def start_realtime(self, processortime=0, repetitions=1):
            pass
    
        def stop(self):
            pass
    

quatm.drivers.fpga.units module


NI-FPGA LabVIEW FPGA modular instruments

PXIe-78xxR / PCIe-78xxR series NI-FPGA
CommunicationNI-FPGA Interface Python API
FPGAXilinx Kintex/Virtex
Digital I/Oup to 1 Gb/s
Analog I/Oup to 3.2 GS/s
ProgrammingLabVIEW 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")

Conrad relay board

Relay Board Conrad
Communicationserial (19200 baud)
Channels8 relays per board
Supportdaisy-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)