Circuit simulations (tidy3d + SAX)

Circuit simulations (tidy3d + SAX)#

Sparameters are common in RF and photonic simulation.

We are going to simulate a MZI interferometer circuit.

For that we need to simulate each of the component Sparameters in tidy3d and then SAX Sparameter circuit solver to solve the Sparameters for the circuit.

We will be using SAX which is open source and tidy3d which requires you to create an account to run simulations in tidy3d cloud.

tidy3d FDTD simulations#

Lets compute the Sparameters of a 1x2 power splitter using tidy3d.

tidy3D is a fast GPU based FDTD tool developed by flexcompute.

To run, you need to create an account and add credits. The number of credits that each simulation takes depends on the simulation computation time.

cloud_model

import gdsfactory as gf
import gplugins as sim
import gplugins.tidy3d as gt

import ubcpdk.components as pdk
from ubcpdk.config import PATH
c = pdk.ebeam_y_1550()
c.plot()
2024-04-12 23:30:41.258 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/ebeam_y_1550.lyp'.
../_images/3b1126ad2f137e3a473add518793c9fc397bf70969f0c135c5d6a708ee01f131.png
sp = gt.write_sparameters(c, filepath=PATH.sparameters / "ebeam_y_1550_20634f71.npz")
23:30:41 UTC WARNING: 'geometry=PolySlab(type='PolySlab', axis=2,               
             sidewall_angle=0.0, reference_plane='middle', slab_bounds=(-13.0,  
             -3.0), dilation=0.0, vertices=array([[ 11.901,   7.001],           
                    [ 11.901,  -7.001],                                         
                    [-11.901,  -7.001],                                         
                    [-11.901,   7.001],                                         
                    [ 11.901,   7.001]])) name='substrate_0' type='Structure'   
             medium=Medium(name='Si', frequency_range=None, allow_gain=False,   
             nonlinear_spec=None, modulation_spec=None, heat_spec=None,         
             type='Medium', permittivity=12.0409, conductivity=0.0)' (at        
             `simulation.structures[0]`) is completely outside of simulation    
             domain.                                                            
             WARNING: 'geometry=PolySlab(type='PolySlab', axis=2,               
             sidewall_angle=0.0, reference_plane='middle', slab_bounds=(-13.0,  
             -3.0), dilation=0.0, vertices=array([[ 11.901,   7.001],           
                    [ 11.901,  -7.001],                                         
                    [-11.901,  -7.001],                                         
                    [-11.901,   7.001],                                         
                    [ 11.901,   7.001]])) name='substrate_0' type='Structure'   
             medium=Medium(name='Si', frequency_range=None, allow_gain=False,   
             nonlinear_spec=None, modulation_spec=None, heat_spec=None,         
             type='Medium', permittivity=12.0409, conductivity=0.0)' (at        
             `simulation.structures[0]`) is completely outside of simulation    
             domain.                                                            
Simulation loaded from PosixPath('/__w/ubc/ubc/sparameters/ebeam_y_1550_20634f71.npz')
sim.plot.plot_sparameters(sp)
../_images/481d025a3b9a5f9a5f67808a87184f69823ece1c9e6cc669abd536d92d593995.png
sim.plot.plot_loss1x2(sp)
../_images/c1ab7073e15168ed899bb9bc38ed9a5c3742d2a0e31625af18914e723ce27594.png

Circuit simulation#

mzi10 = pdk.mzi(splitter=c, delta_length=10)
mzi10.plot()
2024-04-12 23:30:42.200 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/mzi_96d1ff47.lyp'.
../_images/618ef5293ebc8546c9135712e4319260a910a7a9b67e8280d6ca70fe61ac6dab.png
import gdsfactory as gf
import gplugins.sax as gsax
import jax.numpy as jnp
import matplotlib.pyplot as plt
import numpy as np
import sax
def straight(wl=1.5, length=10.0, neff=2.4) -> sax.SDict:
    return sax.reciprocal({("o1", "o2"): jnp.exp(2j * jnp.pi * neff * length / wl)})


def bend_euler(wl=1.5, length=20.0):
    """Assumes a reduced transmission for the euler bend compared to a straight"""
    return {k: 0.99 * v for k, v in straight(wl=wl, length=length).items()}
ebeam_y_1550 = gsax.read.model_from_npz(sp)
netlist = mzi10.get_netlist()
circuit, _ = sax.circuit(
    netlist=netlist,
    models={
        "bend_euler_sc": bend_euler,
        "ebeam_y_1550": ebeam_y_1550,
        "straight": straight,
    },
)
wl = np.linspace(1.5, 1.6)
S = circuit(wl=wl)
plt.figure(figsize=(14, 4))
plt.title("MZI")
plt.plot(1e3 * wl, 10 * np.log10(jnp.abs(S["o1", "o2"]) ** 2))
plt.xlabel("λ [nm]")
plt.ylabel("T")
plt.grid(True)
plt.show()
../_images/ba43fcf3ca2c596c0e2bc0ccfd4b0b2a5d64477027481e97e4d238f8bc4d0db2.png
mzi20 = pdk.mzi(splitter=c, delta_length=20)
mzi20.plot()
2024-04-12 23:30:44.094 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/mzi_b1a77962.lyp'.
../_images/751c47186987000f717e306d07f5984ab317331a79e047f24fe480152483c888.png
netlist = mzi20.get_netlist()
circuit, _ = sax.circuit(
    netlist=netlist,
    models={
        "bend_euler_sc": bend_euler,
        "ebeam_y_1550": ebeam_y_1550,
        "straight": straight,
    },
)
wl = np.linspace(1.5, 1.6)
S = circuit(wl=wl)
plt.figure(figsize=(14, 4))
plt.title("MZI")
plt.plot(1e3 * wl, 10 * np.log10(jnp.abs(S["o1", "o2"]) ** 2))
plt.xlabel("λ [nm]")
plt.ylabel("T")
plt.grid(True)
plt.show()
../_images/0730b322b4a4e1c5b75ebb12e26b0888ab572d06e550fd8b4fe8ad9571dca0aa.png