案例分享:利用ipkiss画圆形螺旋线
全部代码如下:
from si_fab import all as pdk
import ipkiss3.all as i3
import numpy as np
from scipy.constants import pi
class SpiralCircular(i3.PCell):
core_width = i3.PositiveNumberProperty(doc="Core width of the bend waveguide", default=0.4)
radius = i3.PositiveNumberProperty(doc="Radius of the central bends", default=5.0)
spacing = i3.PositiveNumberProperty(doc="Separation between adjacent waveguides", default=0.5)
spiral_length = i3.PositiveNumberProperty(doc="Length of the total spiral waveguide", default=1000.0)
layout_properties = i3.NumpyArrayProperty(doc="Calculated layout properties of the spiral.", locked=True)
def _default_layout_properties(self):
r = self.radius
tot_sep = self.spacing + self.core_width
n_o_loops_act = -(2.0 * r / tot_sep) + np.sqrt(
(2.0 * r / tot_sep) ** 2.0 - ((2.0 * r - self.spiral_length / pi) / tot_sep)
)
n_o_loops = np.floor(n_o_loops_act)
theta_nom = self.spiral_length - 2.0 * r * pi * (2.0 * n_o_loops + 1.0) - (n_o_loops**2.0) * tot_sep * pi
theta_denom = 4.0 * r + (2.0 * n_o_loops + 1.0) * tot_sep
theta_m = theta_nom / theta_denom
r_out = 2.0 * r + (n_o_loops + 0.5) * tot_sep
dx0 = tot_sep * 0.5 * np.sin(theta_m)
dy0 = r_out * (1.0 - np.cos(theta_m)) + (r_out - 0.5 * tot_sep) * np.cos(theta_m)
return np.array([r, tot_sep, n_o_loops, theta_m, r_out, dx0, dy0])
class Layout(i3.LayoutView):
def _generate_elements(self, elems):
for p in self.ports:
elems += i3.Label(
text=p.name,
layer=i3.TECH.PPLAYER.DOC,
coordinate=p.position,
height=5.0,
)
return elems
def _generate_instances(self, insts):
r = self.layout_properties[0]
tot_sep = self.layout_properties[1]
n_o_loops = self.layout_properties[2]
theta_m = self.layout_properties[3]
r_out = self.layout_properties[4]
dx0 = self.layout_properties[5]
dy0 = self.layout_properties[6]
# spiral waveguide
for index in range(int(n_o_loops + 1)):
sign = 1.0 if index % 2 == 0 else -1.0
if index == 0:
radius = r
dy = 0.0
else:
radius = 2.0 * r + (2.0 * index - 1.0) * tot_sep * 0.5
dy = 2.0 * r + (index - 1.0) * tot_sep
shape_wg1 = [
(0.0, -sign * dy),
(sign * radius, -sign * dy),
(sign * radius, -sign * (dy - radius)),
(sign * radius, -sign * (dy - 2.0 * radius)),
(0.0, -sign * (dy - 2.0 * radius)),
]
shape_wg2 = [
(0.0, sign * dy),
(-sign * radius, sign * dy),
(-sign * radius, sign * (dy - radius)),
(-sign * radius, sign * (dy - 2.0 * radius)),
(0.0, sign * (dy - 2.0 * radius)),
]
wg1 = i3.RoundedWaveguide(trace_template=pdk.SWG450())
wg2 = i3.RoundedWaveguide(trace_template=pdk.SWG450())
wg1.Layout(bend_radius=radius, shape=shape_wg1)
wg2.Layout(bend_radius=radius, shape=shape_wg2)
transf = i3.Rotation(rotation=theta_m * (-180.0 / pi)) + i3.Translation(translation=(dx0, -dy0))
insts += i3.SRef(wg1, transformation=transf, flatten=True)
insts += i3.SRef(wg2, transformation=transf, flatten=True)
# output waveguides
wg_in = i3.RoundedWaveguide(trace_template=pdk.SWG450())
wg_out = i3.RoundedWaveguide(trace_template=pdk.SWG450())
if theta_m <= np.pi / 2.0:
shape_wg_in = [
(0.0, 0.0),
(r_out * np.tan(theta_m / 2.0), 0.0),
(r_out * np.sin(theta_m), -r_out * (1.0 - np.cos(theta_m))),
]
shape_wg_out = [
(2 * dx0, -2 * dy0),
(2 * dx0 - r_out * np.tan(theta_m / 2.0), -2 * dy0),
(
2 * dx0 - r_out * np.sin(theta_m),
-2 * dy0 + r_out * (1.0 - np.cos(theta_m)),
),
]
else:
shape_wg_in = [
(0.0, 0.0),
(r_out, 0.0),
(r_out, -r_out),
(r_out, -r_out - r_out * np.tan((theta_m - pi / 2.0) / 2.0)),
(r_out * np.sin(theta_m), -r_out * (1.0 - np.cos(theta_m))),
]
shape_wg_out = [
(2 * dx0, -2 * dy0),
(2 * dx0 - r_out, -2 * dy0),
(2 * dx0 - r_out, -2 * dy0 + r_out),
(
2 * dx0 - r_out,
-2 * dy0 + r_out + r_out * np.tan((theta_m - pi / 2.0) / 2.0),
),
(
2 * dx0 - r_out * np.sin(theta_m),
-2 * dy0 + r_out * (1.0 - np.cos(theta_m)),
),
]
wg_in.Layout(bend_radius=r_out, shape=shape_wg_in)
wg_out.Layout(bend_radius=r_out, shape=shape_wg_out)
insts += i3.SRef(wg_in, name="wg_in", flatten=True)
insts += i3.SRef(wg_out, name="wg_out", flatten=True)
return insts
def _generate_ports(self, ports):
ports += i3.expose_ports(
self.instances,
{
"wg_in:in": "opt1",
"wg_out:in": "opt2",
},
)
return ports
class Netlist(i3.NetlistFromLayout):
pass
if __name__ == '__main__':
SpiralCircular().Layout().visualize()