{ "cells": [ { "cell_type": "markdown", "id": "3b04b431", "metadata": {}, "source": [ "# Resonator spectroscopy\n", "\n", "https://qblox-qblox-instruments.readthedocs-hosted.com/en/master/applications/quantify/tuning_transmon_qubit.html" ] }, { "cell_type": "markdown", "id": "c56871c7", "metadata": {}, "source": [ "## Setup\n", "In this section we configure the hardware configuration which specifies the connectivity of our system." ] }, { "cell_type": "markdown", "id": "6b808a69", "metadata": {}, "source": [ "### Configuration file\n", "\n", "This is a template hardware configuration file for a 1-qubit system with a flux-control line which can be used to tune the qubit frequency.\n", "\n", "The hardware setup is as follows, by cluster slot:\n", "1. **QCM-RF**\n", " - Drive line for `qubit` using fixed 80 MHz IF.\n", "2. **QCM**\n", " - Flux line for `qubit`.\n", "6. **QRM-RF**\n", " - Readout line for `qubit` using a fixed LO set at 7.5 GHz.\n", " \n", "Note that in the hardware configuration below the mixers are uncorrected, but for high fidelity experiments this should also be done for all the modules." ] }, { "cell_type": "code", "execution_count": null, "id": "78e87485", "metadata": {}, "outputs": [], "source": [ "hardware_cfg = {\n", " \"backend\": \"quantify_scheduler.backends.qblox_backend.hardware_compile\",\n", " \"cluster0\": {\n", " \"sequence_to_file\": False, # Boolean flag which dumps waveforms and program dict to JSON file\n", " \"ref\": \"internal\", # Use shared clock reference of the cluster\n", " \"instrument_type\": \"Cluster\",\n", " # ============ DRIVE ============#\n", " \"cluster0_module1\": {\n", " \"instrument_type\": \"QCM_RF\",\n", " \"complex_output_0\": {\n", " \"output_att\": 0,\n", " \"dc_mixer_offset_I\": 0.0,\n", " \"dc_mixer_offset_Q\": 0.0,\n", " \"portclock_configs\": [\n", " {\n", " \"port\": \"qubit:mw\",\n", " \"clock\": \"qubit.01\",\n", " \"interm_freq\": 80e6,\n", " \"mixer_amp_ratio\": 1.0,\n", " \"mixer_phase_error_deg\": 0.0,\n", " }\n", " ],\n", " },\n", " },\n", " # ============ FLUX ============#\n", " \"cluster0_module2\": {\n", " \"instrument_type\": \"QCM\",\n", " \"real_output_0\": {\n", " \"portclock_configs\": [{\"port\": \"qubit:fl\", \"clock\": \"cl0.baseband\"}]\n", " },\n", " },\n", " # ============ READOUT ============#\n", " \"cluster0_module3\": {\n", " \"instrument_type\": \"QRM_RF\",\n", " \"complex_output_0\": {\n", " \"output_att\": 0,\n", " \"input_att\": 0,\n", " \"dc_mixer_offset_I\": 0.0,\n", " \"dc_mixer_offset_Q\": 0.0,\n", " \"lo_freq\": 7.5e9,\n", " \"portclock_configs\": [\n", " {\n", " \"port\": \"qubit:res\",\n", " \"clock\": \"qubit.ro\",\n", " \"mixer_amp_ratio\": 1.0,\n", " \"mixer_phase_error_deg\": 0.0,\n", " }\n", " ],\n", " },\n", " },\n", " },\n", "}" ] }, { "cell_type": "code", "execution_count": null, "id": "7d26c461", "metadata": {}, "outputs": [], "source": [ "import warnings\n", "from pathlib import Path\n", "\n", "import ipywidgets as widgets\n", "import numpy as np\n", "import quantify_core.data.handling as dh\n", "from IPython.display import display\n", "from qblox_instruments import Cluster, ClusterType, PlugAndPlay\n", "from qcodes import Instrument\n", "from qcodes.parameters import ManualParameter\n", "from quantify_core.analysis.single_qubit_timedomain import RabiAnalysis, RamseyAnalysis, T1Analysis\n", "from quantify_core.measurement.control import MeasurementControl\n", "from quantify_core.visualization.pyqt_plotmon import PlotMonitor_pyqt as PlotMonitor\n", "from quantify_scheduler.device_under_test.quantum_device import QuantumDevice\n", "from quantify_scheduler.device_under_test.transmon_element import BasicTransmonElement\n", "from quantify_scheduler.gettables import ScheduleGettable\n", "from quantify_scheduler.instrument_coordinator import InstrumentCoordinator\n", "from quantify_scheduler.instrument_coordinator.components.qblox import ClusterComponent\n", "from quantify_scheduler.operations.gate_library import Measure, Reset\n", "from quantify_scheduler.operations.pulse_library import SetClockFrequency, SquarePulse\n", "from quantify_scheduler.resources import ClockResource\n", "from quantify_scheduler.schedules import heterodyne_spec_sched_nco, rabi_sched, t1_sched\n", "from quantify_scheduler.schedules.timedomain_schedules import ramsey_sched\n", "from quantify_scheduler.schedules.schedule import Schedule\n" ] }, { "cell_type": "markdown", "id": "450716e2", "metadata": {}, "source": [ "### Connect to Cluster\n", "\n", "We now make a connection with the Cluster selected in the dropdown widget. We also define a function to find the modules we're interested in. We select the readout and control module we want to use." ] }, { "cell_type": "code", "execution_count": null, "id": "93081ffa-fecb-45db-89bd-10ef7b97b9b3", "metadata": {}, "outputs": [], "source": [ "# Close all existing QCoDeS Instrument instances\n", "Instrument.close_all()\n", "\n", "# Here we have the option to use a dummy device so that you can run your tests without a physical cluster\n", "dummy_cfg = (\n", " {\n", " 1: ClusterType.CLUSTER_QCM_RF,\n", " 2: ClusterType.CLUSTER_QCM,\n", " 3: ClusterType.CLUSTER_QRM_RF,\n", " }\n", ")\n", "\n", "cluster = Cluster(\n", " name=\"cluster0\", identifier=\"\", dummy_cfg=dummy_cfg\n", ")\n", "\n", "#print(f\"{connect.label} connected\")" ] }, { "cell_type": "markdown", "id": "3aa44d8f", "metadata": {}, "source": [ "### Reset the Cluster\n", "\n", "We reset the Cluster to enter a well-defined state. Note that resetting will clear all stored parameters and repeats startup calibration, so resetting between experiments is usually not desirable." ] }, { "cell_type": "code", "execution_count": null, "id": "433d5e4c-3cd2-446c-930f-81048e06e46a", "metadata": {}, "outputs": [], "source": [ "cluster.reset()\n", "#print(cluster.get_system_state())" ] }, { "cell_type": "markdown", "id": "51449b53", "metadata": {}, "source": [ "Note that a dummy cluster will raise error flags, this is expected behavior and can be ignored." ] }, { "cell_type": "markdown", "id": "a8e19199", "metadata": {}, "source": [ "### Quantum device settings\n", "Here we initialize our `QuantumDevice` and our qubit parameters, checkout this [tutorial](https://quantify-quantify-scheduler.readthedocs-hosted.com/en/latest/tutorials/Operations%20and%20Qubits.html) for further details.\n", "\n", "In short, a `QuantumDevice` contains device elements where we save our found parameters." ] }, { "cell_type": "code", "execution_count": null, "id": "5347b271", "metadata": {}, "outputs": [], "source": [ "qubit = BasicTransmonElement(\"qubit\")\n", "qubit.measure.acq_channel(0)\n", "\n", "quantum_device = QuantumDevice(\"device_1q\")\n", "quantum_device.hardware_config(hardware_cfg)\n", "\n", "quantum_device.add_element(qubit)" ] }, { "cell_type": "markdown", "id": "4b454259", "metadata": {}, "source": [ "### Configure measurement control loop\n", "We will use a `MeasurementControl` object for data acquisition as well as an `InstrumentCoordinator` for controlling the instruments in our setup.\n", "\n", "The `PlotMonitor` is used for live plotting.\n", "\n", "All of these are then associated with the `QuantumDevice`." ] }, { "cell_type": "code", "execution_count": null, "id": "b556e1a0", "metadata": {}, "outputs": [], "source": [ "def configure_measurement_control_loop(\n", " device: QuantumDevice, cluster: Cluster, live_plotting: bool = False\n", ") -> None:\n", " # Close QCoDeS instruments with conflicting names\n", " for name in [\n", " \"PlotMonitor\",\n", " \"meas_ctrl\",\n", " \"ic\",\n", " \"ic_generic\",\n", " f\"ic_{cluster.name}\",\n", " ] + [f\"ic_{module.name}\" for module in cluster.modules]:\n", " try:\n", " Instrument.find_instrument(name).close()\n", " except KeyError as kerr:\n", " pass\n", "\n", " meas_ctrl = MeasurementControl(\"meas_ctrl\")\n", " ic = InstrumentCoordinator(\"ic\")\n", "\n", " # Add cluster to instrument coordinator\n", " ic_cluster = ClusterComponent(cluster)\n", " ic.add_component(ic_cluster)\n", "\n", " if live_plotting:\n", " # Associate plot monitor with measurement controller\n", " plotmon = PlotMonitor(\"PlotMonitor\")\n", " meas_ctrl.instr_plotmon(plotmon.name)\n", "\n", " # Associate measurement controller and instrument coordinator with the quantum device\n", " device.instr_measurement_control(meas_ctrl.name)\n", " device.instr_instrument_coordinator(ic.name)\n", "\n", " return (meas_ctrl, ic)\n", "\n", "\n", "meas_ctrl, instrument_coordinator = configure_measurement_control_loop(\n", " quantum_device, cluster\n", ")" ] }, { "cell_type": "markdown", "id": "77aafa94", "metadata": {}, "source": [ "### Set data directory\n", "This directory is where all of the experimental data as well as all of the post processing will go." ] }, { "cell_type": "code", "execution_count": null, "id": "499a24fd", "metadata": {}, "outputs": [], "source": [ "# Enter your own dataset directory here!\n", "dh.set_datadir(Path(\"example_data\").resolve())" ] }, { "cell_type": "markdown", "id": "79ad8062", "metadata": {}, "source": [ "### Configure external flux control\n", "In the case of flux-tunable transmon qubits, we need to have some way of controlling the external flux.\n", "\n", "This can be done by setting an output bias on a module of the cluster which is then connected to the flux line.\n", "\n", "```python\n", " # e.g. nullify external flux by setting current to 0 A\n", " cluster.module2.out0_current(0.0)\n", "```\n", "\n", "If your system is not using flux-tunable transmons, then you can skip to the next section." ] }, { "cell_type": "code", "execution_count": null, "id": "6d9b6a3e", "metadata": {}, "outputs": [], "source": [ "flux_settable: callable = cluster.module2.out0_offset\n", "flux_settable(0.0)" ] }, { "cell_type": "markdown", "id": "5bbcd617", "metadata": {}, "source": [ "### Activate NCO delay compensation\n", "Compensate for the digital propagation delay for each qubit (i.e each sequencer)\n", "\n", "For more info, please see: https://qblox-qblox-instruments.readthedocs-hosted.com/en/master/api_reference/sequencer.html#pulsar-qcm-sequencer-nco-prop-delay-comp-en\n", "\n", "To avoid mismatches between modulation and demodulation, the delay between any readout frequency or phase changes and the next acquisition should be equal or greater than the total propagation delay (146ns + user defined value)." ] }, { "cell_type": "code", "execution_count": null, "id": "8eaca2e6", "metadata": {}, "outputs": [], "source": [ "for i in range(6):\n", " getattr(cluster.module3, f\"sequencer{i}\").nco_prop_delay_comp_en(True)\n", " getattr(cluster.module3, f\"sequencer{i}\").nco_prop_delay_comp(50)" ] }, { "cell_type": "markdown", "id": "614fedb1", "metadata": {}, "source": [ "## Characterization experiments\n", "The sweep setpoints for all experiments (e.g. `frequency_setpoints` in the spectroscopy experiments) are only examples. The sweep setpoints should be changed to match your own system.\n", "\n", "We show two sets of experiments: The first contains generic characterization experiments for transmon qubits. The second contains 2D experiments for finding the flux sweetspot, applicable for flux-tunable qubits.\n", "\n", "\n", "Here we consider five standard characterization experiments for single qubit tuneup. The experiments are:\n", "1. Resonator spectroscopy\n", " - Used to find the frequency response of the readout resonator when the qubit is in $|0\\rangle$.\n", "2. Qubit spectroscopy (a.k.a two-tone)\n", " - Used to find the $|0\\rangle \\rightarrow |1\\rangle$ drive frequency.\n", "3. Rabi oscillations\n", " - Used to find precise excitation pulse required to excite the qubit to $|1\\rangle$.\n", "4. Ramsey oscillations\n", " - Used to tune the $|0\\rangle \\rightarrow |1\\rangle$ drive frequency more precisely.\n", " - Used to measure $T_2^*$.\n", "5. T1\n", " - Used to find the time it takes for the qubit to decay from $|1\\rangle$ to $|0\\rangle$, the $T_1$ time." ] }, { "cell_type": "markdown", "id": "0b482491", "metadata": {}, "source": [ "## Resonator spectroscopy" ] }, { "cell_type": "code", "execution_count": null, "id": "f3f40181", "metadata": {}, "outputs": [], "source": [ "def create_schedule(*args, **kwargs):\n", " return heterodyne_spec_sched_nco(*args, **kwargs)" ] }, { "cell_type": "code", "execution_count": null, "id": "dc88a4aa", "metadata": {}, "outputs": [], "source": [ "freq = ManualParameter(name=\"freq\", unit=\"Hz\", label=\"Frequency\")\n", "freq.batched = True\n", "freq.batch_size = 100\n", "\n", "spec_sched_kwargs = dict(\n", " pulse_amp=1 / 6,\n", " pulse_duration=2e-6,\n", " frequencies=freq,\n", " acquisition_delay=196e-9,\n", " integration_time=2e-6,\n", " init_duration=10e-6,\n", " port=qubit.ports.readout(),\n", " clock=qubit.name + \".ro\",\n", ")\n", "gettable = ScheduleGettable(\n", " quantum_device,\n", " schedule_function=create_schedule,\n", " schedule_kwargs=spec_sched_kwargs,\n", " real_imag=False,\n", " batched=True,\n", ")\n", "\n", "meas_ctrl.gettables(gettable)\n", "meas_ctrl.verbose(False)\n", "#show_args(spec_sched_kwargs, title=\"spec_sched_kwargs\")" ] }, { "cell_type": "code", "execution_count": null, "id": "9f3a6689", "metadata": {}, "outputs": [], "source": [ "#set_readout_attenuation(quantum_device, qubit, out_att=50, in_att=0)\n", "\n", "quantum_device.cfg_sched_repetitions(400)\n", "\n", "center = 7.7e9\n", "frequency_setpoints = np.linspace(center - 20e6, center + 20e6, 300)\n", "meas_ctrl.settables(freq)\n", "meas_ctrl.setpoints(frequency_setpoints)\n", "\n", "def run_experiment():\n", " rs_ds = meas_ctrl.run(\"resonator spectroscopy\", )" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.17" } }, "nbformat": 4, "nbformat_minor": 5 }