Examples

Germanium Electro-Absorption Modulator

A germanium waveguide electro-absorption modulator with a lateral p-i-n junction, butt-coupled to silicon waveguides.

Compiling…
GeModulator from laylight/ge_modulator.lyl, compiled in your browserOpen in playground

Germanium absorbs light near 1550 nm, and an electric field shifts its absorption edge (the Franz-Keldysh effect): a reverse-biased p-i-n diode across a germanium waveguide is therefore a compact, fast and low-power modulator. Srinivasan et al. grow the germanium in a recess of the silicon, butt-couple it to silicon waveguides and contact it laterally through highly doped silicon on both sides; their 0.6 µm × 40 µm device modulates at 56 Gb/s.

The example draws that layout: a 0.6 µm × 40 µm germanium strip on a silicon slab, joined at both ends to 450 nm silicon waveguides by 5 µm tapers, with the taper dimensions of Liu et al. p and n implants run from either side of a narrow undoped strip in the middle of the germanium out to the slab edges, where p++ and n++ strips carry the contacts. On each side a metal plate runs from the contact to a probe pad, with a via in the pad.

References

  • S. A. Srinivasan et al., "56 Gb/s germanium waveguide electro-absorption modulator," Journal of Lightwave Technology 34(2), 419–424 (2016). doi:10.1109/JLT.2015.2478601
  • Z. Liu et al., "56 Gbps high-speed Ge electro-absorption modulator," Photonics Research 8(10), 1648 (2020), for the taper dimensions. doi:10.1364/PRJ.401140

Parameters

ParameterValueSource
Germanium0.6 µm × 40 µm (350 nm thick in a 110 nm recess, not drawn)Srinivasan 2016, Sec. II–III
Silicon waveguides, tapers450 nm, 5 µm tapersLiu 2020
Silicon slab15 µm wideLiu 2020
Undoped strip in the germanium200 nmassumed, after Srinivasan 2016, Fig. 1(a)
p++ and n++ strips, contacts3 µm, 1 µmassumed
Pads60 µm, 100 µm pitchassumed

The paper's tapers are in polysilicon; the example draws them in silicon.

How it is written

Every layer is a block of one or two statements: the shapes are rectangles placed by their edges on the edges of the slab, and the vias are the pads shrunk by 5 µm, [p_pad, n_pad] - 5um. With eleven layers this is one of the examples where the Python versions take fewer lines: they handle the p side and the n side in one loop over the sign and the layers of that side, and a Laylight layer cannot be a loop variable or a parameter. In tokens Laylight is the shortest.

Implementations

ImplementationLines of codeTokensLayout
Laylight41353reference
gdsfactory41 (1.00×)441 (1.25×)identical
gdstk38 (0.93×)444 (1.26×)identical
KLayout37 (0.90×)409 (1.16×)identical
laylight/ge_modulator.lyl
import "tech.lyl"

# A germanium waveguide electro-absorption modulator, after Srinivasan et al.,
# JLT 2016: a Ge strip grown in a recess of the Si, butt-coupled to tapered Si
# waveguides, with a lateral p-i-n junction contacted through p++ and n++ Si
# on either side and wired to a pair of probe pads.
cell GeModulator(
    ge_width = 600nm,
    ge_length = 40um,
    intrinsic_width = 200nm,  # undoped middle of the Ge
    width = 450nm,  # Si waveguides
    taper_length = 5um,
    access_length = 10um,
    slab_width = 15um,  # Si under and around the Ge
    doped_width = 3um,  # p++ and n++ strips along its edges
    contact_width = 1um,
    pad_size = 60um,
    pad_pitch = 100um,
) {
    layer ge { shape rect with ge_length, ge_width as absorber at self.origin }

    layer si {
        for end in [(ge_length / 2, 0), (-ge_length / 2, 0, 180deg)] {
            shape taper with taper_length, ge_width, width as taper.start at end
            shape rect with access_length, width as access.left_center at taper.end
        }
    }

    layer slab { shape rect with ge_length, slab_width as region at self.origin }

    # p and n implants from the sides of the Ge to the edges of the slab, highly
    # doped at the edges.
    layer p {
        shape rect with ge_length, (slab_width - intrinsic_width) / 2 as p_side
        place p_side.top_center at (0, -intrinsic_width / 2)
    }

    layer n {
        shape rect with ge_length, (slab_width - intrinsic_width) / 2 as n_side
        place n_side.bottom_center at (0, intrinsic_width / 2)
    }

    layer ppp {
        shape rect with ge_length, doped_width as p_plus
        place p_plus.bottom_center at region.bottom_center
    }

    layer npp {
        shape rect with ge_length, doped_width as n_plus.top_center at region.top_center
    }

    layer contact {
        shape rect with ge_length, contact_width as p_contact at p_plus.center
        clone p_contact as n_contact at n_plus.center
    }

    # Metal from each highly doped strip to its pad.
    layer metal {
        define height = (pad_pitch + pad_size - slab_width) / 2 + doped_width
        shape rect with pad_size, height as p_metal.top_center at p_plus.top_center
        clone p_metal as n_metal.bottom_center at n_plus.bottom_center
    }

    layer pad {
        shape rect with pad_size, pad_size as p_pad at (0, -pad_pitch / 2)
        clone p_pad as n_pad at (0, pad_pitch / 2)
    }

    layer via { shape [p_pad, n_pad] - 5um as vias }
}
gdsfactory/ge_modulator.py
"""A germanium waveguide electro-absorption modulator, as laylight/ge_modulator.lyl."""

import gdsfactory as gf

from tech import CONTACT, GE, METAL, N, NPP, P, PAD, PPP, SI, SLAB, VIA


@gf.cell
def ge_modulator(
    ge_width=0.6,
    ge_length=40,
    intrinsic_width=0.2,
    width=0.45,
    taper_length=5,
    access_length=10,
    slab_width=15,
    doped_width=3,
    contact_width=1,
    pad_size=60,
    pad_pitch=100,
):
    """A Ge strip in a recess of the Si, butt-coupled to tapered Si waveguides, with
    a lateral p-i-n junction contacted through p++ and n++ Si and wired to pads."""
    c = gf.Component()

    def box(x0, y0, x1, y1, layer):
        c.add_polygon([(x0, y0), (x1, y0), (x1, y1), (x0, y1)], layer=layer)

    x = ge_length / 2
    y = slab_width / 2
    box(-x, -ge_width / 2, x, ge_width / 2, GE)
    box(-x, -y, x, y, SLAB)
    xs = gf.cross_section.cross_section(width=width, layer=SI)
    for angle in [0, 180]:  # on the right, then turned to the left
        taper = c << gf.components.taper(taper_length, ge_width, width, layer=SI)
        taper.dmove((x, 0))
        taper.drotate(angle)
        access = c << gf.components.straight(access_length, cross_section=xs)
        access.connect("o1", taper.ports["o2"])
    # p and n implants from the sides of the Ge to the edges of the slab, highly
    # doped at the edges.
    half = pad_size / 2
    for s, doped, heavy in [(-1, P, PPP), (1, N, NPP)]:
        y0 = s * (y - doped_width)  # inner edge of the p++ or n++ strip
        yc = s * (y - doped_width / 2)
        yp = s * pad_pitch / 2
        box(-x, s * intrinsic_width / 2, x, s * y, doped)
        box(-x, y0, x, s * y, heavy)
        box(-x, yc - contact_width / 2, x, yc + contact_width / 2, CONTACT)
        box(-half, y0, half, yp + s * half, METAL)
        box(5 - half, yp + 5 - half, half - 5, yp + half - 5, VIA)
        box(-half, yp - half, half, yp + half, PAD)
    return c


if __name__ == "__main__":
    import sys

    ge_modulator().write_gds(sys.argv[1])
gdstk/ge_modulator.py
"""A germanium waveguide electro-absorption modulator, as laylight/ge_modulator.lyl."""

import gdstk

from tech import CONTACT, GE, METAL, N, NPP, P, PAD, PPP, SI, SLAB, VIA


def ge_modulator(
    ge_width=0.6,
    ge_length=40,
    intrinsic_width=0.2,
    width=0.45,
    taper_length=5,
    access_length=10,
    slab_width=15,
    doped_width=3,
    contact_width=1,
    pad_size=60,
    pad_pitch=100,
):
    """A Ge strip in a recess of the Si, butt-coupled to tapered Si waveguides, with
    a lateral p-i-n junction contacted through p++ and n++ Si and wired to pads."""
    cell = gdstk.Cell("GeModulator")
    x = ge_length / 2
    y = slab_width / 2
    cell.add(gdstk.rectangle((-x, -ge_width / 2), (x, ge_width / 2), **GE))
    cell.add(gdstk.rectangle((-x, -y), (x, y), **SLAB))
    for s in [1, -1]:
        wg = gdstk.FlexPath((s * x, 0), ge_width, **SI)
        wg.segment((s * (x + taper_length), 0), width)
        wg.segment((s * access_length, 0), relative=True)
        cell.add(wg)
    # p and n implants from the sides of the Ge to the edges of the slab, highly
    # doped at the edges.
    half = pad_size / 2
    for s, doped, heavy in [(-1, P, PPP), (1, N, NPP)]:
        y0 = s * (y - doped_width)  # inner edge of the p++ or n++ strip
        yc = s * (y - doped_width / 2)
        yp = s * pad_pitch / 2
        pad = gdstk.rectangle((-half, yp - half), (half, yp + half), **PAD)
        cell.add(gdstk.rectangle((-x, s * intrinsic_width / 2), (x, s * y), **doped))
        cell.add(gdstk.rectangle((-x, y0), (x, s * y), **heavy))
        cell.add(
            gdstk.rectangle(
                (-x, yc - contact_width / 2), (x, yc + contact_width / 2), **CONTACT
            )
        )
        cell.add(gdstk.rectangle((-half, y0), (half, yp + s * half), **METAL))
        cell.add(pad, *gdstk.offset(pad, -5, **VIA))
    return cell


if __name__ == "__main__":
    import sys

    lib = gdstk.Library()
    lib.add(ge_modulator())
    lib.write_gds(sys.argv[1])
klayout/ge_modulator.py
"""A germanium waveguide electro-absorption modulator, as laylight/ge_modulator.lyl."""

import klayout.db as kdb

from tech import CONTACT, GE, METAL, N, NPP, P, PAD, PPP, SI, SLAB, VIA, layout
from waveguides import polygon


def ge_modulator(
    ge_width=0.6,
    ge_length=40,
    intrinsic_width=0.2,
    width=0.45,
    taper_length=5,
    access_length=10,
    slab_width=15,
    doped_width=3,
    contact_width=1,
    pad_size=60,
    pad_pitch=100,
):
    """A Ge strip in a recess of the Si, butt-coupled to tapered Si waveguides, with
    a lateral p-i-n junction contacted through p++ and n++ Si and wired to pads."""
    cell = layout.create_cell("GeModulator")

    def shapes(layer):
        return cell.shapes(layout.layer(layer))

    x = ge_length / 2
    y = slab_width / 2
    shapes(GE).insert(kdb.DBox(ge_length, ge_width))
    shapes(SLAB).insert(kdb.DBox(ge_length, slab_width))
    for s in [1, -1]:
        x1 = s * (x + taper_length)
        x2 = x1 + s * access_length
        points = [(s * x, ge_width / 2), (x1, width / 2), (x2, width / 2)]
        shapes(SI).insert(polygon(points + [(px, -py) for px, py in reversed(points)]))
    # p and n implants from the sides of the Ge to the edges of the slab, highly
    # doped at the edges.
    for s, doped, heavy in [(-1, P, PPP), (1, N, NPP)]:
        strip = kdb.DBox(-x, s * (y - doped_width), x, s * y)
        pad = kdb.DBox(pad_size, pad_size).moved(0, s * pad_pitch / 2)
        shapes(doped).insert(kdb.DBox(-x, s * intrinsic_width / 2, x, s * y))
        shapes(heavy).insert(strip)
        shapes(CONTACT).insert(kdb.DBox(ge_length, contact_width).moved(strip.center()))
        shapes(METAL).insert(strip + pad)  # the box enclosing both
        shapes(VIA).insert(pad.enlarged(-5, -5))
        shapes(PAD).insert(pad)
    return cell


if __name__ == "__main__":
    import sys

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

On this page