示例#1
0
def transition(cross_section1, cross_section2, width_type='sine'):
    """ Creates a CrossSection that smoothly transitions between two input
    CrossSections. Only cross-sectional elements that have the `name` (as in
    X.add(..., name = 'wg') ) parameter specified in both input CrosSections
    will be created. Port names will be cloned from the input CrossSections in
    reverse.

    Parameters
    ----------
    cross_section1 : CrossSection
        First input CrossSection
    cross_section2 : CrossSection
        Second input CrossSection
    width_type : {'sine', 'linear'}
        Sets the type of width transition used if any widths are different
        between the two input CrossSections.

    Returns
    -------
    CrossSection
        A smoothly-transitioning CrossSection
    """

    X1 = cross_section1
    X2 = cross_section2
    Xtrans = CrossSection()
    for alias in X1.aliases.keys():
        if alias in X2.aliases:

            offset1 = X1[alias]['offset']
            offset2 = X2[alias]['offset']
            width1 = X1[alias]['width']
            width2 = X2[alias]['width']

            if callable(offset1):
                offset1 = offset1(1)
            if callable(offset2):
                offset2 = offset2(0)
            if callable(width1):
                width1 = width1(1)
            if callable(width2):
                width2 = width2(0)

            offset_fun = _sinusoidal_transition(offset1, offset2)

            if width_type == 'sine':
                width_fun = _sinusoidal_transition(width1, width2)
            elif width_type == 'linear':
                width_fun = _linear_transition(width1, width2)
            else:
                raise ValueError("[PHIDL] transition() width_type " +
                                 "argument must be one of {'sine','linear'}")

            Xtrans.add(width=width_fun,
                       offset=offset_fun,
                       layer=X1[alias]['layer'],
                       ports=(X2[alias]['ports'][0], X1[alias]['ports'][1]),
                       name=alias)

    return Xtrans
def eom_sym(wg_width, length, middle_e_width, e_e_gap, chip_width, offset,
            radius):
    euler_y = mod_euler(radius=radius, angle=-45)[1][1]
    euler_x = mod_euler(radius=radius, angle=-45)[1][0]
    wg_wg_sep = (middle_e_width + e_e_gap) / 2 - 2 * euler_y
    straight = wg_wg_sep * np.sqrt(2)
    if wg_wg_sep < 0:
        raise Exception(
            "middle_e_width is set too small with respect to Euler radius")

    left = chip_width / 2 - length / 2 - 2 * euler_x - wg_wg_sep + offset
    right = left

    P1 = Path()
    P1.append(pp.straight(length=left))
    P1.append(mod_euler(radius=radius, angle=-45)[0])
    P1.append(pp.straight(length=straight))
    P1.append(mod_euler(radius=radius, angle=45)[0])
    P1.append(pp.straight(length=length))
    P1.append(mod_euler(radius=radius, angle=45)[0])
    P1.append(pp.straight(length=straight))
    P1.append(mod_euler(radius=radius, angle=-45)[0])
    P1.append(pp.straight(length=right))

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

    E = Device('EOM_GHz')
    b1 = E.add_ref(waveguide_device1)
    b2 = E.add_ref(waveguide_device1)
    b2.mirror((0, 0), (1, 0))

    square = middle_e_width * 0.6
    square_rec_offset = (middle_e_width - square) / 2
    e_left = left + 2 * euler_x + wg_wg_sep
    e_right = left + 2 * euler_x + wg_wg_sep + length - square

    #side_e_width
    R = pg.rectangle(size=(length, middle_e_width), layer=10)
    S = pg.rectangle(size=(square, square), layer=2)

    #top electrode
    h_top = middle_e_width / 2 + e_e_gap
    E.add_ref(R).move([e_left, h_top])
    E.add_ref(S).move([e_left, h_top + square_rec_offset])
    E.add_ref(S).move([e_right, h_top + square_rec_offset])

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

    #bottom electrode
    h_bot = -3 * middle_e_width / 2 - e_e_gap
    E.add_ref(R).move([e_left, h_bot])
    E.add_ref(S).move([e_left, h_bot + square_rec_offset])
    E.add_ref(S).move([e_right, h_bot + square_rec_offset])
    #E << R
    return E
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
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 dcim(im_gap, im_length, coupler_l, im_r, im_angle, elec_w, e_e_gap, via,
         wg_width, V_Groove_Spacing):
    P = Path()
    euler_y = mod_euler(radius=im_r, angle=im_angle)[1][1]
    euler_x = mod_euler(radius=im_r, angle=im_angle)[1][0]
    l_bend = ((V_Groove_Spacing - im_gap - 4 * euler_y - wg_width) /
              2) / np.sin(np.pi * im_angle / 180)
    P.append(pp.euler(radius=im_r, angle=-im_angle))
    P.append(pp.straight(length=l_bend))
    P.append(pp.euler(radius=im_r, angle=im_angle))
    P.append(pp.straight(length=coupler_l))
    P.append(pp.euler(radius=im_r, angle=im_angle))
    P.append(pp.euler(radius=im_r, angle=-im_angle))
    P.append(pp.straight(length=im_length))
    P.append(pp.euler(radius=im_r, angle=-im_angle))
    P.append(pp.euler(radius=im_r, angle=im_angle))
    P.append(pp.straight(length=coupler_l))
    P.append(pp.euler(radius=im_r, angle=im_angle))
    P.append(pp.straight(length=l_bend))
    P.append(pp.euler(radius=im_r, angle=-im_angle))

    P.movey(V_Groove_Spacing)
    X = CrossSection()
    X.add(width=wg_width, offset=0, layer=30)

    IM = Device('IM')
    IM << P.extrude(X)
    IM << P.extrude(X).mirror(p1=[1, V_Groove_Spacing / 2],
                              p2=[2, V_Groove_Spacing / 2])
    R1 = pg.rectangle(size=(im_length, elec_w), layer=40)
    R2 = pg.rectangle(size=(im_length, elec_w), layer=40)
    R3 = pg.rectangle(size=(im_length, elec_w), layer=40)
    R4 = pg.rectangle(size=(im_length, elec_w), layer=40)

    movex = euler_x * 4 + coupler_l + l_bend * np.cos(np.pi * im_angle / 180)
    movey = euler_y * 2 + im_gap / 2 + wg_width
    IM << R1.move(
        [movex, V_Groove_Spacing / 2 + movey + e_e_gap / 2 - wg_width / 2])
    IM << R2.move([
        movex,
        V_Groove_Spacing / 2 + movey - e_e_gap / 2 - elec_w - wg_width / 2
    ])
    IM << R3.move(
        [movex, V_Groove_Spacing / 2 - movey + e_e_gap / 2 + wg_width / 2])
    IM << R4.move([
        movex,
        V_Groove_Spacing / 2 - movey - e_e_gap / 2 - elec_w + wg_width / 2
    ])
    return IM, movex
def rfpm(wg_width, length, middle_e_width, e_e_gap):

    side_electrode_width = middle_e_width * 2

    P = Path()
    P.append(pp.straight(length=length))

    X = CrossSection()
    X.add(width=wg_width, offset=0, layer=30)
    RFPM = Device()
    RFPM << P.extrude(X)
    Rt = pg.rectangle(size=(length, side_electrode_width), layer=40)
    Rm = pg.rectangle(size=(length, middle_e_width), layer=40)
    Rb = pg.rectangle(size=(length, side_electrode_width), layer=40)
    RFPM << Rt.move([0, e_e_gap / 2])
    RFPM << Rm.move([0, -middle_e_width - e_e_gap / 2])
    RFPM << Rb.move(
        [0, -middle_e_width - side_electrode_width - e_e_gap - e_e_gap / 2])

    square = middle_e_width * 0.9
    side_height = side_electrode_width * 0.9
    square_rec_offset = (side_electrode_width - side_height) / 2
    square_rec_offset_m = (middle_e_width - square) / 2
    e_left = 0
    e_right = e_left + length - square

    #side_e_width
    R = pg.rectangle(size=(length, middle_e_width), layer=40)
    R2 = pg.rectangle(size=(length, side_electrode_width), layer=40)
    S = pg.rectangle(size=(square, square), layer=50)
    S2 = pg.rectangle(size=(square, side_height), layer=50)

    #top electrode
    h_top = e_e_gap / 2
    RFPM.add_ref(S2).move([e_left, h_top + square_rec_offset])
    RFPM.add_ref(S2).move([e_right, h_top + square_rec_offset])

    #middle electrode
    h_mid = -middle_e_width - e_e_gap / 2
    RFPM.add_ref(S).move([e_left, h_mid + square_rec_offset_m])
    RFPM.add_ref(S).move([e_right, h_mid + square_rec_offset_m])

    #bottom electrode
    h_bot = -middle_e_width - side_electrode_width - e_e_gap - e_e_gap / 2
    RFPM.add_ref(S2).move([e_left, h_bot + square_rec_offset])
    RFPM.add_ref(S2).move([e_right, h_bot + square_rec_offset])

    return RFPM
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
def mmi(W, L_tp, W_tp, L_mmi, W_mmi, Y_mmi):
    mm = 10**3
    um = 1

    # Create CrossSections
    X1 = CrossSection()
    X2 = CrossSection()
    X1.add(width=W, offset=0, layer=30, name='wg')
    X2.add(width=W_tp, offset=0, layer=30, name='wg')

    # create Devices by extruding them
    P1 = pp.straight(length=10 * um)
    P2 = pp.straight(length=10 * um)
    WG1 = P1.extrude(X1)
    WG2 = P2.extrude(X2)

    # Place both cross-section Devices and quickplot them
    D = Device()
    wg1 = D << WG1
    wg2 = D << WG2
    wg2.movex(L_tp)

    # Create the transitional CrossSection
    Xtrans = pp.transition(cross_section1=X1,
                           cross_section2=X2,
                           width_type='linear')
    # Create a Path for the transitional CrossSection to follow
    P3 = pp.straight(length=L_tp)
    # Use the transitional CrossSection to create a Device
    WG_in = P3.extrude(Xtrans)
    WG_out1 = P3.extrude(Xtrans)
    WG_out2 = P3.extrude(Xtrans)
    WG_out1.mirror((0, 1), (0, 0))
    WG_out2.mirror((0, 1), (0, 0))

    WG_in << pg.rectangle(size=(L_mmi, W_mmi), layer=30).move(
        [L_tp, -W_mmi / 2])
    WG_in << WG_out1.move([L_mmi + 2 * L_tp, Y_mmi / 2])
    WG_in << WG_out2.move([L_mmi + 2 * L_tp, -Y_mmi / 2])
    return WG_in
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 connect(x2, y2, middle_e_width, chip_width, chip_height, pos, radius,
            length, e_e_gap, setpos):
    mm = 10**3
    um = 1

    M = Path()
    # Dimensions
    margin = 0.5 * mm
    to_pad_term = 0.1 * mm
    pad = 50 * um
    pitch = 100 * um
    side_e_width = middle_e_width * 2
    rad_gap = e_e_gap + middle_e_width / 2 + side_e_width / 2

    if pos == 't':
        Rt = radius + rad_gap * 2
    elif pos == 'm':
        Rt = radius + rad_gap
    else:
        Rt = radius

    if setpos == 't':
        set_bias = 0.6 * mm
    elif setpos == 'm':
        set_bias = 0.3 * mm
    else:
        set_bias = 0

    x1 = (chip_width - length) / 2 - Rt - set_bias
    y1 = margin + to_pad_term
    points = np.array([(x1, y1), (x1, y2), (x2, y2)])
    points = rotate90(points)

    M = pp.smooth(
        points=points,
        radius=Rt,
        corner_fun=pp.arc,
    )
    M.rotate(90)

    X = CrossSection()
    if pos == 'm':
        X.add(width=middle_e_width, offset=0, layer=3)
    else:
        X.add(width=side_e_width, offset=0, layer=3)

    L = M.extrude(X)  #Left Trace

    if pos == 'm':
        # adding pads
        S = pg.rectangle(size=(pad, pad), layer=3)
        L.add_ref(S).move([x1 - pad / 2, margin])
        L.add_ref(S).move([x1 - pad / 2 - pitch, margin])
        L.add_ref(S).move([x1 - pad / 2 + pitch, margin])

        xm1 = x1 - middle_e_width / 2
        xm2 = x1 + middle_e_width / 2
        xm3 = x1 + pad / 2
        xm4 = x1 - pad / 2
        xpts = (xm1, xm2, xm3, xm4)
        ypts = (y1, y1, margin + pad, margin + pad)
        L.add_polygon([xpts, ypts], layer=3)

        xt1 = xm1 + middle_e_width + e_e_gap
        xt2 = xt1 + side_e_width
        xt3 = xm3 + pitch
        xt4 = xm4 + pitch
        xpts = (xt1, xt2, xt3, xt4)
        ypts = (y1, y1, margin + pad, margin + pad)
        L.add_polygon([xpts, ypts], layer=3)

        xb1 = xm1 - side_e_width - e_e_gap
        xb2 = xm1 - e_e_gap
        xb3 = xm3 - pitch
        xb4 = xm4 - pitch
        xpts = (xb1, xb2, xb3, xb4)
        ypts = (y1, y1, margin + pad, margin + pad)
        L.add_polygon([xpts, ypts], layer=3)

    R = pg.copy(L)  # Right Trace
    R.mirror((chip_width / 2, chip_height), (chip_width / 2, 0))

    D = Device('trace')
    D << L
    D << R
    return D