Component level simulation model
Important note: To run the below simulation models in PhotoCAD, upgrades to fnpcell-1.5.1 and sflow-0.8.36 are required
In this section, we will introduce a method for users to write their own S-Matrix for their components. Here we use the simplest waveguide model as an example.
WGModel class
from typing import Any, Sequence, Tuple from fnpcell import all as fp import numpy as np from fnpcell.interfaces import IScatterMatrix from fnpcell.interfaces import angle_between, distance_between from gpdk.technology import get_technology class WGModel(fp.sim.SimModel): op_0: fp.IOwnedPort op_1: fp.IOwnedPort wl0: float = 1.49 neff: float = 2.4 ng: float = 4.0 loss: float = 0.0 def simulate_scatter(self, wavelengths: Sequence[float]) -> IScatterMatrix: wl = np.array(wavelengths) wl0 = np.array(self.wl0) neff = np.array(self.neff) ng = np.array(self.ng) loss = np.array(self.loss) length = fp.distance_between(self.op_0.position, self.op_1.position) dwl = wl - self.wl0 dneff_dwl = (ng - neff) / wl0 neff = neff - dwl * dneff_dwl mag = 10 ** (-loss * length / 20) arg = 2 * np.pi * neff * length / wl op_0 = self.op_0 op_1 = self.op_1 S = fp.sim.SMatrix() S[op_1, op_0] = S[op_0, op_1] = mag, arg return S
Script description
Import functions and modules
from typing import Any, Sequence, Tuple from fnpcell import all as fp import numpy as np from fnpcell.interfaces import IScatterMatrix from fnpcell.interfaces import angle_between, distance_between from gpdk.technology import get_technology
List the ports and parameters that will be implemented in this simulation model.
op_0: fp.IOwnedPort op_1: fp.IOwnedPort wl0: float = 1.49 neff: float = 2.4 ng: float = 4.0 loss: float = 0.0
Define the S-Matrix by calculating the magnitude and argument relation between two ports.
fp.sim.SMatrix()is where the magnitude and argument should be assigned.
def simulate_scatter(self, wavelengths: Sequence[float]) -> IScatterMatrix: wl = np.array(wavelengths) wl0 = np.array(self.wl0) neff = np.array(self.neff) ng = np.array(self.ng) loss = np.array(self.loss) length = fp.distance_between(self.op_0.position, self.op_1.position) dwl = wl - self.wl0 dneff_dwl = (ng - neff) / wl0 neff = neff - dwl * dneff_dwl mag = 10 ** (-loss * length / 20) arg = 2 * np.pi * neff * length / wl op_0 = self.op_0 op_1 = self.op_1 S = fp.sim.SMatrix() S[op_1, op_0] = S[op_0, op_1] = mag, arg return S
Other simulation models
Directional Coupler
class DCModel(fp.sim.SimModel): op_0: fp.IOwnedPort op_1: fp.IOwnedPort op_2: fp.IOwnedPort op_3: fp.IOwnedPort coupling: float = 0.5 def simulate_scatter(self, wavelengths: Sequence[float]) -> IScatterMatrix: coupling = np.array(self.coupling) kappa = coupling**0.5 tau = (1 - coupling) ** 0.5 op_0, op_1, op_2, op_3 = self.op_0, self.op_1, self.op_2, self.op_3 S = fp.sim.SMatrix() S[op_2, op_1] = S[op_1, op_2] = tau, 0 S[op_3, op_1] = S[op_1, op_3] = kappa, np.pi / 2 S[op_2, op_0] = S[op_0, op_2] = kappa, np.pi / 2 S[op_3, op_0] = S[op_0, op_3] = tau, 0 return S
Grating Coupler
def simulate_scatter(self, wavelengths: Sequence[float]) -> IScatterMatrix: wl = np.array(wavelengths) wl0 = np.array(self.wl0) peak_transmission = np.array(self.peak_transmission) bandwidth = np.array(self.bandwidth) sigma = bandwidth / 2.35482 mag = ((peak_transmission ** 0.5) * np.exp(-(wl-wl0) ** 2.0 /( 2.0 * (sigma ** 2.0)))) arg = 2 * np.pi * 2.4 / wl op_0 = self.op_0 op_1 = self.op_1 S = fp.sim.SMatrix() S[op_1, op_0] = S[op_0, op_1] = mag, arg return S