Files
mxpic_forge/mxpic/components/pdks/CUMEC_pdk.py
T
2026-06-04 23:21:39 +08:00

255 lines
11 KiB
Python

from ..gds_devices import gds_lib_load
import nazca as nd
from ..routing import Route
from ..electronics import PADs
CUMEC_LAYER_MAP = {
(31,1): 'STRIP_COR',
(31,2): 'STRIP_CLD',
(31,3): 'STRIP_TRE',
(31,4): 'STRIP_HOL',
(32,1): 'SRIB_COR',
(32,2): 'SRIB_CLD',
(32,3): 'SRIB_TRE',
(32,4): 'SRIB_HOL',
(33,1): 'RIB_COR',
(33,2): 'RIB_CLD',
(33,3): 'RIB_TRE',
(33,4): 'RIB_HOL',
(11,1): 'METAL',
(12,1): 'METAL_2',
(51,1): 'VIA_H2M',
(60,0): 'PASS1',
(63,0): 'PASS2',
(20,0): 'PAD',
(61,0): 'GC_OPEN',
}
class PAD_60_80(gds_lib_load) :
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\bondpads"
lib_name = "BP_60_80"
cellname = "Fixed_BP_60_80"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False)
self.add_pin(pin_name='p1',xya=(0,0,-90))
class GPD_1550(gds_lib_load):
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\photodetector"
lib_name = "GPD_1550_unit"
cell_name = "Fixed_GPD_1550_unit"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["Fixed_GPD_1550_unit"],layermap=CUMEC_LAYER_MAP)
self.w_wg = 0.45
self.length = 110.4
self.add_pin(pin_name='ep1', xya=(55.2, 3.325, 90), width=1) ## anode
self.add_pin(pin_name='en1', xya=(55.2,-3.325,-90), width=1) ## cathod
self.add_pin(pin_name='a1', xya=(0,0,180), width=0.45)
self.add_pin(pin_name='b1', xya=(110.4,0,0), width=self.w_wg)
class EC_1550(gds_lib_load):
'''
CUMEC TE Grating Coupler at 1550nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\edge_couplers"
lib_name = "EC_1550"
cell_name = "Fixed_EC_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["Fixed_EC_1550"],layermap=CUMEC_LAYER_MAP)
self.w_wg = 0.45
self.length = 689.9
self.add_pin(pin_name='g1', xya=(0,0,0), width=self.w_wg)
self.add_pin(pin_name='b0', xya=(-673.9,0,180))
self.add_pin(pin_name='a0',xya=(-673.9,0,0))
class GC_TE_1550(gds_lib_load):
'''
CUMEC TE Grating Coupler at 1550nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\grating_couplers"
lib_name = "GC_TE_1550"
cell_name = "Fixed_GC_TE_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,cellsreused=["Fixed_GC_TE_1550"],layermap=CUMEC_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='g1', xya=(0,0,0), width=self.w_wg)
def generate_test_gds(self,gc2gc_dX=300):
with nd.Cell(name=self.cell.cell_name+"_test",instantiate=False) as C:
gc_input = self.cell.put('g1',-gc2gc_dX/2,0,180)
gc_output = self.cell.put('g1',gc2gc_dX/2,0,0)
stripe=Route(radius=5, width=self.w_wg, xs="strip")
stripe.strt_p2p(pin1=gc_input.pin['g1'],pin2=gc_output.pin['g1'],arrow=False).put()
return C
class GC_TM_1550(gds_lib_load):
'''
CUMEC TE Grating Coupler at 1550nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\grating_couplers"
lib_name = "GC_TM_1550"
cell_name = "Fixed_GC_TM_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,cellsreused=["Fixed_GC_TM_1550"],layermap=CUMEC_LAYER_MAP)
self.w_wg = 0.5
self.add_pin(pin_name='g1', xya=(0,0,0), width=self.w_wg)
def generate_test_gds(self,gc2gc_dX=300):
with nd.Cell(name=self.cell.cell_name+"_test",instantiate=False) as C:
gc_input = self.cell.put('g1',-gc2gc_dX/2,0,180)
gc_output = self.cell.put('g1',gc2gc_dX/2,0,0)
stripe=Route(radius=5, width=self.w_wg, xs="strip")
stripe.strt_p2p(pin1=gc_input.pin['g1'],pin2=gc_output.pin['g1'],arrow=False).put()
return C
class GC_TE_1310(gds_lib_load):
'''
CUMEC TE Grating Coupler at 1310nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\grating_couplers"
lib_name = "GC_TE_1310"
cell_name = "Fixed_GC_TE_1310"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,cellsreused=["Fixed_GC_TE_1310"],layermap=CUMEC_LAYER_MAP)
self.w_wg = 0.38
self.add_pin(pin_name='g1', xya=(0,0,0), width=self.w_wg)
class MMI_1x2_TE_1550(gds_lib_load):
'''
CUMEC TE 1by 2 MMI at 1550nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK",sharp_patch: bool=True) -> None:
lib_path = pdk_path + "\\mmis"
lib_name = "M1X2_TE_1550"
cellname = "Fixed_M1X2_TE_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False,cellsreused=["Fixed_M1X2_TE_1550"],layermap=CUMEC_LAYER_MAP)
self.length = 12
self.width = 1.55
self.w_wg = 0.45
self.add_pin(pin_name='a1', xya=(0,0,180), width=self.w_wg)
self.add_pin(pin_name='b1', xya=(self.length,self.width/2,0), width=self.w_wg)
self.add_pin(pin_name='b2', xya=(self.length,-self.width/2,0), width=self.w_wg)
def generate_test_gds(self,gc,gc2gc_length=300):
with nd.Cell(name=self.cell.cell_name+"_test", instantiate=False) as C:
gc_input = gc.cell.put('g1',0,0,180)
gc_output_1 = gc.cell.put('g1',gc2gc_length, 20,0)
gc_output_2 = gc.cell.put('g1',gc2gc_length,-20,0)
# Put DC
dc = self.cell.put('a1',gc_input.pin['g1'].move((gc2gc_length-self.length)/2,0,0))
# Connect all the ports
stripe=Route(radius=5, width=self.w_wg, xs="strip")
stripe.sbend_route_p2p(pin1=gc_input.pin['g1'],pin2=dc.pin['a1'],arrow=False).put()
stripe.sbend_route_p2p(pin1=gc_output_1.pin['g1'],pin2=dc.pin['b1'],arrow=False).put()
stripe.sbend_route_p2p(pin1=gc_output_2.pin['g1'],pin2=dc.pin['b2'],arrow=False).put()
return C
class MMI_1x2_TE_1310(gds_lib_load):
'''
CUMEC TE 1by 2 MMI at 1310nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK",sharp_patch: bool=True) -> None:
lib_path = pdk_path + "\\mmis"
lib_name = "M1X2_TE_1310"
cellname = "Fixed_M1X2_TE_1310"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False,cellsreused=["Fixed_M1X2_TE_1310"],layermap=CUMEC_LAYER_MAP)
self.length = 15
self.width = 1.45
self.w_wg = 0.38
self.add_pin(pin_name='a1', xya=(0,0,180), width=self.w_wg)
self.add_pin(pin_name='b1', xya=(self.length,self.width/2,0), width=self.w_wg)
self.add_pin(pin_name='b2', xya=(self.length,-self.width/2,0), width=self.w_wg)
class MMI_2x2_TE_1550(gds_lib_load):
'''
CUMEC TE 1by 2 MMI at 1310nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\mmis"
lib_name = "M2X2_TE_1550"
cellname = "Fixed_M2X2_TE_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False,cellsreused=["Fixed_M2X2_TE_1550"],layermap=CUMEC_LAYER_MAP)
self.length = 125.4
self.width = 3
self.w_wg = 0.45
self.add_pin(pin_name='a1', xya=(0,self.width/2,180), width=self.w_wg)
self.add_pin(pin_name='a2', xya=(0,-self.width/2,180), width=self.w_wg)
self.add_pin(pin_name='b1', xya=(self.length,self.width/2,0), width=self.w_wg)
self.add_pin(pin_name='b2', xya=(self.length,-self.width/2,0), width=self.w_wg)
class CRX_TE_1550(gds_lib_load):
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\crossings"
lib_name = "X_TE_1550"
cellname = "Fixed_X_TE_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False,cellsreused=["Fixed_X_TE_1550"],layermap=CUMEC_LAYER_MAP)
self.length = 5
self.width = 5
self.w_wg = 0.45
self.xs = 'strip'
self.L_arm = 5
self.add_pin(pin_name='a1',xya=(-5,0,180),width=self.w_wg)
self.add_pin(pin_name='b1',xya=( 5,0,0),width=self.w_wg)
self.add_pin(pin_name='a2',xya=( 0,5,90),width=self.w_wg)
self.add_pin(pin_name='b2',xya=( 0,-5,-90),width=self.w_wg)
def generate_test_gds(self,gc,num=5,dX_gc2gc=400,w_end=0.2,L_end=10):
with nd.Cell(instantiate=False) as C:
if (isinstance(gc,nd.Cell)):
gc_cell = gc
elif (hasattr(gc,'cell')):
gc_cell = gc.cell
else :
raise Exception("ERROR: In <mxpiv::passive::cross::generate_test_gds>, <gc> is not recongized")
dL = self.L_arm*2
dX = dL*1.75
pic_strip = Route(radius=10,width=self.w_wg,xs=self.xs)
gc_In = gc_cell.put('g1',-dX_gc2gc/2,0,180)
pin_pre = gc_In.pin['g1']
for _idx_ in range(0,num):
inst = self.cell.put('a0',_idx_*dX - (num/2 - 1/2)*dX)
pic_strip.strt_p2p(pin1=pin_pre,pin2=inst.pin['a1'],arrow=False).put()
pin_pre = inst.pin['b1']
nd.taper(length=L_end/2,width1=self.w_wg,width2=w_end,xs=self.xs).put(inst.pin['b2'])
nd.strt(length=L_end/2,width=w_end,xs=self.xs).put()
nd.taper(length=L_end/2,width1=self.w_wg,width2=w_end,xs=self.xs).put(inst.pin['a2'])
nd.strt(length=L_end/2,width=w_end,xs=self.xs).put()
gc_Out = gc_cell.put('g1', dX_gc2gc/2,0,0)
pic_strip.strt_p2p(pin1=pin_pre,pin2=gc_Out.pin['g1'],arrow=False).put()
return C
class PBS_1550(gds_lib_load):
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\polarization_beam_splitter"
lib_name = "PBS_1550"
cellname = "Fixed_PBS_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False,cellsreused=cellname,layermap=CUMEC_LAYER_MAP)
self.length = 5
self.width = 5
self.w_wg = 0.45
self.xs = 'strip'
self.add_pin(pin_name='a1',xya=(-0,0,180),width=self.w_wg)
self.add_pin(pin_name='b1',xya=( 87.2,0,0),width=self.w_wg)
self.add_pin(pin_name='b2',xya=( 87.2,-20,0),width=self.w_wg)