Source code for qibocal.protocols.coherence.spin_echo

from dataclasses import dataclass, field
from typing import Optional

import numpy as np
from qibolab import AcquisitionType, AveragingMode, Parameter, Sweeper

from qibocal.auto.operation import QubitId, Routine
from qibocal.calibration import CalibrationPlatform
from qibocal.result import probability

from . import t1
from .spin_echo_signal import SpinEchoSignalParameters, SpinEchoSignalResults, _update
from .utils import dynamical_decoupling_sequence, exponential_fit_probability, plot


[docs]@dataclass class SpinEchoParameters(SpinEchoSignalParameters): """SpinEcho runcard inputs."""
[docs]@dataclass class SpinEchoResults(SpinEchoSignalResults): """SpinEcho outputs.""" chi2: Optional[dict[QubitId, tuple[float, Optional[float]]]] = field( default_factory=dict ) """Chi squared estimate mean value and error."""
[docs]class SpinEchoData(t1.T1Data): """SpinEcho acquisition outputs."""
[docs]def _acquisition( params: SpinEchoParameters, platform: CalibrationPlatform, targets: list[QubitId], ) -> SpinEchoData: """Data acquisition for SpinEcho""" # create a sequence of pulses for the experiment: sequence, delays = dynamical_decoupling_sequence(platform, targets, kind="CP") # define the parameter to sweep and its range: # delay between pulses wait_range = np.arange( params.delay_between_pulses_start, params.delay_between_pulses_end, params.delay_between_pulses_step, ) durations = [] for q in targets: # this is assuming that RX and RX90 have the same duration duration = platform.natives.single_qubit[q].RX()[0][1].duration durations.append(duration) assert (params.delay_between_pulses_start - duration) / 2 >= 0, ( f"Initial delay too short for qubit {q}, minimum delay should be {duration}" ) assert len(set(durations)) == 1, ( "Cannot run on mulitple qubit with different RX duration." ) sweeper = Sweeper( parameter=Parameter.duration, values=(wait_range - durations[0]) / 2, pulses=delays, ) results = platform.execute( [sequence], [[sweeper]], nshots=params.nshots, relaxation_time=params.relaxation_time, acquisition_type=AcquisitionType.DISCRIMINATION, averaging_mode=AveragingMode.SINGLESHOT, ) data = SpinEchoData() for qubit in targets: ro_pulse = list(sequence.channel(platform.qubits[qubit].acquisition))[-1] result = results[ro_pulse.id] prob = probability(result, state=1) error = np.sqrt(prob * (1 - prob) / params.nshots) data.register_qubit( t1.CoherenceProbType, (qubit), dict( wait=wait_range, prob=prob, error=error, ), ) return data
[docs]def _fit(data: SpinEchoData) -> SpinEchoResults: """Post-processing for SpinEcho.""" t2Echos, fitted_parameters, pcovs, chi2 = exponential_fit_probability(data) return SpinEchoResults(t2Echos, fitted_parameters, pcovs, chi2)
spin_echo = Routine(_acquisition, _fit, plot, _update) """SpinEcho Routine object."""