from __future__ import annotations
import gdsfactory as gf
from gdsfactory.component import Component
from gdsfactory.components.bezier import bezier
from gdsfactory.typings import CrossSectionSpec
[docs]
@gf.cell
def coupler_adiabatic(
length1: float = 20.0,
length2: float = 50.0,
length3: float = 30.0,
wg_sep: float = 1.0,
input_wg_sep: float = 3.0,
output_wg_sep: float = 3.0,
dw: float = 0.1,
cross_section: CrossSectionSpec = "xs_sc",
) -> Component:
"""Returns 50/50 adiabatic coupler.
Design based on asymmetric adiabatic 3dB coupler designs, such as those.
- https://doi.org/10.1364/CLEO.2010.CThAA2,
- https://doi.org/10.1364/CLEO_SI.2017.SF1I.5
- https://doi.org/10.1364/CLEO_SI.2018.STh4B.4
input Bezier curves, with poles set to half of the x-length of the S-bend.
1. is the first half of input S-bend where input widths taper by +dw and -dw
2. is the second half of the S-bend straight with constant, unbalanced widths
3. is the region where the two asymmetric straights gradually come together
4. straights taper back to the original width at a fixed distance from one another
5. is the output S-bend straight.
Args:
length1: region that gradually brings the two asymmetric straights together.
In this region the straight widths gradually change to be different by `dw`.
length2: coupling region, where asymmetric straights gradually
become the same width.
length3: output region where the two straights separate.
wg_sep: Distance between center-to-center in the coupling region (Region 2).
input_wg_sep: Separation of the two straights at the input, center-to-center.
output_wg_sep: Separation of the two straights at the output, center-to-center.
dw: Change in straight width.
In Region 1, top arm tapers to width+dw/2.0, bottom taper to width-dw/2.0.
cross_section: cross_section spec.
"""
# Control points for input and output S-bends
control_points_input_top = [
(0, 0),
(length1 / 2.0, 0),
(length1 / 2.0, -input_wg_sep / 2.0 + wg_sep / 2.0),
(length1, -input_wg_sep / 2.0 + wg_sep / 2.0),
]
control_points_input_bottom = [
(0, -input_wg_sep),
(length1 / 2.0, -input_wg_sep),
(length1 / 2.0, -input_wg_sep / 2.0 - wg_sep / 2.0),
(length1, -input_wg_sep / 2.0 - wg_sep / 2.0),
]
control_points_output_top = [
(length1 + length2, -input_wg_sep / 2.0 + wg_sep / 2.0),
(
length1 + length2 + length3 / 2.0,
-input_wg_sep / 2.0 + wg_sep / 2.0,
),
(
length1 + length2 + length3 / 2.0,
-input_wg_sep / 2.0 + output_wg_sep / 2.0,
),
(
length1 + length2 + length3,
-input_wg_sep / 2.0 + output_wg_sep / 2.0,
),
]
c = Component()
x = gf.get_cross_section(cross_section)
width = float(x.width)
width_top = width + dw
width_bot = width - dw
x_top = x.copy(width=width_top)
x_bot = x.copy(width=width_bot)
coupler = c << gf.components.coupler_straight(length=length2, cross_section=x)
taper_top = c << gf.components.taper(
width1=width, width2=width_top, cross_section=cross_section
)
taper_bot = c << gf.components.taper(
width1=width, width2=width_bot, cross_section=cross_section
)
taper_bot.connect("o1", coupler.ports["o1"])
taper_top.connect("o1", coupler.ports["o2"])
sbend_left_top = c << bezier(
control_points=control_points_input_top, cross_section=x_top
)
sbend_left_bot = c << bezier(
control_points=control_points_input_bottom, cross_section=x_bot
)
sbend_left_top.connect("o2", taper_top.ports["o2"])
sbend_left_bot.connect("o2", taper_bot.ports["o2"])
sbend_right = bezier(control_points=control_points_output_top, cross_section=x)
sbend_right_top = c << sbend_right
sbend_right_bot = c << sbend_right
sbend_right_bot.mirror()
sbend_right_top.connect("o1", coupler.ports["o3"])
sbend_right_bot.connect("o1", coupler.ports["o4"])
c.add_port("o1", port=sbend_left_bot.ports["o1"])
c.add_port("o2", port=sbend_left_top.ports["o1"])
c.add_port("o3", port=sbend_right_top.ports["o2"])
c.add_port("o4", port=sbend_right_bot.ports["o2"])
return c
if __name__ == "__main__":
c = coupler_adiabatic(length3=5)
c.show(show_ports=False)