use std::f64::consts::PI;
#[derive(Debug, Clone, Copy)]
pub struct SlotWaveguide {
pub n_rail: f64,
pub n_slot: f64,
pub n_clad: f64,
pub w_rail: f64,
pub w_slot: f64,
pub height: f64,
}
impl SlotWaveguide {
pub fn new(
n_rail: f64,
n_slot: f64,
n_clad: f64,
w_rail: f64,
w_slot: f64,
height: f64,
) -> Self {
Self {
n_rail,
n_slot,
n_clad,
w_rail,
w_slot,
height,
}
}
pub fn soi_standard() -> Self {
Self {
n_rail: 3.476,
n_slot: 1.444, n_clad: 1.444,
w_rail: 180e-9,
w_slot: 100e-9,
height: 220e-9,
}
}
pub fn soi_air_slot() -> Self {
Self {
n_rail: 3.476,
n_slot: 1.0,
n_clad: 1.0,
w_rail: 200e-9,
w_slot: 120e-9,
height: 220e-9,
}
}
pub fn total_width(&self) -> f64 {
2.0 * self.w_rail + self.w_slot
}
pub fn effective_index_approx(&self, wavelength: f64) -> f64 {
let w_tot = self.total_width();
let f_slot = self.w_slot / w_tot;
let f_rail = 1.0 - f_slot;
let enhancement = (self.n_rail / self.n_slot).powi(2);
let norm = f_rail + f_slot * enhancement;
let n_eff_sq = (f_rail * self.n_rail * self.n_rail
+ f_slot * self.n_slot * self.n_slot * enhancement)
/ norm;
let k0 = 2.0 * PI / wavelength;
let v_h =
k0 * self.height * (self.n_rail * self.n_rail - self.n_clad * self.n_clad).sqrt() / 2.0;
let correction = 1.0 - 0.5 / (v_h * v_h + 1.0).max(1.0);
(n_eff_sq * correction * correction).sqrt().min(self.n_rail)
}
pub fn slot_confinement_factor(&self) -> f64 {
let w_tot = self.total_width();
let f_slot = self.w_slot / w_tot;
let enhancement = (self.n_rail / self.n_slot).powi(2);
f_slot * enhancement / (1.0 + f_slot * (enhancement - 1.0))
}
pub fn beta2_approx(&self, wavelength: f64) -> f64 {
let dl = wavelength * 1e-4; let c = 2.998e8;
let n_p = self.effective_index_approx(wavelength + dl);
let n_0 = self.effective_index_approx(wavelength);
let n_m = self.effective_index_approx(wavelength - dl);
let d2n_dl2 = (n_p - 2.0 * n_0 + n_m) / (dl * dl);
wavelength * wavelength * wavelength / (2.0 * PI * c * c) * d2n_dl2
}
pub fn nonlinear_coefficient(&self, wavelength: f64, n2_rail: f64, n2_slot: f64) -> f64 {
let c = 2.998e8;
let omega = 2.0 * PI * c / wavelength;
let gamma_slot = self.slot_confinement_factor();
let n2_eff = gamma_slot * n2_slot + (1.0 - gamma_slot) * n2_rail;
let a_eff = self.total_width() * self.height;
let n_eff = self.effective_index_approx(wavelength);
omega * n2_eff / (c * n_eff * a_eff)
}
pub fn sensing_figure_of_merit(&self) -> f64 {
let gamma = self.slot_confinement_factor();
let a_eff = self.total_width() * self.height;
gamma / a_eff
}
pub fn index_sensitivity(&self) -> f64 {
self.slot_confinement_factor()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn soi_slot_geometry() {
let wg = SlotWaveguide::soi_standard();
let w = wg.total_width();
assert!((w - 460e-9).abs() < 1e-12);
}
#[test]
fn effective_index_between_clad_and_rail() {
let wg = SlotWaveguide::soi_standard();
let n_eff = wg.effective_index_approx(1550e-9);
assert!(n_eff > wg.n_clad, "n_eff={n_eff:.3} should be > n_clad");
assert!(n_eff < wg.n_rail, "n_eff={n_eff:.3} should be < n_rail");
}
#[test]
fn slot_confinement_factor_positive() {
let wg = SlotWaveguide::soi_standard();
let gamma = wg.slot_confinement_factor();
assert!(gamma > 0.0 && gamma < 1.0, "Γ_slot={gamma:.3}");
}
#[test]
fn slot_confinement_enhanced_over_fill_fraction() {
let wg = SlotWaveguide::soi_standard();
let gamma = wg.slot_confinement_factor();
let f_slot = wg.w_slot / wg.total_width();
assert!(
gamma > f_slot,
"Γ={gamma:.3} should exceed f_slot={f_slot:.3}"
);
}
#[test]
fn nonlinear_coefficient_positive() {
let wg = SlotWaveguide::soi_standard();
let n2_si = 6e-18; let n2_sio2 = 2.2e-20; let gamma = wg.nonlinear_coefficient(1550e-9, n2_si, n2_sio2);
assert!(gamma > 0.0);
assert!(gamma > 10.0 && gamma < 1e5, "γ={gamma:.2e}");
}
#[test]
fn sensing_fom_positive() {
let wg = SlotWaveguide::soi_air_slot();
let fom = wg.sensing_figure_of_merit();
assert!(fom > 0.0);
}
#[test]
fn air_slot_higher_confinement_than_oxide() {
let wg_ox = SlotWaveguide::soi_standard();
let wg_air = SlotWaveguide::soi_air_slot();
assert!(wg_air.slot_confinement_factor() > wg_ox.slot_confinement_factor());
}
}