def _draw_padded_via(self): viaref=DeviceReference(self.via.draw()) size=float(self.via.size*self.over_via) port=viaref.ports['conn'] trace=pg.rectangle(size=(size,size),layer=self.pad_layers[0]) trace.move(origin=trace.center,\ destination=viaref.center) trace2=pg.copy_layer(trace,layer=self.pad_layers[0],new_layer=self.pad_layers[1]) cell=Device(self.name) cell.absorb(cell<<trace) cell.absorb(cell<<trace2) cell.add(viaref) port.midpoint=(port.midpoint[0],cell.ymax) port.width=size cell.add_port(port) if bottom_conn==False: cell.remove_layers(layers=[self.pad_layers[1]]) return cell
def draw(self): ''' Generates layout cell based on current parameters. 'conn' port is included in the cell. Returns ------- cell : phidl.Device. ''' o = self.origin pad=pg.rectangle(size=self.size.coord,\ layer=self.layer).move(origin=(0,0),\ destination=o.coord) cell = Device(self.name) r1 = cell << pad cell.absorb(r1) r2 = cell << pad r2.move(origin=o.coord,\ destination=(o+self.distance).coord) cell.absorb(r2) cell.add_port(name='conn',\ midpoint=(o+Point(self.size.x/2,self.size.y)).coord,\ width=self.size.x,\ orientation=90) del pad return cell
def check(device: Device, joined=False, blocking=True): ''' Shows the device layout. If run by terminal, blocks script until window is closed. Parameters ---------- device : phidl.Device joined : boolean (optional, default False) if true, returns a flattened/joined version of device ''' set_quickplot_options(blocking=blocking) if joined: cell = Device() cell.absorb(cell << device) cell.flatten() qp(join(cell)) else: qp(device)
def add_vias(cell: Device, bbox, via: pt.LayoutPart, spacing: float = 0, tolerance: float = 0): ''' adds via pattern to cell with constraints. Parameters: ----------- cell : Device where the vias will be located bbox : iterable x,y coordinates of box ll and ur to define vias patterns size via : pt.LayoutPart spacing : float tolerance : float (default 0) if not 0, used to determine via distance from target object border Returns: -------- cell_out : Device ''' bbox_cell = pg.bbox(bbox) nvias_x = int(np.floor(bbox_cell.xsize / (via.size + spacing))) nvias_y = int(np.floor(bbox_cell.ysize / (via.size + spacing))) if nvias_x == 0 or nvias_y == 0: return via_cell = pt.draw_array(via.draw(), nvias_x, nvias_y, row_spacing=spacing, column_spacing=spacing) via_cell.move(origin=(via_cell.x, via_cell.y), destination=(bbox_cell.x, bbox_cell.y)) tbr = [] for elem in via_cell.references: if not pt.is_cell_inside(elem, cell, tolerance): tbr.append(elem) via_cell.remove(tbr) cell.absorb(cell.add_ref(via_cell, alias="Vias"))
def mask_names( names=("Bottom Electrode", "Top Electrode", "Via Layer", "Etch Layer", "PartialEtch Layer", "Pad Layer"), layers=(pt.LayoutDefault.layerBottom, pt.LayoutDefault.layerTop, pt.LayoutDefault.layerVias, pt.LayoutDefault.layerEtch, pt.LayoutDefault.layerPartialEtch, pt.LayoutDefault.layerPad), size=250): """ Prints array of strings on different layers. Mostly useful for Layer Sorting on masks. Parameters ---------- names : iterable of str layers : iterable of int size : float Returns ------- cell : phidl.Device. """ text = pc.Text() text['Size'] = size if not len(names) == len(layers): raise ValueError("Unbalanced mask names/layers combo") else: text_cells = [] for label, layer in zip(names, layers): text['Label'] = label text['Layer'] = (layer, ) text_cells.append(text.draw()) g = Group(text_cells) g.distribute(direction='x', spacing=size) cell_name = Device(name='Mask Names') for x in text_cells: cell_name.absorb(cell_name << x) return cell_name
def draw(self): self._set_relations() device_cell=cls.draw(self) probe_cell=self.probe.draw() cell=Device(name=self.name) cell.add_ref(device_cell, alias="Device") self._add_signal_connection(cell,'bottom') probe_ref=cell.add_ref(probe_cell, alias="Probe") self._move_probe_ref(cell) self._setup_signal_routing(cell) cell.absorb(cell<<self._draw_signal_routing()) try: self._setup_ground_routing( cell, 'straight') routing_cell=self._draw_ground_routing() except: self._setup_ground_routing( cell, 'side') try: routing_cell=self._draw_ground_routing() except: import pdb; pdb.set_trace() self._draw_ground_routing() _add_default_ground_vias(self,routing_cell) cell.add_ref(routing_cell,alias=self.name+"GroundTrace") return cell
def _draw_ground_routing(self): if isinstance(self.probe, pc.GSGProbe): routing_cell = Device() routing_cell.absorb(routing_cell << self.gndlefttrace.draw()) routing_cell.absorb(routing_cell << self.gndrighttrace.draw()) return pt.join(routing_cell) else: raise ValueError("To be implemented")
def attach_taper(cell : Device , port : Port , length : float , \ width2 : float, layer=LayoutDefault.layerTop) : t = pg.taper(length=length, width1=port.width, width2=width2, layer=layer) t_ref = cell.add_ref(t) t_ref.connect(1, destination=port) new_port = t_ref.ports[2] new_port.name = port.name cell.absorb(t_ref) cell.remove(port) cell.add_port(new_port)
def draw(self): ''' Generates layout cell based on current parameters. 'top' and 'bottom' ports is included in the cell. Returns ------- cell : phidl.Device. ''' o = self.origin b_main = Bus() b_main.origin = o b_main.layer = self.layer b_main.size = Point(self.x, self.active_area.y) b_main.distance = Point(self.active_area.x + self.x, 0) main_etch = b_main.draw() etch = Device(self.name) etch.absorb(etch << main_etch) port_up=Port('top',\ midpoint=(o+Point(self.x+self.active_area.x/2,self.active_area.y)).coord,\ width=self.active_area.x,\ orientation=-90) port_down=Port('bottom',\ midpoint=(o+Point(self.x+self.active_area.x/2,0)).coord,\ width=self.active_area.x,\ orientation=90) etch.add_port(port_up) etch.add_port(port_down) del main_etch return etch
def _draw_unit_cell(self): o = self.origin rect=pg.rectangle(size=(self.coverage*self.pitch,self.length),\ layer=self.layer) rect.move(origin=(0, 0), destination=o.coord) unitcell = Device() r1 = unitcell << rect unitcell.absorb(r1) r2 = unitcell << rect r2.move(origin=o.coord,\ destination=(o+Point(self.pitch,self.y_offset)).coord) r3 = unitcell << rect r3.move(origin=o.coord,\ destination=(o+Point(2*self.pitch,0)).coord) unitcell.absorb(r2) unitcell.absorb(r3) unitcell.name = "UnitCell" del rect return unitcell
def draw(self): cell=Device() cell.name=self.name d_ref=cell.add_ref(cls.draw(self)) for name,port in d_ref.ports.items(): self.pad.port=port pad_ref=cell.add_ref(self.pad.draw()) pad_ref.connect(pad_ref.ports['conn'], destination=port) cell.absorb(pad_ref) cell.add_port(port,name) return cell
def _draw_unit_cell(self): o = self.origin rect=pg.rectangle(size=(self.coverage*self.pitch,self.length),\ layer=self.layer) rect.move(origin=(0, 0), destination=o.coord) unitcell = Device() r1 = unitcell << rect unitcell.absorb(r1) rect_partialetch=pg.rectangle(\ size=(\ (1-self.coverage)*self.pitch,self.length-self.y_offset),\ layer=LayoutDefault.layerPartialEtch) rect_partialetch.move(origin=o.coord,\ destination=(self.pitch*self.coverage,self.y_offset)) rp1 = unitcell << rect_partialetch rp2 = unitcell << rect_partialetch rp2.move(destination=(self.pitch, 0)) r2 = unitcell << rect r2.move(origin=o.coord,\ destination=(o+Point(self.pitch,self.y_offset)).coord) r3 = unitcell << rect r3.move(origin=o.coord,\ destination=(o+Point(2*self.pitch,0)).coord) unitcell.absorb(r2) unitcell.absorb(r3) unitcell.name = "UnitCell" del rect, rect_partialetch return unitcell
def _draw_device_grounds(self, device_cell, probe_cell, label): output_cell = Device() lx_device_ports = [] rx_device_ports = [] gnd_ports = pt._find_ports(device_cell, 'Ground', depth=0) if not gnd_ports: return output_cell for p in gnd_ports: p_adj = Port(name=p.name, midpoint=p.midpoint, width=probe_cell['Port1'].size[1], orientation=p.orientation) if "LX" in p.name: lx_device_ports.append(p_adj) elif "RX" in p.name: rx_device_ports.append(p_adj) r = pc.MultiRouting() r.layer = self.gndlefttrace.layer r.clearance = pt._bbox_to_tuple(self._bbox_mod(device_cell.bbox)) r.trace_width = self.gnd_routing_width ## left connections if label == 'side': r.source = tuple( pt._find_ports(probe_cell, 'GroundLXW', depth=0)) elif label == 'straight': r.source = (probe_cell.ports['GroundLXN_1'], ) r.destination = tuple(lx_device_ports) r.side = 'left' output_cell.absorb(output_cell << r.draw()) ## right connections if label == 'side': r.source = tuple( pt._find_ports(probe_cell, 'GroundRXE', depth=0)) elif label == 'straight': r.source = (probe_cell.ports['GroundRXN_1'], ) r.destination = tuple(rx_device_ports) r.side = 'right' output_cell.absorb(output_cell << r.draw()) return output_cell
def draw(self): ''' Generates layout cell based on current parameters. 'conn' port is included in the cell. Returns ------- cell : phidl.Device. ''' self._check_anchor() o = self.origin anchor=pg.rectangle(\ size=(self.size-Point(2*self.etch_margin.x,-2*self.etch_margin.y)).coord,\ layer=self.layer) etch_size=Point(\ (self.etch_x-self.size.x)/2,\ self.size.y) offset = Point(self.x_offset, 0) cell = Device(self.name) etch_sx=pg.rectangle(\ size=(etch_size-offset).coord,\ layer=self.etch_layer) etch_dx=pg.rectangle(\ size=(etch_size+offset).coord,\ layer=self.etch_layer) etch_sx_ref=(cell<<etch_sx).move(origin=(0,0),\ destination=(o-Point(0,self.etch_margin.y)).coord) anchor_transl = o + Point(etch_sx.size[0] + self.etch_margin.x, -2 * self.etch_margin.y) anchor_ref=(cell<<anchor).move(origin=(0,0),\ destination=anchor_transl.coord) etchdx_transl = anchor_transl + Point( anchor.size[0] + self.etch_margin.x, +self.etch_margin.y) etch_dx_ref=(cell<<etch_dx).move(origin=(0,0),\ destination=etchdx_transl.coord) cell.add_port(name='conn',\ midpoint=(anchor_transl+Point(self.size.x/2-self.etch_margin.x,self.size.y+2*self.etch_margin.y)).coord,\ width=self.metalized.x,\ orientation=90) if self.etch_choice == True: cell.absorb(etch_sx_ref) cell.absorb(anchor_ref) cell.absorb(etch_dx_ref) else: cell.remove(etch_sx_ref) cell.remove(etch_dx_ref) del anchor, etch_sx, etch_dx return cell
def draw(self): cell = Device() cell.name = self.name supercell = LFERes.draw(self) super_ref = cell.add_ref(supercell) if self.plate_position == 'out, short': plate=pg.rectangle(size=(self.etchpit.active_area.x+8*self.idt.active_area_margin,self.idt.length-self.idt.y_offset/2),\ layer=self.platelayer) plate_ref = cell.add_ref(plate, alias='Plate') transl_rel=Point(self.etchpit.x-4*self.idt.active_area_margin,self.anchor.size.y+2*self.anchor.etch_margin.y+self.bus.size.y\ +self.idt.y_offset*3/4) lr_cell = get_corners(cell)[0] lr_plate = get_corners(plate_ref)[0] plate_ref.move(origin=lr_plate.coord,\ destination=(lr_plate+lr_cell+transl_rel).coord) cell.absorb(plate_ref) del plate elif self.plate_position == 'in, short': plate=pg.rectangle(\ size=(\ self.etchpit.active_area.x-\ 2*self.idt.active_area_margin,\ self.idt.length-self.idt.y_offset/2),\ layer=self.platelayer) plate_ref = cell.add_ref(plate, alias='Plate') transl_rel=Point(self.etchpit.x+\ self.idt.active_area_margin,\ self.anchor.size.y+\ 2*self.anchor.etch_margin.y+\ self.bus.size.y+\ self.idt.y_offset*3/4) lr_cell = get_corners(cell)[0] lr_plate = get_corners(plate_ref)[0] plate_ref.move(origin=lr_plate.coord,\ destination=(lr_plate+lr_cell+transl_rel).coord) cell.absorb(plate_ref) del plate elif self.plate_position == 'out, long': plate=pg.rectangle(\ size=(self.etchpit.active_area.x+\ 8*self.idt.active_area_margin,\ self.idt.length+\ 2*self.bus.size.y+\ self.idt.y_offset),\ layer=self.platelayer) plate_ref = cell.add_ref(plate, alias='Plate') transl_rel=Point(self.etchpit.x-\ 4*self.idt.active_area_margin,\ self.anchor.size.y+2*self.anchor.etch_margin.y) lr_cell = get_corners(cell)[0] lr_plate = get_corners(plate_ref)[0] plate_ref.move(origin=lr_plate.coord,\ destination=(lr_plate+lr_cell+transl_rel).coord) cell.absorb(plate_ref) del plate elif self.plate_position == 'in, long': plate=pg.rectangle(\ size=(\ self.etchpit.active_area.x-\ 2*self.idt.active_area_margin,\ self.idt.length+\ 2*self.bus.size.y+\ self.idt.y_offset), layer=self.platelayer) plate_ref = cell.add_ref(plate, alias='Plate') transl_rel=Point(self.etchpit.x+\ self.idt.active_area_margin,\ self.anchor.size.y+2*self.anchor.etch_margin.y) lr_cell = get_corners(cell)[0] lr_plate = get_corners(plate_ref)[0] plate_ref.move(origin=lr_plate.coord,\ destination=(lr_plate+lr_cell+transl_rel).coord) cell.absorb(plate_ref) del plate for name, port in supercell.ports.items(): cell.add_port(port, name) return cell