Directional Coupler Bend
Full script
from typing import Tuple, cast
from fnpcell import all as fp
from gpdk.components.bend.bend_circular import BendCircular
from gpdk.components.straight.straight import Straight
from gpdk.technology import get_technology
from gpdk.technology.interfaces import CoreCladdingWaveguideType
@fp.pcell_class()
class DirectionalCouplerBend(fp.PCell):
coupler_spacing: float = fp.PositiveFloatParam(default=0.7, doc="Spacing between the two waveguide centre lines.").as_field()
coupler_length: float = fp.PositiveFloatParam(default=6, doc="Length of the directional coupler").as_field()
bend_radius: float = fp.PositiveFloatParam(required=False, doc="Bend radius for the auto-generated bends").as_field()
straight_after_bend: float = fp.PositiveFloatParam(default=6, doc="Length of the straight waveguide after the bend").as_field()
waveguide_type: CoreCladdingWaveguideType = fp.WaveguideTypeParam(type=CoreCladdingWaveguideType, doc="Waveguide parameters").as_field()
port_names: fp.IPortOptions = fp.PortOptionsParam(count=4, default=["op_0", "op_1", "op_2", "op_3"]).as_field()
def _default_waveguide_type(self):
return get_technology().WG.FWG.C.WIRE
def build(self) -> Tuple[fp.InstanceSet, fp.ElementSet, fp.PortSet]:
insts, elems, ports = super().build()
# fmt: off
coupler_spacing = self.coupler_spacing
coupler_length = self.coupler_length
bend_radius = self.bend_radius
straight_after_bend = self.straight_after_bend
waveguide_type = self.waveguide_type
port_names = self.port_names
if bend_radius is None:
bend_radius = cast(float, waveguide_type.BEND_CIRCULAR.radius_eff) # type: ignore
assert (
coupler_spacing > waveguide_type.core_width
), "waveguide core overlap: coupler spacing must be greater than core_width"
dy = coupler_spacing / 2
left_straight_after_bend = Straight(name="lafterbend", length=straight_after_bend, waveguide_type=waveguide_type)
right_straight_after_bend = Straight(name="rafterbend", length=straight_after_bend, waveguide_type=waveguide_type)
left_bend = BendCircular(name="lbend", degrees=90, radius=bend_radius, waveguide_type=waveguide_type)
right_bend = BendCircular(name="rbend", degrees=90, radius=bend_radius, waveguide_type=waveguide_type)
straight_coupler = Straight(name="coupler", length=coupler_length, anchor=fp.Anchor.CENTER, waveguide_type=waveguide_type, transform=fp.translate(0, -dy))
bottom_half = fp.Connected(
name="bottom",
joints=[
straight_coupler["op_0"] <= left_bend["op_0"],
left_bend["op_1"] <= left_straight_after_bend["op_1"],
#
straight_coupler["op_1"] <= right_bend["op_1"],
right_bend["op_0"] <= right_straight_after_bend["op_0"],
],
ports=[
left_straight_after_bend["op_0"],
right_straight_after_bend["op_1"],
],
)
insts += bottom_half
top_half = bottom_half.rotated(degrees=180)
insts += top_half
ports += top_half["op_1"].with_name(port_names[0])
ports += bottom_half["op_0"].with_name(port_names[1]),
ports += bottom_half["op_1"].with_name(port_names[2]),
ports += top_half["op_0"].with_name(port_names[3]),
# fmt: on
return insts, elems, ports
if __name__ == "__main__":
from pathlib import Path
gds_file = Path(__file__).parent / "local" / Path(__file__).with_suffix(".gds").name
library = fp.Library()
TECH = get_technology()
# library += DirectionalCouplerBend()
# library += DirectionalCouplerBend(name="f", coupler_spacing=0.7, coupler_length=6, bend_radius=10, straight_after_bend=6, waveguide_type=TECH.WG.FWG.C.WIRE)
library += DirectionalCouplerBend(name="s", coupler_spacing=1.7, coupler_length=10, bend_radius=10, straight_after_bend=6, waveguide_type=TECH.WG.SWG.C.WIRE)
fp.export_gds(library, file=gds_file)
fp.plot(library)
Parameter description
In the main function, add a DirectionalCouplerBend to the library
library += DirectionalCouplerBend(name="s", coupler_spacing=1.7, coupler_length=10, bend_radius=10, straight_after_bend=6, waveguide_type=TECH.WG.SWG.C.WIRE)
name is the name of the device, here named s, coupler_space, coupler_length, bend_radius and straight_after_bend are marked in the figure below, which is convenient to quickly understand which part of the device is controlled by each parameter.