Exemplo n.º 1
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] = gf.LAYER.WG,
) -> Component:
    """Produces a positive + negative tone linewidth test, used for
    lithography resolution test patterning
    adapted from phidl

    Args:
        line_widths:
        line_spacing:
        height:
        layer:

    """
    D = gf.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
Exemplo n.º 2
0
def litho_calipers(
        notch_size: Tuple[float, float] = (2.0, 5.0),
        notch_spacing: float = 2.0,
        num_notches: int = 11,
        offset_per_notch: float = 0.1,
        row_spacing: float = 0.0,
        layer1: Tuple[int, int] = (1, 0),
        layer2: Tuple[int, int] = (2, 0),
) -> Component:
    """Vernier caliper structure to test lithography alignment
    Only the middle finger is aligned and the rest are offset.

    adapted from phidl

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

    .. plot::
      :include-source:

      import gdsfactory as gf

      c = gf.components.litho_calipers()
      c.plot()
    """

    D = gf.Component()
    num_notches_total = num_notches * 2 + 1
    centre_notch = num_notches
    R1 = pc.rectangle(size=(notch_size), layer=layer1)
    R2 = pc.rectangle(size=(notch_size), layer=layer2)
    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
Exemplo n.º 3
0
def resistance_meander(
    num_squares: int = 1000,
    width: float = 1.0,
    layer: Tuple[int, int] = LAYER.M3,
    pad: ComponentFactory = pad80,
) -> Component:
    """meander to test resistance
    from phidl.geometry

    FIXME, add pad_pitch

    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)
        layer:
        pad: function for pad

    """
    pad = pad()

    pad_size = pad.info.size
    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 = Component()
    Row = pc.rectangle(size=(length_row, width), layer=layer, port_type=None)
    Col = pc.rectangle(size=(width, width), layer=layer, port_type=None)

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

    # Creating entire straight net
    N = 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 = Component()
    pad1 = P.add_ref(pad)
    pad1.movex(-x - width)
    pad2 = P.add_ref(pad)
    pad2.movex(length_row + width)

    pad1.xmax = 0
    pad2.xmin = z

    net = P.add_ref(N)
    net.y = pad1.y
    P.absorb(net)
    P.absorb(pad1)
    P.absorb(pad2)
    return P
Exemplo n.º 4
0
def resistance_meander(
    pad_size: Tuple[float] = (50.0, 50.0),
    num_squares: int = 1000,
    width: float = 1.0,
    res_layer: Tuple[int, int] = LAYER.M3,
    pad_layer: Tuple[int, int] = LAYER.M3,
    gnd_layer: Tuple[int, int] = LAYER.M3,
) -> Component:
    """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:

    """

    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 = 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 straight net
    N = 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 = 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_ref = P.add_ref(pad1)
    pad1_ref.movex(-x - width)
    pad2_ref = P.add_ref(pad1)
    pad2_ref.movex(length_row + width)
    gnd1_ref = P.add_ref(gnd1)
    gnd1_ref.center = pad1_ref.center
    gnd2_ref = P.add_ref(gnd2)
    net = P.add_ref(N)
    net.y = pad1_ref.y
    gnd2_ref.center = pad2_ref.center
    gnd2_ref.movex(2.5)
    P.absorb(net)
    P.absorb(gnd1_ref)
    P.absorb(gnd2_ref)
    P.absorb(pad1_ref)
    P.absorb(pad2_ref)
    return P