Source code for qpdk.cells.snspd
"""Superconducting nanowire single-photon detector (SNSPD)."""
from __future__ import annotations
import gdsfactory as gf
import numpy as np
from gdsfactory.component import Component
from gdsfactory.typings import LayerSpec, Port, Size
[docs]
@gf.cell
def snspd(
wire_width: float = 0.2,
wire_pitch: float = 0.6,
size: Size = (10, 8),
num_squares: int | None = None,
turn_ratio: float = 4,
terminals_same_side: bool = False,
layer: LayerSpec = "M1_DRAW",
port_type: str = "electrical",
) -> Component:
"""Creates an optimally-rounded SNSPD.
Args:
wire_width: Width of the wire.
wire_pitch: Distance between two adjacent wires. Must be greater than `width`.
size: Float2
(width, height) of the rectangle formed by the outer boundary of the
SNSPD.
num_squares: int | None = None
Total number of squares inside the SNSPD length.
turn_ratio: float
Specifies how much of the SNSPD width is dedicated to the 180 degree
turn. A `turn_ratio` of 10 will result in 20% of the width being
comprised of the turn.
terminals_same_side: If True, both ports will be located on the same side of the SNSPD.
layer: layer spec to put polygon geometry on.
port_type: type of port to add to the component.
"""
if num_squares is not None:
xy = np.sqrt(num_squares * wire_pitch * wire_width)
size = (xy, xy)
num_squares = None
xsize, ysize = size
if num_squares is not None:
if xsize is None:
xsize = num_squares * wire_pitch * wire_width / ysize
elif ysize is None:
ysize = num_squares * wire_pitch * wire_width / xsize
num_meanders = int(np.ceil(ysize / wire_pitch))
D = Component()
hairpin = gf.c.optimal_hairpin(
width=wire_width,
pitch=wire_pitch,
turn_ratio=turn_ratio,
length=xsize / 2,
num_pts=20,
layer=layer,
)
if (not terminals_same_side and (num_meanders % 2) == 0) or (
terminals_same_side and (num_meanders % 2) == 1
):
num_meanders += 1
port_type = "electrical"
start_nw = D.add_ref(
gf.c.compass(size=(xsize / 2, wire_width), layer=layer, port_type=port_type)
)
hp_prev = D.add_ref(hairpin)
hp_prev.connect("e1", start_nw.ports["e3"])
alternate = True
last_port: Port | None = None
for _n in range(2, num_meanders):
hp = D.add_ref(hairpin)
if alternate:
hp.connect("e2", hp_prev.ports["e2"])
else:
hp.connect("e1", hp_prev.ports["e1"])
last_port = hp.ports["e2"] if terminals_same_side else hp.ports["e1"]
hp_prev = hp
alternate = not alternate
finish_se = D.add_ref(
gf.c.compass(size=(xsize / 2, wire_width), layer=layer, port_type=port_type)
)
if last_port is not None:
finish_se.connect("e3", last_port)
D.add_port(port=start_nw.ports["e1"], name="e1")
D.add_port(port=finish_se.ports["e1"], name="e2")
D.info["num_squares"] = num_meanders * (xsize / wire_width)
D.info["area"] = xsize * ysize
D.info["xsize"] = xsize
D.info["ysize"] = ysize
D.flatten()
return D
if __name__ == "__main__":
from qpdk import PDK
PDK.activate()
c = snspd()
c.show()