Skip to content

Commit

Permalink
Merge pull request #989 from qiboteam/coupling
Browse files Browse the repository at this point in the history
Update coupling in dispersive shift protocol
  • Loading branch information
Edoardo-Pedicillo authored Oct 22, 2024
2 parents bb83a11 + 7383675 commit 3f7aad7
Showing 1 changed file with 90 additions and 101 deletions.
191 changes: 90 additions & 101 deletions src/qibocal/protocols/dispersive_shift.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from dataclasses import asdict, dataclass, field
from dataclasses import dataclass, field

import numpy as np
import numpy.typing as npt
Expand Down Expand Up @@ -35,24 +35,19 @@ class DispersiveShiftParameters(Parameters):
class DispersiveShiftResults(Results):
"""Dispersive shift outputs."""

frequency_state_zero: dict[QubitId, float]
"""State zero frequency."""
frequency_state_one: dict[QubitId, float]
"""State one frequency."""
fitted_parameters_state_zero: dict[QubitId, list[float]]
"""Fitted parameters state zero."""
fitted_parameters_state_one: dict[QubitId, list[float]]
"""Fitted parameters state one."""
frequencies: dict[QubitId, list[float]]
"""Qubit peak frequencies."""
fitted_parameters: dict[QubitId, list[list[float]]]
"""Fitted parameters. The first element is the resonator frequency when the
qubit is in the ground state, the second one when the qubit is in the first excited
state."""
best_freq: dict[QubitId, float]
"""Readout frequency that maximizes the distance of ground and excited states in iq-plane"""

@property
def state_zero(self):
return {key: value for key, value in asdict(self).items() if "zero" in key}

@property
def state_one(self):
return {key: value for key, value in asdict(self).items() if "one" in key}
def chi(self, target: QubitId) -> float:
"Evaluate the dispersive shift"
freq = self.frequencies[target]
return (freq[0] - freq[1]) / 2


DispersiveShiftType = np.dtype(
Expand Down Expand Up @@ -167,44 +162,44 @@ def _fit(data: DispersiveShiftData) -> DispersiveShiftResults:
qubits = data.qubits
iq_couples = [[], []] # axis 0: states, axis 1: qubit

frequency_0 = {}
frequency_1 = {}
res_frequencies = {}
best_freqs = {}
fitted_parameters_0 = {}
fitted_parameters_1 = {}
fitted_parameters = {}

for i in range(2):
for qubit in qubits:
for qubit in qubits:
freq = []
fit_params = []
for i in range(2):
data_i = data[qubit, i]
fit_result = lorentzian_fit(
data_i, resonator_type=data.resonator_type, fit="resonator"
)
if fit_result is not None:
if i == 0:
frequency_0[qubit], fitted_parameters_0[qubit], _ = fit_result
else:
frequency_1[qubit], fitted_parameters_1[qubit], _ = fit_result
if fit_result is None:
freq = fit_params = None
break

freq.append(fit_result[0])
fit_params.append(fit_result[1])

res_frequencies[qubit] = freq
fitted_parameters[qubit] = fit_params

for idx, qubit in enumerate(qubits):
for i in range(2):
data_i = data[qubit, i]
i_measures = data_i.i
q_measures = data_i.q

iq_couples[i].append(np.stack((i_measures, q_measures), axis=-1))
# for each qubit find the iq couple of 0-1 states that maximize the distance
iq_couples = np.array(iq_couples)

for idx, qubit in enumerate(qubits):
frequencies = data[qubit, 0].freq

max_index = np.argmax(
np.linalg.norm(iq_couples[0][idx] - iq_couples[1][idx], axis=-1)
)
best_freqs[qubit] = frequencies[max_index]

return DispersiveShiftResults(
frequency_state_zero=frequency_0,
frequency_state_one=frequency_1,
fitted_parameters_state_one=fitted_parameters_1,
fitted_parameters_state_zero=fitted_parameters_0,
frequencies=res_frequencies,
fitted_parameters=fitted_parameters,
best_freq=best_freqs,
)

Expand All @@ -222,21 +217,17 @@ def _plot(data: DispersiveShiftData, target: QubitId, fit: DispersiveShiftResult
"phase [rad]",
),
)
# iterate over multiple data folders

fitting_report = ""

data_0 = data[target, 0]
data_1 = data[target, 1]
fit_data_0 = fit.state_zero if fit is not None else None
fit_data_1 = fit.state_one if fit is not None else None

for i, label, q_data, data_fit in list(
for i, label, q_data in list(
zip(
(0, 1),
("State 0", "State 1"),
(data_0, data_1),
(fit_data_0, fit_data_1),
)
):
opacity = 1
Expand Down Expand Up @@ -264,79 +255,73 @@ def _plot(data: DispersiveShiftData, target: QubitId, fit: DispersiveShiftResult
row=1,
col=2,
)

if fit is not None:
freqrange = np.linspace(
min(frequencies),
max(frequencies),
2 * len(q_data),
)
params = data_fit[
(
"fitted_parameters_state_zero"
if i == 0
else "fitted_parameters_state_one"
)
][target]
fig.add_trace(
go.Scatter(
x=freqrange,
y=lorentzian(freqrange, *params),
name=f"{label} Fit",
line=go.scatter.Line(dash="dot"),
),
fig.add_vline(
x=fit.best_freq[target] * HZ_TO_GHZ,
line=dict(color="orange", width=3, dash="dash"),
row=1,
col=1,
)
table_entries = [
"Best Frequency [Hz]",
]
table_values = np.round(
[
fit.best_freq[target],
]
)

if fit is not None:
fig.add_trace(
go.Scatter(
x=[
fit.best_freq[target] * HZ_TO_GHZ,
fit.best_freq[target] * HZ_TO_GHZ,
],
y=[
np.min(np.concatenate((data_0.signal, data_1.signal))),
np.max(np.concatenate((data_0.signal, data_1.signal))),
],
mode="lines",
line=go.scatter.Line(color="orange", width=3, dash="dash"),
name="Best frequency",
),
row=1,
col=1,
)
if fit.frequencies[target] is not None:
freqrange = np.linspace(
min(frequencies),
max(frequencies),
2 * len(q_data),
)
params = fit.fitted_parameters[target][i]
fig.add_trace(
go.Scatter(
x=freqrange,
y=lorentzian(freqrange, *params),
name=f"{label} Fit",
line=go.scatter.Line(dash="dot"),
),
row=1,
col=1,
)

fig.add_vline(
x=fit.best_freq[target] * HZ_TO_GHZ,
line=dict(color="orange", width=3, dash="dash"),
row=1,
col=1,
)
fitting_report = table_html(
table_dict(
target,
[
fig.add_trace(
go.Scatter(
x=[
fit.best_freq[target] * HZ_TO_GHZ,
fit.best_freq[target] * HZ_TO_GHZ,
],
y=[
np.min(np.concatenate((data_0.signal, data_1.signal))),
np.max(np.concatenate((data_0.signal, data_1.signal))),
],
mode="lines",
line=go.scatter.Line(color="orange", width=3, dash="dash"),
name="Best frequency",
),
row=1,
col=1,
)
table_entries = [
"State Zero Frequency [Hz]",
"State One Frequency [Hz]",
"Chi [Hz]",
"Best Frequency [Hz]",
],
np.round(
]
table_values = np.round(
[
fit_data_0["frequency_state_zero"][target],
fit_data_1["frequency_state_one"][target],
(
fit_data_0["frequency_state_zero"][target]
- fit_data_1["frequency_state_one"][target]
)
/ 2,
fit.frequencies[target][0],
fit.frequencies[target][1],
fit.chi(target),
fit.best_freq[target],
]
),
)
)
)

fitting_report = table_html(table_dict(target, table_entries, table_values))
fig.update_layout(
showlegend=True,
xaxis_title="Frequency [GHz]",
Expand All @@ -352,6 +337,10 @@ def _plot(data: DispersiveShiftData, target: QubitId, fit: DispersiveShiftResult

def _update(results: DispersiveShiftResults, platform: Platform, target: QubitId):
update.readout_frequency(results.best_freq[target], platform, target)
if results.frequencies[target] is not None:
delta = platform.qubits[target].drive_frequency - results.frequencies[target][0]
g = np.sqrt(np.abs(results.chi(target) * delta))
update.coupling(g, platform, target)


dispersive_shift = Routine(_acquisition, _fit, _plot, _update)
Expand Down

0 comments on commit 3f7aad7

Please sign in to comment.