Skip to content

Commit 7f37d51

Browse files
committed
feat: Unearth qibosoq interface from 0.1
1 parent 599db8a commit 7f37d51

File tree

5 files changed

+818
-2
lines changed

5 files changed

+818
-2
lines changed

flake.nix

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
extras = [
6363
(lib.strings.concatStrings
6464
(lib.strings.intersperse " -E "
65-
["qblox" "qm" "zh" "rfsoc" "los" "emulator"]))
65+
["qblox" "qm" "zh" "qibosoq" "los" "emulator"]))
6666
];
6767
};
6868
};

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ ruff = "^0.9.1"
8383
qblox = ["qblox-instruments", "qcodes", "qcodes_contrib_drivers", "pyvisa-py"]
8484
qm = ["qm-qua"]
8585
zh = ["laboneq"]
86-
rfsoc = ["qibosoq"]
86+
qibosoq = ["qibosoq"]
8787
los = ["qcodes", "qcodes_contrib_drivers", "pyvisa-py"]
8888
twpa = ["qcodes", "qcodes_contrib_drivers", "pyvisa-py"]
8989
emulator = ["qutip"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""QICK module driver for qibosoq."""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
"""Convert helper functions for qibosoq driver."""
2+
3+
from copy import deepcopy
4+
from dataclasses import asdict
5+
from functools import singledispatch
6+
7+
import numpy as np
8+
import qibosoq.components.base as rfsoc
9+
import qibosoq.components.pulses as rfsoc_pulses
10+
11+
from qibolab.pulses import Pulse, PulseSequence, PulseShape
12+
from qibolab.qubits import Qubit
13+
from qibolab.sweeper import BIAS, DURATION, START, Parameter, Sweeper
14+
15+
HZ_TO_MHZ = 1e-6
16+
NS_TO_US = 1e-3
17+
18+
19+
def replace_pulse_shape(
20+
rfsoc_pulse: rfsoc_pulses.Pulse, shape: PulseShape, sampling_rate: float
21+
) -> rfsoc_pulses.Pulse:
22+
"""Set pulse shape parameters in rfsoc_pulses pulse object."""
23+
if shape.name not in {"Gaussian", "Drag", "Rectangular", "Exponential"}:
24+
new_pulse = rfsoc_pulses.Arbitrary(
25+
**asdict(rfsoc_pulse),
26+
i_values=shape.envelope_waveform_i(sampling_rate),
27+
q_values=shape.envelope_waveform_q(sampling_rate),
28+
)
29+
return new_pulse
30+
new_pulse_cls = getattr(rfsoc_pulses, shape.name)
31+
if shape.name == "Rectangular":
32+
return new_pulse_cls(**asdict(rfsoc_pulse))
33+
if shape.name == "Gaussian":
34+
return new_pulse_cls(**asdict(rfsoc_pulse), rel_sigma=shape.rel_sigma)
35+
if shape.name == "Drag":
36+
return new_pulse_cls(
37+
**asdict(rfsoc_pulse), rel_sigma=shape.rel_sigma, beta=shape.beta
38+
)
39+
if shape.name == "Exponential":
40+
return new_pulse_cls(
41+
**asdict(rfsoc_pulse), tau=shape.tau, upsilon=shape.upsilon, weight=shape.g
42+
)
43+
44+
45+
def pulse_lo_frequency(pulse: Pulse, qubits: dict[int, Qubit]) -> int:
46+
"""Return local_oscillator frequency (HZ) of a pulse."""
47+
pulse_type = pulse.type.name.lower()
48+
try:
49+
lo_frequency = getattr(
50+
qubits[pulse.qubit], pulse_type
51+
).local_oscillator.frequency
52+
except AttributeError:
53+
lo_frequency = 0
54+
return lo_frequency
55+
56+
57+
def convert_units_sweeper(
58+
sweeper: rfsoc.Sweeper, sequence: PulseSequence, qubits: dict[int, Qubit]
59+
) -> rfsoc.Sweeper:
60+
"""Convert units for `qibosoq.abstract.Sweeper` considering also LOs."""
61+
sweeper = deepcopy(sweeper)
62+
for idx, jdx in enumerate(sweeper.indexes):
63+
parameter = sweeper.parameters[idx]
64+
if parameter is rfsoc.Parameter.FREQUENCY:
65+
pulse = sequence[jdx]
66+
lo_frequency = pulse_lo_frequency(pulse, qubits)
67+
sweeper.starts[idx] = (sweeper.starts[idx] - lo_frequency) * HZ_TO_MHZ
68+
sweeper.stops[idx] = (sweeper.stops[idx] - lo_frequency) * HZ_TO_MHZ
69+
elif parameter is rfsoc.Parameter.DELAY:
70+
sweeper.starts[idx] *= NS_TO_US
71+
sweeper.stops[idx] *= NS_TO_US
72+
elif parameter is rfsoc.Parameter.RELATIVE_PHASE:
73+
sweeper.starts[idx] = np.degrees(sweeper.starts[idx])
74+
sweeper.stops[idx] = np.degrees(sweeper.stops[idx])
75+
return sweeper
76+
77+
78+
@singledispatch
79+
def convert(*args):
80+
"""Convert from qibolab obj to qibosoq obj, overloaded."""
81+
raise ValueError(f"Convert function received bad parameters ({type(args[0])}).")
82+
83+
84+
@convert.register
85+
def _(qubit: Qubit) -> rfsoc.Qubit:
86+
"""Convert `qibolab.platforms.abstract.Qubit` to
87+
`qibosoq.abstract.Qubit`."""
88+
if qubit.flux:
89+
return rfsoc.Qubit(qubit.flux.offset, qubit.flux.port.name)
90+
return rfsoc.Qubit(0.0, None)
91+
92+
93+
@convert.register
94+
def _(
95+
sequence: PulseSequence, qubits: dict[int, Qubit], sampling_rate: float
96+
) -> list[rfsoc_pulses.Pulse]:
97+
"""Convert PulseSequence to list of rfosc pulses with relative time."""
98+
last_pulse_start = 0
99+
list_sequence = []
100+
for pulse in sorted(sequence.pulses, key=lambda item: item.start):
101+
start_delay = (pulse.start - last_pulse_start) * NS_TO_US
102+
pulse_dict = asdict(convert(pulse, qubits, start_delay, sampling_rate))
103+
list_sequence.append(pulse_dict)
104+
105+
last_pulse_start = pulse.start
106+
return list_sequence
107+
108+
109+
@convert.register
110+
def _(
111+
pulse: Pulse, qubits: dict[int, Qubit], start_delay: float, sampling_rate: float
112+
) -> rfsoc_pulses.Pulse:
113+
"""Convert `qibolab.pulses.pulse` to `qibosoq.abstract.Pulse`."""
114+
pulse_type = pulse.type.name.lower()
115+
dac = getattr(qubits[pulse.qubit], pulse_type).port.name
116+
adc = qubits[pulse.qubit].feedback.port.name if pulse_type == "readout" else None
117+
lo_frequency = pulse_lo_frequency(pulse, qubits)
118+
119+
rfsoc_pulse = rfsoc_pulses.Pulse(
120+
frequency=(pulse.frequency - lo_frequency) * HZ_TO_MHZ,
121+
amplitude=pulse.amplitude,
122+
relative_phase=np.degrees(pulse.relative_phase),
123+
start_delay=start_delay,
124+
duration=pulse.duration * NS_TO_US,
125+
dac=dac,
126+
adc=adc,
127+
name=pulse.serial,
128+
type=pulse_type,
129+
)
130+
return replace_pulse_shape(rfsoc_pulse, pulse.shape, sampling_rate)
131+
132+
133+
@convert.register
134+
def _(par: Parameter) -> rfsoc.Parameter:
135+
"""Convert a qibolab sweeper.Parameter into a qibosoq.Parameter."""
136+
return getattr(rfsoc.Parameter, par.name.upper())
137+
138+
139+
@convert.register
140+
def _(
141+
sweeper: Sweeper, sequence: PulseSequence, qubits: dict[int, Qubit]
142+
) -> rfsoc.Sweeper:
143+
"""Convert `qibolab.sweeper.Sweeper` to `qibosoq.abstract.Sweeper`.
144+
145+
Note that any unit conversion is not done in this function (to avoid
146+
to do it multiple times). Conversion will be done in
147+
`convert_units_sweeper`.
148+
"""
149+
parameters = []
150+
starts = []
151+
stops = []
152+
indexes = []
153+
154+
if sweeper.parameter is BIAS:
155+
for qubit in sweeper.qubits:
156+
parameters.append(rfsoc.Parameter.BIAS)
157+
indexes.append(list(qubits.values()).index(qubit))
158+
base_value = qubit.flux.offset
159+
values = sweeper.get_values(base_value)
160+
starts.append(values[0])
161+
stops.append(values[-1])
162+
163+
if max(np.abs(starts)) > 1 or max(np.abs(stops)) > 1:
164+
raise ValueError("Sweeper amplitude is set to reach values higher than 1")
165+
else:
166+
for pulse in sweeper.pulses:
167+
idx_sweep = sequence.index(pulse)
168+
indexes.append(idx_sweep)
169+
base_value = getattr(pulse, sweeper.parameter.name)
170+
if idx_sweep != 0 and sweeper.parameter is START:
171+
# do the conversion from start to delay
172+
base_value = base_value - sequence[idx_sweep - 1].start
173+
values = sweeper.get_values(base_value)
174+
starts.append(values[0])
175+
stops.append(values[-1])
176+
177+
if sweeper.parameter is START:
178+
parameters.append(rfsoc.Parameter.DELAY)
179+
elif sweeper.parameter is DURATION:
180+
parameters.append(rfsoc.Parameter.DURATION)
181+
delta_start = values[0] - base_value
182+
delta_stop = values[-1] - base_value
183+
184+
if len(sequence) > idx_sweep + 1:
185+
# if duration-swept pulse is not last
186+
indexes.append(idx_sweep + 1)
187+
t_start = sequence[idx_sweep + 1].start - sequence[idx_sweep].start
188+
parameters.append(rfsoc.Parameter.DELAY)
189+
starts.append(t_start + delta_start)
190+
stops.append(t_start + delta_stop)
191+
else:
192+
parameters.append(convert(sweeper.parameter))
193+
194+
return rfsoc.Sweeper(
195+
parameters=parameters,
196+
indexes=indexes,
197+
starts=starts,
198+
stops=stops,
199+
expts=len(sweeper.values),
200+
)

0 commit comments

Comments
 (0)