Commit edda79c4 authored by Kelvin Loh's avatar Kelvin Loh 🖖
Browse files

Merge branch 'schedule-updates' into 'develop'

Artificial detuning in Ramsey Schedule and bug fixes

See merge request quantify-os/quantify-scheduler!120
parents b8578074 e04960bc
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ Merged branches and closed issues
* Pulsar backend v0.2.2 check. (!48)
* Fix for issue with acq delay . (!45)
* Fix for issue #52. (!44)
* Add artificial detuning to Ramsey schedule (!120)



+33 −8
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ Module containing schedules for common time domain experiments such as a Rabi an
T1 measurement.
"""
from typing import Union
from typing_extensions import Literal
import numpy as np
from quantify.scheduler.types import Schedule
from quantify.scheduler.pulse_library import SquarePulse, IdlePulse, DRAGPulse
@@ -150,6 +151,7 @@ def t1_sched(

def ramsey_sched(
    times: Union[np.ndarray, float],
    artificial_detuning: float,
    qubit: str,
    repetitions: int = 1,
) -> Schedule:
@@ -168,6 +170,12 @@ def ramsey_sched(
    ----------
    times
        an array of wait times tau between the pi/2 pulses.
    artificial_detuning
        frequency in Hz of the software emulated, or `artificial` qubit detuning, which is
        implemented by changing the phase of the second pi/2 (recovery) pulse. The
        artificial detuning changes the observed frequency of the Ramsey oscillation,
        which can be useful to distinguish a slow oscillation due to a small physical
        detuning from the decay of the dephasing noise.
    qubit
        the name of the qubit e.g., :code:`"q0"` to perform the Ramsey experiment on.
    repetitions
@@ -194,11 +202,18 @@ def ramsey_sched(

    schedule = Schedule("Ramsey", repetitions)

    if isinstance(times, float):
        times = [times]

    for i, tau in enumerate(times):
        schedule.add(Reset(qubit), label=f"Reset {i}")
        schedule.add(X90(qubit))
        # FIXME: to be added artificial detuning see #98 # pylint: disable=fixme
        schedule.add(Rxy(theta=90, phi=0, qubit=qubit), ref_pt="start", rel_time=tau)

        # the phase of the second pi/2 phase progresses to propagate
        recovery_phase = np.rad2deg(2 * np.pi * artificial_detuning * tau)
        schedule.add(
            Rxy(theta=90, phi=recovery_phase, qubit=qubit), ref_pt="start", rel_time=tau
        )
        schedule.add(Measure(qubit), label=f"Measurement {i}")
    return schedule

@@ -225,7 +240,7 @@ def echo_sched(
    Parameters
    ----------
    qubit
        the name of the qubit e.g., "q0" to perform the Echo experiment on.
        the name of the qubit e.g., "q0" to perform the echo experiment on.
    times
        an array of wait times between the
    repetitions
@@ -263,6 +278,7 @@ def echo_sched(

def allxy_sched(
    qubit: str,
    elt_select_idx: Union[Literal["All"], int] = "ALL",
    repetitions: int = 1,
) -> Schedule:
    # pylint: disable=line-too-long
@@ -281,6 +297,9 @@ def allxy_sched(
    ----------
    qubit
        the name of the qubit e.g., :code:`"q0"` to perform the experiment on.
    elt_select_idx
        the index of the particular element of the AllXY experiment to exectute -
        or :code:`"All"` for all elemements of the sequence.
    repetitions
        The amount of times the Schedule will be repeated.

@@ -305,7 +324,7 @@ def allxy_sched(
    allxy_combinations = [
        [(0, 0), (0, 0)],
        [(180, 0), (180, 0)],
        [(180, 0), (180, 0)],
        [(180, 90), (180, 90)],
        [(180, 0), (180, 90)],
        [(180, 90), (180, 0)],
        [(90, 0), (0, 0)],
@@ -327,10 +346,16 @@ def allxy_sched(
    ]
    schedule = Schedule("AllXY", repetitions)
    for i, ((th0, phi0), (th1, phi1)) in enumerate(allxy_combinations):
        if elt_select_idx in ("ALL", i):
            schedule.add(Reset(qubit), label=f"Reset {i}")
            schedule.add(Rxy(qubit=qubit, theta=th0, phi=phi0))
            schedule.add(Rxy(qubit=qubit, theta=th1, phi=phi1))
            schedule.add(Measure(qubit), label=f"Measurement {i}")
        elif elt_select_idx > len(allxy_combinations) or elt_select_idx < 0:
            raise ValueError(
                f"Invalid index selected: {elt_select_idx}. "
                "Index must be in range 0 to 21 inclusive."
            )
    return schedule


+40 −3
Original line number Diff line number Diff line
@@ -271,6 +271,7 @@ class TestRamseySched:
        cls.sched_kwargs = {
            "times": np.linspace(4.0e-6, 80e-6, 20),
            "qubit": "q0",
            "artificial_detuning": 250e3,
            "repetitions": 10,
        }

@@ -295,6 +296,7 @@ class TestRamseySched:
        sched_kwargs = {
            "times": 3e-6,  # a floating point time
            "qubit": "q0",
            "artificial_detuning": 250e3,
        }

        sched = ts.ramsey_sched(**sched_kwargs)
@@ -302,6 +304,9 @@ class TestRamseySched:

    def test_operations(self):
        # 4 for a regular Ramsey, more with artificial detuning
        if self.sched_kwargs["artificial_detuning"]:
            assert len(self.sched.operations) == 3 + len(self.sched_kwargs["times"])
        else:
            assert len(self.sched.operations) == 4  # init, x90, Rxy(90,0) and measure

    def test_compiles_qblox_backend(self):
@@ -384,10 +389,42 @@ class TestAllXYSched:
                assert constr["label"][:11] == "Measurement"

    def test_operations(self):
        # 7 operations (x90, y90, X180, Y180, idle, reset measurement)
        # 7 operations (x90, y90, X180, Y180, idle, reset, measurement)
        assert len(self.sched.operations) == 7

    @pytest.mark.xfail  # see #89
    def test_compiles_qblox_backend(self):
        # assert that files properly compile
        qcompile(self.sched, DEVICE_CONFIG, QBLOX_HARDWARE_MAPPING)

    def test_compiles_zi_backend(self):
        # assert that files properly compile
        qcompile(self.sched, DEVICE_CONFIG, ZHINST_HARDWARE_MAPPING)


class TestAllXYSchedElement:
    @classmethod
    def setup_class(cls):
        set_datadir(tmp_dir.name)
        cls.sched_kwargs = {
            "qubit": "q0",
            "elt_select_idx": 4,
        }

        cls.sched = ts.allxy_sched(**cls.sched_kwargs)
        cls.sched = qcompile(cls.sched, DEVICE_CONFIG)

    def test_timing(self):
        # test that the right operations are added and timing is as expected.
        for i, constr in enumerate(self.sched.timing_constraints):
            if i % 4 == 0:
                assert constr["label"][:5] == "Reset"
            if (i - 3) % 4 == 0:
                assert constr["label"][:11] == "Measurement"

    def test_operations(self):
        # 4 operations (X180, Y180, reset, measurement)
        assert len(self.sched.operations) == 4

    def test_compiles_qblox_backend(self):
        # assert that files properly compile
        qcompile(self.sched, DEVICE_CONFIG, QBLOX_HARDWARE_MAPPING)