这个教程主要介绍,在线路设计过程中如何获取器件默认的端口位置,如何自定义一个端口,以及给暴露的自定义的端口命名:
以下图线路为例:
老规矩,所有代码如下:
from si_fab import all as pdk
from ipkiss3 import all as i3
class routed_dc(i3.Circuit):
_name_prefix = "routed_dc"
dc = i3.ChildCellProperty(doc="Directional coupler in circuit")
def _default_dc(self):
return pdk.SiDirectionalCouplerSPower(power_fraction=0.5, target_wavelength=1.55)
def _default_insts(self):
insts = {
"dc": self.dc,
}
return insts
def _default_specs(self):
ports = self.dc.get_default_view(i3.LayoutView).ports
dy = 15
x1 = ports["out2"].x
y1 = ports["out2"].y
x2 = ports["out1"].x
y2 = ports["out1"].y
opt1 = i3.OpticalPort(name="opt1",position=(x1, y1 + dy), angle=180, trace_template=pdk.SWG450())
opt2 = i3.OpticalPort(name="opt2",position=(x2, y2 - dy), angle=180, trace_template=pdk.SWG450())
specs = [
i3.Place("dc", (0, 0)),
i3.ConnectManhattan(opt2, "dc:in1", bend_radius=5),
i3.ConnectManhattan(opt1, "dc:in2", bend_radius=5),
]
return specs
def _default_exposed_ports(self):
exposed_ports = {
"x9_5200_y-16_3250_a180__to_dc_in1:in": "out1",
"dc:out1": "out2",
"dc:out2": "out3",
"x9_5200_y16_3250_a180__to_dc_in2:in": "out4",
}
return exposed_ports
if __name__ == '__main__':
r_dc = routed_dc()
my_circuit = r_dc.Layout()
print(r_dc.Netlist())
my_circuit.visualize(annotate=True)
my_circuit.write_gdsii("Rounted_dc.gds")
可以看到线路就一个器件:dc
def _default_insts(self):
insts = {
"dc": self.dc,
}
return insts
如果想将dc所有的端口都绕向右边,只需要在右边再定义两个端口,并连接起来就行。为了保证所有的端口对齐,首先需要获取dc右边两个端口的坐标。可以通过:
ports = self.dc.get_default_view(i3.LayoutView).ports
获取dc 的端口信息,接着获取对应端口的坐标:
x1 = ports["out2"].x
y1 = ports["out2"].y
x2 = ports["out1"].x
y2 = ports["out1"].y
定义光学端口可以用i3.OpticalPort:
opt1 = i3.OpticalPort(position=(x1, y1 + dy), angle=180, trace_template=pdk.SWG450())
opt2 = i3.OpticalPort(position=(x2, y2 - dy), angle=180, trace_template=pdk.SWG450())
在定义端口的时候需要给出端口的位置、角度以及trace_template
定义完端口,就可以和dc已有的端口做连接了
specs = [
i3.Place("dc", (0, 0)),
i3.ConnectManhattan(opt2, "dc:in1", bend_radius=5),
i3.ConnectManhattan(opt1, "dc:in2", bend_radius=5),
]
注意在连接时,opt1,和opt2是不需要引号的
最后就是给所有暴露的端口命名:
def _default_exposed_ports(self):
exposed_ports = {
"x9_5200_y-16_3250_a180__to_dc_in1:in": "out1",
"dc:out1": "out2",
"dc:out2": "out3",
"x9_5200_y16_3250_a180__to_dc_in2:in": "out4",
}
return exposed_ports
给dc暴露的端口命名很简单:
"dc:out1": "out2",
"dc:out2": "out3",
但是给自定义的端口命名就麻烦一点,因为自定义的波导是ipkiss自动生成的,不是自己添加的ints。
实际上ipkiss自动生成的波导都对应一个线路中的insts,可以通过输出线路网表来查看:
print(r_dc.Netlist())
两段波导分别对应:
x9_5200_y-16_3250_a180__to_dc_in1
x9_5200_y16_3250_a180__to_dc_in2
因此给自定义的两个端口命名时,可以这样:
"x9_5200_y-16_3250_a180__to_dc_in1:in": "out1",
"x9_5200_y16_3250_a180__to_dc_in2:in": "out4",
最终的效果如第一个图