Esempio n. 1
0
def mmi1x2(wg_width=0.35,
           length_port=0.2,
           length_mmi=2.8,
           width_mmi=1.55,
           gap_mmi=0.4):

    D = Device()

    Port_wg = pg.taper(length=length_port,
                       width1=wg_width,
                       width2=wg_width,
                       layer=lys['wg_deep'])
    port_in = D.add_ref(Port_wg)
    MMI = pg.taper(length=length_mmi,
                   width1=width_mmi,
                   width2=width_mmi,
                   layer=lys['wg_deep'])
    mmi = D.add_ref(MMI)

    mmi.connect(port=1, destination=port_in.ports[2])

    port_up = D.add_ref(Port_wg)
    port_up.connect(port=1, destination=mmi.ports[2])
    port_up.movey(gap_mmi)

    port_down = D.add_ref(Port_wg)
    port_down.connect(port=1, destination=mmi.ports[2])
    port_down.movey(-gap_mmi)

    D.add_port(name=1, port=port_in.ports[1])
    D.add_port(name=2, port=port_up.ports[2])
    D.add_port(name=3, port=port_down.ports[2])

    return D
Esempio n. 2
0
def test_port_reference_manipulate():
    D = Device()
    D.add_port(name='test123', midpoint=(5.7, 9.2), orientation=37)
    d = D.add_ref(D).move([1, 1]).rotate(45)
    assert (np.allclose(d.ports['test123'].midpoint,
                        (-2.474873734152916, 11.950104602052654)))
    assert (d.ports['test123'].orientation == 37 + 45)
def poling_region(length=4000,
                  period=5,
                  dutycycle=0.4,
                  gap=25,
                  Lfinger=50,
                  layer=10,
                  pad_width=50):

    #Calculations
    Wfinger = period * dutycycle
    Nfinger = int(length / period) + 1
    length = Nfinger * period - (1 - dutycycle) * period

    P = Device('Poling Electrodes')

    #Positive side
    R = pg.rectangle([length, pad_width], layer=layer)
    F = pg.rectangle([Wfinger, Lfinger], layer=layer)
    P << R
    a = P.add_array(F, columns=Nfinger, rows=1, spacing=(period, 0))
    a.move([0, pad_width])

    #Negative side
    R2 = pg.rectangle([length, pad_width], layer=layer)
    r2 = P.add_ref(R2)
    r2.move([0, pad_width + Lfinger + gap])

    return P
def fang(wg_width, length, orientation):
    F = Device()
    w1 = wg_width
    X1 = CrossSection()
    X1.add(width=w1, offset=0, layer=30, ports=('in', 'out'))

    P = Path()
    P.append(pp.euler(radius=50,
                      angle=45))  # Euler bend (aka "racetrack" curve)
    fang = P.extrude(X1)
    fang = F.add_ref(fang)

    D = pg.taper(length=length,
                 width1=w1,
                 width2=0.000001,
                 port=None,
                 layer=30)
    taper = F.add_ref(D)
    taper.connect(port=1, destination=fang.ports['out'])

    #Defualt is RU, right up
    if orientation == 'RD':
        F.mirror(p1=[0, 0], p2=[1, 0])
    elif orientation == 'LU':
        F.mirror(p1=[0, 0], p2=[0, 1])
    elif orientation == 'LD':
        F.rotate(180, center=[0, 0])

    return F
Esempio n. 5
0
def fibonacci(n, width = 0.008, angle_resolution = 1.5, layer = 0):
	# ---------------------------------------
	# Template that draws a golden spiral
	# n : number of points on the spiral
	# width: width of the spiral
	# ---------------------------------------
	pi = 3.14
	F = Device("spiral")
	start_angle = 0
	dtheta = 360/n
	theta = dtheta
	for i in range(n):
		angle1 = (start_angle)*pi/180
		angle2 = (start_angle + dtheta)*pi/180
		r1 = 0.0053*start_angle
		r2 = 0.0053*(start_angle + dtheta)
		x1 = r1*math.cos(angle1)
		y1 = r1*math.sin(angle1)

		x2 = (r1+width)*math.cos(angle1)
		y2 = (r1+width)*math.sin(angle1)
	
		x3 = (r2+width)*math.cos(angle2)
		y3 = (r2+width)*math.sin(angle2)


		x4 = (r2)*math.cos(angle2)
		y4 = (r2)*math.sin(angle2)


		F.add_polygon([(x1,y1),(x2,y2),(x3,y3),(x4,y4)], layer = layer)
		start_angle += dtheta
	
	return F
Esempio n. 6
0
def give_loopmirror(gap=.5):
    # just an example of augmenting a normal phidl device (loop_mirror_terminator)
    # giving it as a phidl Device as well as port, bounding box, and source things used by MEEP
    D = Device('loopmirror')

    cell = D << pg.rectangle([31, 15], layer=lys['FLOORPLAN'])
    cell.center = (0, 0)

    access = D << pg.compass([8, .35], layer=lys['wg_deep'])
    access.y = cell.y
    access.xmin = cell.xmin

    mmi = mmi1x2(gap_mmi=.5)
    loop = D << loop_mirror_terminator(y_splitter=mmi)
    loop.connect('wg_in_1', access.ports['E'])

    medium_map = get_layer_mapping(lys)

    port = D << pg.rectangle([.1, 1], layer=1)
    source = D << pg.rectangle([.1, 1], layer=2)
    port.y = 0
    source.y = 0
    port.x = loop.xmin - 6
    source.x = loop.xmin - 7

    D.flatten()
    return D
Esempio n. 7
0
def xor_polygons_phidl(A, B, hash_geom=True):
    """ Given two devices A and B, performs a layer-by-layer XOR diff between
    A and B, and returns polygons representing the differences between A and B.
    """
    from phidl import Device
    import gdspy
    # first do a geometry hash to vastly speed up if they are equal
    if hash_geom and (A.hash_geometry() == B.hash_geometry()):
        return Device()

    D = Device()
    A_polys = A.get_polygons(by_spec=True)
    B_polys = B.get_polygons(by_spec=True)
    A_layers = A_polys.keys()
    B_layers = B_polys.keys()
    all_layers = set()
    all_layers.update(A_layers)
    all_layers.update(B_layers)
    for layer in all_layers:
        if (layer in A_layers) and (layer in B_layers):
            p = gdspy.fast_boolean(A_polys[layer],
                                   B_polys[layer],
                                   operation='xor',
                                   precision=0.001,
                                   max_points=4000,
                                   layer=layer[0],
                                   datatype=layer[1])
        elif (layer in A_layers):
            p = A_polys[layer]
        elif (layer in B_layers):
            p = B_polys[layer]
        if p is not None:
            D.add_polygon(p, layer=layer)
    return D
Esempio n. 8
0
    def invert(self, layer, padding=None):
        """Inverts a pattern from positive to negative or vice versa.

        Parameters
        ----------
        layer: string
            Layer of new, inverted device.
        padding: np.array
            Array containing padding of bounding box used to substract device
            [left, right, top, bottom]
        """
        bounding_box = Device('interim_bounding_box')

        if padding is None:
            padding = [0, 0, 0, 0]

        bounding_box.add_polygon(
            [(self.xmin - padding[0], self.ymin - padding[3]),
             (self.xmin - padding[0], self.ymax + padding[2]),
             (self.xmax + padding[1], self.ymax + padding[2]),
             (self.xmax + padding[1], self.ymin - padding[3])],
            layer=layer)

        # perform substraction for positive e-beam resist
        inverse = pg.boolean(A=bounding_box,
                             B=self,
                             operation='A-B',
                             layer=layer)

        return inverse
Esempio n. 9
0
def test_copy_deepcopy():
    D = Device()
    A = pg.ellipse(radii=(10, 5), angle_resolution=2.5, layer=1)
    B = pg.ellipse(radii=(10, 5), angle_resolution=2.5, layer=1)
    a = D << A
    b1 = D << B
    b2 = D << B

    Dcopy = pg.copy(D)
    Ddeepcopy = pg.deepcopy(D)
    h = D.hash_geometry(precision=1e-4)
    assert (h == '0313cd7e58aa265b44dd1ea10265d1088a2f1c6d')
    h = Dcopy.hash_geometry(precision=1e-4)
    assert (h == '0313cd7e58aa265b44dd1ea10265d1088a2f1c6d')
    h = Ddeepcopy.hash_geometry(precision=1e-4)
    assert (h == '0313cd7e58aa265b44dd1ea10265d1088a2f1c6d')

    D << pg.ellipse(radii=(12, 5), angle_resolution=2.5, layer=2)
    h = D.hash_geometry(precision=1e-4)
    assert (h == '856cedcbbb53312ff839b9fe016996357e658d33')
    h = Dcopy.hash_geometry(precision=1e-4)
    assert (h == '0313cd7e58aa265b44dd1ea10265d1088a2f1c6d')
    h = Ddeepcopy.hash_geometry(precision=1e-4)
    assert (h == '0313cd7e58aa265b44dd1ea10265d1088a2f1c6d')

    A.add_ref(pg.ellipse(radii=(12, 5), angle_resolution=2.5, layer=2))
    B.add_polygon([[3, 4, 5], [6.7, 8.9, 10.15]], layer=0)
    h = D.hash_geometry(precision=1e-4)
    assert (h == 'c007b674e8053c11c877860f0552fff18676b68e')
    h = Dcopy.hash_geometry(precision=1e-4)
    assert (h == '2590bd786348ab684616eecdfdbcc9735b156e18')
    h = Ddeepcopy.hash_geometry(precision=1e-4)
    assert (h == '0313cd7e58aa265b44dd1ea10265d1088a2f1c6d')
Esempio n. 10
0
def test_port_add():
    D = Device()
    D.add_port(name='test123', midpoint=(5.7, 9.2), orientation=37)
    D.add_port(name='test456', midpoint=(1.5, 6.7), orientation=99)
    assert (len(D.ports) == 2)
    assert (np.allclose(D.ports['test123'].midpoint, (5.7, 9.2)))
    assert (np.allclose(D.ports['test456'].midpoint, (1.5, 6.7)))
    assert (D.ports['test123'].orientation == 37)
    assert (D.ports['test456'].orientation == 99)
Esempio n. 11
0
def makeCross(x0,y0,width,lw, layer):
	# Make cross with 
	# x0,y0 : center
	# width: width of the bounding box
	# lw: linewidth
	cross = Device("cross")
	cross.add_polygon([(x0-width/2,y0-lw/2),(x0-width/2,y0+lw/2), (x0+width/2,y0+lw/2), (x0+width/2,y0-lw/2) ], layer = layer)
	cross.add_polygon([(x0-lw/2,y0-width/2),(x0-lw/2,y0+width/2), (x0+lw/2,y0+width/2), (x0+lw/2,y0-width/2) ], layer = layer)
	return cross
Esempio n. 12
0
def test_polygon_simplify():
    D = Device()
    t = np.linspace(0, np.pi, 1000)
    x = np.cos(t)
    y = np.sin(t)
    poly = D.add_polygon([x, y])
    h = D.hash_geometry(precision=1e-4)
    assert (h == '0c3b1465c8b6ffd911c41b02114b9a06f606ad91')
    # qp(D)
    poly.simplify(tolerance=1e-1)
    h = D.hash_geometry(precision=1e-4)
    assert (h == '7d9ebcb231fb0107cbbf618353adeb583782ca11')
def wb_pad(x, y, pad, name):
    R = pg.rectangle(size=(pad, pad - 0.5), layer=70)

    D = Device()
    rect1 = D << R
    rect1.move([x, y])

    text_size = 20
    L = pg.text(text=name, size=text_size, layer=97, justify='center')
    D.add_ref(L).move((x + pad / 3, y))

    return D
Esempio n. 14
0
def test_rotate():
    # Test polygon rotation
    D = Device()
    p = D.add_polygon([(8, 6, 7, 9), (6, 8, 9, 5)])
    p.rotate(37.5)
    h = D.hash_geometry(precision=1e-4)
    assert (h == '2e4815072eabe053c3029d9e29a5b3ed59fe9bb7')
    # Test Device rotation
    D = Device()
    p = D.add_polygon([(8, 6, 7, 9), (6, 8, 9, 5)])
    D.rotate(37.5)
    h = D.hash_geometry(precision=1e-4)
    assert (h == '2e4815072eabe053c3029d9e29a5b3ed59fe9bb7')
Esempio n. 15
0
def test_reflect():
    # Test polygon reflection
    D = Device()
    p = D.add_polygon([(8, 6, 7, 9), (6, 8, 9, 5)])
    p.mirror(p1=(1.7, 2.5), p2=(4.5, 9.1))
    h = D.hash_geometry(precision=1e-4)
    assert (h == 'bc6ae5308c2240e425cd503e0cdda30007bbfc4d')
    # Test Device reflection
    D = Device()
    p = D.add_polygon([(8, 6, 7, 9), (6, 8, 9, 5)])
    D.mirror(p1=(1.7, 2.5), p2=(4.5, 9.1))
    h = D.hash_geometry(precision=1e-4)
    assert (h == 'bc6ae5308c2240e425cd503e0cdda30007bbfc4d')
def global_markers(layer_marker=10, layer_mask=20):
    D = Device('Global Markers')
    R = pg.rectangle(size=(20, 20), layer=1)
    a = D.add_array(R, columns=6, rows=6, spacing=(100, 100))
    a.move([-260, -260])  #Center of the array

    R = pg.rectangle(size=(20, 20), layer=1)
    a = D.add_array(R, columns=6, rows=6, spacing=(100, 100))
    a.move([-260, -260])  #Center of the array

    #Add marker cover
    cover = pg.bbox(bbox=a.bbox, layer=layer_mask)
    D << pg.offset(cover, distance=100, layer=layer_mask)
    return D
def waveguide(width=1, length=10, layer=1):
    '''
    Parameters
    ----------
    width : FLOAT, optional
        WIDTH OF THE WAVEGUIDE. The default is 1.
    length : FLOAT, optional
        LENGTH OF THE WAVEGUIDE. The default is 10.
    layer : INT, optional
        LAYER. The default is 1.

    Returns
    -------
    WG : DEVICE (PHIDL)
        WAVEGUIDE OBJECT

    '''
    WG = Device('Waveguide')
    WG.add_polygon([(0, 0), (length, 0), (length, width), (0, width)],
                   layer=layer)
    WG.add_port(name=1, midpoint=[0, width / 2], width=width, orientation=180)
    WG.add_port(name=2,
                midpoint=[length, width / 2],
                width=width,
                orientation=0)
    return WG
Esempio n. 18
0
def phidl_port_translation():
    # Conversion between object and geometric representation of ports
    try:
        pg.with_geometric_ports
    except AttributeError:
        pass  # skipping

    def geom_equal(A, B):
        h1 = A.hash_geometry(precision=1e-4)
        h2 = B.hash_geometry(precision=1e-4)
        return h1 == h2

    init_D = pg.compass(layer=1)
    geom_D = pg.with_geometric_ports(init_D, layer=2)
    end_D = pg.with_object_ports(geom_D, layer=2)
    assert geom_equal(init_D, end_D)

    assert len(geom_D.ports) == 0
    geom_D.remove_layers([2], include_labels=True)
    assert geom_equal(init_D, geom_D)

    assert geom_equal(init_D, end_D)
    for pnam, port in init_D.ports.items():
        assert np.all(end_D.ports[pnam].midpoint == port.midpoint)

    # now through the filesystem
    end2_D = anyCell_to_anyCell(init_D, Device())
    for pnam, port in init_D.ports.items():
        assert np.all(end_D.ports[pnam].midpoint == port.midpoint)
    assert geom_equal(init_D, end2_D)
    assert init_D.name == end2.name
def mzi(length, radius, angle, wg_width, Y_mmi):
    P1 = Path()
    P1.append(pp.euler(radius=radius, angle=-angle))
    P1.append(pp.euler(radius=radius, angle=angle))
    P1.append(pp.straight(length=length))
    P1.append(pp.euler(radius=radius, angle=angle))
    P1.append(pp.euler(radius=radius, angle=-angle))

    X = CrossSection()
    X.add(width=wg_width, offset=0, layer=30)
    waveguide_device1 = P1.extrude(X)

    E = Device('EOM_GHz')
    b1 = E.add_ref(waveguide_device1).move([0, -Y_mmi / 2])
    b2 = E.add_ref(waveguide_device1).move([0, -Y_mmi / 2])
    b2.mirror((0, 0), (1, 0))
    return E
Esempio n. 20
0
def test_add_polygon3():
    D = Device()
    D.add_polygon([(8, 6), (6, 8), (7, 9), (9, 5)], layer=7)
    D.add_polygon([(8, 0), (6, 8), (7, 9), (9, 5)], layer=(8, 0))
    D.add_polygon([(8, 1), (6, 8), (7, 9), (9, 5)], layer=(9, 1))
    h = D.hash_geometry(precision=1e-4)
    assert (h == '96abc3c9e30f3bbb32c5a39aeea2ba0fa3b13ebe')
def bonding_pads(margin, pad, chip_width, chip_height):
    num = 18
    sep = (chip_width - 2 * margin) / num
    P = pg.rectangle(size=(pad, pad), layer=3).move([margin, margin])
    P << pg.rectangle(size=(pad, pad), layer=3).move(
        [margin, chip_height - margin - pad])
    for i in range(1, int(num / 2)):
        P << pg.rectangle(size=(pad, pad), layer=3).move(
            [margin + i * sep, margin])
        P << pg.rectangle(size=(pad, pad), layer=3).move(
            [margin + i * sep, chip_height - margin - pad])

    E = Device('bonding_pads')
    b1 = E.add_ref(P)
    b2 = E.add_ref(P)
    b2.mirror((chip_width / 2, chip_height), (chip_width / 2, 0))

    return E, sep
def waveguide(width=10, height=1):
    WG = Device('waveguide')
    WG.add_polygon([(0, 0), (width, 0), (width, height), (0, height)])
    WG.add_port(name='wgport1',
                midpoint=[0, height / 2],
                width=height,
                orientation=180)
    WG.add_port(name='wgport2',
                midpoint=[width, height / 2],
                width=height,
                orientation=0)
    return WG
def dcimthin(wg_width, off_chip, W, L_tp, W_tp, L_mmi, W_mmi, Y_mmi, length,
             radius, x_pos, y_pos, middle_e_width, e_e_gap):

    if e_e_gap == 9:
        angle = 12.5196846104787
    elif e_e_gap == 7:
        angle = 11.83919343835311
    elif e_e_gap == 11:
        angle = 13.165741242693

    # Parameters
    mmi_length = L_tp * 2 + L_mmi
    side_electrode_width = middle_e_width * 2

    eulerX = mod_euler(radius=radius, angle=angle)[1][0]
    racetrack_length = eulerX * 4 + length
    #mzi_length = racetrack_length + mmi_length*2
    side = x_pos
    #side = (chip_width - mzi_length)/2

    # Devices
    M = mzi(length, radius, angle, wg_width, Y_mmi)

    mmiL = mmi(W, L_tp, W_tp, L_mmi, W_mmi, Y_mmi)
    mmiR = mmi(W, L_tp, W_tp, L_mmi, W_mmi, Y_mmi)
    mmiR.mirror().move([mmi_length, 0])

    E = Device('EOM')
    #E << pg.rectangle(size=(side+off_chip,wg_width), layer=1).move([-off_chip,y_pos-wg_width/2])
    E << mmiL.move([side, y_pos])
    E << M.move([side + mmi_length, y_pos])
    E << mmiR.move([side + mmi_length + racetrack_length, y_pos])
    #E << pg.rectangle(size=(side+off_chip,wg_width), layer=1).move([side+mzi_length,y_pos-wg_width/2])

    e_left = side + mmi_length + 2 * eulerX

    #side_e_width
    R = pg.rectangle(size=(length, middle_e_width), layer=40)
    R2 = pg.rectangle(size=(length, side_electrode_width), layer=40)

    #top electrode
    h_top = middle_e_width / 2 + e_e_gap + y_pos
    E.add_ref(R2).move([e_left, h_top])

    #middle electrode
    E.add_ref(R).move([e_left, y_pos - middle_e_width / 2])

    #bottom electrode
    h_bot = -middle_e_width / 2 - side_electrode_width - e_e_gap + y_pos
    E.add_ref(R2).move([e_left, h_bot])
    return E, e_left
Esempio n. 24
0
def back_and_forth():
    # from phidl to pya and back
    init_device = some_device(10, 20)

    pya_layout = pya.Layout()
    pya_cell = pya_layout.create_cell('newname')
    anyCell_to_anyCell(init_device, pya_cell)

    final_device = Device()
    anyCell_to_anyCell(pya_cell, final_device)

    return init_device, pya_layout, final_device
Esempio n. 25
0
def makeLineSpace(x0,y0,width, height,pitch,ymax, layer):
	#---------------------------------------------#
	# Creates a line space pattern in y-direction
	#	x0: x coordinate of the lower left line
	#	y0: y coordinate of the lower left line
	#	width: width of each line
	#	height: height of each line
	#	pitch: pitch of each line
	#	pitch > height
	#---------------------------------------------#
	if abs(pitch) < abs(height):
		print("pitch must be greater then height")
		return 
	LS = Device('linespace')
	if pitch > 0:
		while y0+height <= ymax:
			Li = makeLine(x0,y0,width,height,layer)
			LS.add_ref(Li)
			y0 += pitch
	elif pitch < 0:
		while y0+height >= -ymax:
                        Li = makeLine(x0,y0,width,height,layer)
                        LS.add_ref(Li)
                        y0 += pitch
	return y0, LS
Esempio n. 26
0
def save_or_visualize(device_name=None, out_file=None):
    ''' Handles a conditional write to file or send over lyipc connection.
        The context manager yields a new empty Device.
        The context block then modifies that device by adding references to it. It does not need to return anything.
        Back to the context manager, the Device is saved if out_file is not None, or it is sent over ipc

        Example::

            with save_or_visualize(out_file='my_box.gds') as D:
                r = D << phidl.geometry.rectangle(size=(10, 10), layer=1)
                r.movex(20)

        will write the device with a rectangle to a file called 'my_box.gds' and do nothing with lyipc.
        By changing out_file to None, it will send an ipc load command instead of writing to a permanent file,
        (Although ipc does write a file to be loaded by klayout, it's name or persistence is not guaranteed.)
    '''
    if device_name is None:
        CELL = Device()
    else:
        CELL = Device(device_name)
    yield CELL
    if out_file is None:
        klayout_quickplot(CELL, 'debugging.gds', fresh=True)
    else:
        CELL.write_gds(out_file)
Esempio n. 27
0
def test_port_remove():
    D = Device()
    D.add_port(name='test123', midpoint=(5.7, 9.2), orientation=37)
    D.add_port(name='test456', midpoint=(1.5, 6.7), orientation=99)
    E = Device()
    d = E << D
    D.remove(D.ports['test123'])
    assert (len(D.ports) == 1)
    assert (len(d.ports) == 1)
    assert (D.ports['test456'])
    assert (d.ports['test456'])
def dcpm(L, elec_w, e_e_gap, via, wg_width):
    P = Path()
    P.append(pp.straight(length=L))

    X = CrossSection()
    X.add(width=wg_width, offset=0, layer=30)
    DCPM = Device()
    DCPM << P.extrude(X)
    R1 = pg.rectangle(size=(L, elec_w), layer=40)
    R2 = pg.rectangle(size=(L, elec_w), layer=40)
    DCPM << R1.move([0, e_e_gap / 2])
    DCPM << R2.move([0, -elec_w - e_e_gap / 2])
    return DCPM
def connection_UR(x1, y1, x2, y2, elec_m, elec_s, e_e_gap, Rt):  #right down

    D = Device()

    x1t = x1 + elec_m / 2 + elec_s / 2 + e_e_gap
    x1b = x1 - elec_m / 2 - elec_s / 2 - e_e_gap

    y2t = y2 - elec_m / 2 - elec_s / 2 - e_e_gap
    y2b = y2 + elec_m / 2 + elec_s / 2 + e_e_gap

    points = np.array([(x1, y1), (x1, y2), (x2, y2)])
    points_t = np.array([(x1t, y1), (x1t, y2t), (x2, y2t)])
    points_b = np.array([(x1b, y1), (x1b, y2b), (x2, y2b)])

    M = pp.smooth(
        points=points,
        radius=Rt + elec_m / 2 + elec_s / 2 + e_e_gap,
        corner_fun=pp.arc,
    )
    M.rotate(90, center=(x1, y1))

    Mt = pp.smooth(
        points=points_t,
        radius=Rt,
        corner_fun=pp.arc,
    )
    Mt.rotate(90, center=(x1t, y1))

    Mb = pp.smooth(
        points=points_b,
        radius=Rt + 2 * (elec_m / 2 + elec_s / 2 + e_e_gap),
        corner_fun=pp.arc,
    )
    Mb.rotate(90, center=(x1b, y1))

    X = CrossSection()
    X.add(width=elec_m, offset=0, layer=70)
    Xt = CrossSection()
    Xt.add(width=elec_s, offset=0, layer=70)
    Xb = CrossSection()
    Xb.add(width=elec_s, offset=0, layer=70)

    L = M.extrude(X)  #Left Trace
    Lt = Mt.extrude(Xt)  #Left Trace
    Lb = Mb.extrude(Xb)  #Left Trace

    D << L
    D << Lt
    D << Lb
    return D
def connectPad(middle_e_width, chip_width, chip_height, radius, length,
               e_e_gap, setpos, side_electrode_width, y_pos):
    T = Device('connections')
    x2 = (chip_width - length) / 2 + middle_e_width
    h_bot = -middle_e_width / 2 - side_electrode_width / 2 - e_e_gap + y_pos
    T << connect(x2, h_bot, middle_e_width, chip_width, chip_height, 'b',
                 radius, length, e_e_gap, setpos)
    h_mid = y_pos
    T << connect(x2, h_mid, middle_e_width, chip_width, chip_height, 'm',
                 radius, length, e_e_gap, setpos)
    h_top = middle_e_width / 2 + e_e_gap + y_pos + side_electrode_width / 2
    T << connect(x2, h_top, middle_e_width, chip_width, chip_height, 't',
                 radius, length, e_e_gap, setpos)
    return T