Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use triggered mode for QM local oscillators #856

Merged
merged 11 commits into from
Apr 8, 2024
20 changes: 16 additions & 4 deletions src/qibolab/instruments/qm/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,26 @@ def register_port(self, port):
is_octave = isinstance(port, (OctaveOutput, OctaveInput))
controllers = self.octaves if is_octave else self.controllers
if port.device not in controllers:
controllers[port.device] = {}
if not is_octave:
controllers[port.device]["analog_inputs"] = DEFAULT_INPUTS
if is_octave:
controllers[port.device] = {}
else:
controllers[port.device] = {
"analog_inputs": DEFAULT_INPUTS,
"digital_outputs": {},
}

device = controllers[port.device]
if port.key in device:
device[port.key].update(port.config)
else:
device[port.key] = port.config
stavros11 marked this conversation as resolved.
Show resolved Hide resolved

if is_octave:
device["connectivity"] = port.opx_port.i.device
con = port.opx_port.i.device
number = port.opx_port.i.number
device["connectivity"] = con
self.register_port(port.opx_port)
self.controllers[con]["digital_outputs"][number] = {}

@staticmethod
def iq_imbalance(g, phi):
Expand Down Expand Up @@ -116,6 +124,7 @@ def register_drive_element(self, qubit, intermediate_frequency=0):
else:
self.elements[f"drive{qubit.name}"] = {
"RF_inputs": {"port": qubit.drive.port.pair},
"digitalInputs": qubit.drive.port.digital_inputs,
}
self.elements[f"drive{qubit.name}"].update(
{
Expand Down Expand Up @@ -168,9 +177,11 @@ def register_readout_element(
}
]
else:

self.elements[f"readout{qubit.name}"] = {
"RF_inputs": {"port": qubit.readout.port.pair},
"RF_outputs": {"port": qubit.feedback.port.pair},
"digitalInputs": qubit.readout.port.digital_inputs,
}
self.elements[f"readout{qubit.name}"].update(
{
Expand Down Expand Up @@ -252,6 +263,7 @@ def register_pulse(self, qubit, qmpulse):
"operation": "control",
"length": pulse.duration,
"waveforms": {"I": serial_i, "Q": serial_q},
"digital_marker": "ON",
}
# register drive pulse in elements
self.elements[f"drive{qubit.name}"]["operations"][
Expand Down
31 changes: 30 additions & 1 deletion src/qibolab/instruments/qm/ports.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
from dataclasses import dataclass, field, fields
from typing import ClassVar, Dict, Optional, Union

DIGITAL_DELAY = 57
DIGITAL_BUFFER = 18
"""Default calibration parameters for digital pulses.

https://docs.quantum-machines.co/1.1.7/qm-qua-sdk/docs/Guides/octave/#calibrating-the-digital-pulse

Digital markers are used for LO triggering.
"""


@dataclass
class QMPort:
Expand Down Expand Up @@ -140,12 +149,32 @@ class OctaveOutput(QMOutput):

Can be external or internal.
"""
output_mode: str = field(default="always_on", metadata={"config": "output_mode"})
output_mode: str = field(default="triggered", metadata={"config": "output_mode"})
"""Can be: "always_on" / "always_off"/ "triggered" / "triggered_reversed"."""
digital_delay: int = DIGITAL_DELAY
"""Delay for digital output channel."""
digital_buffer: int = DIGITAL_BUFFER
"""Buffer for digital output channel."""

opx_port: Optional[OPXOutput] = None
"""OPX+ port that is connected to the Octave port."""

@property
def digital_inputs(self):
"""Generates `digitalInputs` entry for elements in QM config.

Digital markers are used to switch LOs on in triggered mode.
"""
opx = self.opx_port.i.device
number = self.opx_port.i.number
return {
"output_switch": {
"port": (opx, number),
"delay": self.digital_delay,
"buffer": self.digital_buffer,
}
}


@dataclass
class OctaveInput(QMInput):
Expand Down
9 changes: 9 additions & 0 deletions tests/test_instruments_qm.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ def test_qm_register_port(qmcontroller, offset):
"con1": {
"analog_inputs": {1: {}, 2: {}},
"analog_outputs": {1: {"offset": offset, "filter": {}}},
"digital_outputs": {},
}
}

Expand All @@ -179,6 +180,7 @@ def test_qm_register_port_filter(qmcontroller):
"offset": 0.005,
}
},
"digital_outputs": {},
}
}

Expand Down Expand Up @@ -234,6 +236,9 @@ def test_qm_register_drive_element(qmplatform):
else:
target_element = {
"RF_inputs": {"port": ("octave3", 1)},
"digitalInputs": {
"output_switch": {"buffer": 18, "delay": 57, "port": ("con3", 1)}
},
"intermediate_frequency": 1000000,
"operations": {},
}
Expand Down Expand Up @@ -278,6 +283,9 @@ def test_qm_register_readout_element(qmplatform):
target_element = {
"RF_inputs": {"port": ("octave2", 5)},
"RF_outputs": {"port": ("octave2", 1)},
"digitalInputs": {
"output_switch": {"buffer": 18, "delay": 57, "port": ("con2", 9)}
},
"intermediate_frequency": 1000000,
"operations": {},
"time_of_flight": 280,
Expand All @@ -296,6 +304,7 @@ def test_qm_register_pulse(qmplatform, pulse_type, qubit):
target_pulse = {
"operation": "control",
"length": pulse.duration,
"digital_marker": "ON",
"waveforms": {
"I": pulse.envelope_waveform_i().serial,
"Q": pulse.envelope_waveform_q().serial,
Expand Down
Loading