Grating Coupler

b4ef800003494bb1b99bba72bfc63889

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

  1. 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]:
../_images/examples_Grating_Coupler_8_0.svg

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.                             
../_images/examples_Grating_Coupler_10_5.png

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%
../_images/examples_Grating_Coupler_12_23.png

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%
../_images/examples_Grating_Coupler_14_44.png