# This code is part of KQCircuits
# Copyright (C) 2021 IQM Finland Oy
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program. If not, see
# https://www.gnu.org/licenses/gpl-3.0.html.
#
# The software distribution should follow IQM trademark policy for open-source software
# (meetiqm.com/iqm-open-source-trademark-policy). IQM welcomes contributions to the code.
# Please see our contribution agreements for individuals (meetiqm.com/iqm-individual-contributor-license-agreement)
# and organizations (meetiqm.com/iqm-organization-contributor-license-agreement).
from kqcircuits.pya_resolver import pya
from kqcircuits.util.parameters import Param, pdt
from kqcircuits.chips.chip import Chip
from kqcircuits.elements.waveguide_coplanar import WaveguideCoplanar
from kqcircuits.elements.airbridges.airbridge import Airbridge
from kqcircuits.elements.airbridge_connection import AirbridgeConnection
from kqcircuits.elements.waveguide_composite import WaveguideComposite, Node
[docs]
class AirbridgeCrossings(Chip):
"""The PCell declaration for an AirbridgeCrossings chip.
On the left side of the chip there is a straight vertical waveguide and a meandering waveguide crossing it multiple
times. There are airbridges at the crossings. On the right side there is likewise a straight and a meandering
waveguide, but they do not cross at any point. In the center of the chip there is an array of mechanical tests of
airbridges with different lengths and widths.
"""
crossings = Param(pdt.TypeInt, "Number of double crossings", 10, docstring="Number of pairs of airbridge crossings")
b_number = Param(
pdt.TypeInt,
"Number of bridges",
5,
docstring="Number of airbridges in one element of the mechanical test array",
)
[docs]
def build(self):
launchers = self.produce_launchers(
"SMA8",
launcher_assignments={
1: "PL-1-IN",
2: "PL-2-IN",
3: "PL-4-IN",
4: "PL-4-OUT",
5: "PL-2-OUT",
6: "PL-1-OUT",
7: "PL-3-OUT",
8: "PL-3-IN",
},
)
self._produce_transmission_lines(launchers)
self._produce_mechanical_test_array()
def _produce_transmission_lines(self, launchers):
# Left transmission line
self.insert_cell(WaveguideCoplanar, path=pya.DPath([launchers["PL-1-IN"][0], launchers["PL-1-OUT"][0]], 1))
# Right transmission line
self.insert_cell(WaveguideCoplanar, path=pya.DPath([launchers["PL-2-IN"][0], launchers["PL-2-OUT"][0]], 1))
# Crossing transmission line
nodes = [Node(launchers["PL-3-IN"][0])]
ref_x = launchers["PL-1-IN"][0].x
last_y = launchers["PL-3-IN"][0].y
crossings = self.crossings # must be even
step = (launchers["PL-3-IN"][0].y - launchers["PL-3-OUT"][0].y) / (crossings - 0.5) / 2
wiggle = 250
for _ in range(crossings):
nodes.append(Node((ref_x - wiggle, last_y)))
nodes.append(Node((ref_x, last_y), AirbridgeConnection))
nodes.append(Node((ref_x + wiggle, last_y)))
last_y -= step
nodes.append(Node((ref_x + wiggle, last_y)))
nodes.append(Node((ref_x, last_y), AirbridgeConnection))
nodes.append(Node((ref_x - wiggle, last_y)))
last_y -= step
nodes.append(Node(launchers["PL-3-OUT"][0]))
waveguide_cell = self.add_element(WaveguideComposite, nodes=nodes)
self.insert_cell(waveguide_cell)
# TL without crossings
nodes = [Node(launchers["PL-4-IN"][0])]
ref_x = launchers["PL-2-IN"][0].x + 2 * wiggle + 50
last_y = launchers["PL-4-IN"][0].y
for _ in range(crossings):
nodes.append(Node((ref_x + wiggle, last_y)))
nodes.append(Node((ref_x - wiggle, last_y)))
last_y -= step
nodes.append(Node((ref_x - wiggle, last_y)))
nodes.append(Node((ref_x + wiggle, last_y)))
last_y -= step
nodes.append(Node(launchers["PL-4-OUT"][0]))
waveguide_cell = self.add_element(WaveguideComposite, nodes=nodes)
self.insert_cell(waveguide_cell)
def _produce_mechanical_test_array(self):
p_test_origin = pya.DPoint(3600, 9650)
v_distance_step = pya.DVector(0, -2350)
v_length_step = pya.DVector(0, -121)
v_width_step = pya.DVector(400, 0)
for i, length in enumerate(range(22, 60, 2)):
for j, width in enumerate(range(5, 20, 2)):
for k, distance in enumerate(range(2, 22, 5)):
loc = p_test_origin + v_length_step * i + v_width_step * j + v_distance_step * k
create_airbridges = (i + k) % 2 == 1 # airbridges only at every second row
self._produce_mechanical_test(loc, distance, self.b_number, length, width, create_airbridges)
def _produce_mechanical_test(self, loc, distance, number, length, width, create_airbridges):
# pylint: disable=unused-argument
wg_len = ((number * (distance + width)) * 2) + 4
wg_start = loc + pya.DVector(-wg_len / 2, 0)
wg_end = loc + pya.DVector(+wg_len / 2, 0)
# v_step = pya.DVector((distance + width) * 2, 0)
ab = self.add_element(
Airbridge,
# pad_length=1 * width,
# bridge_length=length,
# bridge_width=width,
)
for i in range(number):
# ab_trans = pya.DCplxTrans(1, 0, False, wg_start + v_step * (i + 0.5))
# self.insert_cell(ab, ab_trans)
if 1000 < loc.y < 9000 and create_airbridges:
ab_trans = pya.DCplxTrans(1, 0, False, loc + pya.DVector(50 * (i - (number - 1) / 2), 0))
self.insert_cell(ab, ab_trans)
# waveguide
wg = self.add_element(WaveguideCoplanar, path=pya.DPath([wg_start, wg_end], 1))
self.insert_cell(wg)