5-Qubit Xmon Processor (Barends et al., 2014)

Open in Colab Binder

💡 Running in Colab or Binder? Uncomment the install cell below.

Reproduces the architecture of the 5-qubit linear Xmon processor from Barends et al., “Superconducting quantum circuits at the surface code threshold for fault tolerance”, Nature 508, 500–503 (2014) — the device that demonstrated single- and two-qubit gate fidelities above the surface-code fault-tolerance threshold, built by the team that shortly after formed Google Quantum AI. See also Barends et al., “Coherent Josephson Qubit Suitable for Scalable Quantum Integrated Circuits”, PRL 111, 080502 (2013), for the Xmon qubit design.

Five Xmon transmons in a 1-D chain, each with an individual meandered readout resonator, frequency-multiplexed onto a single feedline through a directional coupler per qubit; XY and Z control lines are routed to wirebond pads on all four chip edges.

Design adapted from the Quantum Device Workshop 2026 capstone-project solution, implemented by Murat Can Sarihan (Google Quantum AI). Component parameters and routing here are a physical-layout example inspired by the published device, not the fabricated chip’s actual mask.

[1]:
# In Colab / Binder, uncomment to install Quantum Metal (lite, no Qt).
# Locally you should already have it via `pip install quantum-metal` or
# `pip install 'quantum-metal[gui]'` for the desktop GUI.
# !pip install -q quantum-metal

💡 Using this tutorial without the Qt GUI

This notebook only uses the headless API (qm.view) so it runs unmodified on Colab, Binder, JupyterHub, or any environment without Qt. See 1.1 Quick start for a complete runnable walkthrough and `docs/headless-usage.rst <https://qiskit-community.github.io/qiskit-metal/headless-usage.html>`__ for the full headless/GUI split.

1. Setup

[2]:
import os

os.environ.setdefault("QISKIT_METAL_HEADLESS", "True")

from qiskit_metal import designs, Dict
import qiskit_metal as qm
from qiskit_metal.qlibrary.qubits.transmon_cross_fl import TransmonCrossFL
from qiskit_metal.qlibrary.couplers.coupled_line_tee import CoupledLineTee
from qiskit_metal.qlibrary.tlines.meandered import RouteMeander
from qiskit_metal.qlibrary.terminations.launchpad_wb import LaunchpadWirebond
from qiskit_metal.qlibrary.terminations.open_to_ground import OpenToGround
from qiskit_metal.qlibrary.tlines.straight_path import RouteStraight
from qiskit_metal.qlibrary.tlines.framed_path import RouteFramed
from qiskit_metal.qlibrary.tlines.anchored_path import RouteAnchors
from qiskit_metal.qlibrary.lumped.cap_n_interdigital import CapNInterdigital

design = designs.DesignPlanar()
design.chips.main.size.size_x = "6.0mm"
design.chips.main.size.size_y = "6.0mm"
design.overwrite_enabled = True

print("Design initialized with a 6x6 mm substrate.")
Design initialized with a 6x6 mm substrate.

2. Place the five Xmon qubits (Q0–Q4)

Each TransmonCrossFL gets a flux line (south arm) and a readout connection pad (north arm); a hand-placed OpenToGround next to each qubit becomes the XY drive-line coupling point.

[3]:
qubit_pitch = 0.45  # mm
qubits, xy_pads = [], []
for i in range(5):
    x_pos = (i - 2) * qubit_pitch
    q = TransmonCrossFL(
        design,
        f"Q{i}",
        options=dict(
            pos_x=f"{x_pos}mm",
            pos_y="0.0mm",
            orientation="0",
            cross_width="30um",
            cross_length="190um",
            cross_gap="50um",
            make_fl=True,
            fl_options=dict(
                t_gap="3um",
                t_inductive_gap="3um",
                t_offset="0um",
                t_top="15um",
                t_width="5um",
            ),
            connection_pads=dict(
                readout=dict(
                    connector_type="0",
                    claw_length="40um",
                    ground_spacing="5um",
                    claw_width="10um",
                    claw_gap="6um",
                    connector_location="90",
                )
            ),
        ),
    )
    qubits.append(q)
    xy_pads.append(
        OpenToGround(
            design,
            f"XY_pad_{i}",
            options=dict(
                pos_x=f"{x_pos - 0.1}mm",
                pos_y="-0.18mm",
                orientation="90",
                width="10um",
                gap="6um",
                termination_gap="6um",
            ),
        )
    )

print("Placed qubits Q0-Q4 and their XY coupling pads.")
Placed qubits Q0-Q4 and their XY coupling pads.
[4]:
fig = qm.view(design)
fig.suptitle("Qubits placed")
fig
[4]:
../../_images/circuit-examples_F.Small-quantum-chips_52-Barends_5Qubit_Xmon_Processor_10_0.png

3. Multiplexed readout feedline

A single feedline runs across the top of the chip. A CoupledLineTee directional coupler sits above each qubit, and CapNInterdigital components terminate the feedline’s input/output before it reaches the edge launchpads.

Each coupler’s second line is the coupling end of a readout resonator. open_termination=False shorts that end to ground; the other end is the open readout claw at the qubit, so each resonator is a quarter-wave (λ/4) resonator. With the coupler’s default, open_termination=True, both ends would be open and the fundamental would be a λ/2 mode at about twice the frequency.

[5]:
total_purcell_length_mm = 0  # tracked from the coupler taps onward

couplers = []
for i in range(5):
    x_pos = (i - 2) * qubit_pitch
    couplers.append(
        CoupledLineTee(
            design,
            f"CLT{i}",
            options=dict(
                pos_x=f"{x_pos}mm",
                pos_y="1.5mm",
                orientation="0",
                coupling_length="200um",
                coupling_space="4um",
                # Short the resonator end to ground: with the open claw at
                # the qubit, each readout resonator is a quarter-wave.
                open_termination=False,
            ),
        )
    )
    total_purcell_length_mm += 0.2

# Wirebond launchpads, three per edge, 1.5 mm apart
LaunchpadWirebond(
    design, "LP_W1", options=dict(pos_x="-2.8mm", pos_y="-1.5mm", orientation="0")
)
LaunchpadWirebond(
    design, "LP_W2", options=dict(pos_x="-2.8mm", pos_y="0.0mm", orientation="0")
)
LaunchpadWirebond(
    design, "LP_W3", options=dict(pos_x="-2.8mm", pos_y="1.5mm", orientation="0")
)
LaunchpadWirebond(
    design, "LP_E1", options=dict(pos_x="2.8mm", pos_y="-1.5mm", orientation="180")
)
LaunchpadWirebond(
    design, "LP_E2", options=dict(pos_x="2.8mm", pos_y="0.0mm", orientation="180")
)
LaunchpadWirebond(
    design, "LP_E3", options=dict(pos_x="2.8mm", pos_y="1.5mm", orientation="180")
)
LaunchpadWirebond(
    design, "LP_S1", options=dict(pos_x="-1.5mm", pos_y="-2.8mm", orientation="90")
)
LaunchpadWirebond(
    design, "LP_S2", options=dict(pos_x="0.0mm", pos_y="-2.8mm", orientation="90")
)
LaunchpadWirebond(
    design, "LP_S3", options=dict(pos_x="1.5mm", pos_y="-2.8mm", orientation="90")
)
LaunchpadWirebond(
    design, "LP_N1", options=dict(pos_x="-1.5mm", pos_y="2.8mm", orientation="270")
)
LaunchpadWirebond(
    design, "LP_N2", options=dict(pos_x="0.0mm", pos_y="2.8mm", orientation="270")
)
LaunchpadWirebond(
    design, "LP_N3", options=dict(pos_x="1.5mm", pos_y="2.8mm", orientation="270")
)

cap_in = CapNInterdigital(
    design, "Cap_input", options=dict(pos_x="-2.4mm", pos_y="1.5mm", orientation="270")
)
cap_out = CapNInterdigital(
    design, "Cap_output", options=dict(pos_x="-1mm", pos_y="2.1mm", orientation="90")
)

print("Placed launchpads and feedline terminations.")
Placed launchpads and feedline terminations.
[6]:
RouteStraight(
    design,
    "Feed_in_lp",
    options=dict(
        pin_inputs=dict(
            start_pin=dict(component="LP_W3", pin="tie"),
            end_pin=dict(component="Cap_input", pin="south_end"),
        )
    ),
)

purcell_left = RouteStraight(
    design,
    "Feed_in_clt",
    options=dict(
        pin_inputs=dict(
            start_pin=dict(component="Cap_input", pin="north_end"),
            end_pin=dict(component="CLT0", pin="prime_start"),
        )
    ),
)
total_purcell_length_mm += purcell_left.length

for i in range(4):
    feed_i = RouteStraight(
        design,
        f"Feed_mid_{i}",
        options=dict(
            pin_inputs=dict(
                start_pin=dict(component=f"CLT{i}", pin="prime_end"),
                end_pin=dict(component=f"CLT{i + 1}", pin="prime_start"),
            )
        ),
    )
    total_purcell_length_mm += feed_i.length

purcell_right = RouteAnchors(
    design,
    "Feed_out_clt",
    options=dict(
        pin_inputs=dict(
            start_pin=dict(component="CLT4", pin="prime_end"),
            end_pin=dict(component="Cap_output", pin="north_end"),
        ),
        anchors=Dict({0: (1.7, 1.5), 1: (1.7, 1.8), 2: (-2.4, 1.8)}),
        fillet="100um",
        advanced=Dict(avoid_collision=False),
    ),
)
total_purcell_length_mm += purcell_right.length

RouteAnchors(
    design,
    "Feed_out_lp",
    options=dict(
        pin_inputs=dict(
            start_pin=dict(component="Cap_output", pin="south_end"),
            end_pin=dict(component="LP_N1", pin="tie"),
        ),
        lead=Dict(start_straight="200um", end_straight="100um"),
        fillet="20um",
        advanced=Dict(avoid_collision=False),
    ),
)

print("Feedline routed.")
print(f"Total Purcell-filter feedline length: {total_purcell_length_mm:.3f} mm")
Feedline routed.
Total Purcell-filter feedline length: 9.028 mm

4. Staggered meander readout resonators

Each qubit’s resonator gets a different total length (4.41–4.57 mm in 0.04 mm steps) so all five readout tones land at distinct frequencies for frequency-domain multiplexing on the single feedline.

[7]:
resonator_lengths = ["4.41mm", "4.45mm", "4.49mm", "4.53mm", "4.57mm"]

for i in range(5):
    RouteMeander(
        design,
        f"ReadoutRes{i}",
        options=dict(
            pin_inputs=dict(
                start_pin=dict(component=f"Q{i}", pin="readout"),
                end_pin=dict(component=f"CLT{i}", pin="second_end"),
            ),
            total_length=resonator_lengths[i],
            fillet="20um",
            lead=dict(start_straight="150um", end_straight="150um"),
            meander=dict(spacing="50um", asymmetry="0um"),
        ),
    )

print("Staggered meander resonators routed.")
05:00PM 51s WARNING [check_lengths]: For path table, component=ReadoutRes0, key=trace has short segments that could cause issues with fillet. Values in (29-30)  are index(es) in shapely geometry.
05:00PM 51s WARNING [check_lengths]: For path table, component=ReadoutRes0, key=cut has short segments that could cause issues with fillet. Values in (29-30)  are index(es) in shapely geometry.
05:00PM 51s WARNING [check_lengths]: For path table, component=ReadoutRes1, key=trace has short segments that could cause issues with fillet. Values in (29-30)  are index(es) in shapely geometry.
05:00PM 51s WARNING [check_lengths]: For path table, component=ReadoutRes1, key=cut has short segments that could cause issues with fillet. Values in (29-30)  are index(es) in shapely geometry.
05:00PM 51s WARNING [check_lengths]: For path table, component=ReadoutRes2, key=trace has short segments that could cause issues with fillet. Values in (29-30)  are index(es) in shapely geometry.
05:00PM 51s WARNING [check_lengths]: For path table, component=ReadoutRes2, key=cut has short segments that could cause issues with fillet. Values in (29-30)  are index(es) in shapely geometry.
05:00PM 51s WARNING [check_lengths]: For path table, component=ReadoutRes3, key=trace has short segments that could cause issues with fillet. Values in (29-30)  are index(es) in shapely geometry.
05:00PM 51s WARNING [check_lengths]: For path table, component=ReadoutRes3, key=cut has short segments that could cause issues with fillet. Values in (29-30)  are index(es) in shapely geometry.
05:00PM 51s WARNING [check_lengths]: For path table, component=ReadoutRes4, key=trace has short segments that could cause issues with fillet. Values in (29-30)  are index(es) in shapely geometry.
05:00PM 51s WARNING [check_lengths]: For path table, component=ReadoutRes4, key=cut has short segments that could cause issues with fillet. Values in (29-30)  are index(es) in shapely geometry.
Staggered meander resonators routed.
[8]:
fig = qm.view(design)
fig.suptitle("Readout feedline and resonators added")
fig
[8]:
../../_images/circuit-examples_F.Small-quantum-chips_52-Barends_5Qubit_Xmon_Processor_18_0.png

5. XY and Z control-line routing

Every qubit’s XY (drive) and Z (flux) line is routed to its own edge launchpad with RouteFramed, using a short list of Manhattan jogs (start_jogged_extension) to dodge the qubits and feedline already on the chip.

[9]:
control_routes = [
    ("XY_pad_0", "open", "LP_W2", "tie", "XY_Line_0", Dict({})),
    ("Q0", "flux_line", "LP_W1", "tie", "Z_Line_0", Dict({})),
    (
        "XY_pad_1",
        "open",
        "LP_S1",
        "tie",
        "XY_Line_1",
        Dict({0: ["R", "50um"], 1: ["L", "2000um"], 2: ["R", "200um"]}),
    ),
    (
        "Q1",
        "flux_line",
        "LP_S2",
        "tie",
        "Z_Line_1",
        Dict({0: ["L", "100um"], 1: ["R", "2000um"], 2: ["L", "200um"]}),
    ),
    (
        "XY_pad_2",
        "open",
        "LP_S3",
        "tie",
        "XY_Line_2",
        Dict({0: ["R", "50um"], 1: ["L", "1800um"], 2: ["L", "500um"]}),
    ),
    (
        "Q2",
        "flux_line",
        "LP_E1",
        "tie",
        "Z_Line_2",
        Dict(
            {
                0: ["L", "100um"],
                1: ["R", "1600um"],
                2: ["L", "2500um"],
                3: ["L", "100um"],
            }
        ),
    ),
    (
        "XY_pad_3",
        "open",
        "LP_E2",
        "tie",
        "XY_Line_3",
        Dict(
            {
                0: ["R", "50um"],
                1: ["L", "1400um"],
                2: ["L", "2100um"],
                3: ["L", "1200um"],
            }
        ),
    ),
    (
        "Q3",
        "flux_line",
        "LP_E3",
        "tie",
        "Z_Line_3",
        Dict(
            {
                0: ["L", "100um"],
                1: ["R", "1200um"],
                2: ["L", "1700um"],
                3: ["L", "800um"],
            }
        ),
    ),
    (
        "XY_pad_4",
        "open",
        "LP_N3",
        "tie",
        "XY_Line_4",
        Dict(
            {
                0: ["R", "50um"],
                1: ["L", "1000um"],
                2: ["L", "1350um"],
                3: ["L", "3700um"],
                4: ["L", "400um"],
            }
        ),
    ),
    (
        "Q4",
        "flux_line",
        "LP_N2",
        "tie",
        "Z_Line_4",
        Dict(
            {
                0: ["L", "100um"],
                1: ["R", "800um"],
                2: ["L", "950um"],
                3: ["L", "3300um"],
                4: ["L", "400um"],
            }
        ),
    ),
]

for start_comp, start_pin, end_comp, end_pin, route_name, jogs in control_routes:
    route_options = dict(
        pin_inputs=dict(
            start_pin=dict(component=start_comp, pin=start_pin),
            end_pin=dict(component=end_comp, pin=end_pin),
        ),
        lead=dict(
            start_straight="100um", end_straight="50um", start_jogged_extension=jogs
        ),
        fillet="20um",
        step_size="0.05mm",
    )
    if "XY" in route_name:
        route_options["lead"]["start_straight"] = "200um"
    RouteFramed(design, route_name, options=route_options)

print("XY and Z control lines routed.")
print(f"Total components: {len(design.components)}")
XY and Z control lines routed.
Total components: 52

6. Completed layout

[10]:
fig = qm.view(design)
fig.suptitle("5-Qubit Xmon Processor — complete layout")
fig
[10]:
../../_images/circuit-examples_F.Small-quantum-chips_52-Barends_5Qubit_Xmon_Processor_23_0.png

7. Export to GDSII

[11]:
import logging
import tempfile
from pathlib import Path

out = Path(tempfile.gettempdir()) / "barends_5qubit_processor.gds"
gds_renderer = design.renderers.gds
gds_renderer.options.short_segments_to_not_fillet = "False"

# The renderer logs notes on cheesing, and that no junction GDS file is set
# (options.path_filename defaults to None, so the junctions are left out of
# the mask); show errors only while exporting.
level = qm.logger.level
qm.logger.setLevel(logging.ERROR)
try:
    gds_renderer.export_to_gds(str(out))
finally:
    qm.logger.setLevel(level)
print(f"Layout exported to GDSII: {out.name}")
Layout exported to GDSII: barends_5qubit_processor.gds

References

  1. Barends, R. et al. Coherent Josephson Qubit Suitable for Scalable Quantum Integrated Circuits. Phys. Rev. Lett. 111, 080502 (2013).

  2. Barends, R. et al. Superconducting quantum circuits at the surface code threshold for fault tolerance. Nature 508, 500–503 (2014).

  3. Sarihan, M. C. Capstone-project solution, Quantum Device Workshop 2026.



For more information, review the Introduction to Quantum Computing and Quantum Hardware lectures below

  • Superconducting Qubits I: Quantizing a Harmonic Oscillator, Josephson Junctions Part 1
Lecture Video Lecture Notes Lab
  • Superconducting Qubits I: Quantizing a Harmonic Oscillator, Josephson Junctions Part 2
Lecture Video Lecture Notes Lab
  • Superconducting Qubits I: Quantizing a Harmonic Oscillator, Josephson Junctions Part 3
Lecture Video Lecture Notes Lab
  • Superconducting Qubits II: Circuit Quantum Electrodynamics, Readout and Calibration Methods Part 1
Lecture Video Lecture Notes Lab
  • Superconducting Qubits II: Circuit Quantum Electrodynamics, Readout and Calibration Methods Part 2
Lecture Video Lecture Notes Lab
  • Superconducting Qubits II: Circuit Quantum Electrodynamics, Readout and Calibration Methods Part 3
Lecture Video Lecture Notes Lab