use std::f64::consts::PI;
#[derive(Debug, Clone)]
pub struct RingResonator {
pub radius: f64,
pub n_eff: f64,
pub n_group: f64,
pub kappa_sq: f64,
pub alpha: f64,
}
impl RingResonator {
pub fn new(radius: f64, n_eff: f64, n_group: f64, kappa_sq: f64, alpha: f64) -> Self {
Self {
radius,
n_eff,
n_group,
kappa_sq,
alpha,
}
}
pub fn circumference(&self) -> f64 {
2.0 * PI * self.radius
}
pub fn fsr(&self, wavelength: f64) -> f64 {
wavelength * wavelength / (self.n_group * self.circumference())
}
pub fn resonances(&self, wavelength: f64, n_resonances: usize) -> Vec<f64> {
let l = self.circumference();
let m_center = (self.n_eff * l / wavelength).round() as i64;
let half = (n_resonances as i64) / 2;
(m_center - half..m_center - half + n_resonances as i64)
.filter(|&m| m > 0)
.map(|m| self.n_eff * l / m as f64)
.collect()
}
pub fn transmission_through(&self, wavelengths: &[f64]) -> Vec<f64> {
let l = self.circumference();
let r = (1.0 - self.kappa_sq).sqrt(); let a_rt = (-self.alpha * l / 2.0).exp();
wavelengths
.iter()
.map(|&wl| {
let k0 = 2.0 * PI / wl;
let phi = k0 * self.n_eff * l;
let cos_phi = phi.cos();
let num = a_rt * a_rt - 2.0 * r * a_rt * cos_phi + r * r;
let den = 1.0 - 2.0 * r * a_rt * cos_phi + r * r * a_rt * a_rt;
if den.abs() < 1e-30 {
0.0
} else {
num / den
}
})
.collect()
}
pub fn transmission_drop(&self, wavelengths: &[f64]) -> Vec<f64> {
let l = self.circumference();
let r = (1.0 - self.kappa_sq).sqrt();
let a_rt = (-self.alpha * l / 2.0).exp();
let kappa_factor = 1.0 - r * r;
wavelengths
.iter()
.map(|&wl| {
let k0 = 2.0 * PI / wl;
let phi = k0 * self.n_eff * l;
let cos_phi = phi.cos();
let den = 1.0 - 2.0 * r * a_rt * cos_phi + r * r * a_rt * a_rt;
if den.abs() < 1e-30 {
return 0.0;
}
kappa_factor * kappa_factor * a_rt * a_rt / (den * den)
})
.collect()
}
pub fn quality_factor(&self, wavelength: f64) -> f64 {
let l = self.circumference();
let r = (1.0 - self.kappa_sq).sqrt();
let a_rt = (-self.alpha * l / 2.0).exp();
let fsr = self.fsr(wavelength);
let finesse = PI * (r * a_rt).sqrt() / (1.0 - r * a_rt);
finesse * wavelength / fsr
}
pub fn finesse(&self) -> f64 {
let l = self.circumference();
let r = (1.0 - self.kappa_sq).sqrt();
let a_rt = (-self.alpha * l / 2.0).exp();
PI * (r * a_rt).sqrt() / (1.0 - r * a_rt)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ring_resonator_fsr() {
let ring = RingResonator::new(5e-6, 2.4, 4.2, 0.1, 0.0);
let fsr = ring.fsr(1550e-9);
let expected = (1550e-9_f64).powi(2) / (4.2 * 2.0 * PI * 5e-6);
let err_nm = (fsr - expected).abs() * 1e9;
assert!(
err_nm < 0.1,
"FSR error = {err_nm:.4} nm (got {:.4} nm, expected {:.4} nm)",
fsr * 1e9,
expected * 1e9
);
}
#[test]
fn ring_resonator_through_at_resonance() {
let ring = RingResonator::new(5e-6, 2.4, 4.2, 0.1, 5000.0); let wl = 1550e-9;
let reso = ring.resonances(wl, 1);
let t_at_res = ring.transmission_through(&reso);
let t_off_res = ring.transmission_through(&[reso[0] + ring.fsr(wl) / 2.0]);
assert!(
t_at_res[0] < t_off_res[0],
"Through port should dip at resonance: T_res={:.4} T_off={:.4}",
t_at_res[0],
t_off_res[0]
);
}
#[test]
fn ring_resonator_fsr_si_waveguide() {
let ring = RingResonator::new(5e-6, 2.4, 4.2, 0.05, 100.0); let fsr_nm = ring.fsr(1550e-9) * 1e9;
let analytical_nm = (1550e-9_f64).powi(2) / (4.2 * 2.0 * PI * 5e-6) * 1e9;
assert!(
(fsr_nm - analytical_nm).abs() < 0.1,
"FSR={fsr_nm:.3} nm, analytical={analytical_nm:.3} nm"
);
}
}