Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 15 additions & 1 deletion src/qibocal/protocols/qubit_spectroscopies/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
from .qubit_ampl_spectroscopy import qubit_amplitude_spectroscopy
from .qubit_broad_spectroscopy_conditional import (
conditional_broad_spectator_spectroscopy,
)
from .qubit_power_spectroscopy import qubit_power_spectroscopy
from .qubit_spectroscopy import qubit_spectroscopy
from .qubit_spectroscopy_conditional import qubit_conditional_spectroscopy
from .qubit_spectroscopy_ef import qubit_spectroscopy_ef
from .qubits_spectroscopy_spectator import qubit_spectroscopy_spectator_scan

__all__ = ["qubit_power_spectroscopy", "qubit_spectroscopy", "qubit_spectroscopy_ef"]
__all__ = [
"qubit_power_spectroscopy",
"qubit_spectroscopy",
"qubit_spectroscopy_ef",
"qubit_conditional_spectroscopy",
"qubit_spectroscopy_spectator_scan",
"qubit_amplitude_spectroscopy",
"conditional_broad_spectator_spectroscopy",
]
162 changes: 162 additions & 0 deletions src/qibocal/protocols/qubit_spectroscopies/qubit_ampl_spectroscopy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
from dataclasses import dataclass

import numpy as np
import plotly.graph_objects as go
from qibolab import (
AcquisitionType,
AveragingMode,
Delay,
Parameter,
PulseSequence,
Sweeper,
)

from qibocal.auto.operation import Parameters, QubitId, Results, Routine
from qibocal.calibration import CalibrationPlatform

from ...update import replace
from ..resonator_spectroscopies.resonator_punchout import ResonatorPunchoutData
from ..utils import HZ_TO_GHZ, readout_frequency
from .qubit_spectroscopy import QubitSpectroscopyResults

__all__ = ["qubit_amplitude_spectroscopy"]


@dataclass
class QubitAmplitudeSpectroscopyParameters(Parameters):
"""QubitPowerSpectroscopy runcard inputs."""

freq_width: int
"""Width for frequency sweep relative to the drive frequency [Hz]."""
freq_step: int
"""Frequency step for sweep [Hz]."""
min_amp: float
"""Minimum amplitude."""
max_amp: float
"""Maximum amplitude."""
step_amp: float
"""Step amplitude."""
duration: int
"""Drive duration."""


@dataclass
class QubitAmplitudeSpectroscopyData(ResonatorPunchoutData):
"""QubitPowerSpectroscopy data acquisition."""


def _acquisition(
params: QubitAmplitudeSpectroscopyParameters,
platform: CalibrationPlatform,
targets: list[QubitId],
) -> QubitAmplitudeSpectroscopyData:
"""Perform a qubit spectroscopy experiment with different amplitudes.

For high amplitude it should be possible to see more peaks: corresponding to
the (0-2)/2 frequency and the 1-2.
This experiment can be used also to test if a peak is a qubit: if it is, the
peak will get larger while increasing the power of the drive.
"""
# define the sequence: RX - MZ
sequence = PulseSequence()
ro_pulses = {}
qd_pulses = {}
freq_sweepers = {}
delta_frequency_range = np.arange(
-params.freq_width / 2, params.freq_width / 2, params.freq_step
)
for qubit in targets:
natives = platform.natives.single_qubit[qubit]
qd_channel, qd_pulse = natives.RX()[0]
ro_channel, ro_pulse = natives.MZ()[0]

qd_pulse = replace(qd_pulse, duration=params.duration)

qd_pulses[qubit] = qd_pulse
ro_pulses[qubit] = ro_pulse

sequence.append((qd_channel, qd_pulse))
sequence.append((ro_channel, Delay(duration=qd_pulse.duration)))
sequence.append((ro_channel, ro_pulse))

f0 = platform.config(qd_channel).frequency
freq_sweepers[qubit] = Sweeper(
parameter=Parameter.frequency,
values=f0 + delta_frequency_range,
channels=[qd_channel],
)

amp_sweeper = Sweeper(
parameter=Parameter.amplitude,
range=(params.min_amp, params.max_amp, params.step_amp),
pulses=[qd_pulses[qubit] for qubit in targets],
)

# data
data = QubitAmplitudeSpectroscopyData(
resonator_type=platform.resonator_type,
amplitudes=amp_sweeper.values.tolist(),
frequencies={qubit: freq_sweepers[qubit].values.tolist() for qubit in targets},
)

results = platform.execute(
[sequence],
[[amp_sweeper], [freq_sweepers[q] for q in targets]],
updates=[
{platform.qubits[q].probe: {"frequency": readout_frequency(q, platform)}}
for q in targets
],
nshots=params.nshots,
relaxation_time=params.relaxation_time,
acquisition_type=AcquisitionType.INTEGRATION,
averaging_mode=AveragingMode.CYCLIC,
)

# retrieve the results for every qubit
for qubit, ro_pulse in ro_pulses.items():
# average signal, phase, i and q over the number of shots defined in the runcard
data.data[qubit] = results[ro_pulse.id]

return data


def _fit(data: QubitAmplitudeSpectroscopyData) -> Results:
"""Do not perform any fitting procedure."""
return Results()


def _plot(
data: ResonatorPunchoutData,
target: QubitId,
fit: QubitSpectroscopyResults | None = None,
):
"""Plot QubitPunchout."""
figures = []
fitting_report = ""
fig = go.Figure()
x, y, _ = data.grid(target)
fig.add_trace(
go.Heatmap(
x=x * HZ_TO_GHZ,
y=y,
z=data.normalized_signal(target).ravel(),
colorbar=dict(title="Normalized signal"),
colorscale="Viridis",
)
)

fig.update_layout(
showlegend=True,
legend=dict(orientation="h"),
)

fig.update_xaxes(title_text="Drive frequency [GHz]")
fig.update_yaxes(title_text="Drive amplitude [a.u.]")

figures.append(fig)

return figures, fitting_report


qubit_amplitude_spectroscopy = Routine(_acquisition, _fit, _plot)
"""QubitAmplitudeSpectroscopy Routine object."""
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
from dataclasses import dataclass

import numpy as np
import plotly.graph_objects as go
from qibolab import (
AcquisitionType,
AveragingMode,
Delay,
Parameter,
PulseSequence,
Sweeper,
)

from qibocal.auto.operation import Parameters, QubitId, Results, Routine
from qibocal.calibration import CalibrationPlatform

from ...update import replace
from ..resonator_spectroscopies.resonator_punchout import ResonatorPunchoutData
from ..utils import HZ_TO_GHZ, readout_frequency
from .qubit_spectroscopy import QubitSpectroscopyResults

__all__ = ["qubit_amplitude_spectroscopy"]


@dataclass
class QubitAmplitudeSpectroscopyParameters(Parameters):
"""QubitPowerSpectroscopy runcard inputs."""

freq_width: int
"""Width for frequency sweep relative to the drive frequency [Hz]."""
freq_step: int
"""Frequency step for sweep [Hz]."""
min_amp: float
"""Minimum amplitude."""
max_amp: float
"""Maximum amplitude."""
step_amp: float
"""Step amplitude."""
duration: int
"""Drive duration."""


@dataclass
class QubitAmplitudeSpectroscopyData(ResonatorPunchoutData):
"""QubitPowerSpectroscopy data acquisition."""


def _acquisition(
params: QubitAmplitudeSpectroscopyParameters,
platform: CalibrationPlatform,
targets: list[QubitId],
) -> QubitAmplitudeSpectroscopyData:
"""Perform a qubit spectroscopy experiment with different amplitudes.

For high amplitude it should be possible to see more peaks: corresponding to
the (0-2)/2 frequency and the 1-2.
This experiment can be used also to test if a peak is a qubit: if it is, the
peak will get larger while increasing the power of the drive.
"""
# define the sequence: RX - MZ
sequence = PulseSequence()
ro_pulses = {}
qd_pulses = {}
freq_sweepers = {}
delta_frequency_range = np.arange(
-params.freq_width / 2, params.freq_width / 2, params.freq_step
)
for qubit in targets:
natives = platform.natives.single_qubit[qubit]
qd_channel, qd_pulse = natives.RX()[0]
ro_channel, ro_pulse = natives.MZ()[0]

qd_pulse = replace(qd_pulse, duration=params.duration)

qd_pulses[qubit] = qd_pulse
ro_pulses[qubit] = ro_pulse

sequence.append((qd_channel, qd_pulse))
sequence.append((ro_channel, Delay(duration=qd_pulse.duration)))
sequence.append((ro_channel, ro_pulse))

f0 = platform.config(qd_channel).frequency
freq_sweepers[qubit] = Sweeper(
parameter=Parameter.frequency,
values=f0 + delta_frequency_range,
channels=[qd_channel],
)

amp_sweeper = Sweeper(
parameter=Parameter.amplitude,
range=(params.min_amp, params.max_amp, params.step_amp),
pulses=[qd_pulses[qubit] for qubit in targets],
)

# data
data = QubitAmplitudeSpectroscopyData(
resonator_type=platform.resonator_type,
amplitudes=amp_sweeper.values.tolist(),
frequencies={qubit: freq_sweepers[qubit].values.tolist() for qubit in targets},
)

results = platform.execute(
[sequence],
[[amp_sweeper], [freq_sweepers[q] for q in targets]],
updates=[
{platform.qubits[q].probe: {"frequency": readout_frequency(q, platform)}}
for q in targets
],
nshots=params.nshots,
relaxation_time=params.relaxation_time,
acquisition_type=AcquisitionType.INTEGRATION,
averaging_mode=AveragingMode.CYCLIC,
)

# retrieve the results for every qubit
for qubit, ro_pulse in ro_pulses.items():
# average signal, phase, i and q over the number of shots defined in the runcard
data.data[qubit] = results[ro_pulse.id]

return data


def _fit(data: QubitAmplitudeSpectroscopyData) -> Results:
"""Do not perform any fitting procedure."""
return Results()


def _plot(
data: ResonatorPunchoutData,
target: QubitId,
fit: QubitSpectroscopyResults | None = None,
):
"""Plot QubitPunchout."""
figures = []
fitting_report = ""
fig = go.Figure()
x, y, _ = data.grid(target)
fig.add_trace(
go.Heatmap(
x=x * HZ_TO_GHZ,
y=y,
z=data.normalized_signal(target).ravel(),
colorbar=dict(title="Normalized signal"),
colorscale="Viridis",
)
)

fig.update_layout(
showlegend=True,
legend=dict(orientation="h"),
)

fig.update_xaxes(title_text="Drive frequency [GHz]")
fig.update_yaxes(title_text="Drive amplitude [a.u.]")

figures.append(fig)

return figures, fitting_report


qubit_amplitude_spectroscopy = Routine(_acquisition, _fit, _plot)
"""QubitAmplitudeSpectroscopy Routine object."""
Loading
Loading