diff --git a/doc/source/protocols/ramsey/ramsey.rst b/doc/source/protocols/ramsey/ramsey.rst index ed35278de..f4c2f9adb 100644 --- a/doc/source/protocols/ramsey/ramsey.rst +++ b/doc/source/protocols/ramsey/ramsey.rst @@ -56,8 +56,8 @@ The expected output is the following: :math:`T_2` and :math:`\Delta \omega` are determined by fitting the output signal using the formula presented above. -If the protocols is successful the drive frequency will be updated. For updating :math:`T_2` -the user is invited to run ``T2 experiment``. +If the protocols is successful the drive frequency will be updated only if a non-zero +detuning is provided. :math:`T_2` is updated only in the case where detuning is not specified. Requirements ^^^^^^^^^^^^ diff --git a/src/qibocal/protocols/ramsey/ramsey.py b/src/qibocal/protocols/ramsey/ramsey.py index cf33eb2f7..c74d42b56 100644 --- a/src/qibocal/protocols/ramsey/ramsey.py +++ b/src/qibocal/protocols/ramsey/ramsey.py @@ -13,14 +13,14 @@ from qibocal.auto.operation import Routine from qibocal.config import log -from ..utils import GHZ_TO_HZ, chi2_reduced, table_dict, table_html +from ..utils import chi2_reduced, table_dict, table_html from .ramsey_signal import ( RamseySignalData, RamseySignalParameters, RamseySignalResults, _update, ) -from .utils import fitting, ramsey_fit, ramsey_sequence +from .utils import fitting, process_fit, ramsey_fit, ramsey_sequence COLORBAND = "rgba(0,100,80,0.2)" COLORBAND_LINE = "rgba(255,255,255,0)" @@ -191,28 +191,14 @@ def _fit(data: RamseyData) -> RamseyResults: probs = qubit_data["prob"] try: popt, perr = fitting(waits, probs, qubit_data.errors) + ( + freq_measure[qubit], + t2_measure[qubit], + delta_phys_measure[qubit], + delta_fitting_measure[qubit], + popts[qubit], + ) = process_fit(popt, perr, qubit_freq, data.detuning) - delta_fitting = popt[2] / (2 * np.pi) - sign = np.sign(data.detuning) if data.detuning != 0 else 1 - delta_phys = int(sign * (delta_fitting * GHZ_TO_HZ - np.abs(data.detuning))) - corrected_qubit_frequency = int(qubit_freq - delta_phys) - t2 = 1 / popt[4] - # TODO: check error formula - freq_measure[qubit] = ( - corrected_qubit_frequency, - perr[2] * GHZ_TO_HZ / (2 * np.pi), - ) - t2_measure[qubit] = (t2, perr[4] * (t2**2)) - popts[qubit] = popt - # TODO: check error formula - delta_phys_measure[qubit] = ( - -delta_phys, - perr[2] * GHZ_TO_HZ / (2 * np.pi), - ) - delta_fitting_measure[qubit] = ( - -delta_fitting * GHZ_TO_HZ, - perr[2] * GHZ_TO_HZ / (2 * np.pi), - ) chi2[qubit] = ( chi2_reduced( probs, @@ -224,6 +210,7 @@ def _fit(data: RamseyData) -> RamseyResults: except Exception as e: log.warning(f"Ramsey fitting failed for qubit {qubit} due to {e}.") return RamseyResults( + detuning=data.detuning, frequency=freq_measure, t2=t2_measure, delta_phys=delta_phys_measure, diff --git a/src/qibocal/protocols/ramsey/ramsey_signal.py b/src/qibocal/protocols/ramsey/ramsey_signal.py index b6f3aa6d3..07bb695c4 100644 --- a/src/qibocal/protocols/ramsey/ramsey_signal.py +++ b/src/qibocal/protocols/ramsey/ramsey_signal.py @@ -14,8 +14,8 @@ from qibocal.auto.operation import Data, Parameters, Results, Routine from qibocal.config import log -from ..utils import GHZ_TO_HZ, table_dict, table_html -from .utils import fitting, ramsey_fit, ramsey_sequence +from ..utils import table_dict, table_html +from .utils import fitting, process_fit, ramsey_fit, ramsey_sequence @dataclass @@ -28,7 +28,7 @@ class RamseySignalParameters(Parameters): """Final delay between RX(pi/2) pulses in ns.""" delay_between_pulses_step: int """Step delay between RX(pi/2) pulses in ns.""" - detuning: Optional[int] = 0 + detuning: Optional[int] = None """Frequency detuning [Hz] (optional). If 0 standard Ramsey experiment is performed.""" unrolling: bool = False @@ -40,6 +40,8 @@ class RamseySignalParameters(Parameters): class RamseySignalResults(Results): """Ramsey outputs.""" + detuning: float + """Qubit frequency detuning.""" frequency: dict[QubitId, Union[float, list[float]]] """Drive frequency [GHz] for each qubit.""" t2: dict[QubitId, Union[float, list[float]]] @@ -61,7 +63,7 @@ class RamseySignalResults(Results): class RamseySignalData(Data): """Ramsey acquisition outputs.""" - detuning: int + detuning: Optional[int] = None """Frequency detuning [Hz].""" qubit_freqs: dict[QubitId, float] = field(default_factory=dict) """Qubit freqs for each qubit.""" @@ -194,29 +196,18 @@ def _fit(data: RamseySignalData) -> RamseySignalResults: signal = qubit_data["signal"] try: popt, perr = fitting(waits, signal) - delta_fitting = popt[2] / (2 * np.pi) - sign = np.sign(data.detuning) if data.detuning != 0 else 1 - delta_phys = int(sign * (delta_fitting * GHZ_TO_HZ - np.abs(data.detuning))) - corrected_qubit_frequency = int(qubit_freq - delta_phys) - t2 = 1 / popt[4] - freq_measure[qubit] = [ - corrected_qubit_frequency, - perr[2] * GHZ_TO_HZ / (2 * np.pi), - ] - t2_measure[qubit] = [t2, perr[4] * (t2**2)] - popts[qubit] = popt - delta_phys_measure[qubit] = [ - -delta_phys, - perr[2] * GHZ_TO_HZ / (2 * np.pi), - ] - delta_fitting_measure[qubit] = [ - -delta_fitting * GHZ_TO_HZ, - perr[2] * GHZ_TO_HZ / (2 * np.pi), - ] + ( + freq_measure[qubit], + t2_measure[qubit], + delta_phys_measure[qubit], + delta_fitting_measure[qubit], + popts[qubit], + ) = process_fit(popt, perr, qubit_freq, data.detuning) except Exception as e: log.warning(f"Ramsey fitting failed for qubit {qubit} due to {e}.") return RamseySignalResults( + detuning=data.detuning, frequency=freq_measure, t2=t2_measure, delta_phys=delta_phys_measure, @@ -295,7 +286,10 @@ def _plot(data: RamseySignalData, target: QubitId, fit: RamseySignalResults = No def _update(results: RamseySignalResults, platform: Platform, target: QubitId): - update.drive_frequency(results.frequency[target][0], platform, target) + if results.detuning is not None: + update.drive_frequency(results.frequency[target][0], platform, target) + else: + update.t2(results.t2[target][0], platform, target) ramsey_signal = Routine(_acquisition, _fit, _plot, _update) diff --git a/src/qibocal/protocols/ramsey/utils.py b/src/qibocal/protocols/ramsey/utils.py index d3c3e95e3..f7a4a8cb7 100644 --- a/src/qibocal/protocols/ramsey/utils.py +++ b/src/qibocal/protocols/ramsey/utils.py @@ -6,7 +6,7 @@ from qibolab.qubits import QubitId from scipy.optimize import curve_fit -from qibocal.protocols.utils import fallback_period, guess_period +from qibocal.protocols.utils import GHZ_TO_HZ, fallback_period, guess_period POPT_EXCEPTION = [0, 0, 0, 0, 1] """Fit parameters output to handle exceptions""" @@ -21,8 +21,8 @@ def ramsey_sequence( platform: Platform, qubit: QubitId, - wait: Optional[int] = 0, - detuning: Optional[int] = 0, + wait: int = 0, + detuning: Optional[int] = None, ): """Pulse sequence used in Ramsey (detuned) experiments. @@ -41,8 +41,9 @@ def ramsey_sequence( ) # apply detuning: - first_pi_half_pulse.frequency += detuning - second_pi_half_pulse.frequency += detuning + if detuning is not None: + first_pi_half_pulse.frequency += detuning + second_pi_half_pulse.frequency += detuning readout_pulse = platform.create_qubit_readout_pulse( qubit, start=second_pi_half_pulse.finish ) @@ -110,3 +111,35 @@ def fitting(x: list, y: list, errors: list = None) -> list: perr[4] / delta_x, ] return popt, perr + + +def process_fit( + popt: list[float], perr: list[float], qubit_frequency: float, detuning: float +): + """Processing Ramsey fitting results.""" + + delta_fitting = popt[2] / (2 * np.pi) + if detuning is not None: + sign = np.sign(detuning) + delta_phys = int(sign * (delta_fitting * GHZ_TO_HZ - np.abs(detuning))) + else: + delta_phys = int(delta_fitting * GHZ_TO_HZ) + + corrected_qubit_frequency = int(qubit_frequency - delta_phys) + t2 = 1 / popt[4] + new_frequency = [ + corrected_qubit_frequency, + perr[2] * GHZ_TO_HZ / (2 * np.pi), + ] + t2 = [t2, perr[4] * (t2**2)] + + delta_phys_measure = [ + -delta_phys, + perr[2] * GHZ_TO_HZ / (2 * np.pi), + ] + delta_fitting_measure = [ + -delta_fitting * GHZ_TO_HZ, + perr[2] * GHZ_TO_HZ / (2 * np.pi), + ] + + return new_frequency, t2, delta_phys_measure, delta_fitting_measure, popt