# This code is part of KQCircuits
# Copyright (C) 2023 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 math import sqrt
from kqcircuits.util.parameters import Param, pdt, add_parameters_from, pya
from kqcircuits.elements.element import Element
from kqcircuits.elements.waveguide_composite import WaveguideComposite
from kqcircuits.elements.waveguide_composite import Node
from kqcircuits.elements.finger_capacitor_square import FingerCapacitorSquare
from kqcircuits.elements.waveguide_coplanar_splitter import WaveguideCoplanarSplitter
from kqcircuits.elements.finger_capacitor_taper import FingerCapacitorTaper
from kqcircuits.util.refpoints import RefpointToEdgePort
[docs]
@add_parameters_from(FingerCapacitorSquare, finger_gap_end=3)
@add_parameters_from(FingerCapacitorTaper, finger_width=10, finger_number=2, finger_gap=3)
class CapacitiveXCoupler(Element):
"""
Capacitive coupler for testing FEM computations.
"""
x_coupler_length = Param(pdt.TypeDouble, "Length of Capacitive X Coupler", 500)
x_coupler_height = Param(pdt.TypeDouble, "Height of Capacitive X Coupler", 500)
x_coupler_variant = Param(pdt.TypeString, "Coupler variant, either (+) or (x)", "+", choices=["+", "x"])
remove_capacitors = Param(pdt.TypeBoolean, "Remove capacitors from the X Coupler", False)
[docs]
def build(self):
length = self.x_coupler_length
height = self.x_coupler_height
if length > height:
center = height
input_length = (length - center) / 2.0
else:
center = length
input_length = (height - center) / 2.0
p0 = (0, 0)
if self.x_coupler_variant == "x":
if height > length:
p11 = (-center / 2.0, -input_length - length / 2.0)
p12 = (-length / 2.0, -center / 2.0)
p13 = (-length / 4.0, -center / 4.0)
else:
p11 = (-input_length - center / 2.0, -height / 2.0)
p12 = (-center / 2.0, -height / 2.0)
p13 = (-center / 4.0, -height / 4.0)
p21 = (-p11[0], p11[1])
p22 = (-p12[0], p12[1])
p23 = (-p13[0], p13[1])
p31 = (-p11[0], -p11[1])
p32 = (-p12[0], -p12[1])
p33 = (-p13[0], -p13[1])
p41 = (p11[0], -p11[1])
p42 = (p12[0], -p12[1])
p43 = (p13[0], -p13[1])
p02 = ((self.a / 2 + self.b) / sqrt(2), (-self.a / 2 - self.b) / sqrt(2))
p04 = ((-self.a / 2 - self.b) / sqrt(2), (self.a / 2 + self.b) / sqrt(2))
elif self.x_coupler_variant == "+":
p11 = (0.0, -height / 2.0)
p12 = (0.0, -height / 3.0)
p13 = (0.0, -height / 4.0)
p21 = (length / 2.0, 0.0)
p22 = (length / 3.0, 0.0)
p23 = (length / 4.0, 0.0)
p31 = (0.0, -p11[1])
p32 = (0.0, -p12[1])
p33 = (0.0, -p13[1])
p41 = (-p21[0], 0.0)
p42 = (-p22[0], 0.0)
p43 = (-p23[0], 0.0)
p02 = (self.a / 2 + self.b, 0.0)
p04 = (-self.a / 2 - self.b, 0.0)
self.refpoints["p11"] = pya.DPoint(*p11)
self.refpoints["p21"] = pya.DPoint(*p21)
self.refpoints["p31"] = pya.DPoint(*p31)
self.refpoints["p41"] = pya.DPoint(*p41)
def _add_capacitor_node(p):
return Node(
p,
FingerCapacitorSquare,
finger_number=self.finger_number,
finger_width=self.finger_width,
finger_gap_end=self.finger_gap_end,
finger_gap=self.finger_gap,
a2=self.a,
b2=self.b,
a=self.a,
b=self.b,
ground_padding=self.b,
)
splitter_port_length = self.a / 2 + self.b
nodes1 = [
Node(p11),
Node(p12),
_add_capacitor_node(p13),
Node(
p0,
WaveguideCoplanarSplitter,
angles=[0, 180, 90, 270],
lengths=4 * [splitter_port_length],
a=self.a,
b=self.b,
),
_add_capacitor_node(p33),
Node(p32),
Node(p31),
]
nodes2 = [Node(p41), Node(p42), _add_capacitor_node(p43), Node(p04)]
nodes3 = [Node(p21), Node(p22), _add_capacitor_node(p23), Node(p02)]
if self.remove_capacitors:
nodes1.pop(4)
nodes1.pop(2)
nodes2.pop(2)
nodes3.pop(2)
if self.x_coupler_variant == "x" and length == height:
nodes1.pop(1)
nodes1.pop(-1)
nodes2.pop(1)
nodes3.pop(1)
self.insert_cell(WaveguideComposite, nodes=nodes1)
self.insert_cell(WaveguideComposite, nodes=nodes2)
self.insert_cell(WaveguideComposite, nodes=nodes3)
[docs]
@classmethod
def get_sim_ports(cls, simulation): # pylint: disable=unused-argument
return [
RefpointToEdgePort("p11"),
RefpointToEdgePort("p21"),
RefpointToEdgePort("p31"),
RefpointToEdgePort("p41"),
]