Examples

Thermo-Optic Phase Shifters

A straight TiN heater over a waveguide, and a folded double-spiral waveguide under a meander heater.

Compiling…
Heaters from laylight/heater.lyl, compiled in your browserOpen in playground

Silicon's refractive index rises with temperature, so a resistive heater on top of a waveguide is the standard phase shifter of silicon photonics. Its efficiency depends on how much of the heat reaches the waveguide: the example shows a plain heater and a compact folded one.

The straight heater follows Jacques et al., who optimized the heater geometry for efficiency and thermal crosstalk: a TiN strip 2.5 µm wide, their optimum, runs 320 µm over a 500 nm strip waveguide. Metal leads cross the ends of the TiN and run to 100 µm bond pads.

The folded heater follows Densmore et al., who folded a 6.3 mm waveguide into a double spiral under one heater, so that a single heater warms a long waveguide and the switching power drops. The spiral is the delay line with Densmore's dimensions: 450 nm waveguides at a 2 µm pitch, 14 turns per spiral, so that 57 to 59 waveguides cross the spiral, inside a 65 µm radius. Over it, the heater is a meander of twelve 10 µm wide stripes at a 12 µm pitch, 1.355 mm long in total, with leads to two pads at its ends.

References

  • M. Jacques et al., "Optimization of thermo-optic phase-shifter design and mitigation of thermal crosstalk on the SOI platform," Optics Express 27(8), 10456–10471 (2019). doi:10.1364/OE.27.010456
  • A. Densmore et al., "Compact and low power thermo-optic switch using folded silicon waveguides," Optics Express 17(13), 10457 (2009). doi:10.1364/OE.17.010457

Parameters

ParameterValueSource
Straight heater waveguide500 nmJacques 2019
TiN strip2.5 µm wide (optimum; 7.5 µm as fabricated), 320 µm longJacques 2019, Sec. 2
Folded waveguide450 nm wide, 2 µm pitch, within a 65 µm radiusDensmore 2009
Turns, center14 turns per spiral, S-bend with a minimum radius of 4 µmderived to match Densmore 2009
Waveguide length6.42 mm (paper: 6.3 mm)from the above
Meander heater12 stripes, 10 µm wide, 12 µm pitch, 1.355 mmDensmore 2009
Leads and pads10 µm × 50 µm leads, 100 µm pads, on the first metalassumed

How it is written

The folded heater does not redraw the spiral: it places the DelayLine cell of the delay-line example with other parameters, and Laylight generates a new cell for them. The meander is a path through two points per stripe, collected in a loop, and the pads are a small cell placed at the meander's start and end anchors. The Python versions reuse the delay line the same way, by importing its function.

Implementations

ImplementationLines of codeTokensLayout
Laylight29326reference
gdsfactory43 (1.48×)436 (1.34×)same within 2 nm
gdstk40 (1.38×)448 (1.37×)same within 3 nm
KLayout41 (1.41×)497 (1.52×)same within 2 nm
laylight/heater.lyl
import "delay_line.lyl"

# A 100 um bond pad at the end of a 10 um wide, 50 um long lead, which starts at
# the origin, where it overlaps the TiN (the pads are assumed).
cell Pad {
    layer metal {
        shape rect with 10um, 50um as lead.bottom_center at self.origin
        shape rect with 100um, 100um as square.bottom_center at lead.top_center
    }
}

# A straight TiN heater over a strip waveguide, after Jacques et al., Opt. Express
# 2019; the leads to the pads cross the ends of the TiN.
# `heater_width` is the paper's optimum (7.5 um as fabricated).
cell StraightHeater(width = 500nm, length = 320um, heater_width = 2.5um) {
    layer si { shape rect with length, width as core at self.origin }

    layer heater { shape rect with length, heater_width as strip at self.origin }

    place Pad at strip.bottom_left offset (5um, 0)
    place Pad at strip.bottom_right offset (-5um, 0)
}

# A folded waveguide under a meander heater, after Densmore et al., Opt. Express
# 2009: the delay line's double spiral with 59 waveguides at a 2 um pitch.
# `length` is that of the meander.
cell FoldedHeater(stripes = 12, stripe_width = 10um, pitch = 12um, length = 1355um) {
    place DelayLine with {
        width = 450nm, gap = 1.55um, turns = 14, inner_radius = 8.3um, p = 0.2
        io_width = 450nm, taper_radius = 10um
    } at self.origin

    layer heater {
        define h = (length - (stripes - 1) * pitch) / stripes    # length of a stripe
        define meander: [point] = []
        for i in 0..stripes {
            define x = (i - (stripes - 1) / 2) * pitch
            define y = pow(-1, i) * h / 2    # up, then down
            meander.append((x, -y))
            meander.append((x, y))
        }
        shape path with meander, stripe_width as wire at self.origin
    }

    # The leads overlap the ends of the meander by 10 um.
    place Pad at (wire.start.x, wire.start.y + 10um) rotate 180deg
    place Pad at (wire.end.x, wire.end.y + 10um) rotate 180deg
}

# The two phase shifters side by side.
cell Heaters {
    place StraightHeater at self.origin
    place FoldedHeater at (400um, 0)
}
gdsfactory/heater.py
"""Thermo-optic phase shifters with TiN heaters, as laylight/heater.lyl."""

import gdsfactory as gf

from delay_line import delay_line
from tech import HEATER, METAL, SI


@gf.cell
def pad():
    """A 100 um bond pad at the end of a 10 um wide, 50 um long lead, which
    starts at the origin, where it overlaps the TiN (the pads are assumed)."""
    c = gf.Component()
    (c << gf.components.rectangle((10, 50), layer=METAL)).dmove((-5, 0))
    (c << gf.components.rectangle((100, 100), layer=METAL)).dmove((-50, 50))
    return c


@gf.cell
def straight_heater(width=0.5, length=320, heater_width=2.5):
    """A straight TiN heater over a strip waveguide, after Jacques et al., Opt.
    Express 2019; the leads to the pads cross the ends of the TiN."""
    c = gf.Component()
    for w, layer in [(width, SI), (heater_width, HEATER)]:
        c << gf.components.rectangle((length, w), layer=layer, centered=True)
    for x in [5 - length / 2, length / 2 - 5]:
        (c << pad()).dmove((x, -heater_width / 2))
    return c


@gf.cell
def folded_heater(stripes=12, stripe_width=10, pitch=12, length=1355):
    """A folded waveguide under a meander heater, after Densmore et al., Opt.
    Express 2009: the delay line's double spiral with 59 waveguides at a 2 um
    pitch."""
    c = gf.Component()
    c << delay_line(
        width=0.45,
        gap=1.55,
        turns=14,
        inner_radius=8.3,
        p=0.2,
        io_width=0.45,
        taper_radius=10,
    )
    h = (length - (stripes - 1) * pitch) / stripes  # length of a stripe
    meander = []
    for i in range(stripes):
        x, y = (i - (stripes - 1) / 2) * pitch, (-1) ** i * h / 2  # up, then down
        meander += [(x, -y), (x, y)]
    c << gf.Path(meander).extrude(width=stripe_width, layer=HEATER)
    # The leads overlap the ends of the meander by 10 um.
    for x, y in [meander[0], meander[-1]]:
        (c << pad()).drotate(180).dmove((x, y + 10))
    return c


@gf.cell
def heaters():
    """The two phase shifters side by side."""
    c = gf.Component()
    c << straight_heater()
    (c << folded_heater()).dmove((400, 0))
    return c


if __name__ == "__main__":
    import sys

    heaters().write_gds(sys.argv[1])
gdstk/heater.py
"""Thermo-optic phase shifters with TiN heaters, as laylight/heater.lyl."""

import gdstk

from delay_line import delay_line
from tech import HEATER, METAL, SI


def pad(x, y, direction=1):
    """A 100 um bond pad at the end of a 10 um wide, 50 um long lead that leaves
    (x, y) upwards (direction 1) or downwards (-1), where it overlaps the TiN
    (the pads are assumed)."""
    lead = gdstk.rectangle((x - 5, y), (x + 5, y + 50 * direction), **METAL)
    square = gdstk.rectangle(
        (x - 50, y + 50 * direction), (x + 50, y + 150 * direction), **METAL
    )
    return [lead, square]


def straight_heater(width=0.5, length=320, heater_width=2.5):
    """A straight TiN heater over a strip waveguide, after Jacques et al., Opt.
    Express 2019; the leads to the pads cross the ends of the TiN."""
    cell = gdstk.Cell("StraightHeater")
    for w, layer in [(width, SI), (heater_width, HEATER)]:
        cell.add(gdstk.rectangle((-length / 2, -w / 2), (length / 2, w / 2), **layer))
    for x in [5 - length / 2, length / 2 - 5]:
        cell.add(*pad(x, -heater_width / 2))
    return cell


def folded_heater(stripes=12, stripe_width=10, pitch=12, length=1355):
    """A folded waveguide under a meander heater, after Densmore et al., Opt.
    Express 2009: the delay line's double spiral with 59 waveguides at a 2 um
    pitch."""
    cell = gdstk.Cell("FoldedHeater")
    spiral = delay_line(
        width=0.45,
        gap=1.55,
        turns=14,
        inner_radius=8.3,
        p=0.2,
        io_width=0.45,
        taper_radius=10,
    )
    cell.add(gdstk.Reference(spiral))
    h = (length - (stripes - 1) * pitch) / stripes  # length of a stripe
    meander = []
    for i in range(stripes):
        x, y = (i - (stripes - 1) / 2) * pitch, (-1) ** i * h / 2  # up, then down
        meander += [(x, -y), (x, y)]
    cell.add(gdstk.FlexPath(meander, stripe_width, **HEATER))
    # The leads overlap the ends of the meander by 10 um.
    for x, y in [meander[0], meander[-1]]:
        cell.add(*pad(x, y + 10, -1))
    return cell


def heaters():
    """The two phase shifters side by side."""
    cell = gdstk.Cell("Heaters")
    cell.add(gdstk.Reference(straight_heater()))
    cell.add(gdstk.Reference(folded_heater(), (400, 0)))
    return cell


if __name__ == "__main__":
    import sys

    top = heaters()
    lib = gdstk.Library()
    lib.add(top, *top.dependencies(True))
    lib.write_gds(sys.argv[1])
klayout/heater.py
"""Thermo-optic phase shifters with TiN heaters, as laylight/heater.lyl."""

import klayout.db as kdb

from delay_line import delay_line
from tech import HEATER, METAL, SI, layout


def pad(shapes, x, y, direction=1):
    """Adds a 100 um bond pad at the end of a 10 um wide, 50 um long lead that
    leaves (x, y) upwards (direction 1) or downwards (-1), where it overlaps the
    TiN (the pads are assumed)."""
    shapes.insert(kdb.DBox(x - 5, y, x + 5, y + 50 * direction))
    shapes.insert(kdb.DBox(x - 50, y + 50 * direction, x + 50, y + 150 * direction))


def straight_heater(width=0.5, length=320, heater_width=2.5):
    """A straight TiN heater over a strip waveguide, after Jacques et al., Opt.
    Express 2019; the leads to the pads cross the ends of the TiN."""
    cell = layout.create_cell("StraightHeater")
    for w, layer in [(width, SI), (heater_width, HEATER)]:
        cell.shapes(layout.layer(layer)).insert(kdb.DBox(length, w))
    metal = cell.shapes(layout.layer(METAL))
    for x in [5 - length / 2, length / 2 - 5]:
        pad(metal, x, -heater_width / 2)
    return cell


def folded_heater(stripes=12, stripe_width=10, pitch=12, length=1355):
    """A folded waveguide under a meander heater, after Densmore et al., Opt.
    Express 2009: the delay line's double spiral with 59 waveguides at a 2 um
    pitch."""
    cell = layout.create_cell("FoldedHeater")
    spiral = delay_line(
        width=0.45,
        gap=1.55,
        turns=14,
        inner_radius=8.3,
        p=0.2,
        io_width=0.45,
        taper_radius=10,
    )
    cell.insert(kdb.DCellInstArray(spiral.cell_index(), kdb.DTrans()))
    h = (length - (stripes - 1) * pitch) / stripes  # length of a stripe
    meander = []
    for i in range(stripes):
        x, y = (i - (stripes - 1) / 2) * pitch, (-1) ** i * h / 2  # up, then down
        meander += [kdb.DPoint(x, -y), kdb.DPoint(x, y)]
    cell.shapes(layout.layer(HEATER)).insert(kdb.DPath(meander, stripe_width))
    # The leads overlap the ends of the meander by 10 um.
    metal = cell.shapes(layout.layer(METAL))
    for end in [meander[0], meander[-1]]:
        pad(metal, end.x, end.y + 10, -1)
    return cell


def heaters():
    """The two phase shifters side by side."""
    cell = layout.create_cell("Heaters")
    for child, x in [(straight_heater(), 0), (folded_heater(), 400)]:
        trans = kdb.DTrans(kdb.DVector(x, 0))
        cell.insert(kdb.DCellInstArray(child.cell_index(), trans))
    return cell


if __name__ == "__main__":
    import sys

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

On this page