可编程光子集成链路
可编程光子链路是光子学发展的一门重要学科,这一部分主要详细讲解如何搭建可重构式可编程光子链路。
这一部分以矩形网络为例,旨在搭建可重构式矩形光网络。可重构参数包括:
基础模块
网络大小
设计参数
第一部分 构建矩形网络
导入必要库文件:
from dataclasses import dataclass
from typing import Mapping, cast
from fnpcell import all as fp
from gpdk.technology import get_technology
from ring_modulator import RingModulator
from h_fanout import HFanout
from gpdk.technology.waveguide_factory import EulerBendFactory
定义可编程光子链路类:
@dataclass(eq=False)
class PICircuit(fp.PCell):
def build(self):
global spacing
insts, elems, ports = super().build()
TECH = get_technology()
row_number = 100
column_number = 100
basic_comp = RingModulator()
basic_comp_y = RingModulator(transform=fp.rotate(degrees=90))
xy_spacing = []
xx_spacing = []
yy_spacing = []
yx_spacing = []
for i in range(row_number + 1):
xy_spacing.append(spacing * i)
for i in range(column_number):
xx_spacing.append(spacing * (i + 0.5))
for i in range(row_number):
yy_spacing.append(spacing * (i + 0.5))
for i in range(column_number + 1):
yx_spacing.append(spacing * i)
x_straight_top_right = []
x_straight_btm_right = []
x_straight_top_left = []
x_straight_btm_left = []
straight_index_min_x = 0
straight_index_max_x = 0
straight_index_min_xt = 0
straight_index_max_xt = 0
for i in range(row_number + 1):
for j in range(column_number):
x = xx_spacing[j]
y = xy_spacing[i]
x_dcoupler = basic_comp["op_0"].repositioned(at=(x, y)).owner
insts += x_dcoupler, f"{0},{i},{j}"
if (i == 0) and (j == 0):
get_position_y = basic_comp["op_1"].position[y]
x_straight_btm_left.append(pdk.Straight(name = "xbl_straight"+str(straight_index_min_x) ,length=20, waveguide_type=TECH.WG.FWG.C.WIRE)["op_0"].repositioned(at=(x-30-0.5*spacing, get_position_y)).owner)
insts += x_straight_btm_left[straight_index_min_x], f"{4},{0},{straight_index_min_x}"
straight_index_min_x = straight_index_min_x+1
if (i == 0) and (j == (column_number-1)):
get_position_y = basic_comp["op_1"].position[y]
x_straight_btm_right.append(pdk.Straight(name = "xbr_straight"+str(straight_index_max_x) ,length=20, waveguide_type=TECH.WG.FWG.C.WIRE)["op_0"].repositioned(at=(x+60+0.5*spacing, get_position_y)).owner)
insts += x_straight_btm_right[straight_index_max_x], f"{4},{1},{straight_index_max_x}"
straight_index_max_x = straight_index_max_x+1
if (i == row_number) and (j == 0):
x_straight_top_left.append(pdk.Straight(name = "xtl_straight"+str(straight_index_min_xt) ,length=20, waveguide_type=TECH.WG.FWG.C.WIRE)["op_0"].repositioned(at=(x-30-0.5*spacing, y)).owner)
insts += x_straight_top_left[straight_index_min_xt], f"{5},{0},{straight_index_min_xt}"
straight_index_min_xt = straight_index_min_xt+1
if (i == row_number) and (j == (column_number-1)):
x_straight_top_right.append(pdk.Straight(name = "xtr_straight"+str(straight_index_max_xt) ,length=20, waveguide_type=TECH.WG.FWG.C.WIRE)["op_0"].repositioned(at=(x+60+0.5*spacing,y)).owner)
insts += x_straight_top_right[straight_index_max_xt], f"{5},{1},{straight_index_max_xt}"
straight_index_max_xt = straight_index_max_xt+1
y_straight_top_right = []
y_straight_btm_right = []
y_straight_top_left = []
y_straight_btm_left = []
straight_index_min = 0
straight_index_max = 0
for i in range(row_number):
for j in range(column_number + 1):
x = yx_spacing[j]
y = yy_spacing[i]
y_dcoupler = basic_comp_y["op_0"].repositioned(at=(x, y)).owner
insts += y_dcoupler, f"{1},{i},{j}"
if (j == 0) :
y_straight_top_right.append(pdk.Straight(name = "tr_straight"+str(straight_index_min) ,length=20, waveguide_type=TECH.WG.FWG.C.WIRE)["op_0"].repositioned(at=(x-30, y+60)).owner)
y_straight_btm_right.append(pdk.Straight(name = "br_straight"+str(straight_index_min) ,length=20, waveguide_type=TECH.WG.FWG.C.WIRE)["op_0"].repositioned(at=(x-30, y-10)).owner)
insts += y_straight_top_right[straight_index_min], f"{2},{0},{straight_index_min}"
insts += y_straight_btm_right[straight_index_min], f"{2},{1},{straight_index_min}"
straight_index_min = straight_index_min+1
if (j == (column_number)) :
y_straight_top_left.append(pdk.Straight(name = "tl_straight"+str(straight_index_max) ,length=10, waveguide_type=TECH.WG.FWG.C.WIRE)["op_0"].repositioned(at=(x+60, y+60)).owner)
y_straight_btm_left.append(pdk.Straight(name = "bl_straight"+str(straight_index_max) ,length=10, waveguide_type=TECH.WG.FWG.C.WIRE)["op_0"].repositioned(at=(x+60, y-10)).owner)
insts += y_straight_top_left[straight_index_max], f"{3},{0},{straight_index_max}"
insts += y_straight_btm_left[straight_index_max], f"{3},{1},{straight_index_max}"
straight_index_max = straight_index_max+1
progcuit = cast(Mapping[str, fp.ICellRef], insts)
# p = progcuit["0,1,3"]["op_2"].position[0]
for i in range(row_number + 1):
for j in range(column_number):
if i == 0 and (j < column_number - 1):
link1 = fp.LinkBetween(start=progcuit[f"{0},{i},{j}"]["op_2"],
end=progcuit[f"{0},{i},{j + 1}"]["op_1"],
bend_factory=EulerBendFactory(radius_min=5, l_max=5, waveguide_type=TECH.WG.FWG.C.WIRE))
insts += link1
if i == row_number and (j < column_number - 1):
link2 = fp.LinkBetween(start=progcuit[f"{0},{i},{j}"]["op_3"],
end=progcuit[f"{0},{i},{j + 1}"]["op_0"],
bend_factory=EulerBendFactory(radius_min=5, l_max=15, waveguide_type=TECH.WG.FWG.C.WIRE))
insts += link2
if (i < row_number) and (j < column_number):
link3 = fp.LinkBetween(start=progcuit[f"{0},{i},{j}"]["op_0"],
end=progcuit[f"{1},{i},{j}"]["op_1"],
bend_factory=EulerBendFactory(radius_min=5, l_max=15, waveguide_type=TECH.WG.FWG.C.WIRE))
insts += link3
link4 = fp.LinkBetween(start=progcuit[f"{0},{i},{j}"]["op_3"],
end=progcuit[f"{1},{i},{j + 1}"]["op_0"],
bend_factory=EulerBendFactory(radius_min=15, l_max=15, waveguide_type=TECH.WG.FWG.C.WIRE))
insts += link4
link5 = fp.LinkBetween(start=progcuit[f"{0},{i + 1},{j}"]["op_1"],
end=progcuit[f"{1},{i},{j}"]["op_2"],
bend_factory=EulerBendFactory(radius_min=15, l_max=15, waveguide_type=TECH.WG.FWG.C.WIRE))
insts += link5
link6 = fp.LinkBetween(start=progcuit[f"{0},{i + 1},{j}"]["op_2"],
end=progcuit[f"{1},{i},{j + 1}"]["op_3"],
bend_factory=EulerBendFactory(radius_min=15, l_max=15, waveguide_type=TECH.WG.FWG.C.WIRE))
insts += link6
n = 0
link7 = fp.LinkBetween(start=progcuit[f"{0},{0},{column_number-1}"]["op_2"],
end=progcuit[f"{4},{1},{0}"]["op_0"],
bend_factory=TECH.WG.FWG.C.WIRE.BEND_CIRCULAR)
insts += link7
ports += progcuit[f"{4},{1},{0}"]["op_1"].with_name("op_"+str(n))
for i in range(row_number):
link8 = fp.LinkBetween(start=progcuit[f"1,{i},{column_number}"]["op_1"],
end=progcuit[f"{3},{1},{i}"]["op_0"],
bend_factory=EulerBendFactory(radius_min=15, l_max=15, waveguide_type=TECH.WG.FWG.C.WIRE))
insts += link8
n = n + 1
ports += progcuit[f"{3},{1},{i}"]["op_1"].with_name("op_"+str(n))
link9 = fp.LinkBetween(start=progcuit[f"1,{i},{column_number}"]["op_2"],
end=progcuit[f"{3},{0},{i}"]["op_0"],
bend_factory=EulerBendFactory(radius_min=15, l_max=15, waveguide_type=TECH.WG.FWG.C.WIRE))
insts += link9
n = n + 1
ports += progcuit[f"{3},{0},{i}"]["op_1"].with_name("op_"+str(n))
n = n + 1
link10 = fp.LinkBetween(start=progcuit[f"{0},{row_number},{column_number-1}"]["op_3"],
end=progcuit[f"{5},{1},{0}"]["op_0"],
bend_factory=EulerBendFactory(radius_min=15, l_max=15, waveguide_type=TECH.WG.FWG.C.WIRE))
insts += link10
ports += progcuit[f"{5},{1},{0}"]["op_1"].with_name("op_"+str(n))
n = n+1
link10 = fp.LinkBetween(start=progcuit[f"{0},{row_number},0"]["op_0"],
end=progcuit[f"{5},{0},{0}"]["op_1"],
bend_factory=EulerBendFactory(radius_min=15, l_max=15, waveguide_type=TECH.WG.FWG.C.WIRE))
insts += link10
ports += progcuit[f"{5},{0},{0}"]["op_0"].with_name("op_"+str(n))
for i in range(row_number-1,-1,-1):
n = n + 1
link11 = fp.LinkBetween(start=progcuit[f"1,{i},0"]["op_3"],
end=progcuit[f"{2},{0},{i}"]["op_1"],
bend_factory=EulerBendFactory(radius_min=15, l_max=15,
waveguide_type=TECH.WG.FWG.C.WIRE))
insts += link11
ports += progcuit[f"{2},{0},{i}"]["op_0"].with_name("op_"+str(n))
n = n + 1
link12 = fp.LinkBetween(start=progcuit[f"1,{i},0"]["op_0"],
end=progcuit[f"{2},{1},{i}"]["op_1"],
bend_factory=EulerBendFactory(radius_min=15, l_max=15,
waveguide_type=TECH.WG.FWG.C.WIRE))
insts += link12
ports += progcuit[f"{2},{1},{i}"]["op_0"].with_name("op_"+str(n))
n = n+1
link13 = fp.LinkBetween(start=progcuit["0,0,0"]["op_1"],
end=progcuit[f"{4},{0},{0}"]["op_1"],
bend_factory=TECH.WG.FWG.C.WIRE.BEND_CIRCULAR)
insts += link13
ports += progcuit[f"{4},{0},{0}"]["op_0"].with_name("op_"+str(n))
# fmt: on
return insts, elems, ports
主函数中调用,并利用‘Hfanout’函数实现端口光栅耦合器设计:
if __name__ == "__main__":
from pathlib import Path
gds_file = Path(__file__).parent / "local" / Path(__file__).with_suffix(".gds").name
library = fp.Library()
TECH = get_technology()
# =============================================================
# fmt: off
def bend_factories(waveguide_type: fp.IWaveguideType):
if waveguide_type == TECH.WG.FWG.C.WIRE:
return EulerBendFactory(radius_min=15, l_max=15, waveguide_type=waveguide_type)
return waveguide_type.bend_factory
library += [
HFanout(name="mmi",
device=PICircuit(),
left_spacing=100,
right_spacing=100,
left_distance=100,
right_distance=100,
bend_factories=bend_factories,
left_waveguide_type=TECH.WG.SWG.C.WIRE,
right_waveguide_type=TECH.WG.SWG.C.WIRE)
]
# fmt: on
# =============================================================
fp.export_gds(library, file=gds_file)
fp.plot(library)
第二部分 参数说明
row_number 光网络横向网格数
column_number 光网络竖向网络数
basic_comp 基础模块器件,这里选用的是微环调制器
spacing 组件间距设置
第三部分 测试说明
首先2*2方形网络
其自动生成版图如下所示
继续测试5*4矩形网络
其自动生成版图如下所示
最后,为了展示PhotoCAD在可编程光子集成链路设计领域的巨大潜力,我们设计了20*30的光网络以及100*100的光网络。
第四部分 总结
PhotoCAD设计大规模可编程光子链路版图性能优异,根据官方提供的可重构代码,我们可以轻松的实现各种复杂网络。