Waveguide Mode Analysis
Overview
Prismo includes a 2D eigenmode solver for analyzing guided modes in waveguide structures. This is essential for:
Understanding waveguide properties
Injecting specific modes
Decomposing fields into modes
Calculating mode-based S-parameters
Basic Mode Solving
Define Waveguide Structure
import numpy as np
from prismo import ModeSolver
# Define cross-section coordinates
x = np.linspace(-2e-6, 2e-6, 100) # 4 μm width
y = np.linspace(-1e-6, 1e-6, 80) # 2 μm height
# Create permittivity profile
# Example: 500nm × 220nm Silicon waveguide on SiO2
epsilon = np.ones((len(x), len(y))) * 1.44**2 # SiO2 background
wg_width = 0.5e-6
wg_height = 0.22e-6
for i, xi in enumerate(x):
for j, yj in enumerate(y):
# Silicon core (centered, on bottom)
if abs(xi) < wg_width/2 and -wg_height < yj < 0:
epsilon[i, j] = 11.68 # Silicon at 1550nm
Solve for Modes
# Create mode solver
mode_solver = ModeSolver(
wavelength=1.55e-6, # Operating wavelength
x=x,
y=y,
epsilon=epsilon
)
# Solve for TE modes
modes = mode_solver.solve(
num_modes=3,
mode_type='TE'
)
# Access fundamental mode
fundamental = mode_solver.get_mode(0)
Mode Properties
# Effective index
neff = fundamental.neff.real
print(f"Effective index: {neff:.4f}")
# Mode fields (Ex, Ey, Ez, Hx, Hy, Hz)
Ex = fundamental.Ex
Hy = fundamental.Hy
# Coordinates
x_coords = fundamental.x
y_coords = fundamental.y
Mode Types
TE Modes
Transverse Electric (Ez = 0, Hz dominant):
te_modes = mode_solver.solve(num_modes=2, mode_type='TE')
TM Modes
Transverse Magnetic (Hz = 0, Ez dominant):
tm_modes = mode_solver.solve(num_modes=2, mode_type='TM')
Vectorial Modes
Full vector modes (all components):
vector_modes = mode_solver.solve(num_modes=2, mode_type='vector')
Using Modes in Simulations
Mode Sources
Inject a specific mode into the simulation:
from prismo import ModeSource
from prismo.sources.waveform import GaussianPulse
# Create waveform
waveform = GaussianPulse(
frequency=193e12,
pulse_width=10e-15
)
# Create mode source
mode_source = ModeSource(
center=(0, 0, 0),
size=(0, 2e-6, 0),
mode=fundamental,
direction='+x',
waveform=waveform,
amplitude=1.0
)
sim.add_source(mode_source)
Mode Expansion Monitors
Decompose simulation fields into mode coefficients:
from prismo import ModeExpansionMonitor
# Create monitor
mode_monitor = ModeExpansionMonitor(
center=(8e-6, 0, 0),
size=(0, 2e-6, 0),
modes=modes, # Use calculated modes
direction='x',
frequencies=frequencies.tolist()
)
sim.add_monitor(mode_monitor)
sim.run(time=50e-15)
# Get mode coefficients
for i, mode in enumerate(modes):
coeff = mode_monitor.get_mode_coefficient(i, domain='frequency')
power = mode_monitor.get_mode_power(i)
print(f"Mode {i}: Power = {power:.3f}")
Mode-Based S-Parameters
Extract S-parameters using mode expansion:
# Get mode coefficients at each port
forward, backward = mode_monitor.separate_forward_backward(
mode_index=0,
frequency_index=5
)
# Calculate S-parameters
s_analyzer = prismo.SParameterAnalyzer(num_ports=2, frequencies=frequencies)
s_analyzer.add_mode_data(
port_index=1,
excitation_port=0,
mode_coefficients={'forward': forward_array, 'backward': backward_array}
)
Tips
Resolution: Use at least 20 points per wavelength in the material
Domain size: Extend beyond waveguide to capture evanescent fields
Boundary conditions: Mode solver assumes zero fields at boundaries
Convergence: Increase grid resolution if modes look incorrect