示例#1
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 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
示例#3
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
示例#4
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)
def complicated_waveguide(width=10, height=1, x=10, y=25, rotation=15):
    C = Device('complicated_waveguide')
    C.add_polygon([(0, 0), (width, 0), (width, height), (0, height)])
    C.add_port(name=1, midpoint=[0, height / 2], width=height, orientation=180)
    C.add_port(name=2,
               midpoint=[width, height / 2],
               width=height,
               orientation=0)
    C.rotate(angle=rotation, center=(0, 0))
    C.move((x, y))
    return C
示例#6
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 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
示例#8
0
def htron(nanowire_width = 0.15, nanowire_spacing = 0.1,
          meander_num_squares = 5000, heater_num_squares = 1):

    # Create blank device
    D = Device(name = 'htron')

    # Basic calculations
    extra_meander_width = 2
    extra_meander_height = 1
    area_per_meander_sq = (nanowire_width+nanowire_spacing)*nanowire_width
    meander_area = area_per_meander_sq*meander_num_squares
    meander_total_width = np.sqrt(meander_area/heater_num_squares)
    meander_total_height = heater_num_squares*meander_total_width
    meander_size = np.array([meander_total_width, meander_total_height])
    heater_size = meander_size

    meander_size = meander_size + [extra_meander_width,extra_meander_height]

    # meander_size = heater_size + np.array([meander_extra_width,0])
    meander_pitch = nanowire_width + nanowire_spacing
    # heater_standoff_y = 1

    # Create components
    Meander = pg.snspd_expanded(wire_width = nanowire_width, wire_pitch = meander_pitch, size = meander_size,
               terminals_same_side = False, connector_width = nanowire_width*4, layer = lys['m2_nw'])
    # heater_size_actual = heater_size + np.array([0, heater_standoff_y])
    Heater = pg.compass(size = heater_size, layer = lys['m3_res'])

    # Add references to components
    m = D.add_ref(Meander)
    h = D.add_ref(Heater)
    h.center = m.center


    # Record meta-information
    heater_area = heater_size[0]*heater_size[1]
    D.info['nanowire_width'] = nanowire_width
    D.info['nanowire_pitch'] = nanowire_width + nanowire_spacing
    D.info['meander_num_squares'] = np.round(m.info['num_squares'],2)
    D.info['meander_size'] = np.round((m.xsize, m.ysize),2).tolist()
    D.info['heater_size'] = np.round(heater_size,2).tolist()
    D.info['heater_area'] = np.round(heater_size[0]*heater_size[1],2)
    D.info['heater_num_squares'] = np.round(heater_num_squares,2)
    D.info['overlap_area'] = np.round(m.ysize*heater_size[0],1)
    D.info['overlap_num_squares'] = np.round(heater_area/area_per_meander_sq,1)

    D.add_port(name = 1, port = h.ports['N'])
    D.add_port(name = 2, port = h.ports['S'])
    D.add_port(name = 3, port = m.ports[1])
    D.add_port(name = 4, port = m.ports[2])

    return D
# negative number, separate the ports).
wg1.connect(port='wgport1', destination=wg2.ports['wgport2'])
wg3.connect(port='wgport2', destination=wg2.ports['wgport1'], overlap=-1)

qp(D)  # quickplot it!

#==============================================================================
# Adding ports
#==============================================================================
# Although our waveguides wg1/wg2/wg3 have ports, they're only references
# of the device ``D`` we're working in, and D itself does not -- it only draws
# the subports (ports of wg1, wg2, wg3) as a convenience.  We need to add ports
# that we specifically want in our new device ``D``. add_port() can take a
# port argument which allows you to pass it an underlying reference port to
# copy. You can also rename the port if you desire:
p1 = D.add_port(port=wg1.ports['wgport2'], name=1)
p2 = D.add_port(port=wg3.ports['wgport1'], name=2)

# Optionally, let's assign some information to these ports.  Every Port has
# a Port.info dictionary which can be used to store information about that port
p1.info['is_useful'] = True
p2.info['is_useful'] = False

qp(D)  # quickplot it!

#==============================================================================
# Taking things a level higher
#==============================================================================
# Now that we have our device ``D`` which is a multi-waveguide device, we
# can add references to that device in a new blank canvas we'll call ``D2``.
# We'll add two copies of ``D`` to D2, and shift one so we can see them both
示例#10
0
def wg_to_snspd(wgnw_width=0.1,
                wgnw_length=100,
                wgnw_gap=0.15,
                num_squares=5000.0,
                meander_width=0.4,
                meander_fill_factor=0.5,
                wg_width=0.75):
    ''' Waveguide coupled to SNSPD with inductor (meander).
        The length and width of the meander are chosen so that it is approximately square

        Args:
            meander_width (float): nanowire width within meander inductor
            num_squares (float): total squares in meander and out-and-back
            wgnw_width (float): width of out-and-back nanowire
            wgnw_length (float): length of out-and-back
            wgnw_gap (float): spacing between the out-and-back wires
            wg_width (float): waveguide width

        Ports:
            el_1: wiring port
            el_gnd: wiring port
            wg_in: input optical port
            de_edge: edge of explicit waveguide on the SNSPD side
    '''

    D = Device('wg_to_snspd')

    # Calculations and checks
    numsquares_wgnw = 2 * wgnw_length / wgnw_width
    numsquares_meander = num_squares - numsquares_wgnw
    if numsquares_meander < 1000:
        print(
            'Warning: Not enough squares in SNSPD meander. Clipped to 1000 from {:.1f}'
            .format(numsquares_meander))
        numsquares_meander = 1000
    meander_pitch = meander_width / meander_fill_factor
    meander_length = np.sqrt(numsquares_meander * meander_width *
                             meander_pitch)
    wgnw_pitch = wgnw_width + wgnw_gap
    wgnw_distance_to_edge = wg_width / 2 - wgnw_width - wgnw_gap / 2
    if wgnw_distance_to_edge < 0:
        print('Warning: nanowire will overhang side of waveguide by {:.3f} um'.
              format(-wgnw_distance_to_edge))

    numsquares_per_taper = 3  # approximate
    D.info[
        'num_squares'] = numsquares_meander + numsquares_wgnw - meander_length / meander_width + 3 * numsquares_per_taper
    # D.info['expected_resistance'] = D.info['num_squares']*EXPECTED_RSQ_WSI
    D.info['wire_width'] = wgnw_width
    D.info['length'] = wgnw_length

    # Geometry
    meander = D << pg.snspd(wire_width=meander_width,
                            wire_pitch=meander_pitch,
                            terminals_same_side=False,
                            size=(meander_length, None),
                            num_squares=numsquares_meander,
                            layer=lys['m2_nw'])
    meander.reflect(p1=(0, 0), p2=(1, 0))

    Taper = pg.optimal_step(start_width=wgnw_width,
                            end_width=meander_width,
                            num_pts=50,
                            width_tol=1e-3,
                            anticrowding_factor=1.2,
                            layer=lys['m2_nw'])
    taper1 = D << Taper
    taper1.connect(2, meander.ports[1])

    wgnw = D << pg.optimal_hairpin(width=wgnw_width,
                                   pitch=wgnw_pitch,
                                   length=wgnw_length,
                                   layer=lys['m2_nw'])
    wgnw.connect(2, taper1.ports[1])

    taper2 = D << Taper
    taper2.reflect()
    taper2.connect(1, wgnw.ports[1])

    # Electrical ports
    exit_bend = D << pg.optimal_90deg(
        width=meander_width, num_pts=15, length_adjust=1, layer=lys['m2_nw'])
    exit_bend.connect(port=2, destination=taper2.ports[2])
    D.add_port('el_gnd', port=exit_bend.ports[1])

    exit_taper = D << pg.optimal_step(start_width=meander_width,
                                      end_width=meander_width * 4,
                                      num_pts=50,
                                      width_tol=1e-3,
                                      anticrowding_factor=1.2,
                                      layer=lys['m2_nw'])
    exit_taper.connect(1, meander.ports[2])
    D.add_port('el_1', port=exit_taper.ports[2])

    # Waveguide and optical ports
    wg = D << pg.compass(size=[wgnw_length + wgnw_distance_to_edge, wg_width],
                         layer=lys['wg_deep'])
    wg.xmax = wgnw.xmax
    wg.y = wgnw.y

    D.add_port('de_edge', port=wg.ports['E'])
    D.add_port('wg_in', port=wg.ports['W'])
    D.ports['de_edge'].info['is_waveguide_edge'] = True

    pos = D.ports['wg_in'].midpoint
    D.move(-1 * pos)

    return D