Ejemplo n.º 1
0
def litho_calipers(
    notch_size: List[int] = [2, 5],
    notch_spacing: int = 2,
    num_notches: int = 11,
    offset_per_notch: float = 0.1,
    row_spacing: int = 0,
    layer_top: int = 1,
    layer_bottom: int = 2,
) -> Component:
    """ vernier caliper structure to test lithography alignment
    Only the middle finger is aligned and the rest are offset.

    Args:
        notch_size: [xwidth, yheight]
        notch_spacing: 2
        num_notches: 11
        offset_per_notch: 0.1
        row_spacing: 0
        layer_top: 1
        layer_bottom:2

    .. plot::
      :include-source:

      import pp

      c = pp.c.litho_calipers()
      pp.plotgds(c)
    """

    D = pp.Component()
    num_notches_total = num_notches * 2 + 1
    centre_notch = num_notches
    R1 = pc.rectangle(size=(notch_size), layer=layer_top)
    R2 = pc.rectangle(size=(notch_size), layer=layer_bottom)
    for i in range(num_notches_total):
        if i == centre_notch:
            D.add_ref(R1).movex(i * (notch_size[0] + notch_spacing)).movey(
                notch_size[1])
            D.add_ref(R2).movex(i * (notch_size[0] + notch_spacing) +
                                offset_per_notch *
                                (centre_notch - i)).movey(-2 * notch_size[1] -
                                                          row_spacing)
        D.add_ref(R1).movex(i * (notch_size[0] + notch_spacing))
        D.add_ref(R2).movex(i * (notch_size[0] + notch_spacing) +
                            offset_per_notch *
                            (centre_notch - i)).movey(-notch_size[1] -
                                                      row_spacing)

    return D
Ejemplo n.º 2
0
def litho_steps(
    line_widths: List[float] = (1.0, 2.0, 4.0, 8.0, 16.0),
    line_spacing: float = 10.0,
    height: float = 100.0,
    layer: Tuple[int, int] = pp.LAYER.WG,
) -> Component:
    """ Produces a positive + negative tone linewidth test, used for
    lithography resolution test patterning

    Args:
        line_widths:
        line_spacing:
        height:
        layer:

    .. plot::
      :include-source:

      import pp

      c = pp.c.litho_steps()
      pp.plotgds(c)

    """
    D = pp.Component()

    height = height / 2
    T1 = pc.text(text="%s" % str(line_widths[-1]),
                 size=height,
                 justify="center",
                 layer=layer)
    D.add_ref(T1).rotate(90).movex(-height / 10)
    R1 = pc.rectangle(size=(line_spacing, height), layer=layer)
    D.add_ref(R1).movey(-height)
    count = 0
    for i in reversed(line_widths):
        count += line_spacing + i
        R2 = pc.rectangle(size=(i, height), layer=layer)
        D.add_ref(R1).movex(count).movey(-height)
        D.add_ref(R2).movex(count - i)

    return D
Ejemplo n.º 3
0
def litho_star(num_lines=20, line_width=2, diameter=200, layer=0):
    """ Creates a circular-star shape from lines, used as a lithographic
    resolution test pattern

    .. plot::
      :include-source:

      import pp

      c = pp.c.litho_star()
      pp.plotgds(c)
    """
    D = pp.Component()

    degree = 180 / num_lines
    R1 = rectangle(size=(line_width, diameter), layer=layer)
    for i in range(num_lines):
        r1 = D.add_ref(R1).rotate(degree * i)
        r1.center = (0, 0)

    return D
Ejemplo n.º 4
0
def test_resistance(
    pad_size=[50, 50],
    num_squares=1000,
    width=1,
    res_layer=0,
    pad_layer=None,
    gnd_layer=None,
):

    """ meander to test resistance
    from phidl.geometry

    Args:
        pad_size: Size of the two matched impedance pads (microns)
        num_squares: Number of squares comprising the resonator wire
        width: The width of the squares (microns)
        res_layer:
        pad_layer:
        gnd_layer:

    .. plot::
      :include-source:

      import pp

      c = pp.c.test_resistance()
      pp.plotgds(c)

    """

    x = pad_size[0]
    z = pad_size[1]

    # Checking validity of input
    if x <= 0 or z <= 0:
        raise ValueError("Pad must have positive, real dimensions")
    elif width > z:
        raise ValueError("Width of cell cannot be greater than height of pad")
    elif num_squares <= 0:
        raise ValueError("Number of squares must be a positive real number")
    elif width <= 0:
        raise ValueError("Width of cell must be a positive real number")

    # Performing preliminary calculations
    num_rows = int(np.floor(z / (2 * width)))
    if num_rows % 2 == 0:
        num_rows -= 1
    num_columns = num_rows - 1
    squares_in_row = (num_squares - num_columns - 2) / num_rows

    # Compensating for weird edge cases
    if squares_in_row < 1:
        num_rows = round(num_rows / 2) - 2
        squares_in_row = 1
    if width * 2 > z:
        num_rows = 1
        squares_in_row = num_squares - 2

    length_row = squares_in_row * width

    # Creating row/column corner combination structure
    T = pp.Component()
    Row = pc.rectangle(size=(length_row, width), layer=res_layer)
    Col = pc.rectangle(size=(width, width), layer=res_layer)

    T.add_ref(Row)
    col = T.add_ref(Col)
    col.move([length_row - width, -width])

    # Creating entire waveguide net
    N = pp.Component("net")
    n = 1
    for i in range(num_rows):
        if i != num_rows - 1:
            d = N.add_ref(T)
        else:
            d = N.add_ref(Row)
        if n % 2 == 0:
            d.reflect(p1=(d.x, d.ymax), p2=(d.x, d.ymin))
        d.movey(-(n - 1) * T.ysize)
        n += 1
    d = N.add_ref(Col).movex(-width)
    d = N.add_ref(Col).move([length_row, -(n - 2) * T.ysize])

    # Creating pads
    P = pp.Component()
    Pad1 = pc.rectangle(size=(x, z), layer=pad_layer)
    Pad2 = pc.rectangle(size=(x + 5, z), layer=pad_layer)
    Gnd1 = offset(Pad1, distance=-5, layer=gnd_layer)
    Gnd2 = offset(Pad2, distance=-5, layer=gnd_layer)
    pad1 = P.add_ref(Pad1).movex(-x - width)
    pad2 = P.add_ref(Pad1).movex(length_row + width)
    P.add_ref(Gnd1).center = pad1.center
    gnd2 = P.add_ref(Gnd2)
    P.add_ref(N).y = pad1.y
    gnd2.center = pad2.center
    gnd2.movex(2.5)

    return P
Ejemplo n.º 5
0
def test_comb(
    pad_size=(200, 200),
    wire_width=1,
    wire_gap=3,
    comb_layer=0,
    overlap_zigzag_layer=1,
    comb_pad_layer=None,
    comb_gnd_layer=None,
    overlap_pad_layer=None,
):
    """ Superconducting heater device from phidl.geometry

    Args:
        pad_size=(200, 200)
        wire_width=1
        wire_gap=3
        comb_layer=0
        overlap_zigzag_layer=1
        comb_pad_layer=None
        comb_gnd_layer=None
        overlap_pad_layer=None

    """
    CI = pp.Component()

    if comb_pad_layer is None:
        comb_pad_layer = comb_layer
    if comb_gnd_layer is None:
        comb_gnd_layer = comb_layer
    if overlap_pad_layer is None:
        overlap_pad_layer = overlap_zigzag_layer
    wire_spacing = wire_width + wire_gap * 2

    # %% pad overlays
    overlay_padb = CI.add_ref(
        pc.rectangle(size=(pad_size[0] * 9 / 10, pad_size[1] * 9 / 10),
                     layer=overlap_pad_layer))
    overlay_padl = CI.add_ref(
        pc.rectangle(size=(pad_size[0] * 9 / 10, pad_size[1] * 9 / 10),
                     layer=comb_pad_layer))
    overlay_padt = CI.add_ref(
        pc.rectangle(size=(pad_size[0] * 9 / 10, pad_size[1] * 9 / 10),
                     layer=comb_pad_layer))
    overlay_padr = CI.add_ref(
        pc.rectangle(size=(pad_size[0] * 9 / 10, pad_size[1] * 9 / 10),
                     layer=comb_gnd_layer))

    overlay_padl.xmin = 0
    overlay_padl.ymin = 0
    overlay_padb.ymax = 0
    overlay_padb.xmin = overlay_padl.xmax + pad_size[1] / 5
    overlay_padr.ymin = overlay_padl.ymin
    overlay_padr.xmin = overlay_padb.xmax + pad_size[1] / 5
    overlay_padt.xmin = overlay_padl.xmax + pad_size[1] / 5
    overlay_padt.ymin = overlay_padl.ymax

    # %% pads
    padl = CI.add_ref(pc.rectangle(size=pad_size, layer=comb_layer))
    padt = CI.add_ref(pc.rectangle(size=pad_size, layer=comb_layer))
    padr = CI.add_ref(pc.rectangle(size=pad_size, layer=comb_layer))
    padb = CI.add_ref(pc.rectangle(size=pad_size, layer=overlap_zigzag_layer))
    padl_nub = CI.add_ref(
        pc.rectangle(size=(pad_size[0] / 4, pad_size[1] / 2),
                     layer=comb_layer))
    padr_nub = CI.add_ref(
        pc.rectangle(size=(pad_size[0] / 4, pad_size[1] / 2),
                     layer=comb_layer))

    padl.xmin = overlay_padl.xmin
    padl.center = [padl.center[0], overlay_padl.center[1]]
    padt.ymax = overlay_padt.ymax
    padt.center = [overlay_padt.center[0], padt.center[1]]
    padr.xmax = overlay_padr.xmax
    padr.center = [padr.center[0], overlay_padr.center[1]]
    padb.ymin = overlay_padb.ymin
    padb.center = [overlay_padb.center[0], padb.center[1]]
    padl_nub.xmin = padl.xmax
    padl_nub.center = [padl_nub.center[0], padl.center[1]]
    padr_nub.xmax = padr.xmin
    padr_nub.center = [padr_nub.center[0], padr.center[1]]

    # %% connected zig

    head = CI.add_ref(
        pc.compass(size=(pad_size[0] / 12, wire_width), layer=comb_layer))
    head.xmin = padl_nub.xmax
    head.ymax = padl_nub.ymax
    connector = CI.add_ref(
        pc.compass(size=(wire_width, wire_width), layer=comb_layer))
    connector.connect(port="W", destination=head.ports["E"])
    old_port = connector.ports["S"]
    top = True
    obj = connector
    while obj.xmax + pad_size[0] / 12 < padr_nub.xmin:
        # long zig zag rectangle
        obj = CI.add_ref(
            pc.compass(size=(pad_size[1] / 2 - 2 * wire_width, wire_width),
                       layer=comb_layer))
        obj.connect(port="W", destination=old_port)
        old_port = obj.ports["E"]
        if top:
            # zig zag edge rectangle
            obj = CI.add_ref(
                pc.compass(size=(wire_width, wire_width), layer=comb_layer))
            obj.connect(port="N", destination=old_port)
            top = False
        else:
            # zig zag edge rectangle
            obj = CI.add_ref(
                pc.compass(size=(wire_width, wire_width), layer=comb_layer))
            obj.connect(port="S", destination=old_port)
            top = True
            # comb rectange
            comb = CI.add_ref(
                pc.rectangle(
                    size=(
                        (padt.ymin - head.ymax) + pad_size[1] / 2 -
                        (wire_spacing + wire_width) / 2,
                        wire_width,
                    ),
                    layer=comb_layer,
                ))
            comb.rotate(90)
            comb.ymax = padt.ymin
            comb.xmax = obj.xmax - (wire_spacing + wire_width) / 2
        old_port = obj.ports["E"]
        obj = CI.add_ref(
            pc.compass(size=(wire_spacing, wire_width), layer=comb_layer))
        obj.connect(port="W", destination=old_port)
        old_port = obj.ports["E"]
        obj = CI.add_ref(
            pc.compass(size=(wire_width, wire_width), layer=comb_layer))
        obj.connect(port="W", destination=old_port)
        if top:
            old_port = obj.ports["S"]
        else:
            old_port = obj.ports["N"]
    old_port = obj.ports["E"]
    if padr_nub.xmin - obj.xmax > 0:
        tail = CI.add_ref(
            pc.compass(size=(padr_nub.xmin - obj.xmax, wire_width),
                       layer=comb_layer))
    else:
        tail = CI.add_ref(
            pc.compass(size=(wire_width, wire_width), layer=comb_layer))
    tail.connect(port="W", destination=old_port)

    # %% disconnected zig

    dhead = CI.add_ref(
        pc.compass(
            size=(padr_nub.ymin - padb.ymax - wire_width, wire_width),
            layer=overlap_zigzag_layer,
        ))
    dhead.rotate(90)
    dhead.ymin = padb.ymax
    dhead.xmax = tail.xmin - (wire_spacing + wire_width) / 2
    connector = CI.add_ref(
        pc.compass(size=(wire_width, wire_width), layer=overlap_zigzag_layer))
    connector.connect(port="S", destination=dhead.ports["E"])
    old_port = connector.ports["N"]
    right = True
    obj = connector
    while obj.ymax + wire_spacing + wire_width < head.ymax:
        obj = CI.add_ref(
            pc.compass(size=(wire_spacing, wire_width),
                       layer=overlap_zigzag_layer))
        obj.connect(port="W", destination=old_port)
        old_port = obj.ports["E"]
        if right:
            obj = CI.add_ref(
                pc.compass(size=(wire_width, wire_width),
                           layer=overlap_zigzag_layer))
            obj.connect(port="W", destination=old_port)
            right = False
        else:
            obj = CI.add_ref(
                pc.compass(size=(wire_width, wire_width),
                           layer=overlap_zigzag_layer))
            obj.connect(port="E", destination=old_port)
            right = True
        old_port = obj.ports["N"]
        obj = CI.add_ref(
            pc.compass(
                size=(
                    dhead.xmin - (head.xmax + head.xmin + wire_width) / 2,
                    wire_width,
                ),
                layer=overlap_zigzag_layer,
            ))
        obj.connect(port="E", destination=old_port)
        old_port = obj.ports["W"]
        obj = CI.add_ref(
            pc.compass(size=(wire_width, wire_width),
                       layer=overlap_zigzag_layer))
        obj.connect(port="S", destination=old_port)
        if right:
            old_port = obj.ports["W"]
        else:
            old_port = obj.ports["E"]

    return CI
Ejemplo n.º 6
0
def test_via(
    num_vias=100,
    wire_width=10,
    via_width=15,
    via_spacing=40,
    pad_size=(300, 300),
    min_pad_spacing=0,
    pad_layer=0,
    wiring1_layer=1,
    wiring2_layer=2,
    via_layer=3,
):
    """ Via cutback to extract via resistance
    from phidl.geometry

    Args:
        num_vias=100
        wire_width=10
        via_width=15
        via_spacing=40
        pad_size=(300, 300)
        min_pad_spacing=0
        pad_layer=0
        wiring1_layer=1
        wiring2_layer=2
        via_layer=3

    Usage:
        Call via_route_test_structure() by indicating the number of vias you want drawn. You can also change the other parameters however
        if you do not specifiy a value for a parameter it will just use the default value
        Ex::

            via_route_test_structure(num_vias=54)

        - or -::

            via_route_test_structure(num_vias=12, pad_size=(100,100),wire_width=8)

        total requested vias (num_vias) -> this needs to be even
        pad size (pad_size) -> given in a pair (width, height)
        wire_width -> how wide each wire should be
        pad_layer -> GDS layer number of the pads
        wiring1_layer -> GDS layer number of the top wiring
        wiring2_layer -> GDS layer number of the bottom wiring
        via_layer -> GDS layer number of the vias
        ex: via_route(54, min_pad_spacing=300)

    .. plot::
      :include-source:

      import pp

      c = pp.c.test_via()
      pp.plotgds(c)
    """

    VR = pp.Component()
    pad1 = VR.add_ref(pc.rectangle(size=pad_size, layer=pad_layer))
    pad1_overlay = VR.add_ref(pc.rectangle(size=pad_size, layer=wiring1_layer))
    pad2 = VR.add_ref(pc.rectangle(size=pad_size, layer=pad_layer))
    pad2_overlay = VR.add_ref(pc.rectangle(size=pad_size, layer=wiring1_layer))
    nub = VR.add_ref(
        pc.compass(size=(3 * wire_width, wire_width), layer=pad_layer))
    nub_overlay = VR.add_ref(
        pc.compass(size=(3 * wire_width, wire_width), layer=wiring1_layer))
    head = VR.add_ref(
        pc.compass(size=(wire_width, wire_width), layer=pad_layer))
    head_overlay = VR.add_ref(
        pc.compass(size=(wire_width, wire_width), layer=wiring1_layer))
    nub.ymax = pad1.ymax - 5
    nub.xmin = pad1.xmax
    nub_overlay.ymax = pad1.ymax - 5
    nub_overlay.xmin = pad1.xmax
    head.connect(port="W", destination=nub.ports["E"])
    head_overlay.connect(port="W", destination=nub_overlay.ports["E"])
    pad1_overlay.xmin = pad1.xmin
    pad1_overlay.ymin = pad1.ymin

    old_port = head.ports["S"]
    count = 0
    width_via_iter = 2 * via_spacing - 2 * wire_width

    pad2.xmin = pad1.xmax + min_pad_spacing
    up = False
    down = True
    edge = True
    current_width = 3 * wire_width + wire_width  # width of nub and 1 overlap
    obj_old = head
    obj = head
    via_iterable = _via_iterable(
        via_spacing=via_spacing,
        wire_width=wire_width,
        wiring1_layer=wiring1_layer,
        wiring2_layer=wiring2_layer,
        via_layer=via_layer,
        via_width=via_width,
    )
    while (count + 2) <= num_vias:
        obj = VR.add_ref(via_iterable)
        obj.connect(port="W", destination=old_port, overlap=wire_width)
        old_port = obj.ports["E"]
        edge = False
        if obj.ymax > pad1.ymax:
            obj.connect(port="W",
                        destination=obj_old.ports["S"],
                        overlap=wire_width)
            old_port = obj.ports["S"]
            current_width += width_via_iter
            down = True
            up = False
            edge = True

        elif obj.ymin < pad1.ymin:
            obj.connect(port="W",
                        destination=obj_old.ports["N"],
                        overlap=wire_width)
            old_port = obj.ports["N"]
            current_width += width_via_iter
            up = True
            down = False
            edge = True
        count = count + 2
        obj_old = obj

    if (current_width < min_pad_spacing
            and (min_pad_spacing - current_width) > 3 * wire_width):
        tail = VR.add_ref(
            pc.compass(
                size=(min_pad_spacing - current_width + wire_width,
                      wire_width),
                layer=wiring1_layer,
            ))
        tail_overlay = VR.add_ref(
            pc.compass(
                size=(min_pad_spacing - current_width + wire_width,
                      wire_width),
                layer=pad_layer,
            ))
    else:
        tail = VR.add_ref(
            pc.compass(size=(3 * wire_width, wire_width), layer=wiring1_layer))
        tail_overlay = VR.add_ref(
            pc.compass(size=(3 * wire_width, wire_width), layer=wiring1_layer))

    if up == True and edge != True:
        tail.connect(port="W", destination=obj.ports["S"], overlap=wire_width)
        tail_overlay.connect(port="W",
                             destination=obj.ports["S"],
                             overlap=wire_width)
    elif down == True and edge != True:
        tail.connect(port="W", destination=obj.ports["N"], overlap=wire_width)
        tail_overlay.connect(port="W",
                             destination=obj.ports["N"],
                             overlap=wire_width)
    else:
        tail.connect(port="W", destination=obj.ports["E"], overlap=wire_width)
        tail_overlay.connect(port="W",
                             destination=obj.ports["E"],
                             overlap=wire_width)

    pad2.xmin = tail.xmax
    pad2_overlay.xmin = pad2.xmin
    pad2_overlay.ymin = pad2.ymin

    return VR