案例分享:设计光栅耦合器
全部代码如下:
from si_fab import all as pdk
from ipkiss3 import all as i3
import numpy as np
class grating_coupler(i3.PCell):
"""SOI grating coupler."""
_name_prefix = "grating_coupler_soi"
trace_template = i3.TraceTemplateProperty(doc="the trace template of waveguide")
waveguide_length = i3.PositiveNumberProperty(doc="the length of waveguide")
r = i3.PositiveNumberProperty(doc="the radius of the first grating tooth")
sector_angle = i3.AngleProperty(doc="the sector angle")
grating_period = i3.PositiveNumberProperty(doc="the period of grating")
duty_cycle = i3.PositiveNumberProperty(doc="the duty cycle of grating")
period_number = i3.IntProperty(doc="number of grating periods")
length3 = i3.PositiveNumberProperty(default=5, doc="the length of waveguide3")
length4 = i3.PositiveNumberProperty(default=5, doc="the length of waveguide4")
length5 = i3.PositiveNumberProperty(default=2, doc="the length of waveguide5")
def _default_trace_template(self):
return pdk.SWG450()
def _default_waveguide_length(self):
return 10.0
def _default_r(self):
return 50.0
def _default_sector_angle(self):
return 20.0
def _default_grating_period(self):
return 4.0
def _default_duty_cycle(self):
return 0.5
def _default_period_number(self):
return 10
class Layout(i3.LayoutView):
def _generate_elements(self, elems):
length_triangle = self.r + self.grating_period * self.period_number + 10 - self.grating_period * (
1 - self.duty_cycle)
elems += i3.Wedge(
layer=self.trace_template.core_layer,
begin_coord=(0.0, 0.0),
end_coord=(length_triangle, 0.0),
begin_width=0.0,
end_width=length_triangle * np.tan(np.radians(self.sector_angle / 2)) * 2,
)
for period in range(self.period_number):
elems += i3.ArcPath(
layer=i3.TECH.PPLAYER.SI_TRENCH,
center=(0.0, 0.0),
radius=self.r + period * self.grating_period,
start_angle=-self.sector_angle / 2,
end_angle=self.sector_angle / 2,
line_width=self.grating_period * self.duty_cycle,
)
elems += i3.Rectangle(
layer=self.trace_template.core_layer,
center=(length_triangle + self.length5 / 2, 0.0),
box_size=(self.length5, length_triangle * np.tan(np.radians(self.sector_angle / 2)) * 2),
)
core_width = self.trace_template.core_width
clad_width = self.trace_template.cladding_width
elems += i3.Wedge(
layer=i3.TECH.PPLAYER.SI_CLADDING,
begin_coord=(core_width / np.tan(np.radians(self.sector_angle / 2)) / 2, 0.0),
end_coord=(length_triangle + self.length5, 0.0),
begin_width=clad_width,
end_width=(length_triangle + self.length5) * np.tan(
np.radians(self.sector_angle / 2)) * 2 + clad_width - core_width,
)
elems += i3.Rectangle(
layer=i3.TECH.PPLAYER.SI_CLADDING,
center=(length_triangle + self.length5 + self.length4 / 2, 0.0),
box_size=(
self.length4,
(length_triangle + self.length5) * np.tan(
np.radians(self.sector_angle / 2)) * 2 + clad_width - core_width),
)
return elems
def _generate_instances(self, insts):
core_width = self.trace_template.core_width
length1 = core_width / np.tan(np.radians(self.sector_angle / 2)) / 2
wg_in = i3.RoundedWaveguide(trace_template=self.trace_template, name="wg_in")
shape = [(-self.waveguide_length + length1, 0), (length1, 0)]
wg_in.Layout(
shape=shape,
)
insts += i3.SRef(wg_in, name="wg_in")
return insts
def _generate_ports(self, ports):
core_width = self.trace_template.core_width
length1 = core_width / np.tan(np.radians(self.sector_angle / 2)) / 2
ports += i3.OpticalPort(
name="in",
position=(-self.waveguide_length + length1, 0.0),
angle=180.0,
trace_template=self.trace_template,
)
return ports
class Netlist(i3.NetlistFromLayout):
pass
if __name__ == '__main__':
grating_coupler().Layout().visualize(annotate=True)