Skip to content

Commit

Permalink
Modify curved waveguide discretization method such that length is con…
Browse files Browse the repository at this point in the history
…served
  • Loading branch information
jukkarabina committed Oct 8, 2024
1 parent 7a7e336 commit 3860c18
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# and organizations (meetiqm.com/iqm-organization-contributor-license-agreement).


from math import pi, sin, cos
from math import pi, sin, cos, ceil

from kqcircuits.elements.element import Element
from kqcircuits.pya_resolver import pya
Expand All @@ -26,24 +26,37 @@
from kqcircuits.elements.waveguide_coplanar_straight import WaveguideCoplanarStraight


def arc(r, start, stop, n):
def arc(r, start, stop, n, mode=1):
"""Returns list of points of an arc
Args:
r: radius
start: begin angle in radians
stop: end angle in radians
n: number of corners in full circle
mode: discretization method, 0=shortcut, 1=match length, other=detour
.. MARKERS_FOR_PNG 0,91 0,100
"""
n_steps = max(round(abs(stop - start) * n / (2 * pi)), 1)
step = (stop - start) / n_steps
r_corner = r / cos(step / 2)
match mode:
case 0: # shortcut method, where points are on the arc
end_ratio = 1.0
r_scale = lambda _: 1.0
case 1: # matching length method, where combined length of segments equals the analytical length of the arc
end_ratio = 0.7339449 # based on trigonometric calculations and a few degree Taylor series approximation
r_scale = lambda x: 1 + x**2 / 24 + x**4 * 7 / 5760 # approximation for x/2 / sin(x/2) that accepts x=0
case _: # detour method, where segments are tangents on the arc
end_ratio = 0.5
r_scale = lambda x: 1.0 / cos(x / 2)

c_steps = 2 * end_ratio - 1 # nominal constant steps at start and end
n_steps = max(round(abs(stop - start) * n / (2 * pi) - c_steps), ceil(1 - c_steps))
step = (stop - start) / (n_steps + c_steps)
r_corner = r * r_scale(step)

pts = [pya.DPoint(r * cos(start), r * sin(start))]
for i in range(n_steps):
alpha = start + step * (i + 0.5)
alpha = start + step * (i + end_ratio)
pts.append(pya.DPoint(r_corner * cos(alpha), r_corner * sin(alpha)))
pts.append(pya.DPoint(r * cos(stop), r * sin(stop)))
return pts
Expand Down Expand Up @@ -88,6 +101,7 @@ def build_geometry(element, trans, alpha):
shape = round_dpath_width(pya.DPath(pts, element.a), element.layout.dbu)
element.cell.shapes(element.get_layer("waveguide_path")).insert(trans * shape)
if element.add_metal:
shape = pya.DPolygon(left_inner_arc + list(reversed(right_inner_arc)))
element.cell.shapes(element.get_layer("base_metal_addition")).insert(trans * shape)

# Protection layer
Expand Down
10 changes: 9 additions & 1 deletion tests/elements/waveguide_coplanar/test_waveguide_length.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@
# Please see our contribution agreements for individuals (meetiqm.com/iqm-individual-contributor-license-agreement)
# and organizations (meetiqm.com/iqm-organization-contributor-license-agreement).

import pytest

from kqcircuits.pya_resolver import pya
from kqcircuits.elements.waveguide_coplanar import WaveguideCoplanar
from kqcircuits.elements.finger_capacitor_square import FingerCapacitorSquare
from kqcircuits.elements.waveguide_coplanar_curved import WaveguideCoplanarCurved


def test_presence_of_length():
Expand All @@ -28,3 +29,10 @@ def test_presence_of_length():
waveguide_cell = WaveguideCoplanar.create(layout, path=pya.DPath([pya.DPoint(0, 0), pya.DPoint(0, 99)], 0))
assert hasattr(waveguide_cell, "length")
assert waveguide_cell.length() == 99


@pytest.mark.parametrize("n, alpha", [(16, 3), (32, 1), (64, 2), (128, 0.5)])
def test_length_of_curve(n, alpha):
layout = pya.Layout()
waveguide_cell = WaveguideCoplanarCurved.create(layout, n=n, alpha=alpha, r=100)
assert abs(waveguide_cell.length() - 100 * alpha) <= 0.001

0 comments on commit 3860c18

Please sign in to comment.