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

Cryoscope related protocols #974

Draft
wants to merge 23 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9c97d69
feat: Start cryoscope
andrea-pasquale Mar 29, 2024
61513b3
feat: Add cryoscope over amplitude
andrea-pasquale Apr 2, 2024
53c0597
refactor: Something that starts making sense
andrea-pasquale Apr 29, 2024
9a58cf0
feat: fit working
andrea-pasquale Apr 30, 2024
f7fe9a3
clean: Clean up
andrea-pasquale Apr 30, 2024
796f51b
fix: Fix timing
andrea-pasquale May 1, 2024
843fe72
feat: Use correctly truncated pulses
andrea-pasquale May 1, 2024
44b17b5
feat: Filterssss
andrea-pasquale May 13, 2024
846fd83
Merge branch 'main' into test_cryoscope
andrea-pasquale May 13, 2024
ed85e83
Merge branch 'main' into test_cryoscope
andrea-pasquale Aug 24, 2024
67531da
feat: Working cryoscope version
andrea-pasquale Aug 29, 2024
7e0fbeb
feat: Add QM filters
andrea-pasquale Aug 30, 2024
eef60f3
refactor: Clean up
andrea-pasquale Aug 31, 2024
1d120bb
refactor: Clean up code
andrea-pasquale Sep 2, 2024
dc99101
build: Remove filters file
andrea-pasquale Sep 2, 2024
2a1eadd
Merge branch '0.2-more-protocols' into test_cryoscope
andrea-pasquale Nov 12, 2024
2eda0f9
feat: Adding cryoscope amplitude and flux_gate protocols
andrea-pasquale Nov 13, 2024
ec5c455
doc: Adding documentation
andrea-pasquale Nov 18, 2024
8951f31
Merge branch '0.2' into test_cryoscope
andrea-pasquale Nov 18, 2024
4d6bb08
feat: Sweepers and add tests
andrea-pasquale Nov 18, 2024
5544539
feat: Add unrolling as option to cryoscope
andrea-pasquale Nov 18, 2024
b451ac6
Merge branch '0.2' into test_cryoscope
andrea-pasquale Jan 10, 2025
4d45751
Merge branch '0.2' into test_cryoscope
andrea-pasquale Jan 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/qibocal/protocols/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
from .drag import drag_tuning
from .drag_simple import drag_simple
from .flipping import flipping
from .flux_amplitude_frequency import flux_amplitude_frequency
from .flux_dependence.qubit_crosstalk import qubit_crosstalk
from .flux_dependence.qubit_flux_dependence import qubit_flux
from .flux_dependence.resonator_flux_dependence import resonator_flux
from .flux_gate import flux_gate
from .qubit_power_spectroscopy import qubit_power_spectroscopy
from .qubit_spectroscopy import qubit_spectroscopy
from .qubit_spectroscopy_ef import qubit_spectroscopy_ef
Expand Down Expand Up @@ -51,6 +53,7 @@
chevron,
chevron_signal,
correct_virtual_z_phases,
cryoscope,
optimize_two_qubit_gate,
)
from .two_qubit_state_tomography import two_qubit_state_tomography
Expand Down Expand Up @@ -105,7 +108,10 @@
"standard_rb_2q",
"standard_rb_2q_inter",
"optimize_two_qubit_gate",
"cryoscope",
"ramsey_zz",
"flux_gate",
"flux_amplitude_frequency",
"cpmg",
"drag_simple",
]
239 changes: 239 additions & 0 deletions src/qibocal/protocols/flux_amplitude_frequency.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
"""Experiment to compute detuning from flux pulses."""

from dataclasses import dataclass, field

import numpy as np
import numpy.typing as npt
import plotly.graph_objects as go
from qibolab import (
AcquisitionType,
AveragingMode,
Delay,
Parameter,
Platform,
Pulse,
PulseSequence,
Rectangular,
Sweeper,
)

from qibocal.auto.operation import Data, Parameters, QubitId, Results, Routine


@dataclass
class FluxAmplitudeFrequencyParameters(Parameters):
"""FluxAmplitudeFrequency runcard inputs."""

amplitude_min: int
"""Minimum flux pulse amplitude."""
amplitude_max: int
"""Maximum flux amplitude."""
amplitude_step: int
"""Flux pulse amplitude step."""
duration: float
"""Flux pulse duration."""


@dataclass
class FluxAmplitudeFrequencyResults(Results):
"""FluxAmplitudeFrequency outputs."""

detuning: dict[QubitId, float] = field(default_factory=dict)
"""Frequency detuning."""
fitted_parameters: dict[tuple[QubitId, str], list[float]] = field(
default_factory=dict
)
"""Fitted parameters for every qubit."""

# TODO: to be fixed
def __contains__(self, key):
return True


FluxAmplitudeFrequencyType = np.dtype([("amplitude", float), ("prob_1", np.float64)])
"""Custom dtype for FluxAmplitudeFrequency."""


def ramsey_flux(
platform: Platform,
qubit: QubitId,
amplitude: float,
duration: int,
measure: str,
):
"""Compute sequences at fixed amplitude of flux pulse for <X> and <Y>"""

assert measure in ["X", "Y"]

native = platform.natives.single_qubit[qubit]

drive_channel, ry90 = native.R(theta=np.pi / 2, phi=np.pi / 2)[0]
_, rx90 = native.R(theta=np.pi / 2)[0]
ro_channel, ro_pulse = native.MZ()[0]
flux_channel = platform.qubits[qubit].flux

flux_pulse = Pulse(duration=duration, amplitude=amplitude, envelope=Rectangular())

# create the sequences
sequence = PulseSequence()

if measure == "X":
sequence.extend(
[
(drive_channel, ry90),
(flux_channel, Delay(duration=ry90.duration)),
(flux_channel, flux_pulse),
(drive_channel, Delay(duration=flux_pulse.duration)),
(drive_channel, ry90),
(
ro_channel,
Delay(duration=ry90.duration + flux_pulse.duration + ry90.duration),
),
(ro_channel, ro_pulse),
]
)
else:
sequence.extend(
[
(drive_channel, ry90),
(flux_channel, Delay(duration=rx90.duration)),
(flux_channel, flux_pulse),
(drive_channel, Delay(duration=flux_pulse.duration)),
(drive_channel, rx90),
(
ro_channel,
Delay(duration=ry90.duration + flux_pulse.duration + rx90.duration),
),
(ro_channel, ro_pulse),
]
)
return sequence


@dataclass
class FluxAmplitudeFrequencyData(Data):
"""FluxAmplitudeFrequency acquisition outputs."""

flux_pulse_duration: float
"""Flux pulse amplitude."""
data: dict[tuple[QubitId, str], npt.NDArray[FluxAmplitudeFrequencyType]] = field(
default_factory=dict
)


def _acquisition(
params: FluxAmplitudeFrequencyParameters,
platform: Platform,
targets: list[QubitId],
) -> FluxAmplitudeFrequencyData:

data = FluxAmplitudeFrequencyData(
flux_pulse_duration=params.duration,
)
amplitudes = np.arange(
params.amplitude_min, params.amplitude_max, params.amplitude_step
)

options = dict(
nshots=params.nshots,
acquisition_type=AcquisitionType.DISCRIMINATION,
averaging_mode=AveragingMode.CYCLIC,
)

for measure in ["X", "Y"]:
sequence = PulseSequence()
for qubit in targets:
sequence += ramsey_flux(
platform,
qubit,
duration=params.duration,
amplitude=params.amplitude_max / 2,
measure=measure,
)

sweeper = Sweeper(
parameter=Parameter.amplitude,
range=(params.amplitude_min, params.amplitude_max, params.amplitude_step),
pulses=[
pulse[1]
for pulse in sequence
if pulse[0] in [platform.qubits[target].flux for target in targets]
and isinstance(pulse[1], Pulse)
],
)
result = platform.execute([sequence], [[sweeper]], **options)

for qubit in targets:
ro_pulse = list(sequence.channel(platform.qubits[qubit].acquisition))[-1]
data.register_qubit(
FluxAmplitudeFrequencyType,
(qubit, measure),
dict(
amplitude=amplitudes,
prob_1=result[ro_pulse.id],
),
)

return data


def _fit(data: FluxAmplitudeFrequencyData) -> FluxAmplitudeFrequencyResults:

fitted_parameters = {}
detuning = {}
qubits = np.unique([i[0] for i in data.data]).tolist()

for qubit in qubits:
amplitudes = data[qubit, "X"].amplitude
X_exp = 1 - 2 * data[qubit, "X"].prob_1
Y_exp = 1 - 2 * data[qubit, "Y"].prob_1

phase = np.unwrap(np.angle(X_exp + 1j * Y_exp))
# normalize phase ?
phase -= phase[0]
det = phase / data.flux_pulse_duration / 2 / np.pi

fitted_parameters[qubit] = np.polyfit(amplitudes, det, 2).tolist()
detuning[qubit] = det.tolist()
return FluxAmplitudeFrequencyResults(
detuning=detuning, fitted_parameters=fitted_parameters
)


def _plot(
data: FluxAmplitudeFrequencyData,
fit: FluxAmplitudeFrequencyResults,
target: QubitId,
):
"""FluxAmplitudeFrequency plots."""

fig = go.Figure()

amplitude = data[(target, "X")].amplitude

if fit is not None:
fig.add_trace(
go.Scatter(
x=amplitude,
y=fit.detuning[target],
name="Detuning",
)
)
fig.add_trace(
go.Scatter(
x=amplitude,
y=np.polyval(fit.fitted_parameters[target], amplitude),
name="fit",
)
)

fig.update_layout(
showlegend=True,
xaxis_title="Flux pulse amplitude [a.u.]",
yaxis_title="Detuning [GHz]",
)

return [fig], ""


flux_amplitude_frequency = Routine(_acquisition, _fit, _plot)
Loading
Loading