1×2 MMI Splitter
A multimode interference splitter with tapered access waveguides, compact and tolerant to fabrication.
MMI1x2 from laylight/mmi.lyl, compiled in your browserOpen in playgroundA multimode interference (MMI) splitter is a short, wide waveguide section. Light entering it in the middle excites several modes, which interfere along the section and form two images of the input at a specific length: placing two output waveguides there splits the power in half. Linear tapers widen the access waveguides where they meet the multimode section, which lowers the loss and makes the device less sensitive to fabrication.
The example reproduces the optimized 1×2 MMI of Sheng et al., fabricated in a 248 nm CMOS process: a 3.6 µm × 11.5 µm multimode section, 500 nm access waveguides widened to 1.2 µm, and two outputs 0.6 µm apart at a quarter of the width from either side. The paper gives the taper as an angle of 1°; read as the half-angle of each sidewall, that is a 20 µm long taper.
The splitter is the building block of the Mach-Zehnder interferometers, which import it in all four tools.
Reference
- Z. Sheng et al., "A compact and low-loss MMI coupler fabricated with CMOS technology," IEEE Photonics Journal 4(6), 2272–2277 (2012). doi:10.1109/JPHOT.2012.2230320
Parameters
| Parameter | Value | Source |
|---|---|---|
| Access waveguide width | 500 nm | Sheng 2012, Sec. 2 |
| Multimode section | 3.6 µm × 11.5 µm | Sheng 2012, Sec. 2 |
| Taper | 500 nm → 1.2 µm, 20 µm long | Sheng 2012, Sec. 2 (length from the 1° taper angle) |
| Output separation | 1.8 µm between centers (0.6 µm gap) | Sheng 2012, Sec. 2 |
How it is written
Each part is a primitive, placed by its anchors in the statement that defines it where the line allows: the input taper's start at the cell origin, the multimode section's left_center on the taper's end, and the output tapers' start on the section's right_center, offset by half the pitch. The two output tapers are one shape and a clone. The ports are markers on the taper ends, which the Mach-Zehnder interferometer uses to connect its arms.
The six parameters follow the cell's name, their types given by their defaults. They do not fit on one line, so the header lists one per line with its comment, as ruff does with the Python signatures.
Implementations
| Implementation | Lines of code | Tokens | Layout |
|---|---|---|---|
| Laylight | 18 | 136 | reference |
| gdsfactory | 22 (1.22×) | 184 (1.35×) | identical |
| gdstk | 20 (1.11×) | 201 (1.48×) | identical |
| KLayout | 21 (1.17×) | 225 (1.65×) | identical |
import "tech.lyl"
# A 1x2 multimode interference splitter with tapered access waveguides, after
# Sheng et al., IEEE Photonics J. 2012 (taper length from its 1 deg taper angle).
cell MMI1x2(
width = 500nm, # access waveguide width
taper_width = 1.2um,
taper_length = 20um,
mmi_width = 3.6um,
mmi_length = 11.5um,
pitch = 1.8um, # distance between the output waveguides
) {
marker {
input { at in_taper.start }
output { at { top.end; bottom.end } }
}
layer si {
shape taper with taper_length, width, taper_width as in_taper
place in_taper.start at self.origin
shape rect with mmi_length, mmi_width as body.left_center at in_taper.end
shape taper with taper_length, taper_width, width as top
place top.start at body.right_center offset (0, pitch / 2)
clone top as bottom.start at body.right_center offset (0, -pitch / 2)
}
}
"""A 1x2 MMI splitter with tapered access waveguides, as laylight/mmi.lyl."""
import gdsfactory as gf
from tech import SI
@gf.cell
def mmi1x2(
width=0.5,
taper_width=1.2,
taper_length=20,
mmi_width=3.6,
mmi_length=11.5,
pitch=1.8,
):
c = gf.Component()
taper = gf.components.taper(taper_length, width, taper_width, layer=SI)
in_taper = c << taper
body = c << gf.components.rectangle((mmi_length, mmi_width), layer=SI)
body.dmove((taper_length, -mmi_width / 2))
c.add_port("o1", port=in_taper.ports["o1"])
for name, y in [("o2", pitch / 2), ("o3", -pitch / 2)]:
out_taper = c << taper
out_taper.dmirror_x()
out_taper.dmove((2 * taper_length + mmi_length, y))
c.add_port(name, port=out_taper.ports["o1"])
return c
if __name__ == "__main__":
import sys
mmi1x2().write_gds(sys.argv[1])
"""A 1x2 MMI splitter with tapered access waveguides, as laylight/mmi.lyl."""
import gdstk
from tech import SI
def taper(x, y, length, w1, w2):
"""A linear taper from width w1 at (x, y) to w2 at (x + length, y)."""
points = [(x, y - w1 / 2), (x + length, y - w2 / 2)]
points += [(x + length, y + w2 / 2), (x, y + w1 / 2)]
return gdstk.Polygon(points, **SI)
def mmi1x2(
width=0.5,
taper_width=1.2,
taper_length=20,
mmi_width=3.6,
mmi_length=11.5,
pitch=1.8,
):
cell = gdstk.Cell("MMI1x2")
x = taper_length + mmi_length
cell.add(taper(0, 0, taper_length, width, taper_width))
cell.add(gdstk.rectangle((taper_length, -mmi_width / 2), (x, mmi_width / 2), **SI))
for y in [pitch / 2, -pitch / 2]:
cell.add(taper(x, y, taper_length, taper_width, width))
return cell
if __name__ == "__main__":
import sys
lib = gdstk.Library()
lib.add(mmi1x2())
lib.write_gds(sys.argv[1])
"""A 1x2 MMI splitter with tapered access waveguides, as laylight/mmi.lyl."""
import klayout.db as kdb
from tech import SI, layout
def taper(x, y, length, w1, w2):
"""A linear taper from width w1 at (x, y) to w2 at (x + length, y)."""
points = [(x, y - w1 / 2), (x + length, y - w2 / 2)]
points += [(x + length, y + w2 / 2), (x, y + w1 / 2)]
return kdb.DPolygon([kdb.DPoint(px, py) for px, py in points])
def mmi1x2(
width=0.5,
taper_width=1.2,
taper_length=20,
mmi_width=3.6,
mmi_length=11.5,
pitch=1.8,
):
cell = layout.create_cell("MMI1x2")
si = cell.shapes(layout.layer(SI))
x = taper_length + mmi_length
si.insert(taper(0, 0, taper_length, width, taper_width))
si.insert(kdb.DBox(taper_length, -mmi_width / 2, x, mmi_width / 2))
for y in [pitch / 2, -pitch / 2]:
si.insert(taper(x, y, taper_length, taper_width, width))
return cell
if __name__ == "__main__":
import sys
mmi1x2()
layout.write(sys.argv[1])