Examples

1×2 MMI Splitter

A multimode interference splitter with tapered access waveguides, compact and tolerant to fabrication.

Compiling…
MMI1x2 from laylight/mmi.lyl, compiled in your browserOpen in playground

A 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

ParameterValueSource
Access waveguide width500 nmSheng 2012, Sec. 2
Multimode section3.6 µm × 11.5 µmSheng 2012, Sec. 2
Taper500 nm → 1.2 µm, 20 µm longSheng 2012, Sec. 2 (length from the 1° taper angle)
Output separation1.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

ImplementationLines of codeTokensLayout
Laylight18136reference
gdsfactory22 (1.22×)184 (1.35×)identical
gdstk20 (1.11×)201 (1.48×)identical
KLayout21 (1.17×)225 (1.65×)identical
laylight/mmi.lyl
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)
    }
}
gdsfactory/mmi.py
"""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])
gdstk/mmi.py
"""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])
klayout/mmi.py
"""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])

On this page