案例分享:画微环调制器
全部代码如下:
from si_fab import all as pdk
from ipkiss3 import all as i3
class DC(i3.PCell):
straight_length = i3.PositiveNumberProperty(default=200)
radius = i3.PositiveNumberProperty(default=50)
spacing = i3.PositiveNumberProperty(default=1)
straight_waveguide = i3.ChildCellProperty()
arc_waveguide = i3.ChildCellProperty()
trace_template = i3.TraceTemplateProperty(
default=pdk.SWG450(), doc="The trace template for waveguide and heater"
)
def _default_straight_waveguide(self):
wg = i3.Waveguide(trace_template=self.trace_template)
wg.Layout(shape=i3.Shape([(0, 0), (self.straight_length, 0)]))
return wg
def _default_arc_waveguide(self):
wg = i3.RoundedWaveguide(trace_template=self.trace_template)
wg.Layout(shape=i3.ShapeArc(radius=self.radius, start_angle=0, start_face_angle=90, end_angle=180,
end_face_angle=270))
return wg
class Layout(i3.LayoutView):
def _generate_instances(self, insts):
insts += i3.place_and_route(
insts={
"wg1": self.straight_waveguide,
"wg2": self.arc_waveguide,
},
specs=[
i3.Place("wg1:in", (-self.straight_length / 2, 0)),
]
)
insts = i3.place_and_route(
insts=insts,
specs=[
i3.PlaceRelative("wg2:out", "wg1:in",
(self.straight_length / 2 - self.radius, -self.radius - self.spacing))
]
)
return insts
def _generate_ports(self, ports):
ports += i3.expose_ports(
instances=self.instances,
port_name_map={
"wg1:in": "in1",
"wg2:in": "out2",
"wg1:out": "out1",
"wg2:out": "in2",
}
)
return ports
class Netlist(i3.NetlistFromLayout):
pass
class Ring_modulator(i3.Circuit):
_name_prefix = "Ring_modulator"
dc = i3.ChildCellProperty()
heater = i3.ChildCellProperty()
radius = i3.PositiveNumberProperty(default=50)
dc_distance = i3.PositiveNumberProperty(default=300)
heater_length = i3.PositiveNumberProperty(default=100)
trace_template = i3.TraceTemplateProperty(
default=pdk.SWG450(), doc="The trace template for waveguide and heater"
)
straight_length = i3.PositiveNumberProperty(default=200)
spacing = i3.PositiveNumberProperty(default=0.8)
# Set the default value for the heater
def _default_dc(self):
return DC(straight_length=self.straight_length,
radius=self.radius,
trace_template=self.trace_template,
spacing=self.spacing)
def _default_heater(self):
ht = pdk.HeatedWaveguide(trace_template=self.trace_template)
ht.Layout(shape=i3.Shape([(0, 0), (self.heater_length, 0)]))
return ht
def _default_insts(self): # element naming
insts = {
"heater1": self.heater,
"heater2": self.heater,
"dc1": self.dc,
"dc2": self.dc,
}
return insts
def _default_specs(self): # coordinate
specs = [
i3.Place("dc1", (0.0, 0.0)),
i3.PlaceRelative("dc2", "dc1", (0.0, -self.dc_distance)),
i3.FlipV("dc2"),
i3.Place("heater1", (-self.radius, -self.dc_distance / 2 - self.heater_length / 2), 90),
i3.Place("heater2", (self.radius, -self.dc_distance / 2 - self.heater_length / 2), 90),
i3.ConnectManhattan("dc1:in2", "heater1:out"),
i3.ConnectManhattan("dc1:out2", "heater2:out"),
i3.ConnectManhattan("dc2:in2", "heater1:in"),
i3.ConnectManhattan("dc2:out2", "heater2:in"),
]
return specs
def _default_exposed_ports(self): # port definition
exposed_ports = {
"heater1:elec1": "elec1",
"heater1:elec2": "elec2",
"heater2:elec1": "elec3",
"heater2:elec2": "elec4",
"dc1:in1": "in1",
"dc2:in1": "in2",
"dc1:out1": "out1",
"dc2:out1": "out2",
}
return exposed_ports
if __name__ == "__main__":
Ring_modulator().Layout().visualize(annotate=True,legacy=True)