EME: Interlayer Taper
Heterogeneous platforms put two waveguide layers on one chip, such as a SiN layer above an SOI layer, and move light between them with an interlayer (vertical) taper. Here a 1000 x 400 nm SiN waveguide sits 200 nm above the 220 nm Si layer. Along a linear taper the Si widens from a 150 nm tip to a 500 nm wire while the SiN above it narrows to a 300 nm tip, and the fundamental mode moves from the SiN down into the Si.
Highlighted features: two cores in two layers placed with shape(position=...), a taper_section that changes both widths at once, a length sweep of the taper with sweep(), confinement() on each core, and plot(plane='x-y', slice_position=...) showing the cross-section along the taper.
Where the two guides are far from phase matched, each supermode of the pair lives mostly in one core. As the Si widens its index rises through the SiN’s, and the two lowest supermodes approach each other and then part again without crossing. In between the fundamental supermode is a hybrid of the two cores. A taper slow enough for the light to stay in the fundamental supermode carries it from the SiN into the Si, and a fast one leaves part of it in the second supermode, which ends in the SiN tip and is lost. The closer the two supermodes approach, the shorter the taper can be, and a thinner oxide between the layers brings them closer.
The example first solves the two lowest supermodes and the fundamental’s share of power in the Si at points along the taper, then the SiN to Si coupling for tapers from 5 to 100 um. A taper’s slices keep their cross-sections when only its length changes, so the sweep solves no new modes. A 5 um taper couples 58 %, 20 um is the shortest of the sweep above 95 %, and from 30 um on the coupling levels off at 99.2 to 99.6 %. What a long taper still loses is scattered where the Si tip begins and the SiN tip ends, which the taper’s length does not change. The figures show the field of one taper from the side, where the light can be seen moving down, from above, and in the x-y plane at the taper’s start, at 35 % of its length, where the fundamental supermode spans both cores, and at its end.
This code example is licensed under the BSD 3-Clause License.
import sys
import numpy as np
import emodeconnection as emc
from matplotlib import pyplot as plt
## An interlayer taper that moves light from a SiN waveguide down into a Si
## wire 200 nm below it, as in a SiN-on-SOI platform. Along the taper the Si
## widens from a 150 nm tip while the SiN above it narrows, so the
## fundamental mode slides from the SiN into the Si. The coupling is solved
## against the taper length, and the mode's hybridization is shown along it.
## Set simulation parameters
wavelength = 1550 # [nm] wavelength
dx, dy = 20, 20 # [nm] resolution
h_si = 220 # [nm] Si thickness
h_sin = 400 # [nm] SiN thickness
gap = 200 # [nm] oxide between the top of the Si and the bottom of the SiN
w_si_tip, w_si = 150, 500 # [nm] Si width at the taper's start and end
w_sin, w_sin_tip = 1000, 300 # [nm] SiN width at the taper's start and end
h_box = 1500 # [nm] oxide below the Si
window_width = 4000 # [nm]
window_height = 4000 # [nm] which leaves 1680 nm of oxide above the SiN
num_modes = 16 # [-]
lead = 2000 # [nm] input SiN and output Si waveguides
taper_lengths = np.array([5, 10, 15, 20, 30, 40, 60, 80, 100]) * 1000 # [nm]
taper_length = 30000 # [nm] the taper whose field is plotted
y_si = h_box + h_si / 2 # [nm] height of the Si core's center
y_sin = h_box + h_si + gap + h_sin / 2 # [nm] height of the SiN core's center
em = emc.EMode(emode_cmd=sys.argv[1:], simulation_name='interlayer_taper')
## The layers are not symmetric top to bottom, so 'TE-h' folds only the
## vertical mirror plane through the two cores, and half the window is solved
em.settings(
wavelength=wavelength, x_resolution=dx, y_resolution=dy,
window_width=window_width, window_height=window_height,
num_modes=num_modes, boundary_condition='TE-h', background_material='SiO2')
def cores(w_bottom, w_top):
"""The Si core `w_bottom` wide and the SiN core `w_top` wide, a width of 0 for none."""
for name, material, width, height, y in (('si', 'Si', w_bottom, h_si, y_si),
('sin', 'SiN', w_top, h_sin, y_sin)):
em.shape(name=name, material=material if width else 'SiO2', width=max(width, dx),
height=height, position=[0, y])
## The four cross-sections: the SiN input alone, the two ends of the taper,
## and the Si output alone. Where a core is absent it is drawn as oxide.
for name, w_bottom, w_top in (('sin_wg', 0, w_sin), ('start', w_si_tip, w_sin),
('end', w_si, w_sin_tip), ('si_wg', w_si, 0)):
cores(w_bottom, w_top)
em.label_profile(name=name)
## The hybridization: the two lowest supermodes along the taper, and the
## share of the fundamental's power inside each core, from the cross-section
## at each point of the linear taper
positions = np.linspace(0, 1, 21) # [-] fraction of the taper length
supermodes, in_si, in_sin = [], [], []
for t in positions:
cores(w_si_tip + t * (w_si - w_si_tip), w_sin + t * (w_sin_tip - w_sin))
em.FDM()
supermodes.append(np.real(np.asarray(em.get('effective_index')))[:2])
share = em.confinement(shape_list=['si', 'sin'], mode_list=[0])
in_si.append(share['si'][0])
in_sin.append(share['sin'][0])
supermodes = np.array(supermodes)
closest = np.argmin(supermodes[:, 0] - supermodes[:, 1])
print(f'closest approach of the two supermodes at {positions[closest]:.2f} of the taper: '
f'delta n_eff = {supermodes[closest, 0] - supermodes[closest, 1]:.3f}')
for label, i in (('start', 0), ('end', -1)):
print(f'fundamental mode power in the Si core at the {label}: {in_si[i]:.3f}')
print(f'fundamental mode power in the SiN core at the {label}: {in_sin[i]:.3f}')
## SiN in, the taper, Si out
em.straight_section(name='in', profile='sin_wg', length=lead)
em.taper_section(name='taper', profile='start', profile_end='end', length=taper_length)
em.straight_section(name='out', profile='si_wg', length=lead)
def coupling(S):
"""Power from the SiN mode into the Si mode, and the power reflected."""
return (np.abs(S.block('right', 'left')[0, 0]) ** 2,
np.sum(np.abs(S.block('left', 'left')[:, 0]) ** 2))
## The coupling against the taper length. A taper's slices keep their cross
## sections when only its length changes, so this solves no new modes.
data = em.sweep(key='section, taper, length', values=taper_lengths, result='S_matrix')
results = np.array([coupling(S) for S in data['S_matrix']])
em.taper_section(name='taper', length=taper_length)
em.EME()
## The field along the taper, and the cross-section at its start, at 35 % of
## its length where the mode is a hybrid of the two cores, and at its end. An
## x-y plot's slice_position is a z position in um.
em.plot(component='Ex', plot_function='abs', plane='z-x', file_name='interlayer_zx',
file_type='png')
em.plot(component='Ex', plot_function='abs', plane='z-y', file_name='interlayer_zy',
file_type='png')
for label, z in (('start', lead), ('hybrid', lead + 0.35 * taper_length),
('end', lead + taper_length)):
em.plot(component='Ex', plot_function='abs', plane='x-y', slice_position=z / 1000,
file_name=f'interlayer_xy_{label}', file_type='png')
em.close()
print(f'\n{"taper (um)":>11s}{"coupling":>10s}{"loss (dB)":>11s}{"reflection (dB)":>17s}')
for length, (T, R) in zip(taper_lengths, results):
print(f'{length / 1000:>11.0f}{T:>10.4f}{-10 * np.log10(T):>11.3f}{10 * np.log10(R):>17.1f}')
above = taper_lengths[results[:, 0] >= 0.95]
print(f'\nshortest taper with at least 95 % coupling: {above.min() / 1000:.0f} um')
## Plot the supermodes and the coupling
fig, ax = plt.subplots(1, 2, figsize=(10, 3.8))
ax[0].plot(positions, supermodes[:, 0], label='supermode 0')
ax[0].plot(positions, supermodes[:, 1], label='supermode 1')
ax[0].set_xlabel('Position along the taper (fraction of its length)')
ax[0].set_ylabel('Effective index')
twin = ax[0].twinx()
twin.plot(positions, in_si, color='gray', ls='--', label='supermode 0 power in the Si core')
twin.plot(positions, in_sin, color='gray', ls=':', label='supermode 0 power in the SiN core')
twin.set_ylabel('Power inside the core')
twin.set_ylim(0, 1)
lines = ax[0].get_lines() + twin.get_lines()
ax[0].legend(lines, [line.get_label() for line in lines], fontsize=8, loc='center right')
ax[0].grid(True, alpha=0.3)
ax[1].plot(taper_lengths / 1000, 100 * results[:, 0], marker='o')
ax[1].set_xlabel('Taper length (μm)')
ax[1].set_ylabel('SiN to Si coupling (%)')
ax[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('interlayer_taper.png', dpi=300, bbox_inches='tight')
Console output:
EMode3D 1.0.8 - email
Meshing completed in 0.0 sec
Solving modes completed in 1.5 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.5 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.7 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.5 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.6 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.6 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.5 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.6 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.5 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.6 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.5 sec
Meshing completed in 0.0 sec
Solving modes completed in 1.5 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.5 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.5 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.5 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.4 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.5 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.7 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.5 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.6 sec
Meshing completed in 0.1 sec
Solving modes completed in 1.6 sec
closest approach of the two supermodes at 0.25 of the taper: delta n_eff = 0.204
fundamental mode power in the Si core at the start: 0.007
fundamental mode power in the SiN core at the start: 0.618
fundamental mode power in the Si core at the end: 0.779
fundamental mode power in the SiN core at the end: 0.003
Sweeping section parameter 'length'...
Solving EME: length = 100000... completed in 3 min 50.4 sec
Solving EME: length = 80000... completed in 1.5 sec
Solving EME: length = 60000... completed in 1.5 sec
Solving EME: length = 40000... completed in 1.4 sec
Solving EME: length = 30000... completed in 1.5 sec
Solving EME: length = 20000... completed in 1.5 sec
Solving EME: length = 15000... completed in 1.4 sec
Solving EME: length = 10000... completed in 1.4 sec
Solving EME: length = 5000... completed in 1.4 sec
completed in 4 min 2.0 sec
Solving S-matrices...
Solving section: in... completed in 0.0 sec
Solving section: taper... completed in 52.7 sec
Solving section: out... completed in 0.0 sec
completed in 55.0 sec
Exited EMode
taper (um) coupling loss (dB) reflection (dB)
5 0.5752 2.402 -36.7
10 0.8479 0.717 -36.7
15 0.9334 0.299 -40.0
20 0.9578 0.187 -42.1
30 0.9921 0.034 -43.7
40 0.9957 0.019 -43.4
60 0.9953 0.020 -38.2
80 0.9947 0.023 -43.2
100 0.9963 0.016 -36.7
shortest taper with at least 95 % coupling: 20 um
Figures: