Examples

Microring Resonators

A 1.5 µm-radius all-pass microring, and an ultrahigh-Q racetrack with Euler bends and a pulley coupler.

Compiling…
Microrings from laylight/microring.lyl, compiled in your browserOpen in playground

A microring resonator is a closed waveguide loop next to a bus waveguide: light at the wavelengths for which the loop is a whole number of wavelengths long couples into it and is lost, so the bus transmits a comb of narrow dips. The example holds two very different rings.

The all-pass microring of Xu, Fattal and Beausoleil is one of the smallest silicon rings: 1.5 µm in radius, with a 450 nm wide ring waveguide. Its bus is only 250 nm wide, narrower than the ring, so that the propagation constants of the bus and the bent ring waveguide match and light can couple across the 340 nm gap of such a short coupler.

The Euler racetrack of Zhang et al. reaches an ultrahigh Q with wide multimode waveguides: 1.6 µm everywhere, so little light reaches the rough sidewalls. The straight sections are 260 µm long. Each 180° bend is an Euler bend whose curvature grows from zero at the straight sections to 1/15 µm⁻¹ at the apex, so the fundamental mode passes from straight to bent waveguide without exciting higher-order modes. The access waveguide wraps around the apex of one bend, concentric with it at a 260 nm gap, and turns back to vertical on either side.

The paper's bends start from a small curvature of 1/600 µm⁻¹ rather than from zero; the example's Euler bends start from zero, the standard Euler bend of all four tools. Their effective radius comes out at 30.0 µm instead of the paper's 29 µm. The gap is 260 nm at the apex and closes to 255 nm at the ends of the 20° coupler, since the Euler bend straightens out away from its apex while the access arc stays circular.

References

  • Q. Xu, D. Fattal and R. G. Beausoleil, "Silicon microring resonators with 1.5-µm radius," Optics Express 16(6), 4309–4315 (2008). doi:10.1364/OE.16.004309
  • L. Zhang et al., "Ultrahigh-Q silicon racetrack resonators," Photonics Research 8(5), 684–689 (2020). doi:10.1364/PRJ.387816

Parameters

ParameterValueSource
Ring radius (to the waveguide center)1.5 µmXu 2008
Ring and bus width450 nm and 250 nmXu 2008
Gap340 nmXu 2008
Racetrack width1.6 µmZhang 2020
Straight sections260 µmZhang 2020
Bends180° Euler bends, minimum radius 15 µm at the apexZhang 2020 (curvature starting from zero instead of 1/600 µm⁻¹)
Coupler600 nm access waveguide, 260 nm gap at the apex, radius 16.36 µmZhang 2020 (width derived from the concentric radius)
Coupler angle, leads20°, 10 µmassumed

How it is written

The racetrack is four shapes chained by their anchors: a straight path, an euler bend placed on its end, and clones of both placed on the bend's end and on the second straight's end. The access waveguide starts at a point computed from the bend's right_center anchor (its apex); a loop over the two sides places two arcs and a lead, the first one turned by rotate side * 90deg. gdsfactory's version builds the same chain by adding gf.path segments and extruding them, which is about as short; gdstk and KLayout compute the racetrack's centerline with the Euler helper of the waveguides example.

Implementations

ImplementationLines of codeTokensLayout
Laylight34316reference
gdsfactory36 (1.06×)344 (1.09×)same within 3 nm
gdstk39 (1.15×)468 (1.48×)same within 2 nm
KLayout48 (1.41×)596 (1.89×)same within 3 nm
laylight/microring.lyl
import "tech.lyl"

# An all-pass microring of 1.5 um radius whose bus is narrower than the ring
# for phase matching, after Xu et al., Opt. Express 2008 (bus length assumed).
# The radius is that of the waveguide's center.
cell AllPassRing(
    radius = 1.5um, width = 450nm, bus_width = 250nm, gap = 340nm, bus_length = 10um
) {
    layer si {
        shape rect with bus_length, bus_width as bus at self.origin
        shape ring with radius, width as ring
        place ring at bus.top_center offset (0, gap + width / 2 + radius)
    }
}

# A racetrack of multimode waveguides whose 180 deg bends are Euler bends,
# their curvature growing from 0 at the straights to 1 / radius at the apex,
# with a pulley coupler concentric with one apex, after Zhang et al., Photonics
# Res. 2020. The coupler angle and the leads are assumed.
cell EulerRacetrack(
    radius = 15um,  # smallest bend radius, at the apex
    width = 1.6um,
    length = 260um,  # straight sections
    gap = 260nm,  # at the apex
    access_width = 600nm,
    coupler_angle = 20deg,
    lead_length = 10um,
) {
    layer si {
        shape path with [(0, 0), (length, 0)], width as bottom.start at self.origin
        clone bottom as top.start at right.end
        shape euler with {
            min_radius = radius, width = width, angle = 180deg, p = 1
        } as right.start at bottom.end
        clone right as left.start at top.end

        # The access waveguide is concentric with the apex of the right bend
        # and turns back to vertical on either side of it.
        define apex = right.right_center + (gap + access_width / 2, 0)
        define r = radius + width / 2 + gap + access_width / 2
        for side in [1, -1] {
            shape arc with r, access_width, side * coupler_angle / 2 as half
            place half.start at apex rotate side * 90deg
            shape arc with r, access_width, -side * coupler_angle / 2 as bend
            place bend.start at half.end
            shape path with [(0, 0), (lead_length, 0)], access_width as lead
            place lead.start at bend.end
        }
    }
}

# The two resonators side by side.
cell Microrings {
    place AllPassRing at (-50um, 0)
    place EulerRacetrack at self.origin
}
gdsfactory/microring.py
"""A circular microring and an Euler-bend racetrack, as laylight/microring.lyl."""

import gdsfactory as gf

from tech import SI


@gf.cell
def all_pass_ring(radius=1.5, width=0.45, bus_width=0.25, gap=0.34, bus_length=10):
    """An all-pass microring of 1.5 um radius whose bus is narrower than the
    ring for phase matching, after Xu et al., Opt. Express 2008 (bus length
    assumed)."""
    c = gf.Component()
    c << gf.components.rectangle((bus_length, bus_width), SI, centered=True)
    ring = c << gf.components.ring(radius, width, layer=SI)
    ring.dmove((0, bus_width / 2 + gap + width / 2 + radius))
    return c


@gf.cell
def euler_racetrack(
    radius=15,
    width=1.6,
    length=260,
    gap=0.26,
    access_width=0.6,
    coupler_angle=20,
    lead_length=10,
):
    """A racetrack of multimode waveguides whose 180 deg bends are Euler bends,
    their curvature growing from 0 at the straights to 1 / radius at the apex,
    with a pulley coupler concentric with one apex, after Zhang et al.,
    Photonics Res. 2020. The coupler angle and the leads are assumed."""
    c = gf.Component()
    half = gf.path.straight(length) + gf.path.euler(radius, 180, p=1)
    track = c << (half + half).extrude(width=width, layer=SI)
    # The access waveguide is concentric with the apex of the right bend and
    # turns back to vertical on either side of it.
    apex = (track.dxmax + gap + access_width / 2, track.dy)
    r = radius + width / 2 + gap + access_width / 2
    for side in [1, -1]:
        a = side * coupler_angle / 2
        access = gf.path.arc(r, a) + gf.path.arc(r, -a) + gf.path.straight(lead_length)
        ref = c << access.extrude(width=access_width, layer=SI)
        ref.drotate(90 * side)
        ref.dmove(apex)
    return c


@gf.cell
def microrings():
    """The two resonators side by side."""
    c = gf.Component()
    (c << all_pass_ring()).dmove((-50, 0))
    c << euler_racetrack()
    return c


if __name__ == "__main__":
    import sys

    microrings().write_gds(sys.argv[1])
gdstk/microring.py
"""A circular microring and an Euler-bend racetrack, as laylight/microring.lyl."""

import gdstk
import numpy as np

from tech import SI
from waveguides import euler


def all_pass_ring(radius=1.5, width=0.45, bus_width=0.25, gap=0.34, bus_length=10):
    """An all-pass microring of 1.5 um radius whose bus is narrower than the
    ring for phase matching, after Xu et al., Opt. Express 2008 (bus length
    assumed)."""
    cell = gdstk.Cell("AllPassRing")
    x, y = bus_length / 2, bus_width / 2
    cell.add(gdstk.rectangle((-x, -y), (x, y), **SI))
    center = (0, y + gap + width / 2 + radius)
    r1, r2 = radius - width / 2, radius + width / 2
    cell.add(gdstk.ellipse(center, r2, inner_radius=r1, tolerance=1e-3, **SI))
    return cell


def euler_racetrack(
    radius=15,
    width=1.6,
    length=260,
    gap=0.26,
    access_width=0.6,
    coupler_angle=20,
    lead_length=10,
):
    """A racetrack of multimode waveguides whose 180 deg bends are Euler bends,
    their curvature growing from 0 at the straights to 1 / radius at the apex,
    with a pulley coupler concentric with one apex, after Zhang et al.,
    Photonics Res. 2020. The coupler angle and the leads are assumed."""
    cell = gdstk.Cell("EulerRacetrack")
    bend = euler(radius, 180, p=1) + (length, 0)
    height = bend[-1, 1]
    # The closed loop: the right bend, the left bend and back to the start.
    track = np.vstack([bend, (length, height) - bend, [(length, 0)]])
    cell.add(gdstk.FlexPath(track, width, tolerance=1e-3, **SI))
    # The access waveguide runs up past the right bend: a reverse bend, an arc
    # concentric with the apex of the bend and another reverse bend.
    r = radius + width / 2 + gap + access_width / 2
    a = np.radians(coupler_angle / 2)
    x = bend[:, 0].max() - radius + r * (2 * np.cos(a) - 1)
    y = height / 2 - 2 * r * np.sin(a) - lead_length
    access = gdstk.FlexPath((x, y), access_width, tolerance=1e-3, **SI)
    access.segment((0, lead_length), relative=True).arc(r, np.pi, np.pi - a)
    access.arc(r, -a, a).arc(r, np.pi + a, np.pi)
    cell.add(access.segment((0, lead_length), relative=True))
    return cell


def microrings():
    """The two resonators side by side."""
    cell = gdstk.Cell("Microrings")
    cell.add(gdstk.Reference(all_pass_ring(), (-50, 0)))
    cell.add(gdstk.Reference(euler_racetrack()))
    return cell


if __name__ == "__main__":
    import sys

    top = microrings()
    lib = gdstk.Library()
    lib.add(top, *top.dependencies(True))
    lib.write_gds(sys.argv[1])
klayout/microring.py
"""A circular microring and an Euler-bend racetrack, as laylight/microring.lyl."""

import klayout.db as kdb
import numpy as np

from tech import SI, layout
from waveguides import euler, path, polygon


def arc(x, y, radius, a1, a2, n=500):
    """Points of a circular arc around (x, y) from angle a1 to a2 (radians)."""
    a = np.linspace(a1, a2, n)
    return np.column_stack([x + radius * np.cos(a), y + radius * np.sin(a)])


def all_pass_ring(radius=1.5, width=0.45, bus_width=0.25, gap=0.34, bus_length=10):
    """An all-pass microring of 1.5 um radius whose bus is narrower than the
    ring for phase matching, after Xu et al., Opt. Express 2008 (bus length
    assumed)."""
    cell = layout.create_cell("AllPassRing")
    si = cell.shapes(layout.layer(SI))
    x, y = bus_length / 2, bus_width / 2
    si.insert(kdb.DBox(-x, -y, x, y))
    cy = y + gap + width / 2 + radius
    ring = polygon(arc(0, cy, radius + width / 2, 0, 2 * np.pi))
    hole = arc(0, cy, radius - width / 2, 0, 2 * np.pi)
    ring.insert_hole([kdb.DPoint(*p) for p in hole])
    si.insert(ring)
    return cell


def euler_racetrack(
    radius=15,
    width=1.6,
    length=260,
    gap=0.26,
    access_width=0.6,
    coupler_angle=20,
    lead_length=10,
):
    """A racetrack of multimode waveguides whose 180 deg bends are Euler bends,
    their curvature growing from 0 at the straights to 1 / radius at the apex,
    with a pulley coupler concentric with one apex, after Zhang et al.,
    Photonics Res. 2020. The coupler angle and the leads are assumed."""
    cell = layout.create_cell("EulerRacetrack")
    si = cell.shapes(layout.layer(SI))
    bend = euler(radius, 180, p=1) + (length, 0)
    height = bend[-1, 1]
    # The closed loop: the right bend, the left bend and back to the start.
    si.insert(path(np.vstack([bend, (length, height) - bend, [(length, 0)]]), width))
    # The access waveguide runs up past the right bend: a reverse bend, an arc
    # concentric with the apex of the bend (around its center of curvature
    # there) and another reverse bend (around centers 2 r further out).
    r = radius + width / 2 + gap + access_width / 2
    a = np.radians(coupler_angle / 2)
    x, y = bend[:, 0].max() - radius, height / 2
    x2, y2 = x + 2 * r * np.cos(a), 2 * r * np.sin(a)
    access = [
        [(x2 - r, y - y2 - lead_length)],
        arc(x2, y - y2, r, np.pi, np.pi - a),
        arc(x, y, r, -a, a),
        arc(x2, y + y2, r, np.pi + a, np.pi),
        [(x2 - r, y + y2 + lead_length)],
    ]
    si.insert(path(np.vstack(access), access_width))
    return cell


def microrings():
    """The two resonators side by side."""
    cell = layout.create_cell("Microrings")
    for child, x in [(all_pass_ring(), -50), (euler_racetrack(), 0)]:
        cell.insert(kdb.DCellInstArray(child.cell_index(), kdb.DCplxTrans(x, 0)))
    return cell


if __name__ == "__main__":
    import sys

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

On this page