Source code for quantify_scheduler.schedules.spectroscopy_schedules

# Repository: https://gitlab.com/quantify-os/quantify-scheduler
# Licensed according to the LICENCE file on the main branch
"""Module containing schedules for common spectroscopy experiments."""
from __future__ import annotations

from typing import TYPE_CHECKING

from quantify_scheduler.enums import BinMode
from quantify_scheduler.operations.acquisition_library import SSBIntegrationComplex
from quantify_scheduler.operations.gate_library import Measure, Reset
from quantify_scheduler.operations.nv_native_library import ChargeReset, CRCount
from quantify_scheduler.operations.pulse_library import (
    IdlePulse,
    SetClockFrequency,
    SquarePulse,
)
from quantify_scheduler.operations.shared_native_library import SpectroscopyOperation
from quantify_scheduler.resources import ClockResource
from quantify_scheduler.schedules.schedule import Schedule

if TYPE_CHECKING:
    import numpy as np


[docs] def heterodyne_spec_sched( pulse_amp: float, pulse_duration: float, frequency: float, acquisition_delay: float, integration_time: float, port: str, clock: str, init_duration: float = 10e-6, repetitions: int = 1, port_out: str | None = None, ) -> Schedule: """ Generate a schedule for performing heterodyne spectroscopy. Parameters ---------- pulse_amp Amplitude of the spectroscopy pulse in Volt. pulse_duration Duration of the spectroscopy pulse in seconds. frequency Frequency of the spectroscopy pulse in Hertz. acquisition_delay Start of the data acquisition with respect to the start of the spectroscopy pulse in seconds. integration_time Integration time of the data acquisition in seconds. port Location on the device where the acquisition is performed. clock Reference clock used to track the spectroscopy frequency. init_duration The relaxation time or dead time. repetitions The amount of times the Schedule will be repeated. port_out Output port on the device where the pulse should be applied. If `None`, then use the same as `port`. """ sched = Schedule("Heterodyne spectroscopy", repetitions) sched.add_resource(ClockResource(name=clock, freq=frequency)) sched.add(IdlePulse(duration=init_duration), label="buffer") if port_out is None: port_out = port pulse = sched.add( SquarePulse( duration=pulse_duration, amp=pulse_amp, port=port_out, clock=clock, ), label="spec_pulse", ) sched.add( SSBIntegrationComplex( duration=integration_time, port=port, clock=clock, acq_index=0, acq_channel=0, ), ref_op=pulse, ref_pt="start", rel_time=acquisition_delay, label="acquisition", ) return sched
[docs] def heterodyne_spec_sched_nco( pulse_amp: float, pulse_duration: float, frequencies: np.ndarray, acquisition_delay: float, integration_time: float, port: str, clock: str, init_duration: float = 10e-6, repetitions: int = 1, port_out: str | None = None, ) -> Schedule: """ Generate a batched schedule for performing fast heterodyne spectroscopy using the :class:`~quantify_scheduler.operations.pulse_library.SetClockFrequency` operation for doing an NCO sweep. .. admonition:: Example use of the ``heterodyne_spec_sched_nco`` schedule :class: tip .. jupyter-execute:: import numpy as np from qcodes.instrument.parameter import ManualParameter from quantify_scheduler.gettables import ScheduleGettable from quantify_scheduler.device_under_test.quantum_device import QuantumDevice from quantify_scheduler.device_under_test.transmon_element import BasicTransmonElement from quantify_scheduler.schedules.spectroscopy_schedules import heterodyne_spec_sched_nco quantum_device = QuantumDevice(name="quantum_device") q0 = BasicTransmonElement("q0") quantum_device.add_element(q0) ... # Manual parameter for batched schedule ro_freq = ManualParameter("ro_freq", unit="Hz") ro_freq.batched = True ro_freqs = np.linspace(start=4.5e9, stop=5.5e9, num=11) quantum_device.cfg_sched_repetitions(5) # Configure the gettable qubit = quantum_device.get_element("q0") schedule_kwargs = { "pulse_amp": qubit.measure.pulse_amp(), "pulse_duration": qubit.measure.pulse_duration(), "frequencies": ro_freqs, "acquisition_delay": qubit.measure.acq_delay(), "integration_time": qubit.measure.integration_time(), "port": qubit.ports.readout(), "clock": qubit.name + ".ro", "init_duration": qubit.reset.duration(), } spec_gettable = ScheduleGettable( quantum_device=quantum_device, schedule_function=heterodyne_spec_sched_nco, schedule_kwargs=schedule_kwargs, real_imag=False, batched=True, ) ... quantum_device.close() q0.close() Parameters ---------- pulse_amp Amplitude of the spectroscopy pulse in Volt. pulse_duration Duration of the spectroscopy pulse in seconds. frequencies Sample frequencies for the spectroscopy pulse in Hertz. acquisition_delay Start of the data acquisition with respect to the start of the spectroscopy pulse in seconds. integration_time Integration time of the data acquisition in seconds. port Location on the device where the acquisition is performed. clock Reference clock used to track the spectroscopy frequency. init_duration The relaxation time or dead time. repetitions The amount of times the Schedule will be repeated. port_out Output port on the device where the pulse should be applied. If `None`, then use the same as `port`. """ # noqa: E501 Line too long sched = Schedule("Fast heterodyne spectroscopy (NCO sweep)", repetitions) sched.add_resource(ClockResource(name=clock, freq=frequencies.flat[0])) if port_out is None: port_out = port for acq_idx, freq in enumerate(frequencies): sched.add(IdlePulse(duration=init_duration), label=f"buffer {acq_idx}") sched.add( SetClockFrequency(clock=clock, clock_freq_new=freq), label=f"set_freq {acq_idx} ({clock} {freq:e} Hz)", ) spec_pulse = sched.add( SquarePulse( duration=pulse_duration, amp=pulse_amp, port=port_out, clock=clock, ), label=f"spec_pulse {acq_idx})", ) sched.add( SSBIntegrationComplex( duration=integration_time, port=port, clock=clock, acq_index=acq_idx, acq_channel=0, bin_mode=BinMode.AVERAGE, ), ref_op=spec_pulse, ref_pt="start", rel_time=acquisition_delay, label=f"acquisition {acq_idx})", ) return sched
[docs] def two_tone_spec_sched( spec_pulse_amp: float, spec_pulse_duration: float, spec_pulse_port: str, spec_pulse_clock: str, spec_pulse_frequency: float, ro_pulse_amp: float, ro_pulse_duration: float, ro_pulse_delay: float, ro_pulse_port: str, ro_pulse_clock: str, ro_pulse_frequency: float, ro_acquisition_delay: float, ro_integration_time: float, init_duration: float = 10e-6, repetitions: int = 1, ) -> Schedule: """ Generate a schedule for performing two-tone spectroscopy. Parameters ---------- spec_pulse_amp Amplitude of the spectroscopy pulse in Volt. spec_pulse_duration Duration of the spectroscopy pulse in seconds. spec_pulse_port Location on the device where the spectroscopy pulse should be applied. spec_pulse_clock Reference clock used to track the spectroscopy frequency. spec_pulse_frequency Frequency of the spectroscopy pulse in Hertz. ro_pulse_amp Amplitude of the readout (spectroscopy) pulse in Volt. ro_pulse_duration Duration of the readout (spectroscopy) pulse in seconds. ro_pulse_delay Time between the end of the spectroscopy pulse and the start of the readout (spectroscopy) pulse. ro_pulse_port Location on the device where the readout (spectroscopy) pulse should be applied. ro_pulse_clock Reference clock used to track the readout (spectroscopy) frequency. ro_pulse_frequency Frequency of the readout (spectroscopy) pulse in Hertz. ro_acquisition_delay Start of the data acquisition with respect to the start of the readout pulse in seconds. ro_integration_time Integration time of the data acquisition in seconds. init_duration The relaxation time or dead time. repetitions The amount of times the Schedule will be repeated. """ sched = Schedule("Two-tone spectroscopy", repetitions) sched.add_resource(ClockResource(name=spec_pulse_clock, freq=spec_pulse_frequency)) sched.add_resource(ClockResource(name=ro_pulse_clock, freq=ro_pulse_frequency)) sched.add( IdlePulse(duration=init_duration), label="buffer", ) sched.add( SquarePulse( duration=spec_pulse_duration, amp=spec_pulse_amp, port=spec_pulse_port, clock=spec_pulse_clock, ), label="spec_pulse", ) ro_pulse = sched.add( SquarePulse( duration=ro_pulse_duration, amp=ro_pulse_amp, port=ro_pulse_port, clock=ro_pulse_clock, ), label="readout_pulse", rel_time=ro_pulse_delay, ) sched.add( SSBIntegrationComplex( duration=ro_integration_time, port=ro_pulse_port, clock=ro_pulse_clock, acq_index=0, acq_channel=0, ), ref_op=ro_pulse, ref_pt="start", rel_time=ro_acquisition_delay, label="acquisition", ) return sched
[docs] def two_tone_spec_sched_nco( spec_pulse_amp: float, spec_pulse_duration: float, spec_pulse_port: str, spec_pulse_clock: str, spec_pulse_frequencies: np.ndarray, ro_pulse_amp: float, ro_pulse_duration: float, ro_pulse_delay: float, ro_pulse_port: str, ro_pulse_clock: str, ro_pulse_frequency: float, ro_acquisition_delay: float, ro_integration_time: float, init_duration: float, repetitions: int = 1, ) -> Schedule: """ Generate a batched schedule for performing fast two-tone spectroscopy using the :class:`~quantify_scheduler.operations.pulse_library.SetClockFrequency` operation for doing an NCO sweep. For long-lived qubits, it is advisable to use a small number of repetitions and compensate by doing continuous spectroscopy (low amplitude, long duration pulse with simultaneous long readout). The "dead-time" between two data points needs to be sufficient to properly reset the qubit. That means that `init_duration` should be >> T1 (so typically >200us). .. admonition:: Example use of the ``two_tone_spec_sched_nco`` schedule :class: tip .. jupyter-execute:: import numpy as np from qcodes.instrument.parameter import ManualParameter from quantify_scheduler.gettables import ScheduleGettable from quantify_scheduler.device_under_test.quantum_device import QuantumDevice from quantify_scheduler.device_under_test.transmon_element import BasicTransmonElement from quantify_scheduler.schedules.spectroscopy_schedules import two_tone_spec_sched_nco quantum_device = QuantumDevice(name="quantum_device") q0 = BasicTransmonElement("q0") quantum_device.add_element(q0) ... # Manual parameter for batched schedule spec_freq = ManualParameter("spec_freq", unit="Hz") spec_freq.batched = True spec_freqs = np.linspace(start=4.5e9, stop=5.5e9, num=11) quantum_device.cfg_sched_repetitions(5) # Configure the gettable qubit = quantum_device.get_element("q0") schedule_kwargs = { "spec_pulse_amp": 0.5, "spec_pulse_duration": 8e-6, "spec_pulse_port": qubit.ports.microwave(), "spec_pulse_clock": qubit.name + ".01", "spec_pulse_frequencies": spec_freqs, "ro_pulse_amp": qubit.measure.pulse_amp(), "ro_pulse_duration": qubit.measure.pulse_duration(), "ro_pulse_delay": 300e-9, "ro_pulse_port": qubit.ports.readout(), "ro_pulse_clock": qubit.name + ".ro", "ro_pulse_frequency": 7.04e9, "ro_acquisition_delay": qubit.measure.acq_delay(), "ro_integration_time": qubit.measure.integration_time(), "init_duration": 300e-6, } spec_gettable = ScheduleGettable( quantum_device=quantum_device, schedule_function=two_tone_spec_sched_nco, schedule_kwargs=schedule_kwargs, real_imag=False, batched=True, ) ... quantum_device.close() q0.close() Parameters ---------- spec_pulse_amp Amplitude of the spectroscopy pulse in Volt. spec_pulse_duration Duration of the spectroscopy pulse in seconds. spec_pulse_port Location on the device where the spectroscopy pulse should be applied. spec_pulse_clock Reference clock used to track the spectroscopy frequency. spec_pulse_frequencies Sample frequencies for the spectroscopy pulse in Hertz. ro_pulse_amp Amplitude of the readout (spectroscopy) pulse in Volt. ro_pulse_duration Duration of the readout (spectroscopy) pulse in seconds. ro_pulse_delay Time between the end of the spectroscopy pulse and the start of the readout (spectroscopy) pulse. ro_pulse_port Location on the device where the readout (spectroscopy) pulse should be applied. ro_pulse_clock Reference clock used to track the readout (spectroscopy) frequency. ro_pulse_frequency Frequency of the readout (spectroscopy) pulse in Hertz. ro_acquisition_delay Start of the data acquisition with respect to the start of the readout pulse in seconds. ro_integration_time Integration time of the data acquisition in seconds. init_duration The relaxation time or dead time. repetitions The amount of times the Schedule will be repeated. """ sched = Schedule("Fast two-tone spectroscopy (NCO sweep)", repetitions) sched.add_resources( [ ClockResource(name=spec_pulse_clock, freq=spec_pulse_frequencies.flat[0]), ClockResource(name=ro_pulse_clock, freq=ro_pulse_frequency), ] ) for acq_idx, spec_pulse_freq in enumerate(spec_pulse_frequencies): sched.add(IdlePulse(duration=init_duration), label=f"buffer {acq_idx}") sched.add( SetClockFrequency(clock=spec_pulse_clock, clock_freq_new=spec_pulse_freq), label=f"set_freq {acq_idx} ({spec_pulse_clock} {spec_pulse_freq:e} Hz)", ) spec_pulse = sched.add( SquarePulse( duration=spec_pulse_duration, amp=spec_pulse_amp, port=spec_pulse_port, clock=spec_pulse_clock, ), label=f"spec_pulse {acq_idx}", ) ro_pulse = sched.add( SquarePulse( duration=ro_pulse_duration, amp=ro_pulse_amp, port=ro_pulse_port, clock=ro_pulse_clock, ), ref_op=spec_pulse, ref_pt="end", rel_time=ro_pulse_delay, label=f"readout_pulse {acq_idx}", ) sched.add( SSBIntegrationComplex( duration=ro_integration_time, port=ro_pulse_port, clock=ro_pulse_clock, acq_index=acq_idx, acq_channel=0, bin_mode=BinMode.AVERAGE, ), ref_op=ro_pulse, ref_pt="start", rel_time=ro_acquisition_delay, label=f"acquisition {acq_idx}", ) return sched
[docs] def nv_dark_esr_sched( qubit: str, repetitions: int = 1, ) -> Schedule: """ Generates a schedule for a dark ESR experiment on an NV-center. The spectroscopy frequency is taken from the device element. Please use the clock specified in the `spectroscopy_operation` entry of the device config. This schedule can currently not be compiled with the Zurich Instruments backend. Parameters ---------- qubit Name of the `DeviceElement` representing the NV-center. repetitions Number of schedule repetitions. Returns ------- : Schedule with a single frequency """ sched = Schedule("Dark ESR Schedule", repetitions=repetitions) sched.add(ChargeReset(qubit), label="Charge reset") sched.add(CRCount(qubit, acq_index=0), label="CRCount pre") sched.add(Reset(qubit), label="Reset") sched.add(SpectroscopyOperation(qubit), label="Spectroscopy") sched.add(Measure(qubit, acq_index=1), label="Measure") sched.add(CRCount(qubit, acq_index=2), label="CRCount post") return sched
[docs] def nv_dark_esr_sched_nco( qubit: str, spec_clock: str, spec_frequencies: np.ndarray, repetitions: int = 1, ) -> Schedule: """ Generates a schedule for a dark ESR experiment on an NV-center, in which the NCO frequency is swept. .. note:: This schedule currently cannot be compiled with the Zurich Instruments backend. Parameters ---------- qubit Name of the `DeviceElement` representing the NV-center. spec_clock Reference clock of the spectroscopy operation. spec_frequencies Sample frequencies for the spectroscopy pulse in Hertz. repetitions Number of schedule repetitions. Returns ------- : Schedule with NCO frequency sweeping for spectroscopy operation. """ sched = Schedule("Dark ESR Schedule (NCO sweep)", repetitions=repetitions) sched.add(ChargeReset(qubit), label="Charge reset pre 0") sched.add(CRCount(qubit, acq_index=0), label="CRCount pre 0") for idx, spec_freq in enumerate(spec_frequencies): sched.add( SetClockFrequency(clock=spec_clock, clock_freq_new=spec_freq), label=f"set_freq ({spec_clock} {spec_freq:e} Hz)", ) sched.add(Reset(qubit), label=f"Reset {idx}") sched.add(SpectroscopyOperation(qubit), label=f"Spectroscopy ({spec_freq:e} Hz)") sched.add(Measure(qubit, acq_index=idx * 2 + 1), label=f"Measure {idx}") sched.add(CRCount(qubit, acq_index=idx * 2 + 2), label=f"CRCount post {idx}") return sched