Examples

Waveguide Crossing

A low-loss single-etch waveguide crossing: four identical tapers, each given by its widths at 13 points.

Compiling…
Crossing from laylight/crossing.lyl, compiled in your browserOpen in playground

Where two waveguides cross in a single silicon layer, light diffracts into the crossing waveguide and is lost. A good crossing widens each arm before the center, so that the light focuses through the intersection and narrows again on the far side. Ma et al. optimized the width profile of such a taper numerically, for a crossing with a 9 µm × 9 µm footprint made with a single full etch.

Each arm of the crossing is a 4.5 µm taper whose width is given at 13 equally spaced points, from the 500 nm waveguide at the outer end to the center. The four arms are copies of one taper, rotated by 90° steps, and their union is the crossing. The paper interpolates the 13 widths with a spline; Laylight has no spline primitive, so all four implementations join them with straight lines.

References

  • Y. Ma et al., "Ultralow loss single layer submicron silicon waveguide crossing for SOI optical interconnect," Optics Express 21(24), 29374 (2013). doi:10.1364/OE.21.029374

Parameters

ParameterValueSource
Taper length4.5 µm, 13 points 0.375 µm apartMa 2013, Sec. 2
Widths (1550 nm design)0.5, 0.6, 0.95, 1.32, 1.44, 1.46, 1.466, 1.52, 1.58, 1.62, 1.76, 2.15, 0.5 µmMa 2013, Table 1
Interpolationstraight lines between the pointsassumed (the paper uses a spline)

The last width, 0.5 µm at the center, does not affect the result: 0.375 µm from the center the perpendicular arms are already 2.15 µm wide and cover the whole central square.

How it is written

The widths are a parameter whose default is the table of the paper, a constant of type [size], so other designs of the table drop in. The outline of one arm is collected into a list of points in two loops, along one edge and back along the other, and a third loop places four copies of the polygon rotated by k * 90deg. gdstk is as short here: numpy builds the outline from the widths in two lines, with array reversal and concatenation that Laylight lists do not have.

Implementations

ImplementationLines of codeTokensLayout
Laylight12158reference
gdsfactory14 (1.17×)167 (1.06×)identical
gdstk12 (1.00×)158 (1.00×)identical
KLayout14 (1.17×)185 (1.17×)identical
laylight/crossing.lyl
import "tech.lyl"

# Widths at 13 equally spaced points from the waveguide (w1) to the centre (w13),
# Table 1 of Ma et al. (1550 nm design).
define ma_widths = [500nm, 600nm, 950nm, 1.32um, 1.44um, 1.46um, 1.466um, 1.52um,
    1.58um, 1.62um, 1.76um, 2.15um, 500nm]

# A low-loss waveguide crossing after Ma et al., Opt. Express 2013: four
# identical tapers of `length`, each given by its `widths`, joined by straight
# lines (the paper interpolates them with a spline).
cell Crossing(widths = ma_widths, length = 4.5um) {
    layer si {
        define n = len(widths)
        define step = length / (n - 1)
        define outline: [point] = []
        for i in 0..n { outline.append(((n - 1 - i) * step, widths[i] / 2)) }
        for i in 0..n { outline.append((i * step, -widths[n - 1 - i] / 2)) }
        for k in 0..4 {   # the four arms overlap at the centre
            shape polygon with outline as arm at self.origin rotate k * 90deg
        }
    }
}
gdsfactory/crossing.py
"""A low-loss waveguide crossing, as laylight/crossing.lyl."""

import gdsfactory as gf
import numpy as np

from tech import SI

# Widths at 13 equally spaced points from the waveguide (w1) to the centre (w13).
WIDTHS = (0.5, 0.6, 0.95, 1.32, 1.44, 1.46, 1.466, 1.52, 1.58, 1.62, 1.76, 2.15, 0.5)


@gf.cell
def crossing(widths=WIDTHS, length=4.5):
    """Four identical tapers whose widths are joined by straight lines (the
    paper interpolates them with a spline)."""
    x = np.linspace(length, 0, len(widths))
    y = np.array(widths) / 2
    arm = gf.Component()
    arm.add_polygon(np.column_stack([np.r_[x, x[::-1]], np.r_[y, -y[::-1]]]), layer=SI)
    c = gf.Component()
    for angle in [0, 90, 180, 270]:  # the four arms overlap at the centre
        (c << arm).drotate(angle)
    return c


if __name__ == "__main__":
    import sys

    crossing().write_gds(sys.argv[1])
gdstk/crossing.py
"""A low-loss waveguide crossing, as laylight/crossing.lyl."""

import gdstk
import numpy as np

from tech import SI

# Widths at 13 equally spaced points from the waveguide (w1) to the centre (w13).
WIDTHS = (0.5, 0.6, 0.95, 1.32, 1.44, 1.46, 1.466, 1.52, 1.58, 1.62, 1.76, 2.15, 0.5)


def crossing(widths=WIDTHS, length=4.5):
    """Four identical tapers whose widths are joined by straight lines (the
    paper interpolates them with a spline)."""
    x = np.linspace(length, 0, len(widths))
    y = np.array(widths) / 2
    arm = np.column_stack([np.r_[x, x[::-1]], np.r_[y, -y[::-1]]])
    cell = gdstk.Cell("Crossing")
    for k in range(4):  # the four arms overlap at the centre
        cell.add(gdstk.Polygon(arm, **SI).rotate(k * np.pi / 2))
    return cell


if __name__ == "__main__":
    import sys

    top = crossing()
    lib = gdstk.Library()
    lib.add(top, *top.dependencies(True))
    lib.write_gds(sys.argv[1])
klayout/crossing.py
"""A low-loss waveguide crossing, as laylight/crossing.lyl."""

import klayout.db as kdb
import numpy as np

from tech import SI, layout
from waveguides import polygon

# Widths at 13 equally spaced points from the waveguide (w1) to the centre (w13).
WIDTHS = (0.5, 0.6, 0.95, 1.32, 1.44, 1.46, 1.466, 1.52, 1.58, 1.62, 1.76, 2.15, 0.5)


def crossing(widths=WIDTHS, length=4.5):
    """Four identical tapers whose widths are joined by straight lines (the
    paper interpolates them with a spline)."""
    x = np.linspace(length, 0, len(widths))
    y = np.array(widths) / 2
    arm = polygon(np.column_stack([np.r_[x, x[::-1]], np.r_[y, -y[::-1]]]))
    cell = layout.create_cell("Crossing")
    si = cell.shapes(layout.layer(SI))
    for k in range(4):  # the four arms overlap at the centre
        si.insert(arm.transformed(kdb.DCplxTrans(1, 90 * k, False, 0, 0)))
    return cell


if __name__ == "__main__":
    import sys

    crossing()
    layout.write(sys.argv[1])

On this page