use std::f64::consts::PI;
#[derive(Debug, Clone)]
pub struct DirectionalCoupler {
pub kappa: f64,
pub beta: f64,
pub length: f64,
}
impl DirectionalCoupler {
pub fn new(kappa: f64, beta: f64, length: f64) -> Self {
Self {
kappa,
beta,
length,
}
}
pub fn from_coupling_length(lc: f64, beta: f64, length: f64) -> Self {
let kappa = PI / (2.0 * lc);
Self::new(kappa, beta, length)
}
pub fn coupling_length(&self) -> f64 {
PI / (2.0 * self.kappa)
}
pub fn through_power(&self) -> f64 {
(self.kappa * self.length).cos().powi(2)
}
pub fn cross_power(&self) -> f64 {
(self.kappa * self.length).sin().powi(2)
}
pub fn splitting_ratio(&self) -> f64 {
self.cross_power() / self.through_power().max(1e-30)
}
pub fn transfer_matrix(&self) -> [[num_complex::Complex64; 2]; 2] {
use num_complex::Complex64;
let kl = self.kappa * self.length;
let cos_kl = kl.cos();
let sin_kl = kl.sin();
let phase = Complex64::new(0.0, self.beta * self.length).exp();
[
[phase * cos_kl, phase * Complex64::new(0.0, sin_kl)],
[phase * Complex64::new(0.0, sin_kl), phase * cos_kl],
]
}
pub fn propagate(&self, e_in: [num_complex::Complex64; 2]) -> [num_complex::Complex64; 2] {
let t = self.transfer_matrix();
[
t[0][0] * e_in[0] + t[0][1] * e_in[1],
t[1][0] * e_in[0] + t[1][1] * e_in[1],
]
}
}
pub fn half_coupler(kappa: f64, beta: f64) -> DirectionalCoupler {
let lc = PI / (2.0 * kappa);
DirectionalCoupler::new(kappa, beta, lc / 2.0)
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn full_coupling_at_lc() {
let kappa = 1000.0; let lc = PI / (2.0 * kappa);
let coupler = DirectionalCoupler::new(kappa, 1.0e7, lc);
assert_relative_eq!(coupler.cross_power(), 1.0, max_relative = 1e-10);
assert_relative_eq!(coupler.through_power(), 0.0, epsilon = 1e-10);
}
#[test]
fn half_coupling() {
let kappa = 1000.0;
let coupler = half_coupler(kappa, 1.0e7);
assert_relative_eq!(coupler.through_power(), 0.5, max_relative = 1e-10);
assert_relative_eq!(coupler.cross_power(), 0.5, max_relative = 1e-10);
}
#[test]
fn power_conservation() {
let kappa = 500.0;
let coupler = DirectionalCoupler::new(kappa, 1.0e7, 1e-3);
let total = coupler.through_power() + coupler.cross_power();
assert_relative_eq!(total, 1.0, max_relative = 1e-10);
}
#[test]
fn transfer_matrix_power_conservation() {
use num_complex::Complex64;
let kappa = 1000.0;
let lc = PI / (2.0 * kappa);
let coupler = DirectionalCoupler::new(kappa, 1.5e7, lc * 0.3);
let e_in = [Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)];
let e_out = coupler.propagate(e_in);
let p_out = e_out[0].norm_sqr() + e_out[1].norm_sqr();
assert_relative_eq!(p_out, 1.0, max_relative = 1e-10);
}
}