-
Notifications
You must be signed in to change notification settings - Fork 6
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
RX90 calibration implementation #1044
base: 0.2
Are you sure you want to change the base?
Changes from 64 commits
14f80b4
ec4b7ad
9f63c69
33db217
32cceda
7661361
d03f383
d0c1228
e6a2395
144f468
c112748
f083434
f52765f
efcb55a
66f0b71
1f16f50
f8e9021
a08cf3c
0f9ec82
6111a46
973b318
3164fd8
393d039
1742dc1
30dd98c
f521abc
bf70bf6
349e312
07a62b8
1873ccb
ef2e21a
7deade0
222539d
62230c9
23ae111
4dbcc34
3427756
3c676ff
df453df
92e0d71
1f9d532
31db8b7
c579cbb
64e5352
3c4e0d9
04cf0f9
cf73084
f6bfcaf
454f5b5
47a22b5
96dd44e
07a4bcd
e8cea9a
4052755
12fedb5
b58e13a
32308e2
57904a1
3b6769d
29a1296
022240d
8b0995d
98bcf1d
17ba606
7b907ae
7660fde
2d8c8f7
1bac594
af82fec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,9 @@ Rabi rate is larger than the decay and the pure dephasing rate, | |
|
||
where :math:`\Omega_R` is the Rabi frequency and :math:`\tau` the decay time. | ||
|
||
In qibocal we implemented also another version of the Rabi experiment which can be used to tune the amplitude (duration) of the drive pulse in order | ||
to excite the qubit from the ground state up to state :math:`\frac{\ket{0}-i\ket{1}}{\sqrt{2}}`. | ||
|
||
Parameters | ||
^^^^^^^^^^ | ||
|
||
|
@@ -103,6 +106,29 @@ It follows an example runcard and plot for the signal exepriment | |
|
||
.. image:: rabi_signal.png | ||
|
||
In all the previous examples we run Rabi experiments for calibrating the amplitude (duration) of the drive pulse | ||
to excite the qubit from the ground state up to state :math:`\ket{1}`. | ||
All these example runcards can be modified to calibrate the amplitude (duration) of the drive pulse | ||
to excite the qubit from the ground state up to state :math:`\frac{\ket{0}-i\ket{1}}{\sqrt{2}}` by simply setting the `rx90` parameter to `True`. | ||
Comment on lines
+109
to
+112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of mentioning the experiment in the general section, and describe it only in the example, you may move this description up, and just cite here you're performing the pi/2 described above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moreover, a description of the sequence (i.e. "same, but replace each pi with two pi/2") and a brief motivation may be appreciated. Then, you may cite this section in the flipping, instead of repeating it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even a reference to the literature you consulted may be appreciated as well :) |
||
|
||
In the following we show an example runcard | ||
|
||
.. code-block:: yaml | ||
|
||
|
||
- id: Rabi signal | ||
operation: rabi_amplitude_signal | ||
parameters: | ||
min_amp: 0.01 | ||
max_amp: 0.16 | ||
step_amp: 0.002 | ||
pulse_length: 40 | ||
nshots: 1024 | ||
relaxation_time: 50000 | ||
rx90: True | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another tab here ^^ |
||
|
||
.. image:: rabi_amplitude_rx90 | ||
|
||
Requirements | ||
^^^^^^^^^^^^ | ||
- :ref:`qubit-spectroscopy` | ||
|
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -23,25 +23,45 @@ | |||||||||||||
|
||||||||||||||
|
||||||||||||||
def flipping_sequence( | ||||||||||||||
platform: CalibrationPlatform, qubit: QubitId, delta_amplitude: float, flips: int | ||||||||||||||
platform: CalibrationPlatform, | ||||||||||||||
qubit: QubitId, | ||||||||||||||
delta_amplitude: float, | ||||||||||||||
flips: int, | ||||||||||||||
rx90: bool, | ||||||||||||||
): | ||||||||||||||
"""Pulse sequence for flipping experiment.""" | ||||||||||||||
|
||||||||||||||
sequence = PulseSequence() | ||||||||||||||
natives = platform.natives.single_qubit[qubit] | ||||||||||||||
sequence |= natives.R(theta=np.pi / 2) | ||||||||||||||
|
||||||||||||||
for _ in range(flips): | ||||||||||||||
if rx90: | ||||||||||||||
sequence |= natives.RX90() | ||||||||||||||
|
||||||||||||||
qd_channel, rx_pulse = natives.RX()[0] | ||||||||||||||
for _ in range(flips): | ||||||||||||||
qd_channel, qd_pulse = natives.RX90()[0] | ||||||||||||||
|
||||||||||||||
rx_detuned = update.replace( | ||||||||||||||
rx_pulse, amplitude=rx_pulse.amplitude + delta_amplitude | ||||||||||||||
) | ||||||||||||||
sequence.append((qd_channel, rx_detuned)) | ||||||||||||||
sequence.append((qd_channel, rx_detuned)) | ||||||||||||||
qd_detuned = update.replace( | ||||||||||||||
qd_pulse, delta_amplitude=qd_pulse.amplitude + delta_amplitude | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
sequence |= natives.MZ() | ||||||||||||||
sequence.append((qd_channel, qd_detuned)) | ||||||||||||||
sequence.append((qd_channel, qd_detuned)) | ||||||||||||||
sequence.append((qd_channel, qd_detuned)) | ||||||||||||||
sequence.append((qd_channel, qd_detuned)) | ||||||||||||||
|
||||||||||||||
else: | ||||||||||||||
sequence |= natives.R(theta=np.pi / 2) | ||||||||||||||
|
||||||||||||||
for _ in range(flips): | ||||||||||||||
qd_channel, qd_pulse = natives.RX()[0] | ||||||||||||||
|
||||||||||||||
qd_detuned = update.replace( | ||||||||||||||
qd_pulse, amplitude=qd_pulse.amplitude + delta_amplitude | ||||||||||||||
) | ||||||||||||||
sequence.append((qd_channel, qd_detuned)) | ||||||||||||||
sequence.append((qd_channel, qd_detuned)) | ||||||||||||||
|
||||||||||||||
sequence |= natives.MZ() | ||||||||||||||
|
||||||||||||||
return sequence | ||||||||||||||
|
||||||||||||||
|
@@ -59,6 +79,8 @@ class FlippingParameters(Parameters): | |||||||||||||
Defaults to ``False``.""" | ||||||||||||||
delta_amplitude: float = 0 | ||||||||||||||
"""Amplitude detuning.""" | ||||||||||||||
rx90: bool = False | ||||||||||||||
"""Calibration of native pi pulse, if true calibrates pi/2 pulse""" | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
@dataclass | ||||||||||||||
|
@@ -73,6 +95,8 @@ class FlippingResults(Results): | |||||||||||||
"""Difference in amplitude between detuned value and fit.""" | ||||||||||||||
fitted_parameters: dict[QubitId, dict[str, float]] | ||||||||||||||
"""Raw fitting output.""" | ||||||||||||||
rx90: bool | ||||||||||||||
"""Pi or Pi_half calibration""" | ||||||||||||||
chi2: dict[QubitId, list[float]] = field(default_factory=dict) | ||||||||||||||
"""Chi squared estimate mean value and error. """ | ||||||||||||||
|
||||||||||||||
|
@@ -90,8 +114,10 @@ class FlippingData(Data): | |||||||||||||
"""Resonator type.""" | ||||||||||||||
delta_amplitude: float | ||||||||||||||
"""Amplitude detuning.""" | ||||||||||||||
pi_pulse_amplitudes: dict[QubitId, float] | ||||||||||||||
"""Pi pulse amplitudes for each qubit.""" | ||||||||||||||
pulse_amplitudes: dict[QubitId, float] | ||||||||||||||
"""Pulse amplitudes for each qubit.""" | ||||||||||||||
rx90: bool | ||||||||||||||
"""Pi or Pi_half calibration""" | ||||||||||||||
data: dict[QubitId, npt.NDArray[FlippingType]] = field(default_factory=dict) | ||||||||||||||
"""Raw data acquired.""" | ||||||||||||||
|
||||||||||||||
|
@@ -120,10 +146,15 @@ def _acquisition( | |||||||||||||
data = FlippingData( | ||||||||||||||
resonator_type=platform.resonator_type, | ||||||||||||||
delta_amplitude=params.delta_amplitude, | ||||||||||||||
pi_pulse_amplitudes={ | ||||||||||||||
qubit: platform.natives.single_qubit[qubit].RX[0][1].amplitude | ||||||||||||||
pulse_amplitudes={ | ||||||||||||||
qubit: ( | ||||||||||||||
platform.natives.single_qubit[qubit].RX90[0][1].amplitude | ||||||||||||||
if params.rx90 | ||||||||||||||
else platform.natives.single_qubit[qubit].RX[0][1].amplitude | ||||||||||||||
) | ||||||||||||||
Comment on lines
+152
to
+156
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, this is just for fun, and at the level of code golf. But just for you to know that such an option exists
Suggested change
|
||||||||||||||
for qubit in targets | ||||||||||||||
}, | ||||||||||||||
rx90=params.rx90, | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
options = { | ||||||||||||||
|
@@ -144,6 +175,7 @@ def _acquisition( | |||||||||||||
qubit=qubit, | ||||||||||||||
delta_amplitude=params.delta_amplitude, | ||||||||||||||
flips=flips, | ||||||||||||||
rx90=params.rx90, | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
sequences.append(sequence) | ||||||||||||||
|
@@ -197,9 +229,7 @@ def _fit(data: FlippingData) -> FlippingResults: | |||||||||||||
chi2 = {} | ||||||||||||||
for qubit in qubits: | ||||||||||||||
qubit_data = data[qubit] | ||||||||||||||
detuned_pi_pulse_amplitude = ( | ||||||||||||||
data.pi_pulse_amplitudes[qubit] + data.delta_amplitude | ||||||||||||||
) | ||||||||||||||
detuned_pulse_amplitude = data.pulse_amplitudes[qubit] + data.delta_amplitude | ||||||||||||||
y = qubit_data.prob | ||||||||||||||
x = qubit_data.flips | ||||||||||||||
|
||||||||||||||
|
@@ -222,10 +252,14 @@ def _fit(data: FlippingData) -> FlippingResults: | |||||||||||||
perr = np.sqrt(np.diag(perr)).tolist() | ||||||||||||||
popt = popt.tolist() | ||||||||||||||
correction = popt[2] / 2 | ||||||||||||||
|
||||||||||||||
if data.rx90: | ||||||||||||||
correction = correction / 2 | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In some other contexts, there is a difference between redefinition and in-place mutation, and the distinction may be very relevant. However, in this case it's just about a single scalar, so it makes no difference (to the point that a compiler may optimize the operation anyhow). So, better to use the idiomatic shortcut ;)
Suggested change
|
||||||||||||||
|
||||||||||||||
corrected_amplitudes[qubit] = [ | ||||||||||||||
float(detuned_pi_pulse_amplitude * np.pi / (np.pi + correction)), | ||||||||||||||
float(detuned_pulse_amplitude * np.pi / (np.pi + correction)), | ||||||||||||||
float( | ||||||||||||||
detuned_pi_pulse_amplitude | ||||||||||||||
detuned_pulse_amplitude | ||||||||||||||
* np.pi | ||||||||||||||
* 1 | ||||||||||||||
/ (np.pi + correction) ** 2 | ||||||||||||||
|
@@ -237,11 +271,9 @@ def _fit(data: FlippingData) -> FlippingResults: | |||||||||||||
fitted_parameters[qubit] = popt | ||||||||||||||
|
||||||||||||||
delta_amplitude_detuned[qubit] = [ | ||||||||||||||
-correction * detuned_pi_pulse_amplitude / (np.pi + correction), | ||||||||||||||
-correction * detuned_pulse_amplitude / (np.pi + correction), | ||||||||||||||
np.abs( | ||||||||||||||
np.pi | ||||||||||||||
* detuned_pi_pulse_amplitude | ||||||||||||||
* np.power(np.pi + correction, -2) | ||||||||||||||
np.pi * detuned_pulse_amplitude * np.power(np.pi + correction, -2) | ||||||||||||||
) | ||||||||||||||
* perr[2] | ||||||||||||||
/ 2, | ||||||||||||||
|
@@ -267,6 +299,7 @@ def _fit(data: FlippingData) -> FlippingResults: | |||||||||||||
delta_amplitude, | ||||||||||||||
delta_amplitude_detuned, | ||||||||||||||
fitted_parameters, | ||||||||||||||
data.rx90, | ||||||||||||||
chi2, | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
|
@@ -358,7 +391,7 @@ def _plot(data: FlippingData, target: QubitId, fit: FlippingResults = None): | |||||||||||||
|
||||||||||||||
|
||||||||||||||
def _update(results: FlippingResults, platform: CalibrationPlatform, qubit: QubitId): | ||||||||||||||
update.drive_amplitude(results.amplitude[qubit], platform, qubit) | ||||||||||||||
update.drive_amplitude(results.amplitude[qubit], results.rx90, platform, qubit) | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
flipping = Routine(_acquisition, _fit, _plot, _update) | ||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -80,7 +80,7 @@ def _acquisition( | |||||||||||
"""Data acquisition for Rabi experiment sweeping amplitude.""" | ||||||||||||
|
||||||||||||
sequence, qd_pulses, ro_pulses, durations = sequence_amplitude( | ||||||||||||
targets, params, platform | ||||||||||||
targets, params, platform, params.rx90 | ||||||||||||
) | ||||||||||||
frequency_range = np.arange( | ||||||||||||
params.min_freq, | ||||||||||||
|
@@ -101,7 +101,7 @@ def _acquisition( | |||||||||||
pulses=[qd_pulses[qubit] for qubit in targets], | ||||||||||||
) | ||||||||||||
|
||||||||||||
data = RabiAmplitudeFreqData(durations=durations) | ||||||||||||
data = RabiAmplitudeFreqData(durations=durations, rx90=params.rx90) | ||||||||||||
|
||||||||||||
results = platform.execute( | ||||||||||||
[sequence], | ||||||||||||
|
@@ -186,6 +186,7 @@ def _fit(data: RabiAmplitudeFreqData) -> RabiAmplitudeFrequencyResults: | |||||||||||
fitted_parameters=fitted_parameters, | ||||||||||||
frequency=fitted_frequencies, | ||||||||||||
chi2=chi2, | ||||||||||||
rx90=data.rx90, | ||||||||||||
) | ||||||||||||
|
||||||||||||
|
||||||||||||
|
@@ -234,10 +235,16 @@ def _plot( | |||||||||||
row=1, | ||||||||||||
col=1, | ||||||||||||
) | ||||||||||||
|
||||||||||||
if data.rx90: | ||||||||||||
pulse_name = "Pi-half pulse" | ||||||||||||
else: | ||||||||||||
pulse_name = "Pi pulse" | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In these cases, it is especially convenient to use the ternary
Suggested change
|
||||||||||||
|
||||||||||||
fitting_report = table_html( | ||||||||||||
table_dict( | ||||||||||||
target, | ||||||||||||
["Optimal rabi frequency", "Pi-pulse amplitude"], | ||||||||||||
["Optimal rabi frequency", f"{pulse_name} amplitude"], | ||||||||||||
[ | ||||||||||||
fit.frequency[target], | ||||||||||||
f"{fit.amplitude[target][0]:.6f} +- {fit.amplitude[target][1]:.6f} [a.u.]", | ||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try to indent with spaces, not tabs (you can set your editor to do that)