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 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
Exemple #5
0
def straight(length=5, num_pts=100):
    """ Creates a straight Path

    Parameters
    ----------
    length : int or float
        Total length of straight path
    num_pts : int
        Number of points along Path

    Returns
    -------
    Path
        A Path object with the specified straight section
    """
    x = np.linspace(0, length, num_pts)
    y = x * 0
    points = np.array((x, y)).T

    P = Path()
    P.append(points)
    return P
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 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
Exemple #8
0
def smooth(
    points = [(20,0), (40,0), (80,40), (80,10), (100,10),], 
    radius = 4,
    corner_fun = euler,
    **kwargs
    ):
    """ Create a smooth path from a series of waypoints. Corners will be rounded
    using `corner_fun` and any additional key word arguments (for example,
    `use_eff = True` when `corner_fun = pp.euler`)

    Parameters
    ----------
    points : array-like[N][2]
        List of waypoints for the path to follow
    radius : int or float
        Radius of curvature, this argument will be passed to `corner_fun`
    corner_fun : function
        The function that controls how the corners are rounded. Typically either
        `arc()` or `euler()`
    **kwargs : dict
        Extra keyword arguments that will be passed to `corner_fun`

    Returns
    -------
    Path
        A Path object with the specified smoothed path.
    """
    points = np.asfarray(points)
    normals = np.diff(points, axis = 0)
    normals = (normals.T/np.linalg.norm(normals, axis = 1)).T
    # normals_rev = normals*np.array([1,-1])
    dx = np.diff(points[:,0])
    dy = np.diff(points[:,1])
    ds = np.sqrt(dx**2 + dy**2)
    theta = np.degrees(np.arctan2(dy,dx))
    dtheta = np.diff(theta)
    dtheta = dtheta - 360*np.floor((dtheta + 180)/360)

    # FIXME add caching
    # Create arcs
    paths = []
    radii = []
    for dt in dtheta:
        P = corner_fun(radius = radius, angle = dt, **kwargs)
        chord = np.linalg.norm(P.points[-1,:] - P.points[0,:])
        r = (chord/2)/np.sin(np.radians(dt/2))
        r = np.abs(r)
        radii.append(r)
        paths.append(P)

    d = np.abs(np.array(radii)/np.tan(np.radians(180-dtheta)/2))
    encroachment = np.concatenate([[0],d]) + np.concatenate([d,[0]])
    if np.any(encroachment > ds):
        raise ValueError('[PHIDL] smooth(): Not enough distance between points to to fit curves.  Try reducing the radius or spacing the points out farther')
    p1 = points[1:-1,:] - normals[:-1,:]*d[:,np.newaxis]

    # Move arcs into position
    new_points = []
    new_points.append( [points[0,:]] )
    for n,dt in enumerate(dtheta):
        P = paths[n]
        P.rotate(theta[n] - 0)
        P.move(p1[n])
        new_points.append(P.points)
    new_points.append( [points[-1,:]] )
    new_points = np.concatenate(new_points)

    P = Path()
    P.rotate(theta[0])
    P.append(new_points)
    P.move(points[0,:])

    return P
Exemple #9
0
def smooth(points=[
    (20, 0),
    (40, 0),
    (80, 40),
    (80, 10),
    (100, 10),
],
           radius=4,
           corner_fun=euler,
           **kwargs):
    """ Create a smooth path from a series of waypoints. Corners will be rounded
    using `corner_fun` and any additional key word arguments (for example,
    `use_eff = True` when `corner_fun = pp.euler`)

    Parameters
    ----------
    points : array-like[N][2]
        List of waypoints for the path to follow
    radius : int or float
        Radius of curvature, this argument will be passed to `corner_fun`
    corner_fun : function
        The function that controls how the corners are rounded. Typically either
        `arc()` or `euler()`
    **kwargs : dict
        Extra keyword arguments that will be passed to `corner_fun`

    Returns
    -------
    Path
        A Path object with the specified smoothed path.
    """

    points, normals, ds, theta, dtheta = _compute_segments(points)
    colinear_elements = np.concatenate([[False],
                                        np.abs(dtheta) < 1e-6, [False]])
    if np.any(colinear_elements):
        new_points = points[~colinear_elements, :]
        points, normals, ds, theta, dtheta = _compute_segments(new_points)

    if np.any(np.abs(np.abs(dtheta) - 180) < 1e-6):
        raise ValueError(
            '[PHIDL] smooth() received points which double-back on themselves'
            +
            '--turns cannot be computed when going forwards then exactly backwards.'
        )

    # FIXME add caching
    # Create arcs
    paths = []
    radii = []
    for dt in dtheta:
        P = corner_fun(radius=radius, angle=dt, **kwargs)
        chord = np.linalg.norm(P.points[-1, :] - P.points[0, :])
        r = (chord / 2) / np.sin(np.radians(dt / 2))
        r = np.abs(r)
        radii.append(r)
        paths.append(P)

    d = np.abs(np.array(radii) / np.tan(np.radians(180 - dtheta) / 2))
    encroachment = np.concatenate([[0], d]) + np.concatenate([d, [0]])
    if np.any(encroachment > ds):
        raise ValueError(
            '[PHIDL] smooth(): Not enough distance between points to to fit curves.  Try reducing the radius or spacing the points out farther'
        )
    p1 = points[1:-1, :] - normals[:-1, :] * d[:, np.newaxis]

    # Move arcs into position
    new_points = []
    new_points.append([points[0, :]])
    for n, dt in enumerate(dtheta):
        P = paths[n]
        P.rotate(theta[n] - 0)
        P.move(p1[n])
        new_points.append(P.points)
    new_points.append([points[-1, :]])
    new_points = np.concatenate(new_points)

    P = Path()
    P.rotate(theta[0])
    P.append(new_points)
    P.move(points[0, :])

    return P