Skip to content

Added flair and stretch options to pg.snspd_candelabra() method. #212

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 153 additions & 17 deletions phidl/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -5861,10 +5861,13 @@ def snspd_expanded(

def snspd_candelabra( # noqa: C901
wire_width=0.52,
wire_pitch=0.56,
wire_pitch=0.6,
haxis=90,
vaxis=50,
flair=1.0,
stretch=1.0,
equalize_path_lengths=False,
center_ports=True,
xwing=False,
layer=0,
):
Expand All @@ -5883,9 +5886,20 @@ def snspd_candelabra( # noqa: C901
The parameter `haxis` is prioritized over `vaxis`.
vaxis : int or float
Length of vertical diagonal of the rhomboidal active area.
flair : int or float (> 1.0)
Factor by which to expand wire width before 90-degree bends.
Only applies of xwing is False.
Increase wire_pitch to compensate. (Try 1.05)
stretch : int or float
Factor by which to scale bending width in hairpin bends.
Only applies of xwing is False.
Applies on top of flair value. (Try 1.5)
equalize_path_lengths : bool
If True, adds wire segments to hairpin bends to equalize path lengths
from center to center for all parallel wires in active area.
center_ports : bool
If True, centers the input and output ports along the x-axis.
Only applies of xwing is False.
xwing : bool
If True, replaces 90-degree bends with 135-degree bends.
layer : int
Expand All @@ -5903,11 +5917,15 @@ def off_axis_uturn(
wire_pitch=0.56,
pfact=10.0 / 3,
sharp=False,
flair=1.05,
stretch=1.5,
pad_length=0,
layer=0,
):
"""Returns phidl device low-crowding u-turn for candelabra meander."""
barc = optimal_90deg(width=wire_width, layer=layer)
if flair < 1.0:
flair = 1.0
barc = optimal_90deg(width=wire_width * flair, layer=layer)
if not sharp:
# For non-rounded outer radii
# Not fully implemented
Expand All @@ -5917,23 +5935,23 @@ def off_axis_uturn(
port2or = barc.ports[2].orientation
barc = boolean(
A=barc,
B=copy(barc).move([-wire_width, -wire_width]),
B=copy(barc).move([-wire_width * flair, -wire_width * flair]),
operation="not",
layer=layer,
)
barc.add_port(
name=1, midpoint=port1mp, width=wire_width, orientation=port1or
name=1, midpoint=port1mp, width=wire_width * flair, orientation=port1or
)
barc.add_port(
name=2, midpoint=port2mp, width=wire_width, orientation=port2or
name=2, midpoint=port2mp, width=wire_width * flair, orientation=port2or
)
pin = optimal_hairpin(
width=wire_width,
pitch=pfact * wire_width,
length=8 * wire_width,
width=wire_width * flair,
pitch=pfact * wire_width * flair,
length=8 * wire_width * flair,
layer=layer,
)
pas = compass(size=(wire_width, wire_pitch), layer=layer)
pas = compass(size=(wire_width * flair, wire_pitch), layer=layer)
D = Device()
arc1 = D.add_ref(barc)
arc1.rotate(90)
Expand All @@ -5943,6 +5961,7 @@ def off_axis_uturn(
pas1.connect(pas1.ports["N"], pin1.ports[2])
arc2 = D.add_ref(barc)
arc2.connect(2, pas1.ports["S"])

if pad_length > 0:
pin1.movey(pad_length * 0.5)
tempc = D.add_ref(
Expand All @@ -5959,18 +5978,63 @@ def off_axis_uturn(
)
)
tempc.connect("N", pin1.ports[2])
D.add_port(
xdist = arc2.ports[1].x - arc1.ports[1].x
D.movex(-arc1.ports[1].x)
if stretch > 1.0:
D.flatten()
for poly in D.polygons:
poly.scale(stretch, 1.0)
Dtemp = Device()
Dtemp.add_ref(D)
Dtemp.add_port(
name=1,
midpoint=arc1.ports[1].midpoint,
midpoint=[0, arc1.ports[1].midpoint[1]],
width=wire_width,
orientation=arc1.ports[1].orientation,
)
D.add_port(
Dtemp.add_port(
name=2,
midpoint=arc2.ports[1].midpoint,
midpoint=[xdist * stretch, arc2.ports[1].midpoint[1]],
width=wire_width,
orientation=arc2.ports[1].orientation,
)
D = Device()
D.add_ref(Dtemp)
if flair > 1.0:
step1 = D.add_ref(
optimal_step(
start_width=wire_width,
end_width=wire_width * flair,
symmetric=False,
layer=layer,
)
)
step2 = D.add_ref(
optimal_step(
start_width=wire_width,
end_width=wire_width * flair,
symmetric=False,
layer=layer,
)
)
step1.connect(2, Dtemp.ports[1])
step2.connect(2, Dtemp.ports[2])
D.add_port(name=1, port=step1.ports[1])
D.add_port(name=2, port=step2.ports[1])
else:
D.add_port(
name=1,
midpoint=Dtemp.ports[1].midpoint,
width=wire_width,
orientation=arc1.ports[1].orientation,
)
D.add_port(
name=2,
midpoint=Dtemp.ports[2].midpoint,
width=wire_width,
orientation=arc2.ports[1].orientation,
)

return D

def xwing_uturn(
Expand Down Expand Up @@ -6044,25 +6108,94 @@ def xwing_uturn(

return Dtemp

def bendS(
wire_width=0.52,
wire_pitch=0.6,
haxis=90,
flair=1.05,
stretch=1.5,
vaxis=50,
layer=0,
):

D = Device()
step1 = D.add_ref(
optimal_step(
start_width=wire_width * flair,
end_width=wire_width,
symmetric=True,
layer=layer,
)
)
wire_width = wire_width * flair
barc = optimal_90deg(width=wire_width, layer=layer)
step1.connect(1, barc.ports[2])
port1mp = [barc.ports[1].x, barc.ports[1].y]
port1or = barc.ports[1].orientation
port2mp = [step1.ports[2].x, step1.ports[2].y]
port2or = step1.ports[2].orientation
barc = boolean(
A=barc,
B=copy(barc).move([-wire_width, -wire_width]),
operation="not",
layer=layer,
)
D.add_ref(barc)
D.flatten()
for poly in D.polygons:
poly.scale(stretch, 1.0)
D.add_port(
name=1,
midpoint=[port1mp[0] * stretch, port1mp[1]],
width=wire_width * stretch,
orientation=port1or,
)
D.add_port(
name=2,
midpoint=[port2mp[0] * stretch, port2mp[1]],
width=wire_width / flair,
orientation=port2or,
)

return D

D = Device(name="snspd_candelabra")
if xwing:
Dtemp = xwing_uturn(wire_width=wire_width, wire_pitch=wire_pitch, layer=layer)
else:
Dtemp = off_axis_uturn(
wire_width=wire_width, wire_pitch=wire_pitch, layer=layer
wire_width=wire_width,
wire_pitch=wire_pitch,
flair=flair,
stretch=stretch,
layer=layer,
)
Dtemp_mirrored = deepcopy(Dtemp).mirror([0, 0], [0, 1])
padding = Dtemp.xsize
maxll = haxis - 2 * padding
dll = abs(Dtemp.ports[1].x - Dtemp.ports[2].x) + wire_pitch
dll = abs(Dtemp.ports[1].x - Dtemp.ports[2].x) + wire_pitch * stretch
half_num_meanders = int(np.ceil(0.5 * vaxis / wire_pitch)) + 2

if xwing:
bend = D.add_ref(
arc(radius=wire_width * 3, width=wire_width, theta=90, layer=layer)
).rotate(180)
else:
bend = D.add_ref(optimal_90deg(width=wire_width, layer=layer))
if stretch > 1.0:
bend = D.add_ref(
bendS(
wire_width=wire_width,
wire_pitch=wire_pitch,
haxis=haxis,
flair=flair,
stretch=stretch,
vaxis=vaxis,
layer=layer,
)
)
else:
bend = D.add_ref(optimal_90deg(width=wire_width, layer=layer))

if (maxll - dll * half_num_meanders) <= 0.0:
while (maxll - dll * half_num_meanders) <= 0.0:
half_num_meanders = half_num_meanders - 1
Expand Down Expand Up @@ -6136,7 +6269,10 @@ def xwing_uturn(

D.movex(-D.x)
if not xwing:
bend.movex(-bend.ports[1].x)
if center_ports:
bend.movex(-bend.ports[1].x)
else:
bend.movex(3 * wire_width - 2 * bend.ports[2].x)
if (fpas.ports["W"].x - bend.ports[2].x) > 0:
tempc = D.add_ref(
compass(
Expand Down
Loading