Coverage for qpdk / samples / resonator_test_chip.py: 100%
53 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-14 10:27 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-14 10:27 +0000
1# ---
2# jupyter:
3# jupytext:
4# text_representation:
5# extension: .py
6# format_name: percent
7# format_version: '1.3'
8# jupytext_version: 1.17.3
9# ---
11# %% [markdown]
12# # Resonator Test Chip
13#
14# This example demonstrates creating a resonator test chip for characterizing superconducting microwave resonators.
15#
16# The design is inspired by {cite:p}`norrisImprovedParameterTargeting2024`.
18# %%
19import gdsfactory as gf
20import numpy as np
22from qpdk import tech
23from qpdk.cells.chip import chip_edge
24from qpdk.cells.helpers import fill_magnetic_vortices
25from qpdk.cells.launcher import launcher
26from qpdk.cells.resonator import resonator_coupled
27from qpdk.cells.waveguides import straight
28from qpdk.logger import logger
29from qpdk.tech import (
30 coplanar_waveguide,
31 route_bundle_cpw,
32 route_bundle_sbend,
33)
35# %% [markdown]
36# ## Resonator Test Chip Function
37#
38# Creates a test chip with two probelines and multiple resonators for characterization.
41# %%
42@gf.cell
43def resonator_test_chip_python(
44 probeline_length: float = 9000.0,
45 probeline_separation: float = 1000.0,
46 resonator_length: float = 4000.0,
47 coupling_length: float = 200.0,
48 coupling_gap: float = 16.0,
49) -> gf.Component:
50 """Creates a resonator test chip with two probelines and 16 resonators.
52 The chip features two horizontal probelines running west to east, each with
53 launchers on both ends. Eight quarter-wave resonators are coupled to each
54 probeline, with systematically varied cross-section parameters for
55 characterization studies.
57 Args:
58 probeline_length: Length of each probeline in µm.
59 probeline_separation: Vertical separation between probelines in µm.
60 resonator_length: Length of each resonator in µm.
61 coupling_length: Length of coupling region between resonator and probeline in µm.
62 coupling_gap: Gap between resonator and probeline for coupling in µm.
64 Returns:
65 Component: A gdsfactory component containing the complete test chip layout.
66 """
67 c = gf.Component()
69 # Create different cross-sections for resonators with systematic parameter variation
70 # 8 different combinations of width and gap for each probeline
71 width_values = np.linspace(8, 30, 8, dtype=int)
72 gap_values = np.linspace(6, 20, 8, dtype=int)
74 n_resonators = len(width_values)
75 resonator_cross_sections = [
76 coplanar_waveguide(width=width_values[i], gap=gap_values[i])
77 for i in range(n_resonators)
78 ]
80 # Standard cross-section for probelines
81 probeline_xs = coplanar_waveguide(width=10, gap=6)
83 probeline_y_positions = [0, probeline_separation]
85 for probeline_idx, y_pos in enumerate(probeline_y_positions):
86 # Add launchers at both ends
87 launcher_west = c.add_ref(launcher())
88 launcher_west.move((0, y_pos))
89 launcher_east = c.add_ref(launcher()) # Create some probeline straight
90 launcher_east.mirror_x()
91 launcher_east.move((probeline_length, y_pos))
93 # Add resonators along the probeline
94 resonator_spacing = probeline_length / 9 # Space for 8 resonators
96 previous_port = launcher_west.ports["o1"]
97 for res_idx in range(n_resonators):
98 # Calculate resonator position along probeline
99 x_position = (res_idx + 1) * resonator_spacing
101 # Create resonator with unique cross-section
102 coupled_resonator = resonator_coupled(
103 length=resonator_length,
104 meanders=6,
105 cross_section=resonator_cross_sections[res_idx],
106 open_start=True,
107 open_end=False, # Quarter-wave resonator
108 cross_section_non_resonator=probeline_xs,
109 coupling_straight_length=coupling_length,
110 coupling_gap=coupling_gap,
111 )
112 resonator_ref = c.add_ref(coupled_resonator)
113 # Position resonator above probeline
114 if probeline_idx != 0:
115 resonator_ref.mirror_y()
117 resonator_ref.move((x_position - resonator_ref.size_info.width / 2, y_pos))
118 logger.debug(f"Added resonator {res_idx} at x={x_position} µm")
120 if res_idx == 0:
121 # Add some straight before connecting the first resonator
122 first_straight_ref = c.add_ref(
123 straight(length=200.0, cross_section=probeline_xs)
124 )
125 first_straight_ref.connect("o1", resonator_ref.ports["coupling_o1"])
126 route_bundle_sbend(
127 c,
128 ports1=[previous_port],
129 ports2=[first_straight_ref.ports["o2"]],
130 cross_section=probeline_xs,
131 )
132 else:
133 route_bundle_cpw(
134 c,
135 ports1=[previous_port],
136 ports2=[resonator_ref.ports["coupling_o1"]],
137 cross_section=probeline_xs,
138 )
140 previous_port = resonator_ref.ports["coupling_o2"]
142 # Add some straight before connecting to the final launcher
143 final_straight_ref = c.add_ref(
144 straight(length=400.0, cross_section=probeline_xs)
145 )
146 final_straight_ref.connect("o1", previous_port)
148 # Connect final launcher to probeline
149 route_bundle_sbend(
150 c,
151 ports1=[final_straight_ref.ports["o2"]],
152 ports2=[launcher_east.ports["o1"]],
153 cross_section=probeline_xs,
154 )
156 return c
159# %% [markdown]
160# ## Filled Resonator Test Chip
161#
162# Version of the test chip with magnetic vortex trapping holes in the ground plane.
165# %%
166@gf.cell
167def filled_resonator_test_chip() -> gf.Component:
168 """Creates a resonator test chip filled with magnetic vortex trapping holes.
170 This version includes the complete resonator test chip layout with additional
171 ground plane holes to trap magnetic vortices, improving the performance of
172 superconducting quantum circuits. Includes chip edge components with extra
173 y-padding to keep resonators away from the chip edges.
175 Returns:
176 Component: Test chip with ground plane fill patterns and chip edges.
177 """
178 c = gf.Component()
179 test_chip = resonator_test_chip_python()
180 c << test_chip
181 chip_edge_ref = c << chip_edge(
182 size=(test_chip.xsize + 200, test_chip.ysize + 800),
183 width=100.0,
184 layer=tech.LAYER.M1_ETCH,
185 )
186 chip_edge_ref.move((test_chip.xmin - 100, test_chip.ymin - 400))
187 return fill_magnetic_vortices(
188 component=c,
189 rectangle_size=(15.0, 15.0),
190 gap=70.0,
191 stagger=2,
192 )
195if __name__ == "__main__":
196 from qpdk import PDK
198 PDK.activate()
200 # Create and display the filled version
201 filled_chip = filled_resonator_test_chip()
202 filled_chip.show()