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

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# --- 

10 

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`. 

17 

18# %% 

19import gdsfactory as gf 

20import numpy as np 

21 

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) 

34 

35# %% [markdown] 

36# ## Resonator Test Chip Function 

37# 

38# Creates a test chip with two probelines and multiple resonators for characterization. 

39 

40 

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. 

51 

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. 

56 

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. 

63 

64 Returns: 

65 Component: A gdsfactory component containing the complete test chip layout. 

66 """ 

67 c = gf.Component() 

68 

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) 

73 

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 ] 

79 

80 # Standard cross-section for probelines 

81 probeline_xs = coplanar_waveguide(width=10, gap=6) 

82 

83 probeline_y_positions = [0, probeline_separation] 

84 

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)) 

92 

93 # Add resonators along the probeline 

94 resonator_spacing = probeline_length / 9 # Space for 8 resonators 

95 

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 

100 

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() 

116 

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") 

119 

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 ) 

139 

140 previous_port = resonator_ref.ports["coupling_o2"] 

141 

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) 

147 

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 ) 

155 

156 return c 

157 

158 

159# %% [markdown] 

160# ## Filled Resonator Test Chip 

161# 

162# Version of the test chip with magnetic vortex trapping holes in the ground plane. 

163 

164 

165# %% 

166@gf.cell 

167def filled_resonator_test_chip() -> gf.Component: 

168 """Creates a resonator test chip filled with magnetic vortex trapping holes. 

169 

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. 

174 

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 ) 

193 

194 

195if __name__ == "__main__": 

196 from qpdk import PDK 

197 

198 PDK.activate() 

199 

200 # Create and display the filled version 

201 filled_chip = filled_resonator_test_chip() 

202 filled_chip.show()