luceda ipkiss教程 54:器件设计(i3.Pcell)

发布时间:2023年12月26日

在ipkiss中,器件是通过参数单元pcell的方式来定义的,一个完整的器件模型包含:布局视图Layout、网表视图Netlist以及行为模型视图CircuitModel,以1x2mmi为例:
在这里插入图片描述
所有代码如下:

from si_fab import all as pdk
from ipkiss3 import all as i3
import numba as nb
import numpy as np
from matplotlib import pyplot as plt


# Building the MMI PCell with properties that describe its geometry
class MMI1x2(i3.PCell):
    """MMI with 1 input and 2 outputs."""

    _name_prefix = "MMI1x2"
    trace_template = i3.TraceTemplateProperty(doc="Trace template of the access waveguide")
    width = i3.PositiveNumberProperty(default=4.0, doc="Width of the MMI section.")
    length = i3.PositiveNumberProperty(default=20.0, doc="Length of the MMI secion.")
    taper_width = i3.PositiveNumberProperty(default=1.0, doc="Width of the taper.")
    taper_length = i3.PositiveNumberProperty(default=5.0, doc="Length of the taper")
    waveguide_spacing = i3.PositiveNumberProperty(default=2.0, doc="Spacing between the waveguides.")

    def _default_trace_template(self):
        return pdk.SiWireWaveguideTemplate()

    class Layout(i3.LayoutView):
        def _generate_elements(self, elems):
            length = self.length
            width = self.width
            taper_length = self.taper_length
            taper_width = self.taper_width
            half_waveguide_spacing = 0.5 * self.waveguide_spacing
            core_layer = self.trace_template.core_layer
            cladding_layer = self.trace_template.cladding_layer
            core_width = self.trace_template.core_width

            # Si core
            elems += i3.Rectangle(
                layer=core_layer,
                center=(0.5 * length, 0.0),
                box_size=(length, width),
            )
            elems += i3.Wedge(
                layer=core_layer,
                begin_coord=(-taper_length, 0.0),
                end_coord=(0.0, 0.0),
                begin_width=core_width,
                end_width=taper_width,
            )
            elems += i3.Wedge(
                layer=core_layer,
                begin_coord=(length, half_waveguide_spacing),
                end_coord=(length + taper_length, half_waveguide_spacing),
                begin_width=taper_width,
                end_width=core_width,
            )
            elems += i3.Wedge(
                layer=core_layer,
                begin_coord=(length, -half_waveguide_spacing),
                end_coord=(length + taper_length, -half_waveguide_spacing),
                begin_width=taper_width,
                end_width=core_width,
            )

            # Cladding
            elems += i3.Rectangle(
                layer=cladding_layer,
                center=(0.5 * length, 0.0),
                box_size=(length + 2 * taper_length, width + 2.0),
            )
            return elems

        def _generate_ports(self, ports):
            length = self.length
            taper_length = self.taper_length
            trace_template = self.trace_template
            half_waveguide_spacing = 0.5 * self.waveguide_spacing

            ports += i3.OpticalPort(
                name="in1",
                position=(-taper_length, 0.0),
                angle=180.0,
                trace_template=trace_template,
            )
            ports += i3.OpticalPort(
                name="out1",
                position=(length + taper_length, -half_waveguide_spacing),
                angle=0.0,
                trace_template=trace_template,
            )
            ports += i3.OpticalPort(
                name="out2",
                position=(length + taper_length, half_waveguide_spacing),
                angle=0.0,
                trace_template=trace_template,
            )
            return ports

    class Netlist(i3.NetlistFromLayout):
        pass

    class CircuitModel(i3.CircuitModelView):
        center_wavelength = i3.PositiveNumberProperty(doc="Center wavelength")
        transmission = i3.NumpyArrayProperty(doc="Polynomial coefficients, transmission as a function of wavelength")
        reflection_in = i3.NumpyArrayProperty(
            doc="Polynomial coefficients, reflection at input port as a function of wavelength"
            )
        reflection_out = i3.NumpyArrayProperty(
            doc="Polynomial coefficients, reflection at output ports as a function  of wavelength"
            )
        def _default_center_wavelength(self):
            return 1.55

        def _default_transmission(self):
            return [0.707]

        def _default_reflection_in(self):
            return [0.0]

        def _default_reflection_out(self):
            return [0.0]


        def _generate_model(self):
            return MMI1x2Model(
                center_wavelength=self.center_wavelength,
                transmission=self.transmission,
                reflection_in=self.reflection_in,
                reflection_out=self.reflection_out,
            )


@nb.njit()
def polyval(p, x):
    """Simple polynomial evaluation using Horner's scheme."""
    result = p[0]
    for c in p[1:]:
        result = result * x + c
    return result


class MMI1x2Model(i3.CompactModel):
    """Model for a 1x2 MMI.
    * center_wavelength: the center wavelength at which the device operates
    * reflection_in: polynomial coefficients relating reflection at the input port and wavelength
    * reflection_out: polynomial coefficients relating reflection at the output ports and wavelength
    * transmission: polynomial coefficients relating transmission and wavelength
    """

    parameters = [
        "center_wavelength",
        "reflection_in",
        "reflection_out",
        "transmission",
    ]

    terms = [
        i3.OpticalTerm(name="in1"),
        i3.OpticalTerm(name="out1"),
        i3.OpticalTerm(name="out2"),
    ]

    def calculate_smatrix(parameters, env, S):
        reflection_in = polyval(parameters.reflection_in, env.wavelength - parameters.center_wavelength)
        reflection_out = polyval(parameters.reflection_out, env.wavelength - parameters.center_wavelength)
        transmission = polyval(parameters.transmission, env.wavelength - parameters.center_wavelength)
        S["in1", "out1"] = S["out1", "in1"] = transmission
        S["in1", "out2"] = S["out2", "in1"] = transmission
        S["in1", "in1"] = reflection_in
        S["out1", "out1"] = S["out2", "out2"] = reflection_out


if __name__ == '__main__':
    MMI1x2().Layout().visualize(annotate=True,show=False)
    mmi_cm = MMI1x2().CircuitModel()
    wavelengths = np.linspace(1.5, 1.6, 501)
    S_total = mmi_cm.get_smatrix(wavelengths=wavelengths)

    # 2. We plot the transmission
    plt.figure(2)
    plt.plot(wavelengths, i3.signal_power_dB(S_total["out1", "in1"]), "-", linewidth=2.2, label="in1 -> out1")
    plt.plot(wavelengths, i3.signal_power_dB(S_total["out2", "in1"]), "-", linewidth=2.2, label="in1 -> out2")
    plt.ylim(-5, 0)
    plt.xlabel("Wavelength [um]", fontsize=16)
    plt.ylabel("Transmission [dB]", fontsize=16)
    plt.legend(fontsize=14, loc=4)
    plt.show()

代码中包含:

器件参数:

_name_prefix = "MMI1x2"
 trace_template = i3.TraceTemplateProperty(doc="Trace template of the access waveguide")
 width = i3.PositiveNumberProperty(default=4.0, doc="Width of the MMI section.")
 length = i3.PositiveNumberProperty(default=20.0, doc="Length of the MMI secion.")
 taper_width = i3.PositiveNumberProperty(default=1.0, doc="Width of the taper.")
 taper_length = i3.PositiveNumberProperty(default=5.0, doc="Length of the taper")
 waveguide_spacing = i3.PositiveNumberProperty(default=2.0, doc="Spacing between the waveguides.")

 def _default_trace_template(self):
     return pdk.SiWireWaveguideTemplate()

器件形状(Layout):

    class Layout(i3.LayoutView):
        def _generate_elements(self, elems):
            length = self.length
            width = self.width
            taper_length = self.taper_length
            taper_width = self.taper_width
            half_waveguide_spacing = 0.5 * self.waveguide_spacing
            core_layer = self.trace_template.core_layer
            cladding_layer = self.trace_template.cladding_layer
            core_width = self.trace_template.core_width

            # Si core
            elems += i3.Rectangle(
                layer=core_layer,
                center=(0.5 * length, 0.0),
                box_size=(length, width),
            )
            elems += i3.Wedge(
                layer=core_layer,
                begin_coord=(-taper_length, 0.0),
                end_coord=(0.0, 0.0),
                begin_width=core_width,
                end_width=taper_width,
            )
            elems += i3.Wedge(
                layer=core_layer,
                begin_coord=(length, half_waveguide_spacing),
                end_coord=(length + taper_length, half_waveguide_spacing),
                begin_width=taper_width,
                end_width=core_width,
            )
            elems += i3.Wedge(
                layer=core_layer,
                begin_coord=(length, -half_waveguide_spacing),
                end_coord=(length + taper_length, -half_waveguide_spacing),
                begin_width=taper_width,
                end_width=core_width,
            )

            # Cladding
            elems += i3.Rectangle(
                layer=cladding_layer,
                center=(0.5 * length, 0.0),
                box_size=(length + 2 * taper_length, width + 2.0),
            )
            return elems

        def _generate_ports(self, ports):
            length = self.length
            taper_length = self.taper_length
            trace_template = self.trace_template
            half_waveguide_spacing = 0.5 * self.waveguide_spacing

            ports += i3.OpticalPort(
                name="in1",
                position=(-taper_length, 0.0),
                angle=180.0,
                trace_template=trace_template,
            )
            ports += i3.OpticalPort(
                name="out1",
                position=(length + taper_length, -half_waveguide_spacing),
                angle=0.0,
                trace_template=trace_template,
            )
            ports += i3.OpticalPort(
                name="out2",
                position=(length + taper_length, half_waveguide_spacing),
                angle=0.0,
                trace_template=trace_template,
            )
            return ports

器件与外界交互的端口(netlist):

    class Netlist(i3.NetlistFromLayout):
        pass

器件的行为模型:

    class CircuitModel(i3.CircuitModelView):
        center_wavelength = i3.PositiveNumberProperty(doc="Center wavelength")
        transmission = i3.NumpyArrayProperty(doc="Polynomial coefficients, transmission as a function of wavelength")
        reflection_in = i3.NumpyArrayProperty(
            doc="Polynomial coefficients, reflection at input port as a function of wavelength"
            )
        reflection_out = i3.NumpyArrayProperty(
            doc="Polynomial coefficients, reflection at output ports as a function  of wavelength"
            )
        def _default_center_wavelength(self):
            return 1.55

        def _default_transmission(self):
            return [0.707]

        def _default_reflection_in(self):
            return [0.0]

        def _default_reflection_out(self):
            return [0.0]


        def _generate_model(self):
            return MMI1x2Model(
                center_wavelength=self.center_wavelength,
                transmission=self.transmission,
                reflection_in=self.reflection_in,
                reflection_out=self.reflection_out,
            )

该行为模型需要输入的参数包括:中心波长、端口传输谱,以及端口的发射谱,有了这些参数,行为模型可以继承紧凑模型(compactmodel):
紧凑模型(compactmodel)的定义:

class MMI1x2Model(i3.CompactModel):
    """Model for a 1x2 MMI.
    * center_wavelength: the center wavelength at which the device operates
    * reflection_in: polynomial coefficients relating reflection at the input port and wavelength
    * reflection_out: polynomial coefficients relating reflection at the output ports and wavelength
    * transmission: polynomial coefficients relating transmission and wavelength
    """

    parameters = [
        "center_wavelength",
        "reflection_in",
        "reflection_out",
        "transmission",
    ]

    terms = [
        i3.OpticalTerm(name="in1"),
        i3.OpticalTerm(name="out1"),
        i3.OpticalTerm(name="out2"),
    ]

    def calculate_smatrix(parameters, env, S):
        reflection_in = polyval(parameters.reflection_in, env.wavelength - parameters.center_wavelength)
        reflection_out = polyval(parameters.reflection_out, env.wavelength - parameters.center_wavelength)
        transmission = polyval(parameters.transmission, env.wavelength - parameters.center_wavelength)
        S["in1", "out1"] = S["out1", "in1"] = transmission
        S["in1", "out2"] = S["out2", "in1"] = transmission
        S["in1", "in1"] = reflection_in
        S["out1", "out1"] = S["out2", "out2"] = reflection_out

紧凑模型包括,1、从行为模型继承的参数:

parameters = [
        "center_wavelength",
        "reflection_in",
        "reflection_out",
        "transmission",
    ]

2、仿真的光学端口:

 terms = [
        i3.OpticalTerm(name="in1"),
        i3.OpticalTerm(name="out1"),
        i3.OpticalTerm(name="out2"),
    ]

3、散射矩阵:

    def calculate_smatrix(parameters, env, S):
        reflection_in = polyval(parameters.reflection_in, env.wavelength - parameters.center_wavelength)
        reflection_out = polyval(parameters.reflection_out, env.wavelength - parameters.center_wavelength)
        transmission = polyval(parameters.transmission, env.wavelength - parameters.center_wavelength)
        S["in1", "out1"] = S["out1", "in1"] = transmission
        S["in1", "out2"] = S["out2", "in1"] = transmission
        S["in1", "in1"] = reflection_in
        S["out1", "out1"] = S["out2", "out2"] = reflection_out

有了行为模型,就可以对器件进行仿真:

MMI1x2().Layout().visualize(annotate=True,show=False)
    mmi_cm = MMI1x2().CircuitModel()
    wavelengths = np.linspace(1.5, 1.6, 501)
    S_total = mmi_cm.get_smatrix(wavelengths=wavelengths)

    # 2. We plot the transmission
    plt.figure(2)
    plt.plot(wavelengths, i3.signal_power_dB(S_total["out1", "in1"]), "-", linewidth=2.2, label="in1 -> out1")
    plt.plot(wavelengths, i3.signal_power_dB(S_total["out2", "in1"]), "-", linewidth=2.2, label="in1 -> out2")
    plt.ylim(-5, 0)
    plt.xlabel("Wavelength [um]", fontsize=16)
    plt.ylabel("Transmission [dB]", fontsize=16)
    plt.legend(fontsize=14, loc=4)
    plt.show()

仿真结果:
在这里插入图片描述

文章来源:https://blog.csdn.net/qq_34316088/article/details/135228456
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。