Source code for qibocal.protocols.ramsey.utils

from typing import Optional

import numpy as np
from qibolab import Platform
from qibolab.pulses import PulseSequence
from qibolab.qubits import QubitId
from scipy.optimize import curve_fit

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"""
PERR_EXCEPTION = [1] * 5
"""Fit errors to handle exceptions; their choice has no physical meaning
and is meant to avoid breaking the code."""
THRESHOLD = 0.5
"""Threshold parameters for find_peaks to guess
   frequency for sinusoidal fit."""


[docs]def ramsey_sequence( platform: Platform, qubit: QubitId, wait: int = 0, detuning: Optional[int] = None, ): """Pulse sequence used in Ramsey (detuned) experiments. The pulse sequence is the following: RX90 -- wait -- RX90 -- MZ If detuning is specified the RX90 pulses will be sent to frequency = drive_frequency + detuning """ sequence = PulseSequence() first_pi_half_pulse = platform.create_RX90_pulse(qubit, start=0) second_pi_half_pulse = platform.create_RX90_pulse( qubit, start=first_pi_half_pulse.finish + wait ) # apply 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 ) sequence.add(first_pi_half_pulse, second_pi_half_pulse, readout_pulse) return sequence
[docs]def ramsey_fit(x, offset, amplitude, delta, phase, decay): """Dumped sinusoidal fit.""" return offset + amplitude * np.sin(x * delta + phase) * np.exp(-x * decay)
[docs]def fitting(x: list, y: list, errors: list = None) -> list: """ Given the inputs list `x` and outputs one `y`, this function fits the `ramsey_fit` function and returns a list with the fit parameters. """ y_max = np.max(y) y_min = np.min(y) x_max = np.max(x) x_min = np.min(x) delta_y = y_max - y_min delta_x = x_max - x_min y = (y - y_min) / delta_y x = (x - x_min) / delta_x err = errors / delta_y if errors is not None else None period = fallback_period(guess_period(x, y)) omega = 2 * np.pi / period p0 = [ 0.5, 0.5, omega, 0, 1, ] popt, perr = curve_fit( ramsey_fit, x, y, p0=p0, maxfev=5000, bounds=( [0, 0, 0, -np.pi, 0], [1, 1, np.inf, np.pi, np.inf], ), sigma=err, ) popt = [ delta_y * popt[0] + y_min, delta_y * popt[1] * np.exp(x_min * popt[4] / delta_x), popt[2] / delta_x, popt[3] - x_min * popt[2] / delta_x, popt[4] / delta_x, ] perr = np.sqrt(np.diag(perr)) perr = [ delta_y * perr[0], delta_y * np.exp(x_min * popt[4] / delta_x) * np.sqrt(perr[1] ** 2 + (popt[1] * x_min * perr[4] / delta_x) ** 2), perr[2] / delta_x, np.sqrt(perr[3] ** 2 + (perr[2] * x_min / delta_x) ** 2), perr[4] / delta_x, ] return popt, perr
[docs]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