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 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
def test_align(): D = Device() # Create different-sized rectangles and add them to D then distribute them [ D.add_ref( pg.rectangle(size=[n * 15 + 20, n * 15 + 20]).move((n, n * 4))) for n in [0, 2, 3, 1, 2] ] D.distribute(elements='all', direction='x', spacing=5, separation=True) # Align top edges D.align(elements='all', alignment='ymax') h = D.hash_geometry(precision=1e-4) assert (h == '38025959a80e46e47eabcf3f096c6273427dabc3') D = Device() # Create different-sized rectangles and add them to D then distribute them [ D.add_ref( pg.rectangle(size=[n * 15 + 20, n * 15 + 20]).move((n, n * 4))) for n in [0, 2, 3, 1, 2] ] D.distribute(elements='all', direction='x', spacing=5, separation=True) # Align top edges D.align(elements='all', alignment='y') h = D.hash_geometry(precision=1e-4) assert (h == 'ed32ee1ce1f3da8f6216020877d6c1b64097c600')
def test_distribute(): D = Device() # Create different-sized rectangles and add them to D [ D.add_ref( pg.rectangle(size=[n * 15 + 20, n * 15 + 20]).move((n, n * 4))) for n in [0, 2, 3, 1, 2] ] # Distribute all the rectangles in D along the x-direction with a separation of 5 D.distribute( elements='all', # either 'all' or a list of objects direction='x', # 'x' or 'y' spacing=5, separation=True) h = D.hash_geometry(precision=1e-4) assert (h == '1aa688d7dfb59e94d28dd0d9b8f324ff30281d70') D = Device() [ D.add_ref( pg.rectangle(size=[n * 15 + 20, n * 15 + 20]).move((n, n * 4))) for n in [0, 2, 3, 1, 2] ] D.distribute(elements='all', direction='x', spacing=100, separation=False, edge='xmin') h = D.hash_geometry(precision=1e-4) assert (h == '18be0ef1db78095233d2f3ae5f065d9f453a6c07')
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
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
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
def main(): #---- Example of using the templates---# D = Device() # Make a golden spiral with 1000 grids F = fibonacci(1000) D.add_ref(F) D.write_gds("spiral.gds") # Make a ring resonator D2 = Device() C = makeResonator() D2.add_ref(C) D2.write_gds("resonator.gds")
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 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 test_write_and_import_gds(): D = Device() D.add_ref(pg.rectangle(size=[1.5, 2.7], layer=[3, 2])) D.add_ref(pg.rectangle(size=[0.8, 2.5], layer=[9, 7])) D.add_array(pg.rectangle(size=[1, 2], layer=[4, 66]), rows=3, columns=2, spacing=[14, 7.5]) D.add_array(pg.rectangle(size=[1.5, 2.5], layer=[4, 67]), rows=1, columns=2, spacing=[14, 7.5]) D.add_polygon([[3, 4, 5], [6.7, 8.9, 10.15]], layer=[7, 8]) D.add_polygon([[3, 4, 5], [1.7, 8.9, 10.15]], layer=[7, 9]) precision = 1e-4 unit = 1e-6 h1 = D.hash_geometry(precision=precision) D.write_gds('temp.gds', precision=unit * precision, unit=1e-6) Dimport = pg.import_gds('temp.gds', flatten=False) h2 = Dimport.hash_geometry(precision=precision) assert (h1 == h2)
def triplet_pad(x, y, pad, pad_g, elec_m, elec, elec_s, e_e_gap, pos): R = pg.rectangle(size=(pad, pad), layer=70) D = Device() rect1 = D << R rect2 = D << R rect3 = D << R rect1.move([x, y]) rect2.move([x - pad_g, y]) rect3.move([x + pad_g, y]) #middle connector pad xm1 = x - elec_m / 2 xm2 = x - pad / 2 xm3 = x + pad / 2 xm4 = x + elec_m / 2 xpts = (xm1 + pad / 2, xm2 + pad / 2, xm3 + pad / 2, xm4 + pad / 2) ypts = (y + pad + elec, y + elec, y + elec, y + pad + elec) if pos == 'u': ypts = (y - elec, y, y, y - elec) D.add_polygon([xpts, ypts], layer=70) text_size = 20 L = pg.text(text='S', size=text_size, layer=97, justify='center') D.add_ref(L).move((x + pad / 3, y)) #left connector pad xm1 = x - elec_m / 2 - e_e_gap - elec_s xm2 = x - pad / 2 - pad_g xm3 = x + pad / 2 - pad_g xm4 = x - elec_m / 2 - e_e_gap xpts = (xm1 + pad / 2, xm2 + pad / 2, xm3 + pad / 2, xm4 + pad / 2) ypts = (y + pad + elec, y + elec, y + elec, y + pad + elec) if pos == 'u': ypts = (y - elec, y, y, y - elec) D.add_polygon([xpts, ypts], layer=70) L = pg.text(text='G', size=text_size, layer=97, justify='center') D.add_ref(L).move((x - pad_g + +pad / 3, y)) #left connector pad xm1 = x + elec_m / 2 + e_e_gap xm2 = x + pad / 2 + pad_g - pad xm3 = x + pad / 2 + pad_g xm4 = x + elec_m / 2 + e_e_gap + elec_s xpts = (xm1 + pad / 2, xm2 + pad / 2, xm3 + pad / 2, xm4 + pad / 2) ypts = (y + pad + elec, y + elec, y + elec, y + pad + elec) if pos == 'u': ypts = (y - elec, y, y, y - elec) D.add_polygon([xpts, ypts], layer=70) L = pg.text(text='G', size=text_size, layer=97, justify='center') D.add_ref(L).move((x + pad_g + +pad / 3, y)) return D
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 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 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
def test_bbox(): D = Device() D.add_polygon([(0, 0), (10, 0), (10, 10), (0, 10)], layer=2) assert (D._bb_valid == False) # Calculating the bbox should change _bb_valid to True once it's cached assert (D.bbox.tolist() == [[0, 0], [10, 10]]) assert (D._bb_valid == True) E = Device() e1 = E.add_ref(D) e2 = E.add_ref(D) e2.movex(30) assert (E._bb_valid == False) assert (E.bbox.tolist() == [[0, 0], [40, 10]]) assert (E._bb_valid == True) D.add_polygon([(0, 0), (100, 0), (100, 100), (0, 100)], layer=2) D.add_polygon([(0, 0), (100, 0), (100, 100), (0, 100)], layer=2) assert (E.bbox.tolist() == [[0, 0], [130, 100]]) assert (e1.bbox.tolist() == [[0, 0], [100, 100]]) assert (e2.bbox.tolist() == [[30, 0], [130, 100]])
def makeResonator(radius = 10, width = 0.5, space = 1.0): #------------------------ # Make a ring resonator # radius: of the ring # width: of the ring and the line # space: space between the edge of the ring and the line #------------------------ C= Device("Resonator") R = pg.ring(radius = radius, width = width) C.add_ref(R) L1 = makeLine(radius+space,-radius,width,2*radius) C.add_ref(L1) L2 = makeLine(-radius-space-width,-radius,width,2*radius) C.add_ref(L2) return C
Texpanded = pg.offset(T, distance=2, join_first=True, precision=1e-6, num_divisions=[1, 1], layer=0) Tshrink = pg.offset(T, distance=-1.5, join_first=True, precision=1e-6, num_divisions=[1, 1], layer=0) # Plot the original geometry, the expanded, and the shrunk versions D = Device() t1 = D.add_ref(T) t2 = D.add_ref(Texpanded) t3 = D.add_ref(Tshrink) D.distribute([t1, t2, t3], direction='x', spacing=5) qp(D) # quickplot the geometry create_image(D, 'offset') # example-invert import phidl.geometry as pg from phidl import quickplot as qp E = pg.ellipse(radii=(10, 5)) D = pg.invert(E, border=0.5, precision=1e-6, layer=0) qp(D) # quickplot the geometry create_image(D, 'invert')
# Define global variables xmax = 500 ymax = 500 xmin = 0 ymin = 0 xm = (xmax-xmin)/2.0 ym = (ymax-ymin)/2.0 # Cover the entire macro D.add_polygon([(0,0),(xmax,0),(xmax,ymax),(0,ymax) ], layer = 0) ## Place the pattern rec Cross = makeCross(xm,ym,100,10, layer) Cross.rotate(45,center = [xm,ym]) D.add_ref(Cross) # calculate offset due to the cross xoff = math.sqrt(100*50) yoff = math.sqrt(100*50) ## Top left 1 x0 = 10 y0 = ym y0, LS1 = makeLineSpace(x0,y0, 240 - xoff ,10,20,ym + yoff, layer) D.add_ref(LS1) ## Top left 2 x0 = 10 y0 = y0 y0, LS1 = makeLineSpace(x0,y0,240,10,20,500, layer) D.add_ref(LS1)
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
elec_s = 28 * um #side_e_width pad_m = 1.5 * mm #RF pads n_rf = 4 #number of RF pobres spacing = 300 xoff = chip_width - (n_rf * 2 * spacing - pad) - pad_m yoff = height - pad #-pad/2 #Initial device setup D = Device('mac') D << pg.rectangle(size=(chip_width, height), layer=0) L = pg.text(text='MAC CHIP REV # 0', size=40, layer=30, justify='center') D.add_ref(L).move((1.8 * mm, yoff)) D.write_gds('mac_0.gds') # Length matching math and constants # In[3]: #Lower arm (a and phi) path lengths a_to_phi = 450.934996607 * um phi_len = 14 * mm - 0.169 * um phi_to_co = 15603.1440005 * um c_leg = 5.00436311264 #upper arm (b*c) path lengths b_to_c = 314.158991993 * um c_len = c_leg + 40 + c_leg + 14174.808 + c_leg + 40 + c_leg
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
from phidl import Device # Create `T`, an ellipse and rectangle which will be offset (expanded / contracted) T = Device() e = T << pg.ellipse(radii = (10,5), layer = 1) r = T << pg.rectangle(size = [15,5], layer = 2) r.move([3,-2.5]) Texpanded = pg.offset(T, distance = 2, join_first = True, precision = 1e-6, num_divisions = [1,1], layer = 0) Tshrink = pg.offset(T, distance = -1.5, join_first = True, precision = 1e-6, num_divisions = [1,1], layer = 0) # Plot the original geometry, the expanded, and the shrunk versions D = Device() t1 = D.add_ref(T) t2 = D.add_ref(Texpanded) t3 = D.add_ref(Tshrink) D.distribute([t1,t2,t3], direction = 'x', spacing = 5) qp(D) # quickplot the geometry create_image(D, 'offset') # example-invert import phidl.geometry as pg from phidl import quickplot as qp E = pg.ellipse(radii = (10,5)) D = pg.invert(E, border = 0.5, precision = 1e-6, layer = 0) qp(D) # quickplot the geometry create_image(D, 'invert')
def eom(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.814353309 elif e_e_gap == 7: angle = 12.1500390158 elif e_e_gap == 11: angle = 13.4465651249 # 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]) square = middle_e_width * 0.9 side_height = side_electrode_width * 0.9 square_rec_offset = (side_electrode_width - side_height) / 2 e_left = side + mmi_length + 2 * eulerX 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 = middle_e_width / 2 + e_e_gap + y_pos E.add_ref(R2).move([e_left, h_top]) E.add_ref(S2).move([e_left, h_top + square_rec_offset]) E.add_ref(S2).move([e_right, h_top + square_rec_offset]) #middle electrode E.add_ref(R).move([e_left, y_pos - middle_e_width / 2]) E.add_ref(S).move([e_left, y_pos - square / 2]) E.add_ref(S).move([e_right, y_pos - square / 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]) E.add_ref(S2).move([e_left, h_bot + square_rec_offset]) E.add_ref(S2).move([e_right, h_bot + square_rec_offset]) return E
# First we create the waveguides. As you can see from the waveguide() function # definition, the waveguide() function creates another Device ("WG"). # This can be thought of as the waveguide() function creating another GDS cell, # only this one has some geometry inside it. # # Let's create two of these Devices by calling the waveguide() function WG1 = waveguide(width=10, height=1) WG2 = waveguide(width=12, height=2) # Now we've made two waveguides Device WG1 and WG2, and we have a blank # device D. We can add references from the devices WG1 and WG2 to our blank # device byz using the add_ref() function. # After adding WG1, we see that the add_ref() function returns a handle to our # reference, which we will label with lowercase letters wg1 and wg2. This # handle will be useful later when we want to move wg1 and wg2 around in D. wg1 = D.add_ref(WG1) # Using the function add_ref() wg2 = D << WG2 # Using the << operator which is identical to add_ref() # Alternatively, we can do this all on one line wg3 = D.add_ref(waveguide(width=14, height=3)) qp(D) # quickplot it! #============================================================================== # Creating polygons #============================================================================== # Create and add a polygon from separate lists of x points and y points # e.g. [(x1, x2, x3, ...), (y1, y2, y3, ...)] poly1 = D.add_polygon([(8, 6, 7, 9), (6, 8, 9, 5)]) # Alternatively, create and add a polygon from a list of points
# First we create the waveguides. As you can see from the waveguide() function # definition, the waveguide() function creates another Device ("WG"). # This can be thought of as the waveguide() function creating another GDS cell, # only this one has some geometry inside it. # # Let's create two of these Devices by calling the waveguide() function WG1 = waveguide(width=10, height=1) WG2 = waveguide(width=12, height=2) # Now we've made two waveguides Device WG1 and WG2, and we have a blank # device D. We can add references from the devices WG1 and WG2 to our blank # device byz using the add_ref() function. # After adding WG1, we see that the add_ref() function returns a handle to our # reference, which we will label with lowercase letters wg1 and wg2. This # handle will be useful later when we want to move wg1 and wg2 around in D. wg1 = D.add_ref(WG1) wg2 = D.add_ref(WG2) # Alternatively, we can do this all on one line wg3 = D.add_ref(waveguide(width=14, height=3)) quickplot(D) #============================================================================== # Creating polygons #============================================================================== # Create and add a polygon from separate lists of x points and y points # e.g. [(x1, x2, x3, ...), (y1, y2, y3, ...)] poly1 = D.add_polygon([(8, 6, 7, 9), (6, 8, 9, 5)]) # Alternatively, create and add a polygon from a list of points