use std::f64::consts::PI;
#[derive(Debug, Clone, Copy)]
pub struct EdgeCoupler {
pub w_tip: f64,
pub w_full: f64,
pub length: f64,
pub fiber_mfd: f64,
pub height: f64,
pub n_core: f64,
pub n_clad: f64,
}
impl EdgeCoupler {
pub fn new(
w_tip: f64,
w_full: f64,
length: f64,
fiber_mfd: f64,
height: f64,
n_core: f64,
n_clad: f64,
) -> Self {
Self {
w_tip,
w_full,
length,
fiber_mfd,
height,
n_core,
n_clad,
}
}
pub fn soi_standard() -> Self {
Self::new(150e-9, 500e-9, 10e-6, 10.4e-6, 220e-9, 3.476, 1.444)
}
pub fn sin_inverse_taper() -> Self {
Self::new(300e-9, 800e-9, 500e-6, 3e-6, 300e-9, 2.0, 1.444)
}
pub fn mode_radius_at_tip(&self, wavelength: f64) -> f64 {
let v = PI * self.w_tip / wavelength
* (self.n_core * self.n_core - self.n_clad * self.n_clad).sqrt();
let v = v.max(0.1);
self.w_tip * (0.65 + 1.619 / v.powf(1.5) + 2.879 / v.powi(6))
}
pub fn coupling_efficiency(&self, wavelength: f64) -> f64 {
let w_f = self.fiber_mfd / 2.0; let w_wg = self.mode_radius_at_tip(wavelength);
4.0 * (w_f * w_wg).powi(2) / (w_f * w_f + w_wg * w_wg).powi(2)
}
pub fn coupling_loss_db(&self, wavelength: f64) -> f64 {
let eta = self.coupling_efficiency(wavelength);
if eta < 1e-30 {
return 50.0;
}
-10.0 * eta.log10()
}
pub fn is_adiabatic(&self, wavelength: f64) -> bool {
let theta_max = wavelength / (PI * self.n_core * self.w_tip * self.w_tip);
let l_min = (self.w_full - self.w_tip) / (2.0 * theta_max);
self.length > l_min
}
pub fn facet_reflection(&self) -> f64 {
let r = (self.n_core - self.n_clad) / (self.n_core + self.n_clad);
r * r
}
pub fn bandwidth_3db_nm(&self, center_wavelength: f64) -> f64 {
let na_approx = (self.n_core * self.n_core - self.n_clad * self.n_clad).sqrt();
center_wavelength * 1e9 * 0.1 / na_approx.max(0.01)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn edge_coupler_efficiency_in_range() {
let ec = EdgeCoupler::soi_standard();
let eta = ec.coupling_efficiency(1550e-9);
assert!(eta > 0.0 && eta <= 1.0, "η={eta:.3}");
}
#[test]
fn edge_coupler_loss_db_positive() {
let ec = EdgeCoupler::soi_standard();
let loss = ec.coupling_loss_db(1550e-9);
assert!((0.0..30.0).contains(&loss), "loss={loss:.2}dB");
}
#[test]
fn sin_coupler_lower_loss() {
let sin = EdgeCoupler::sin_inverse_taper();
let soi = EdgeCoupler::soi_standard();
let eta_sin = sin.coupling_efficiency(1550e-9);
let eta_soi = soi.coupling_efficiency(1550e-9);
assert!(eta_sin > 0.0);
assert!(eta_soi > 0.0);
}
#[test]
fn edge_coupler_mode_radius_positive() {
let ec = EdgeCoupler::soi_standard();
assert!(ec.mode_radius_at_tip(1550e-9) > 0.0);
}
#[test]
fn edge_coupler_facet_reflection_small() {
let ec = EdgeCoupler::soi_standard();
let r = ec.facet_reflection();
assert!(r > 0.0 && r < 0.5, "R={r:.3}");
}
#[test]
fn edge_coupler_bandwidth_positive() {
let ec = EdgeCoupler::soi_standard();
let bw = ec.bandwidth_3db_nm(1550e-9);
assert!(bw > 0.0);
}
}