Skip to main content

A standalone Python driver for the sp2 Quantum GateKeeper

Project description

sp2 Quantum gatekeeperlib

gatekeeperlib is a direct Python interface to the sp2 Quantum GateKeeper. One GateKeeper object owns one serial connection and NumPy arrays carry acquired data back to the caller.

Install

gatekeeperlib requires Python 3.10 or newer. We highly recommend using uv as your package manager. To add it to a uv project:

uv add gatekeeperlib

If you would like to use pip instead, use:

python -m pip install gatekeeperlib

Connect

If exactly one GateKeeper is connected, the port can be selected automatically:

from gatekeeper import GateKeeper

gk = GateKeeper()

If multiple GateKeepers are connected, specify the port:

from gatekeeper import GateKeeper

gk = GateKeeper("COM3")
print(gk.idn())
print(gk.serial_number())

gk.close()

A context manager closes that instance's broker connection even when an experiment raises an error:

with GateKeeper("/dev/cu.usbmodem14101") as gk:
    gk.set_voltage(0, 0.25)
    measured = gk.read_voltage(0)

An integer is shorthand for a Windows COM port:

GateKeeper(3)  # COM3

Use GateKeeper.find_ports() to find connected GateKeepers.

The first instance for a port makes its Python process the serial host. Instances in other Python processes automatically share that host, so the same GateKeeper can be used from multiple shells without mixing responses. Commands are serialized and stop() can interrupt an active waveform from another shell. The physical port closes automatically when the host process exits; no detached background process remains. If the host disappears, the next process automatically becomes the host. After a timeout the host closes, reopens, and resynchronizes the physical port before the next command.

print(gk.is_serial_host, gk.serial_host_pid)

Full Command List

Find the full command list here

Basic Examples

Output shapes

All acquired arrays are channel-major.

Method Shape
dac_led_buffer_ramp (n_adc, points)
time_series_buffer_ramp (n_adc, points * dac_interval_us // adc_interval_us)
dac_led_buffer_ramp_2d (n_adc, lines * fast_points)
time_series_buffer_ramp_2d (n_adc, lines * fast_points * dac_interval_us // adc_interval_us)
time_series_adc_read (n_adc, points)
adc_read().data (n_adc, samples)
boxcar_buffer_ramp (n_adc, 2 * points * measures_per_step * averages)
awg_stream (n_adc, waveform_points * cycles)

For 2D ramps, lines equals the number of slow points. It doubles when retrace=True and snake=False. The 2D result is flattened in LabRAD acquisition order.

Synchronized gate sweep

data = gk.dac_led_buffer_ramp(
    channels=[2],
    reads=[1],
    start=-0.5,
    stop=0.5,
    points=600,
    dac_interval=200e-6,
)

A scalar start or stop is broadcast to every selected DAC. Pass a list to give each DAC its own range. When settling_time is omitted, the library chooses it from the active ADC conversion times.

One-dimensional time-series ramp

To sample the ADC independently of the DAC steps, provide both intervals:

trace = gk.time_series_buffer_ramp(
    channels=[0],
    reads=[0, 1],
    start=-0.5,
    stop=0.5,
    points=600,
    dac_interval=500e-6,
    adc_interval=250e-6,
)

Here, two ADC samples are acquired during each DAC interval, so trace.shape is (2, 1200).

Two-dimensional map

fast_gate = dict(ch=0, start=-1.0, stop=1.0, points=180)
slow_gate = dict(ch=1, start=4.0, stop=6.9, points=128)

image = gk.dac_led_buffer_ramp_2d(
    fast=fast_gate,
    slow=slow_gate,
    reads=[1],
    dac_interval=180e-6,
)

For an ordinary forward scan, reshape a channel before plotting it:

adc_1_image = image[0].reshape(slow_gate["points"], fast_gate["points"])

An axis can move several DACs together by using lists for ch, start, and stop. snake=True alternates acquisition direction and retrace=True records both directions. Samples remain in acquisition order, exactly as they do in the LabRAD return value.

To update a plot or another consumer after every acquired point:

def show_point(point):
    print(point.line_index, point.point_index, point.values)

image = gk.dac_led_buffer_ramp_2d(
    fast=fast_gate,
    slow=slow_gate,
    reads=[0, 1],
    dac_interval=500e-6,
    on_point=show_point,
    hdf5_path="scan.h5",
)

When hdf5_path is provided, the file uses the exact LabRAD layout: one 2-D dataset named data, with point_index, line_index, dac_*, and adc_* columns plus the same scan metadata attributes. Coordinates for the complete scan are present when the file is created, and each ADC row is flushed as its point arrives, so the lab 2D plotter can open it in SWMR live mode. Use on_line= when a completed-line callback is also useful. Existing files are never overwritten.

Two-dimensional time-series ramp

time_series_image = gk.time_series_buffer_ramp_2d(
    fast=fast_gate,
    slow=slow_gate,
    reads=[0, 1],
    dac_interval=500e-6,
    adc_interval=250e-6,
)

With the axes above, time_series_image.shape is (2, 46080).

ADC-only acquisition

trace = gk.time_series_adc_read(reads=[0, 1], points=1000, rate=1e3)
print(trace.shape)  # (2, 1000)

For access to the sample period measured by the firmware, use adc_read:

capture = gk.adc_read(
    reads=[0, 1],
    duration=1.0,
    conversion_time=250e-6,
)

print(capture.sample_rate)
print(capture.data.shape)

Arbitrary waveform generation

import numpy as np

# One row per DAC channel and one column per waveform sample.
wave = np.array([
    [0.0, 0.1, 0.0, -0.1],  # DAC 0
    [0.0, 0.2, 0.0, -0.2],  # DAC 1
])

gk.awg_write(channels=[0, 1], waveform=wave, rate=10e3)

# AWG output repeats until stopped.
gk.stop()

To acquire one ADC frame for every waveform step:

samples = gk.awg_stream(
    channels=[0, 1],
    reads=[0, 1],
    waveform=wave[:2],
    rate=10e3,
    cycles=4,
    hdf5_path="waveform-readback.h5",
)

Pass on_reading= to receive each AdcReading as it arrives.

More than one GateKeeper

Create one normal connection per instrument:

from gatekeeper import GateKeeper

with (
    GateKeeper("/dev/cu.usbmodem-left") as gk1,
    GateKeeper("/dev/cu.usbmodem-right") as gk2,
):
    gk1.set_voltage(0, 0.1)
    gk2.set_voltage(0, -0.1)

    left_reading = gk1.read_voltage(0)
    right_reading = gk2.read_voltage(0)

Each object owns only its own serial connection.

API overview

All public times are seconds, rates are samples per second, voltages are volts, and channels are integers from 0 through 7.

Area Methods
Connection find_ports, idn, ready, nop, serial_number, firmware_version, close
Direct DAC set_voltage, get_dac, set_dac_code, initialize
DAC limits set_full_scale, get_full_scale, set_upper_limit, set_lower_limit, get_upper_limit, get_lower_limit
DAC calibration calibrate_dacs, set_offset_and_gain, get_offset_and_gain
Direct ADC read_voltage, read_voltages, idle_adc, active_adc_channels, reset_adcs, hard_reset_adcs
ADC timing set_chopping, get_chopping, set_conversion_time, set_conversion_filter, get_conversion_time
ADC calibration calibrate_adc_zero, calibrate_adc_full_scale, get_adc_zero_scale_calibration, get_adc_full_scale_calibration, get_saved_adc_zero_scale_calibration, get_saved_adc_full_scale_calibration, set_adc_zero_scale_calibration, set_adc_full_scale_calibration, set_saved_adc_zero_scale_calibration, set_saved_adc_full_scale_calibration, hard_reset_calibration
Ramps ramp, dac_led_buffer_ramp, time_series_buffer_ramp, dac_led_buffer_ramp_2d, time_series_buffer_ramp_2d, boxcar_buffer_ramp
ADC capture adc_read, time_series_adc_read
Waveforms awg_write, awg_stream, stop
Low-level access write, read, query, read_bytes, bytes_waiting, clear_input, set_timeout

Errors and interruption

Invalid local arguments raise ValueError. A firmware FAILURE response or a binary-transfer timeout raises GateKeeperError. Call stop() to stop any blocking process; e.g., buffer ramps, AWG.

Development

Live-device validation instructions are in live_tests/LIVE_HARDWARE_TESTING.md.

uv sync --extra test
uv run pytest
uv run ruff check .
uv run ty check src
uv build

Publishing

The upload scripts load test_pypi_key or pypi_key from the ignored .env file, build fresh distributions, validate them with Twine, and upload them:

uv run python upload_to_test_pypi.py
uv run python upload_to_pypi.py

To build and validate without uploading:

uv run python upload_to_test_pypi.py --check-only
uv run python upload_to_pypi.py --check-only

The same scripts work with ordinary Python on Windows, macOS, and Linux. If uv is unavailable, install the publishing tools with python -m pip install build twine first.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gatekeeperlib-0.1.3.tar.gz (33.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gatekeeperlib-0.1.3-py3-none-any.whl (25.8 kB view details)

Uploaded Python 3

File details

Details for the file gatekeeperlib-0.1.3.tar.gz.

File metadata

  • Download URL: gatekeeperlib-0.1.3.tar.gz
  • Upload date:
  • Size: 33.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for gatekeeperlib-0.1.3.tar.gz
Algorithm Hash digest
SHA256 dc8eccd4a5abdd039c91273254d8570d813bc1d830dc33c92e58ae75e7060e9e
MD5 5bb71d1750188800a25c36108a00ec26
BLAKE2b-256 8d3d7e693f5a69d27ebc572bfca998d01caa323c0f72130a424bea5cebd013ca

See more details on using hashes here.

File details

Details for the file gatekeeperlib-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: gatekeeperlib-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 25.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for gatekeeperlib-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 54e9396fece4bd603143a04158610d9d3c45c4c78b094b724fe1c73a1883583f
MD5 6a6a90d90a7d9e3c6477b94b73c30be0
BLAKE2b-256 de2fc8ff1d230064ea633169234645784e4492bb4ce4dfc30412a198be8d2de2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page