From d5445f4edcd33f54ba1cc7af75671cf21d48915c Mon Sep 17 00:00:00 2001 From: Andrea Date: Thu, 7 Dec 2023 11:12:45 +0400 Subject: [PATCH 1/9] fix: Fix rabi fitting by including phase in period estimate Fixes #656 but it requires more tests. --- .../protocols/characterization/rabi/amplitude.py | 4 ++-- .../characterization/rabi/amplitude_signal.py | 4 +++- .../protocols/characterization/rabi/length.py | 2 +- .../characterization/rabi/length_signal.py | 5 ++++- .../protocols/characterization/rabi/utils.py | 16 +++++++++++++++- 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/qibocal/protocols/characterization/rabi/amplitude.py b/src/qibocal/protocols/characterization/rabi/amplitude.py index 68de5974a..3b2f6cc68 100644 --- a/src/qibocal/protocols/characterization/rabi/amplitude.py +++ b/src/qibocal/protocols/characterization/rabi/amplitude.py @@ -150,7 +150,7 @@ def _fit(data: RabiAmplitudeData) -> RabiAmplitudeResults: index = local_maxima[0] if len(local_maxima) > 0 else None # 0.5 hardcoded guess for less than one oscillation f = x[index] / (x[1] - x[0]) if index is not None else 0.5 - pguess = [0.5, 0.5, 1 / f, np.pi / 2] + pguess = [0.5, 0.5, 1 / f, 0] try: popt, perr = curve_fit( utils.rabi_amplitude_function, @@ -165,7 +165,7 @@ def _fit(data: RabiAmplitudeData) -> RabiAmplitudeResults: sigma=qubit_data.error, ) perr = np.sqrt(np.diag(perr)) - pi_pulse_parameter = np.abs(popt[2] / 2) + pi_pulse_parameter = utils.correct_period(period=popt[2], phase=popt[3]) except: log.warning("rabi_fit: the fitting was not succesful") diff --git a/src/qibocal/protocols/characterization/rabi/amplitude_signal.py b/src/qibocal/protocols/characterization/rabi/amplitude_signal.py index 5447cd65f..620ac303e 100644 --- a/src/qibocal/protocols/characterization/rabi/amplitude_signal.py +++ b/src/qibocal/protocols/characterization/rabi/amplitude_signal.py @@ -155,7 +155,9 @@ def _fit(data: RabiAmplitudeVoltData) -> RabiAmplitudeVoltResults: popt[2] * (x_max - x_min), popt[3] - 2 * np.pi * x_min / (x_max - x_min) / popt[2], ] - pi_pulse_parameter = np.abs((translated_popt[2]) / 2) + pi_pulse_parameter = utils.correct_period( + period=translated_popt[2], phase=translated_popt[3] + ) except: log.warning("rabi_fit: the fitting was not succesful") diff --git a/src/qibocal/protocols/characterization/rabi/length.py b/src/qibocal/protocols/characterization/rabi/length.py index 126a359bc..3c4ca89c9 100644 --- a/src/qibocal/protocols/characterization/rabi/length.py +++ b/src/qibocal/protocols/characterization/rabi/length.py @@ -169,7 +169,7 @@ def _fit(data: RabiLengthData) -> RabiLengthResults: sigma=qubit_data.error, ) perr = np.sqrt(np.diag(perr)) - pi_pulse_parameter = np.abs(popt[2] / 2) + pi_pulse_parameter = utils.correct_period(period=popt[2], phase=popt[3]) except: log.warning("rabi_fit: the fitting was not succesful") pi_pulse_parameter = 0 diff --git a/src/qibocal/protocols/characterization/rabi/length_signal.py b/src/qibocal/protocols/characterization/rabi/length_signal.py index 37757a72a..321b3f338 100644 --- a/src/qibocal/protocols/characterization/rabi/length_signal.py +++ b/src/qibocal/protocols/characterization/rabi/length_signal.py @@ -161,7 +161,10 @@ def _fit(data: RabiLengthVoltData) -> RabiLengthVoltResults: popt[3] - 2 * np.pi * x_min / popt[2] / (x_max - x_min), popt[4] / (x_max - x_min), ] - pi_pulse_parameter = np.abs(translated_popt[2] / 2) + pi_pulse_parameter = utils.correct_period( + period=translated_popt[2], phase=translated_popt[3] + ) + except: log.warning("rabi_fit: the fitting was not succesful") pi_pulse_parameter = 0 diff --git a/src/qibocal/protocols/characterization/rabi/utils.py b/src/qibocal/protocols/characterization/rabi/utils.py index 00b1e8aeb..1442935bc 100644 --- a/src/qibocal/protocols/characterization/rabi/utils.py +++ b/src/qibocal/protocols/characterization/rabi/utils.py @@ -12,7 +12,7 @@ def rabi_amplitude_function(x, offset, amplitude, period, phase): Args: x: Input data. """ - return offset + amplitude * np.sin(2 * np.pi * x / period + phase) + return offset + amplitude * np.cos(2 * np.pi * x / period + phase) def rabi_length_function(x, offset, amplitude, period, phase, t2_inv): @@ -190,3 +190,17 @@ def extract_rabi(data): if "RabiLength" in data.__class__.__name__: return "length", "Time [ns]", rabi_length_function raise RuntimeError("Data has to be a data structure of the Rabi routines.") + + +def correct_period(period: float, phase: float): + """Correct period by taking phase into account. + + https://github.com/qiboteam/qibocal/issues/656 + """ + + naive_half_period = period / 2 + # solution of cos (2 pi x / period + phase) = +/- 1 for k in [-2,2] + solutions = [naive_half_period * (k - phase / np.pi) for k in [-2, -1, 0, 1, 2]] + # chose solution closest to naive_half period + + return solutions[np.argmin(np.abs(solutions - naive_half_period))] From 9984ebc2b4053af6211446d5a954626ca496772d Mon Sep 17 00:00:00 2001 From: Andrea Date: Thu, 7 Dec 2023 15:54:28 +0400 Subject: [PATCH 2/9] style: Improve function with period correction --- .../protocols/characterization/rabi/amplitude.py | 6 +++++- .../characterization/rabi/amplitude_signal.py | 2 +- .../protocols/characterization/rabi/length.py | 6 +++++- .../protocols/characterization/rabi/length_signal.py | 8 ++++++-- src/qibocal/protocols/characterization/rabi/utils.py | 12 ++++-------- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/qibocal/protocols/characterization/rabi/amplitude.py b/src/qibocal/protocols/characterization/rabi/amplitude.py index 3b2f6cc68..7854ab6e5 100644 --- a/src/qibocal/protocols/characterization/rabi/amplitude.py +++ b/src/qibocal/protocols/characterization/rabi/amplitude.py @@ -165,7 +165,11 @@ def _fit(data: RabiAmplitudeData) -> RabiAmplitudeResults: sigma=qubit_data.error, ) perr = np.sqrt(np.diag(perr)) - pi_pulse_parameter = utils.correct_period(period=popt[2], phase=popt[3]) + pi_pulse_parameter = ( + popt[2] + / 2 + * utils.period_correction_factor(period=popt[2], phase=popt[3]) + ) except: log.warning("rabi_fit: the fitting was not succesful") diff --git a/src/qibocal/protocols/characterization/rabi/amplitude_signal.py b/src/qibocal/protocols/characterization/rabi/amplitude_signal.py index 620ac303e..4f2dca95b 100644 --- a/src/qibocal/protocols/characterization/rabi/amplitude_signal.py +++ b/src/qibocal/protocols/characterization/rabi/amplitude_signal.py @@ -155,7 +155,7 @@ def _fit(data: RabiAmplitudeVoltData) -> RabiAmplitudeVoltResults: popt[2] * (x_max - x_min), popt[3] - 2 * np.pi * x_min / (x_max - x_min) / popt[2], ] - pi_pulse_parameter = utils.correct_period( + pi_pulse_parameter = utils.period_correction_factor( period=translated_popt[2], phase=translated_popt[3] ) diff --git a/src/qibocal/protocols/characterization/rabi/length.py b/src/qibocal/protocols/characterization/rabi/length.py index 3c4ca89c9..fee3acbf9 100644 --- a/src/qibocal/protocols/characterization/rabi/length.py +++ b/src/qibocal/protocols/characterization/rabi/length.py @@ -169,7 +169,11 @@ def _fit(data: RabiLengthData) -> RabiLengthResults: sigma=qubit_data.error, ) perr = np.sqrt(np.diag(perr)) - pi_pulse_parameter = utils.correct_period(period=popt[2], phase=popt[3]) + pi_pulse_parameter = ( + popt[2] + / 2 + * utils.period_correction_factor(period=popt[2], phase=popt[3]) + ) except: log.warning("rabi_fit: the fitting was not succesful") pi_pulse_parameter = 0 diff --git a/src/qibocal/protocols/characterization/rabi/length_signal.py b/src/qibocal/protocols/characterization/rabi/length_signal.py index 321b3f338..d93815199 100644 --- a/src/qibocal/protocols/characterization/rabi/length_signal.py +++ b/src/qibocal/protocols/characterization/rabi/length_signal.py @@ -161,8 +161,12 @@ def _fit(data: RabiLengthVoltData) -> RabiLengthVoltResults: popt[3] - 2 * np.pi * x_min / popt[2] / (x_max - x_min), popt[4] / (x_max - x_min), ] - pi_pulse_parameter = utils.correct_period( - period=translated_popt[2], phase=translated_popt[3] + pi_pulse_parameter = ( + translated_popt[2] + / 2 + * utils.period_correction_factor( + period=translated_popt[2], phase=translated_popt[3] + ) ) except: diff --git a/src/qibocal/protocols/characterization/rabi/utils.py b/src/qibocal/protocols/characterization/rabi/utils.py index 1442935bc..c7bdcb664 100644 --- a/src/qibocal/protocols/characterization/rabi/utils.py +++ b/src/qibocal/protocols/characterization/rabi/utils.py @@ -192,15 +192,11 @@ def extract_rabi(data): raise RuntimeError("Data has to be a data structure of the Rabi routines.") -def correct_period(period: float, phase: float): +def period_correction_factor(phase: float): """Correct period by taking phase into account. https://github.com/qiboteam/qibocal/issues/656 """ - - naive_half_period = period / 2 - # solution of cos (2 pi x / period + phase) = +/- 1 for k in [-2,2] - solutions = [naive_half_period * (k - phase / np.pi) for k in [-2, -1, 0, 1, 2]] - # chose solution closest to naive_half period - - return solutions[np.argmin(np.abs(solutions - naive_half_period))] + # solution of cos (2 pi x / period + phase) = +/- 1 for k in [-2,-1,0,1,2] + # with k that gets correction closest to period + return np.round(phase / np.pi + 1) - phase / np.pi From c42a41314c3e6381272f178379317991e00ead66 Mon Sep 17 00:00:00 2001 From: Andrea Date: Thu, 7 Dec 2023 16:06:54 +0400 Subject: [PATCH 3/9] fix: Fix pylint by correcting function arguments --- src/qibocal/protocols/characterization/rabi/amplitude.py | 4 +--- .../protocols/characterization/rabi/amplitude_signal.py | 2 +- src/qibocal/protocols/characterization/rabi/length.py | 4 +--- src/qibocal/protocols/characterization/rabi/length_signal.py | 4 +--- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/qibocal/protocols/characterization/rabi/amplitude.py b/src/qibocal/protocols/characterization/rabi/amplitude.py index 7854ab6e5..7bcc8e228 100644 --- a/src/qibocal/protocols/characterization/rabi/amplitude.py +++ b/src/qibocal/protocols/characterization/rabi/amplitude.py @@ -166,9 +166,7 @@ def _fit(data: RabiAmplitudeData) -> RabiAmplitudeResults: ) perr = np.sqrt(np.diag(perr)) pi_pulse_parameter = ( - popt[2] - / 2 - * utils.period_correction_factor(period=popt[2], phase=popt[3]) + popt[2] / 2 * utils.period_correction_factor(phase=popt[3]) ) except: diff --git a/src/qibocal/protocols/characterization/rabi/amplitude_signal.py b/src/qibocal/protocols/characterization/rabi/amplitude_signal.py index 4f2dca95b..c1c936e25 100644 --- a/src/qibocal/protocols/characterization/rabi/amplitude_signal.py +++ b/src/qibocal/protocols/characterization/rabi/amplitude_signal.py @@ -156,7 +156,7 @@ def _fit(data: RabiAmplitudeVoltData) -> RabiAmplitudeVoltResults: popt[3] - 2 * np.pi * x_min / (x_max - x_min) / popt[2], ] pi_pulse_parameter = utils.period_correction_factor( - period=translated_popt[2], phase=translated_popt[3] + phase=translated_popt[3] ) except: diff --git a/src/qibocal/protocols/characterization/rabi/length.py b/src/qibocal/protocols/characterization/rabi/length.py index fee3acbf9..a0a8f0662 100644 --- a/src/qibocal/protocols/characterization/rabi/length.py +++ b/src/qibocal/protocols/characterization/rabi/length.py @@ -170,9 +170,7 @@ def _fit(data: RabiLengthData) -> RabiLengthResults: ) perr = np.sqrt(np.diag(perr)) pi_pulse_parameter = ( - popt[2] - / 2 - * utils.period_correction_factor(period=popt[2], phase=popt[3]) + popt[2] / 2 * utils.period_correction_factor(phase=popt[3]) ) except: log.warning("rabi_fit: the fitting was not succesful") diff --git a/src/qibocal/protocols/characterization/rabi/length_signal.py b/src/qibocal/protocols/characterization/rabi/length_signal.py index d93815199..3aa968df3 100644 --- a/src/qibocal/protocols/characterization/rabi/length_signal.py +++ b/src/qibocal/protocols/characterization/rabi/length_signal.py @@ -164,9 +164,7 @@ def _fit(data: RabiLengthVoltData) -> RabiLengthVoltResults: pi_pulse_parameter = ( translated_popt[2] / 2 - * utils.period_correction_factor( - period=translated_popt[2], phase=translated_popt[3] - ) + * utils.period_correction_factor(phase=translated_popt[3]) ) except: From abdb497a46119fea63b6e27fe051b15b22a508c6 Mon Sep 17 00:00:00 2001 From: andrea-pasquale Date: Fri, 8 Dec 2023 10:43:01 +0400 Subject: [PATCH 4/9] fix: Add missing pi pulse parameter in rabi_amplitude_signal --- .../protocols/characterization/rabi/amplitude_signal.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qibocal/protocols/characterization/rabi/amplitude_signal.py b/src/qibocal/protocols/characterization/rabi/amplitude_signal.py index c1c936e25..136efb5c1 100644 --- a/src/qibocal/protocols/characterization/rabi/amplitude_signal.py +++ b/src/qibocal/protocols/characterization/rabi/amplitude_signal.py @@ -155,8 +155,10 @@ def _fit(data: RabiAmplitudeVoltData) -> RabiAmplitudeVoltResults: popt[2] * (x_max - x_min), popt[3] - 2 * np.pi * x_min / (x_max - x_min) / popt[2], ] - pi_pulse_parameter = utils.period_correction_factor( - phase=translated_popt[3] + pi_pulse_parameter = ( + translated_popt[2] + / 2 + * utils.period_correction_factor(phase=translated_popt[3]) ) except: From 27f9ad8ea993c5a1adf27d9c70f16a008b7a0e8b Mon Sep 17 00:00:00 2001 From: andrea-pasquale Date: Fri, 8 Dec 2023 11:33:58 +0400 Subject: [PATCH 5/9] revert: restore initial guess on phase --- src/qibocal/protocols/characterization/rabi/amplitude_signal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibocal/protocols/characterization/rabi/amplitude_signal.py b/src/qibocal/protocols/characterization/rabi/amplitude_signal.py index 136efb5c1..5c896f1c0 100644 --- a/src/qibocal/protocols/characterization/rabi/amplitude_signal.py +++ b/src/qibocal/protocols/characterization/rabi/amplitude_signal.py @@ -136,7 +136,7 @@ def _fit(data: RabiAmplitudeVoltData) -> RabiAmplitudeVoltResults: index = local_maxima[0] if len(local_maxima) > 0 else None # 0.5 hardcoded guess for less than one oscillation f = x[index] / (x[1] - x[0]) if index is not None else 0.5 - pguess = [0.5, 1, 1 / f, np.pi / 2] + pguess = [0.5, 1, 1 / f, 0] try: popt, _ = curve_fit( utils.rabi_amplitude_function, From ec8b25f0ec8aa002bb9318d79321a5b772236b71 Mon Sep 17 00:00:00 2001 From: Andrea Pasquale Date: Tue, 12 Dec 2023 11:28:15 +0400 Subject: [PATCH 6/9] (refactor): use np.modf instead of np.round Co-authored-by: Alessandro Candido --- src/qibocal/protocols/characterization/rabi/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibocal/protocols/characterization/rabi/utils.py b/src/qibocal/protocols/characterization/rabi/utils.py index c7bdcb664..df471a2dc 100644 --- a/src/qibocal/protocols/characterization/rabi/utils.py +++ b/src/qibocal/protocols/characterization/rabi/utils.py @@ -199,4 +199,4 @@ def period_correction_factor(phase: float): """ # solution of cos (2 pi x / period + phase) = +/- 1 for k in [-2,-1,0,1,2] # with k that gets correction closest to period - return np.round(phase / np.pi + 1) - phase / np.pi + return 1 - np.modf(phase / np.pi)[0] From 15019a36329a4137bf418a32f9b89cea9e30ffe8 Mon Sep 17 00:00:00 2001 From: Andrea Date: Tue, 12 Dec 2023 12:28:30 +0400 Subject: [PATCH 7/9] doc: improve docstring for period_correction_factor --- .../protocols/characterization/rabi/utils.py | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/qibocal/protocols/characterization/rabi/utils.py b/src/qibocal/protocols/characterization/rabi/utils.py index df471a2dc..11a7831e9 100644 --- a/src/qibocal/protocols/characterization/rabi/utils.py +++ b/src/qibocal/protocols/characterization/rabi/utils.py @@ -193,10 +193,24 @@ def extract_rabi(data): def period_correction_factor(phase: float): - """Correct period by taking phase into account. + r"""Correct period by taking phase into account. https://github.com/qiboteam/qibocal/issues/656 + + We want to find the first maximum or minimum which will + correspond to an exchange of population between 0 and 1. + To find it we need to solve the following equation + :math:`\cos(2 \pi x / T + \phi) = \pm 1` which will give us + the following solution + + .. math:: + + x = ( k - \phi / \pi) T / 2 + + + for integer :math:`k`, which is chosen such that we get the smallest + correction compared to :math:`T/2`. + """ - # solution of cos (2 pi x / period + phase) = +/- 1 for k in [-2,-1,0,1,2] - # with k that gets correction closest to period + return 1 - np.modf(phase / np.pi)[0] From 12214cff62695d809aab928d510622b3ac7ddadd Mon Sep 17 00:00:00 2001 From: Andrea Date: Tue, 12 Dec 2023 12:30:59 +0400 Subject: [PATCH 8/9] fix: use correct rabi function --- src/qibocal/protocols/characterization/rabi/length_signal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibocal/protocols/characterization/rabi/length_signal.py b/src/qibocal/protocols/characterization/rabi/length_signal.py index 3aa968df3..9e635cbbb 100644 --- a/src/qibocal/protocols/characterization/rabi/length_signal.py +++ b/src/qibocal/protocols/characterization/rabi/length_signal.py @@ -144,7 +144,7 @@ def _fit(data: RabiLengthVoltData) -> RabiLengthVoltResults: pguess = [0, np.sign(y[0]) * 0.5, 1 / f, 0, 0] try: popt, _ = curve_fit( - utils.rabi_amplitude_function, + utils.rabi_length_function, x, y, p0=pguess, From 1fe8cd1828259b7033e1e37d67f3313e1f981fdb Mon Sep 17 00:00:00 2001 From: Andrea Pasquale Date: Tue, 12 Dec 2023 13:53:14 +0400 Subject: [PATCH 9/9] docs: add multiplicative in docstring Co-authored-by: Alessandro Candido --- src/qibocal/protocols/characterization/rabi/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibocal/protocols/characterization/rabi/utils.py b/src/qibocal/protocols/characterization/rabi/utils.py index 11a7831e9..ead560e27 100644 --- a/src/qibocal/protocols/characterization/rabi/utils.py +++ b/src/qibocal/protocols/characterization/rabi/utils.py @@ -209,7 +209,7 @@ def period_correction_factor(phase: float): for integer :math:`k`, which is chosen such that we get the smallest - correction compared to :math:`T/2`. + multiplicative correction compared to :math:`T/2`. """