Grating Coupler¶
This example shows how to use the focused grating stencil to create a grating coupler component equivalent to the one demonstrated in [1]. We use a Gaussian port to model the fiber input and a Tidy3D model to evaluate the grating S parameters.
References
Frederik Van Laere, Tom Claes, Jonathan Schrauwen, Stijn Scheerlinck, Wim Bogaerts, Dirk Taillaert, Liam O’Faolain, Dries Van Thourhout, Roel Baets, “Compact Focusing Grating Couplers for Silicon-on-Insulator Integrated Circuits,” in IEEE Photonics Technology Letters, vol. 19, no. 23, pp. 1919-1921, Dec.1, 2007, doi: 10.1109/LPT.2007.908762
[1]:
import numpy as np
import tidy3d as td
import photonforge as pf
from matplotlib import pyplot as plt
The technology used in the reference work [1] is similar to the default available as PhotonForge’s basic technology, with 2 important differences: the slab thickness and the absence of the top cladding.
Technology Setup¶
Changing the slab thickness to emulate the 70 nm etch depth is a matter of setting slab_thickness to 150 nm:
[2]:
tech = pf.basic_technology(slab_thickness=0.15)
pf.config.default_technology = tech
Unfortunately, there is no argument to remove the top cladding, because the basic technology sets top and bottom media to the background medium, and we cannot set the top cladding thickness to 0 because it is used to set the port dimensions.
A better option is to add an new extrusion specification to the technology that creates a extra air volume above the substrate level with infinite thickness. That can be accomplished with the insert_extrusion_spec function:
[3]:
# An empty mask covers the whole device bounds
air_extrusion = pf.ExtrusionSpec(pf.MaskSpec(), td.Medium(permittivity=1.0), limits=(0, pf.Z_INF))
# Insert air volume first, so that all core extrusions override the air clad
tech.insert_extrusion_spec(0, air_extrusion)
tech.extrusion_specs[0]
[3]:
ExtrusionSpec(mask_spec=MaskSpec(operand1=[], operand2=[], operation='+'), medium=Medium(permittivity=1.0), limits=(0, 2e+07), sidewall_angle=0, reference="top")
Now we can design the component based on the technology we created, using its layers and port specifications, and the focused grating stencil. We will create is as a parametric component with a few parameters we can latter use for fine-tuning or optimizing for other wavelengths. We use the parameters from the reference work to create the component in this case.
[4]:
@pf.parametric_component
def grating_coupler(
*,
period,
focal_length,
length,
angle,
fiber_angle,
fiber_translation=0,
fill_factor=0.5,
):
n_env = 1.0 # Top cladding refractive index
waist_radius = 6.0
gaussian_port_height = 0.5 # Make sure the Gaussian port above the core
input_length = 1.0 # Small waveguide section for the taper mode to accommodate
# Get the core width for the strip waveguide port
port_spec = tech.ports["Strip"]
layer = tech.layers["WG_CORE"].layer
input_width = sum(w for w, _, l in port_spec.path_profiles if l == layer)
# Define the port input vector based on the fiber angle
sin_angle = np.sin(fiber_angle / 180 * np.pi)
cos_angle = np.cos(fiber_angle / 180 * np.pi)
input_vector = (-sin_angle, 0, -cos_angle)
# Use automatic naming from the parametric_component decorator
c = pf.Component()
# Add the waveguide section
for layer, path in port_spec.get_paths((0, 0)):
c.add(layer, path.segment((input_length, 0)))
grating = pf.stencil.focused_grating(
1.55,
period,
n_env * sin_angle,
focal_length=focal_length,
length=length,
angle=angle,
fill_factor=fill_factor,
input_width=input_width,
)
# Move the grating structures to make room for the waveguide section
for structure in grating:
structure.translate((input_length, 0))
c.add("WG_CORE", *grating)
# Add the 150 nm slab around the whole grating
grating_slab = pf.envelope(grating[1:], period)
c.add("SLAB", grating_slab)
# Add a cladding polygon around the component, but trimmed at the waveguide port
clad_region = pf.envelope(grating, 1.5, trim_x_min=True)
c.add("WG_CLAD", clad_region)
c.add_port(pf.Port((0, 0), 0, port_spec))
gaussian_port_center = (
np.array((focal_length + 0.5 * length + fiber_translation, 0, 0))
+ input_vector / input_vector[2] * gaussian_port_height
)
c.add_port(
pf.GaussianPort(
gaussian_port_center,
input_vector,
waist_radius,
polarization_angle=90,
field_tolerance=1e-2,
)
)
# This is a large model, so we probably want to minimize the simulation size wherever possible.
# We decrease the refinement from 20 (default) to 15, which has minimal impact on the final
# result. We can increase it back for later for verification, if needed. We also specify the
# symmetry in the y axis (assuming TE mode) to halve the computation domain.
grid_spec = td.GridSpec.auto(wavelength=1.55, min_steps_per_wvl=15)
c.add_model(
pf.Tidy3DModel(symmetry=(0, -1, 0), grid_spec=grid_spec),
"Tidy3D",
)
return c
grating = grating_coupler(focal_length=12.5, length=15.5, period=0.63, angle=45, fiber_angle=10)
grating
[4]:
Once we define the simulation wavelengths, we can get the simulations for the grating to make sure our port placement and setup is correct.
[5]:
wavelengths = np.linspace(1.5, 1.6, 21)
sims = grating.models["Tidy3D"].get_simulations(grating, pf.C_0 / wavelengths)
_ = sims["P1@0"].plot(y=0)
22:36:32 -03 WARNING: Starting in version 2.11, the behavior of GaussianBeam with direction '-' and non-zero 'waist_distance' has changed. The waist position is now defined consistently for both forward- and backward-propagating beams: a positive 'waist_distance' always places the beam waist behind the source/monitor plane (toward the negative normal axis). This ensures reciprocity between Gaussian sources and overlap monitors used for port-based S-matrix calculations. If your simulation relied on the previous behavior (where the waist position flipped with direction), you may need to adjust your waist distance values.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
22:36:33 -03 WARNING: Suppressed 1 WARNING message.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
Now we can compute the S parameters as usual:
[6]:
s_matrix = grating.s_matrix(pf.C_0 / wavelengths)
_ = pf.plot_s_matrix(s_matrix, y="dB")
Starting…
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
22:36:34 -03 WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
Loading simulation from local cache. View cached task using web UI at 'https://tidy3d.simulation.cloud/workbench?taskId=fdve-82f3bf8d-336 3-4e53-bb61-014cb6ea68ab'.
22:36:35 -03 WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Warning messages were found in the solver log. For more information, check 'SimulationData.log' or use 'web.download_log(task_id)'.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
Loading simulation from local cache. View cached task using web UI at 'https://tidy3d.simulation.cloud/workbench?taskId=fdve-38cddbf2-cbb 6-49a2-93b0-f29f5fb3446e'.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
22:36:36 -03 WARNING: Warning messages were found in the solver log. For more information, check 'SimulationData.log' or use 'web.download_log(task_id)'.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
Loading simulation from local cache. View cached task using web UI at 'https://tidy3d.simulation.cloud/workbench?taskId=mo-22dc525d-c113- 4651-9a9a-25a80c5b427c'.
Progress: 100%
Fiber Adjustment¶
We see that the wavelength of the efficiency peak is very close to that of the experimental results, but the loss is a little higher. The experiments show values between -5 dB and -6 dB per grating. That extra penalty can be removed by adjusting the Gaussian port position over the grating, which is one of the experimental adjustments done to optimize the transmission that is difficult to measure.
A simple parametric sweep can be used here to improve the result, which reaches the desired level above -6 dB. Note that we’re only running the simulations we really require for the transmission by explicitly setting the ports and modes we want as input for the Tidy3D model.
[7]:
_, ax = plt.subplots(1, 1, tight_layout=True)
for dx in range(-3, 1):
grating.update(fiber_translation=dx)
# The model is updated after the component because the component update re-creates the model
grating.models["Tidy3D"].update(verbose=False)
s = grating.s_matrix(pf.C_0 / wavelengths, model_kwargs={"inputs": ["P0@0"]})
ax.plot(pf.C_0 / s.frequencies, 20 * np.log10(np.abs(s["P0@0", "P1@0"])), label=f"Δx={dx} μm")
ax.set(xlabel="Wavelength (μm)", ylabel="Transmission")
ax.legend()
ax.grid(True)
Starting…
22:36:37 -03 WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
22:36:38 -03 WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Warning messages were found in the solver log. For more information, check 'SimulationData.log' or use 'web.download_log(task_id)'.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
22:36:39 -03 WARNING: Suppressed 1 WARNING message.
Progress: 100%
Starting…
22:36:40 -03 WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Warning messages were found in the solver log. For more information, check 'SimulationData.log' or use 'web.download_log(task_id)'.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
Progress: 100%
Starting…
22:36:41 -03 WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
22:36:42 -03 WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Warning messages were found in the solver log. For more information, check 'SimulationData.log' or use 'web.download_log(task_id)'.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
Progress: 100%
Starting…
22:36:43 -03 WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
WARNING: Structure at 'structures[2]' has bounds that extend exactly to simulation edges. This can cause unexpected behavior. If intending to extend the structure to infinity along one dimension, use td.inf as a size variable instead to make this explicit.
WARNING: Suppressed 1 WARNING message.
Progress: 100%