Waveguide Crossing
A low-loss single-etch waveguide crossing: four identical tapers, each given by its widths at 13 points.
Crossing from laylight/crossing.lyl, compiled in your browserOpen in playgroundWhere 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
| Parameter | Value | Source |
|---|---|---|
| Taper length | 4.5 µm, 13 points 0.375 µm apart | Ma 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 µm | Ma 2013, Table 1 |
| Interpolation | straight lines between the points | assumed (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
| Implementation | Lines of code | Tokens | Layout |
|---|---|---|---|
| Laylight | 12 | 158 | reference |
| gdsfactory | 14 (1.17×) | 167 (1.06×) | identical |
| gdstk | 12 (1.00×) | 158 (1.00×) | identical |
| KLayout | 14 (1.17×) | 185 (1.17×) | identical |
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
}
}
}
"""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])
"""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])
"""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])