Germanium Electro-Absorption Modulator
A germanium waveguide electro-absorption modulator with a lateral p-i-n junction, butt-coupled to silicon waveguides.
GeModulator from laylight/ge_modulator.lyl, compiled in your browserOpen in playgroundGermanium 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
| Parameter | Value | Source |
|---|---|---|
| Germanium | 0.6 µm × 40 µm (350 nm thick in a 110 nm recess, not drawn) | Srinivasan 2016, Sec. II–III |
| Silicon waveguides, tapers | 450 nm, 5 µm tapers | Liu 2020 |
| Silicon slab | 15 µm wide | Liu 2020 |
| Undoped strip in the germanium | 200 nm | assumed, after Srinivasan 2016, Fig. 1(a) |
| p++ and n++ strips, contacts | 3 µm, 1 µm | assumed |
| Pads | 60 µm, 100 µm pitch | assumed |
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
| Implementation | Lines of code | Tokens | Layout |
|---|---|---|---|
| Laylight | 41 | 353 | reference |
| gdsfactory | 41 (1.00×) | 441 (1.25×) | identical |
| gdstk | 38 (0.93×) | 444 (1.26×) | identical |
| KLayout | 37 (0.90×) | 409 (1.16×) | identical |
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 }
}
"""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])
"""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])
"""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])