Exceptional coupling for waveguide crosstalk reduction#

This notebook contains large simulations. Running the entire notebook will cost about 20 FlexCredits.

The current technological trend emphasizes the dense integration of photonic components on a chip. However, as the proximity between these components increases, the issue of crosstalk becomes more significant and detrimental. Therefore, we need to apply other design ideas to actively minimize the crosstalk.

In this notebook, we investigate the crosstalk between two strip waveguides, which are fundamental photonic components. We demonstrate that the utilization of anisotropic metamaterial (also known as subwavelength grating (swg)) cladding enables remarkable reduction of crosstalk by leveraging the exceptional coupling as proposed in the article Md Borhan Mia, Syed Z. Ahmed, Ishtiaque Ahmed, Yun Jo Lee, Minghao Qi, and Sangsik Kim, "Exceptional coupling in photonic anisotropic metamaterials for extremely low waveguide crosstalk," Optica 7, 881-887 (2020) DOI: 10.1364/OPTICA.394987. The waveguide with anisotropic metamaterial cladding is shown to have an extreme skin depth and thus it’s termed eskid waveguide. The reduced skin depth leads to reduced crosstalk. Moreover, at a certain wavelength, exceptional coupling occurs where the symmetric and antisymmetric modes have identical effective index and the coupling is zero in principle.

Schematic of the anisotropic metamaterial for crosstalk reduction

For more integrated photonic examples such as the waveguide crossing, the strip to slot waveguide converter, and the broadband directional coupler, please visit our examples page.

[1]:
import numpy as np
import matplotlib.pyplot as plt
import gdstk

import tidy3d as td
import tidy3d.web as web

Simulation Setup#

For the simulation, we will investigate the wavelength range between 1500 nm and 1600 nm.

[2]:
lda0 = 1.55  # central wavelength
freq0 = td.C_0 / lda0  # central frequency
ldas = np.linspace(1.5, 1.6, 101)  # wavelength range
freqs = td.C_0 / ldas  # frequency range
fwidth = 0.5 * (np.max(freqs) - np.min(freqs))  # width of the source frequency range

Define materials.

[3]:
n_si = 3.43  # silicon refractive index
si = td.Medium(permittivity=n_si**2)

n_sio2 = 1.444  # silicon oxide refractive index
sio2 = td.Medium(permittivity=n_sio2**2)

Define geometric parameters.

[4]:
w = 0.45  # waveguide width
h = 0.22  # waveguide thickness
p = 0.1  # period of the swg
frac = 0.5  # filling fraction
N = 5  # number of grating periods
L = 100  # length of the coupling region
inf_eff = 1e2  # effective infinity

Define the waveguides and the anisotropic metamaterial cladding. The most convenient way is to use gdstk.

[5]:
R = 10  # radius of the bend

cell_eskid = gdstk.Cell("eskid")  # define a cell for the eskid waveguides
cell_ref = gdstk.Cell("ref")  # define a cell for bare strip waveguides

# define the top strip waveguide
path_1 = gdstk.RobustPath(initial_point=(-L / 2 - R, inf_eff), width=w, layer=1, datatype=0)

path_1.vertical(y=(N + 0.5) * p / 2 + w / 2 + R)
path_1.arc(radius=R, initial_angle=-np.pi, final_angle=-np.pi / 2)
path_1.horizontal(x=L / 2)
path_1.arc(radius=R, initial_angle=-np.pi / 2, final_angle=0)
path_1.vertical(y=inf_eff)
cell_eskid.add(path_1)
cell_ref.add(path_1)

# define the bottom strip waveguide
path_2 = path_1.copy()
path_2.mirror(p1=(1, 0))
cell_eskid.add(path_2)
cell_ref.add(path_2)

# define the swg between the waveguides
path_3 = gdstk.RobustPath(
    initial_point=(-1.2 * L / 2, 0),
    width=[frac * p, frac * p, frac * p, frac * p, frac * p],
    offset=p,
    layer=1,
    datatype=0,
)

path_3.horizontal(x=1.2 * L / 2)
cell_eskid.add(path_3)

# define the swg on the top
path_4 = gdstk.RobustPath(
    initial_point=(-L / 2 - R / 2, (N + 0.5) * p + w + R / 2),
    width=[frac * p, frac * p, frac * p, frac * p, frac * p],
    offset=p,
    layer=1,
    datatype=0,
)

path_4.arc(radius=R / 2, initial_angle=-np.pi, final_angle=-np.pi / 2)
path_4.horizontal(x=L / 2)
path_4.arc(radius=R / 2, initial_angle=-np.pi / 2, final_angle=0)
cell_eskid.add(path_4)

# define the swg on the bottom
path_5 = path_4.copy()
path_5.mirror(p1=(1, 0))
cell_eskid.add(path_5);
[5]:
<gdstk.Cell at 0x7fcd5fc23bf0>

After the gds cell is created, we can define Tidy3D geometries from the gds cell and visualize them.

[6]:
# define tidy3d geometries from the gds cell
eskid_geo = td.PolySlab.from_gds(
    cell_eskid,
    gds_layer=1,
    axis=2,
    slab_bounds=(-h / 2, h / 2),
)

# plot the geometries
fig, ax = plt.subplots()
for geo in eskid_geo:
    geo.plot(z=0, ax=ax)

ax.set_xlim(-0.7 * L, 0.7 * L)
ax.set_ylim(-0.2 * R, 0.2 * R)
ax.set_aspect("auto")
plt.show()
../_images/notebooks_ZeroCrossTalkTE_13_0.png

Define Tidy3D Structures using the previously defined geometries and materials.

[7]:
# define tidy3d structures from the geometries
eskid_structure = [td.Structure(geometry=geo, medium=si) for geo in eskid_geo]

# define the substrate structure
substrate = td.Structure(
    geometry=td.Box.from_bounds(
        rmin=(-inf_eff, -inf_eff, -inf_eff), rmax=(inf_eff, inf_eff, -h / 2)
    ),
    medium=sio2,
)

Define a ModeSource to excite the TE0 mode at the input waveguide and then define two ModeMonitors at the through port and cross port to measure the transmission. And finally we add a FieldMonitor at the \(z=0\) plane to visualize the power propagation and coupling.

[8]:
# add a mode source as excitation
mode_spec = td.ModeSpec(num_modes=1, target_neff=n_si)

input_x = -L / 2 - R
input_y = (N + 1) * p / 2 + w / 2 + R + lda0 / 4

mode_source = td.ModeSource(
    center=(input_x, input_y, 0),
    size=(5 * w, 0, 9 * h),
    source_time=td.GaussianPulse(freq0=freq0, fwidth=fwidth),
    direction="-",
    mode_spec=mode_spec,
    mode_index=0,
)

# add a mode monitor to measure transmission at the through port
mode_monitor_I1 = td.ModeMonitor(
    center=(-input_x, input_y, 0),
    size=(5 * w, 0, 9 * h),
    freqs=freqs,
    mode_spec=mode_spec,
    name="I1",
)

# add a mode monitor to measure transmission at the cross port
mode_monitor_I2 = td.ModeMonitor(
    center=(-input_x, -input_y, 0),
    size=(5 * w, 0, 9 * h),
    freqs=freqs,
    mode_spec=mode_spec,
    name="I2",
)

# add a filed monitor to visualize field distribution at z=0
field_monitor = td.FieldMonitor(
    size=(td.inf, td.inf, 0), freqs=[freq0], interval_space=(3, 3, 1), name="field"
)
[19:05:49] WARNING: Default value for the field monitor           monitor.py:261
           'colocate' setting has changed to 'True' in Tidy3D                   
           2.4.0. All field components will be colocated to the                 
           grid boundaries. Set to 'False' to get the raw fields                
           on the Yee grid instead.                                             

Define a Tidy3D Simulation using the components above. Due to the thin anisotropic metamaterial claddings, a fine grid needs to be used to ensure an accurate simulation. Here we use the automatic nonuniform grid with min_steps_per_wvl set to 20.

[9]:
# simulation domain size
Lx = 1.25 * L
Ly = 2.4 * R
Lz = 9 * h
sim_size = (Lx, Ly, Lz)

run_time = 5e-12  # simulation run time

# construct simulation
sim_eskid = td.Simulation(
    size=sim_size,
    grid_spec=td.GridSpec.auto(min_steps_per_wvl=20, wavelength=lda0),
    structures=eskid_structure + [substrate],
    sources=[mode_source],
    monitors=[mode_monitor_I1, mode_monitor_I2, field_monitor],
    run_time=run_time,
    boundary_spec=td.BoundarySpec.all_sides(boundary=td.PML()),
)

# plot the simulation
sim_eskid.plot(z=0)
plt.show()
../_images/notebooks_ZeroCrossTalkTE_19_0.png

Since the simulation contains very thin waveguides, it’s crucial to have a sufficiently small grid size to resolve them. We can inspect the grid by using the plot_grid method.

[10]:
# inspect the grid
ax = sim_eskid.plot(z=0, hlim=[-1,1], vlim=[-1,1])
sim_eskid.plot_grid(z=0, ax=ax, hlim=[-1,1], vlim=[-1,1])
plt.show()
../_images/notebooks_ZeroCrossTalkTE_21_0.png

Once everything is confirmed, we submit the simulation job to the server. The fine grid combined with the large simulation domain will lead to a higher FlexCredit cost. Before running the simulation, we can get a cost estimation using estimate_cost. This prevents us from accidentally running large jobs that we set up by mistake. The estimated cost is the maximum cost corresponding to running all the time steps.

[11]:
job = web.Job(simulation=sim_eskid, task_name="eskid", verbose=True)
estimated_cost = web.estimate_cost(job.task_id)
[19:05:50] Created task 'eskid' with task_id                       webapi.py:188
           'fdve-8a858953-f5c8-4798-bf49-8ad896eb2ef1v1'.                       
The estimated maximum cost is 13.799 Flex Credits.

The cost is reasonable given the simulation size so we can run the simulation now.

[12]:
sim_data_eskid = job.run(path="data/eskid.hdf5")
[19:05:56] status = queued                                         webapi.py:361
[19:06:17] status = preprocess                                     webapi.py:355
[19:06:22] Maximum FlexCredit cost: 13.799. Use                    webapi.py:341
           'web.real_cost(task_id)' to get the billed FlexCredit                
           cost after a simulation run.                                         
           starting up solver                                      webapi.py:377
           running solver                                          webapi.py:386
           To cancel the simulation, use 'web.abort(task_id)' or   webapi.py:387
           'web.delete(task_id)' or abort/delete the task in the                
           web UI. Terminating the Python script will not stop the              
           job running on the cloud.                                            

Result Analysis and Visualization#

We define a helper function postprocess to plot the crosstalk and field distribution. The crosstalk is defined as \(I_2/I_1\), where \(I_1\) is the power transmitted to the through port and \(I_2\) is the power transmitted to the cross port.

[13]:
def postprocess(sim_data):
    I1 = np.abs(sim_data["I1"].amps.sel(mode_index=0, direction="+")) ** 2
    I2 = np.abs(sim_data["I2"].amps.sel(mode_index=0, direction="-")) ** 2
    crosstalk = I2 / I1

    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4), tight_layout=True)

    ax1.plot(ldas, 10 * np.log10(crosstalk))
    ax1.set_xlabel("Wavelength ($\mu m$)")
    ax1.set_xlim(np.min(ldas), np.max(ldas))
    ax1.set_ylim(-80, 0)
    ax1.set_ylabel("Crosstalk (dB)")

    sim_data.plot_field("field", "E", "abs", vmin=0, vmax=80, ax=ax2)
    ax2.set_aspect("auto")
    plt.show()

Call the postprocess function on the simulation data of the eskid waveguide simulation. Here we see the crosstalk is below -40 dB around the 100 nm bandwidth. At about 1550 nm, exception coupling occurs and the crosstalk is well below -80 dB. The exceptional coupling wavelength can be effectively tuned by changing the geometric parameters such as the waveguide width.

From the field distribution plot, we see the field stays at the top waveguide throughout the coupling regime, confirming the low crosstalk.

[14]:
postprocess(sim_data_eskid)
../_images/notebooks_ZeroCrossTalkTE_30_0.png

Reference Simulation#

The crosstalk of the eskid waveguide has been shown to be very low. As a comparison, we simulate two strip waveguides with the same spacing without the anisotropic metamaterial claddings.

[15]:
# define geometries for the bare strip waveguides
ref_geo = td.PolySlab.from_gds(
    cell_ref,
    gds_layer=1,
    axis=2,
    slab_bounds=(-h / 2, h / 2),
)

# define structures for the bare strip waveguides
ref_structure = [td.Structure(geometry=geo, medium=si) for geo in ref_geo]

# copy the simulation and update the structures to bare strip waveguides
sim_ref = sim_eskid.copy(update={"structures": ref_structure + [substrate]})

# plot simulation
sim_ref.plot(z=0)
plt.show()
../_images/notebooks_ZeroCrossTalkTE_33_0.png

submit the simulation job to the server.

[16]:
sim_data_ref = web.run(sim_ref, task_name="ref", path="data/ref.hdf5")
[19:20:39] Created task 'ref' with task_id                         webapi.py:188
           'fdve-d791f8e1-055f-45ee-9ef6-af786f86b4bdv1'.                       
[19:20:44] status = queued                                         webapi.py:361
[19:21:14] status = preprocess                                     webapi.py:355
[19:21:17] Maximum FlexCredit cost: 12.242. Use                    webapi.py:341
           'web.real_cost(task_id)' to get the billed FlexCredit                
           cost after a simulation run.                                         
           starting up solver                                      webapi.py:377
           running solver                                          webapi.py:386
           To cancel the simulation, use 'web.abort(task_id)' or   webapi.py:387
           'web.delete(task_id)' or abort/delete the task in the                
           web UI. Terminating the Python script will not stop the              
           job running on the cloud.                                            
[19:33:01] early shutoff detected, exiting.                        webapi.py:404
           status = postprocess                                    webapi.py:419
[19:33:09] status = success                                        webapi.py:426
[19:33:12] loading SimulationData from data/ref.hdf5               webapi.py:590

Apply the same visualization to the simulation data. We can see that the crosstalk is much larger in the bare strip waveguide case, around -10 dB. In the field distribution plot, a noticeable amount of energy is coupled to the lower waveguide. This comparison further validifies the effectiveness of the anisotropic metamaterial cladding design for crosstalk suppression.

[17]:
postprocess(sim_data_ref)
../_images/notebooks_ZeroCrossTalkTE_37_0.png

Final Remark#

The proposed design in this example achieves exceptional coupling only for the TE mode. A different anisotropic metamaterial-based design achieving zero crosstalk for the TM mode is proposed by the same research group. For detail, please refer to Kabir, M.F., Mia, M.B., Ahmed, I. et al. Anisotropic leaky-like perturbation with subwavelength gratings enables zero crosstalk. Light Sci Appl 12, 135 (2023) DOI:10.1038/s41377-023-01184-5.

[ ]: