Exemple #1
0
def coupler90(
    bend_radius=10.0,
    width=0.5,
    gap=0.2,
    waveguide_factory=waveguide,
    bend90_factory=bend_circular,
):
    """ Waveguide coupled to a bend with gap

    Args:
        bend_radius: um
        width: waveguide width (um)
        gap: um

    .. plot::
      :include-source:

      import pp
      c = pp.c.coupler90()
      pp.plotgds(c)

    """
    y = width + gap
    _bend = bend90_factory(radius=bend_radius, width=width).ref((0, y))
    c = Component()

    _wg = c.add_ref(waveguide_factory(length=bend_radius, width=width))
    c.add(_bend)

    # This component is a leaf cell => using absorb
    c.absorb(_wg)
    c.absorb(_bend)

    port_width = 2 * width + gap

    c.add_port(port=_wg.ports["E0"], name="E0")
    c.add_port(port=_bend.ports["N0"], name="N0")
    c.add_port(name="W0", midpoint=[0, y / 2], width=port_width, orientation=180)
    c.y = y
    return c
Exemple #2
0
def coupler_straight(
        length=10,
        width=0.5,
        gap=0.27,
        layer=pp.LAYER.WG,
        layer_cladding=pp.layer("wgclad"),
        cladding_offset=3,
):
    """ straight coupled waveguides. Two multimode ports

    .. plot::
      :include-source:

      import pp

      c = pp.c.coupler_straight()
      pp.plotgds(c)

    """

    c = Component()

    # Top path
    c.add_polygon([(0, 0), (length, 0), (length, width), (0, width)],
                  layer=layer)
    y = width + gap

    # Bottom path
    c.add_polygon([(0, y), (length, y), (length, width + y), (0, width + y)],
                  layer=layer)

    # One multimode port on each side
    port_w = width * 2 + gap

    c.add_port(name="W0",
               midpoint=[0, port_w / 2],
               width=port_w,
               orientation=180)
    c.add_port(name="E0",
               midpoint=[length, port_w / 2],
               width=port_w,
               orientation=0)

    c.width = width
    c.length = length

    # cladding
    ymax = 2 * width + gap + cladding_offset
    c.add_polygon(
        [(0, -cladding_offset), (length, -cladding_offset), (length, ymax),
         (0, ymax)],
        layer=layer_cladding,
    )

    return c
def waveguide_heater(
    length=10.0,
    width=0.5,
    heater_width=0.5,
    heater_spacing=1.2,
    metal_connection=True,
    sstw=2.0,
    trench_width=0.5,
    trench_keep_out=2.0,
    trenches=[
        {
            "nb_segments": 2,
            "lane": 1,
            "x_start_offset": 0
        },
        {
            "nb_segments": 2,
            "lane": -1,
            "x_start_offset": 0
        },
    ],
    layers_heater=[LAYER.HEATER],
    waveguide_factory=waveguide,
    layer_trench=LAYER.DEEPTRENCH,
):
    """ waveguide with heater

    .. code::
    
        TTTTTTTTTTTTT    TTTTTTTTTTTTT <-- trench
        
        HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH <-- heater
        
        ------------------------------ <-- waveguide

        HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH <-- heater
        
        TTTTTTTTTTTTT    TTTTTTTTTTTTT <-- trench

    .. plot::
      :include-source:

      import pp

      c = pp.c.waveguide_heater()
      pp.plotgds(c)
    
    """
    c = Component()

    _heater = heater(length=length,
                     width=heater_width,
                     layers_heater=layers_heater)

    y_heater = heater_spacing + (width + heater_width) / 2
    heater_top = c << _heater
    heater_bot = c << _heater

    heater_top.movey(+y_heater)
    heater_bot.movey(-y_heater)

    wg = c << waveguide_factory(length=length, width=width)

    for i in [heater_top, heater_bot, wg]:
        c.absorb(i)

    # Add wg ports
    for p in wg.ports.values():
        c.add_port(name=p.name, port=p)

    # Add heater ports
    for p in heater_top.ports.values():
        c.add_port(name="HT" + p.name, port=p)

    for p in heater_bot.ports.values():
        c.add_port(name="HB" + p.name, port=p)

    c.settings["width"] = width
    c.settings["heater_width"] = heater_width
    c.settings["heater_spacing"] = heater_spacing
    c.settings["length"] = length
    add_trenches(c,
                 sstw,
                 trench_width,
                 trench_keep_out,
                 trenches,
                 layer_trench=layer_trench)

    return c
def wg_heater_connected(
    waveguide_heater=waveguide_heater,
    wg_heater_connector=wg_heater_connector,
    tlm_layers=[
        LAYER.VIA1, LAYER.M1, LAYER.VIA2, LAYER.M2, LAYER.VIA3, LAYER.M3
    ],
    **kwargs,
):
    """
    .. plot::
      :include-source:

      import pp

      c = pp.c.wg_heater_connected()
      pp.plotgds(c)

    """
    wg_heater = waveguide_heater(**kwargs)
    conn1 = wg_heater_connector(
        heater_ports=[wg_heater.ports["E0"], wg_heater.ports["E2"]],
        tlm_layers=tlm_layers,
    )

    conn2 = wg_heater_connector(
        heater_ports=[wg_heater.ports["W0"], wg_heater.ports["W2"]],
        tlm_layers=tlm_layers,
    )

    cmp = Component()
    for c in [wg_heater, conn1, conn2]:
        _c = cmp.add_ref(c)
        cmp.absorb(_c)

    for i, p in enumerate(wg_heater.get_optical_ports()):
        cmp.add_port(name=i, port=p)

    i += 1
    cmp.add_port(name=i, port=conn1.ports["0"])
    i += 1
    cmp.add_port(name=i, port=conn2.ports["0"])

    return cmp
def wg_heater_connector(
    heater_ports,
    metal_width=10.0,
    tlm_layers=[
        LAYER.VIA1, LAYER.M1, LAYER.VIA2, LAYER.M2, LAYER.VIA3, LAYER.M3
    ],
):
    """
    Connects together a pair of wg heaters and connect to a M3 port
    """

    cmp = Component()
    assert len(heater_ports) == 2
    assert (heater_ports[0].orientation == heater_ports[1].orientation
            ), "both ports should be facing in the same direction"
    angle = heater_ports[0].orientation
    angle = angle % 360
    assert angle in [0, 180], "angle should be 0 or 180, got {}".format(angle)

    dx = 0.0
    dy = 0.0

    angle_to_dps = {0: [(-dx, -dy), (-dx, dy)], 180: [(dx, -dy), (dx, dy)]}
    ports = heater_ports
    hw = heater_ports[0].width

    if angle in [0, 180]:
        ports.sort(key=lambda p: p.y)
    else:
        ports.sort(key=lambda p: p.x)

    _heater_to_metal = tlm(width=0.5, height=0.5, layers=tlm_layers, vias=[])

    tlm_positions = []
    for port, dp in zip(ports, angle_to_dps[angle]):
        # Extend heater
        p = port.midpoint

        # Add via/metal transitions
        tlm_pos = p + dp
        hm = _heater_to_metal.ref(position=tlm_pos)
        tlm_positions += [tlm_pos]
        cmp.add(hm)

    ss = 1 if angle == 0 else -1

    # Connect both sides with top metal
    edge_metal_piece_width = 7.0
    x = ss * edge_metal_piece_width / 2
    top_metal_layer = tlm_layers[-1]
    cmp.add_polygon(
        line(
            tlm_positions[0] + (x, -hw / 2),
            tlm_positions[1] + (x, hw / 2),
            edge_metal_piece_width,
        ),
        layer=top_metal_layer,
    )

    # Add metal port
    cmp.add_port(
        name="0",
        midpoint=0.5 * sum(tlm_positions) +
        (ss * edge_metal_piece_width / 2, 0),
        orientation=angle,
        width=metal_width,
        layer=top_metal_layer,
        port_type="dc",
    )

    return cmp
def coupler90(
    bend_radius=10.0,
    width=0.5,
    gap=0.2,
    waveguide_factory=waveguide,
    bend90_factory=bend_circular,
):
    """ Waveguide coupled to a bend with gap

    Args:
        bend_radius: um
        width: waveguide width (um)
        gap: um

    .. plot::
      :include-source:

      import pp
      c = pp.c.coupler90()
      pp.plotgds(c)

    """
    # pp.drc.assert_on_1nm_grid((width + gap) / 2)
    y = pp.drc.snap_to_1nm_grid((width + gap) / 2)

    c = Component()

    wg = c << waveguide_factory(length=bend_radius, width=width)
    bend = c << bend90_factory(radius=bend_radius, width=width)

    pbw = bend.ports["W0"]
    bend.movey(pbw.midpoint[1] + gap + width)

    # This component is a leaf cell => using absorb
    c.absorb(wg)
    c.absorb(bend)

    port_width = 2 * width + gap

    c.add_port(port=wg.ports["E0"], name="E0")
    c.add_port(port=bend.ports["N0"], name="N0")
    c.add_port(name="W0", midpoint=[0, y], width=port_width, orientation=180)
    return c
Exemple #7
0
def _bend_circular_heater(
    radius=10,
    wg_width=0.5,
    theta=-90,
    start_angle=0,
    angle_resolution=2.5,
    heater_to_wg_distance=1.2,
    heater_width=0.5,
):
    """ Creates an arc of arclength ``theta`` starting at angle ``start_angle``

    Args:
        radius
        width: of the waveguide
        theta: arc length
        start_angle:
        angle_resolution
    """
    component = Component()

    wg_bend = bend_circular(
        radius=radius,
        width=wg_width,
        theta=theta,
        start_angle=start_angle,
        angle_resolution=angle_resolution,
        layer=LAYER.WG,
    ).ref((0, 0))

    a = heater_to_wg_distance + wg_width / 2 + heater_width / 2

    heater_outer = bend_circular(
        radius=radius + a,
        width=heater_width,
        theta=theta,
        start_angle=start_angle,
        angle_resolution=angle_resolution,
        layer=LAYER.HEATER,
    ).ref((0, -a))

    heater_inner = bend_circular(
        radius=radius - a,
        width=heater_width,
        theta=theta,
        start_angle=start_angle,
        angle_resolution=angle_resolution,
        layer=LAYER.HEATER,
    ).ref((0, a))

    component.add(wg_bend)
    component.add(heater_outer)
    component.add(heater_inner)

    component.absorb(wg_bend)
    component.absorb(heater_outer)
    component.absorb(heater_inner)

    i = 0

    for device in [wg_bend, heater_outer, heater_inner]:
        for port in device.ports.values():
            component.ports["{}".format(i)] = port
            i += 1

    component.info["length"] = wg_bend.info["length"]
    component.radius = radius
    component.width = wg_width
    return component