use std::f64::consts::PI;
pub const SPEED_OF_LIGHT: f64 = 299_792_458.0;
pub const EPSILON_0: f64 = 8.854_187_812_8e-12;
pub const MU_0: f64 = 1.256_637_062_12e-6;
pub const Z0: f64 = 376.730_313_668;
pub const PLANCK: f64 = 6.626_070_15e-34;
pub const HBAR: f64 = 1.054_571_817e-34;
pub const BOLTZMANN: f64 = 1.380_649e-23;
pub const ELECTRON_CHARGE: f64 = 1.602_176_634e-19;
pub const ELECTRON_MASS: f64 = 9.109_383_701_5e-31;
pub const AVOGADRO: f64 = 6.022_140_76e23;
pub const FINE_STRUCTURE: f64 = 7.297_352_569_3e-3;
pub const STEFAN_BOLTZMANN: f64 = 5.670_374_419e-8;
pub const NM_TO_M: f64 = 1e-9;
pub const UM_TO_M: f64 = 1e-6;
pub const CM_TO_M: f64 = 1e-2;
pub const MM_TO_M: f64 = 1e-3;
pub const EV_TO_J: f64 = ELECTRON_CHARGE;
pub const J_TO_EV: f64 = 1.0 / EV_TO_J;
pub fn wavelength_to_frequency(lambda_m: f64) -> f64 {
SPEED_OF_LIGHT / lambda_m
}
pub fn frequency_to_wavelength(freq_hz: f64) -> f64 {
SPEED_OF_LIGHT / freq_hz
}
pub fn wavelength_to_omega(lambda_m: f64) -> f64 {
2.0 * PI * SPEED_OF_LIGHT / lambda_m
}
pub fn omega_to_wavelength(omega: f64) -> f64 {
2.0 * PI * SPEED_OF_LIGHT / omega
}
pub fn ev_to_wavelength_nm(ev: f64) -> f64 {
1_239.841_93 / ev
}
pub fn wavelength_nm_to_ev(nm: f64) -> f64 {
1_239.841_93 / nm
}
pub fn dbm_to_watts(dbm: f64) -> f64 {
1e-3 * 10_f64.powf(dbm / 10.0)
}
pub fn watts_to_dbm(w: f64) -> f64 {
10.0 * (w / 1e-3).log10()
}
pub fn neff_to_beta(n_eff: f64, lambda_m: f64) -> f64 {
2.0 * PI * n_eff / lambda_m
}
pub fn beta_to_neff(beta: f64, lambda_m: f64) -> f64 {
beta * lambda_m / (2.0 * PI)
}
pub fn temperature_c_to_k(c: f64) -> f64 {
c + 273.15
}
pub fn temperature_k_to_c(k: f64) -> f64 {
k - 273.15
}
pub fn loss_per_m_to_db_per_cm(loss_per_m: f64) -> f64 {
loss_per_m * 10.0 / (10_f64.ln() * 100.0)
}
pub fn db_per_cm_to_loss_per_m(db_per_cm: f64) -> f64 {
db_per_cm * 10_f64.ln() * 100.0 / 10.0
}
pub fn db_per_km_to_loss_per_m(db_per_km: f64) -> f64 {
db_per_km * 10_f64.ln() / (10.0 * 1000.0)
}
pub fn finesse_to_q(finesse: f64, fsr_hz: f64, resonance_hz: f64) -> f64 {
finesse * resonance_hz / fsr_hz
}
pub fn q_to_linewidth_hz(q: f64, resonance_hz: f64) -> f64 {
resonance_hz / q
}
pub fn group_index_to_group_velocity(ng: f64) -> f64 {
SPEED_OF_LIGHT / ng
}
pub fn dispersion_ps_per_nm_per_km_to_si(d: f64) -> f64 {
d * 1e-6
}
pub fn dispersion_si_to_ps_per_nm_per_km(d_si: f64) -> f64 {
d_si * 1e6
}
pub fn photon_energy_j(lambda_m: f64) -> f64 {
PLANCK * SPEED_OF_LIGHT / lambda_m
}
pub fn photon_energy_ev(lambda_nm: f64) -> f64 {
wavelength_nm_to_ev(lambda_nm)
}
pub fn thermal_voltage(temperature_k: f64) -> f64 {
BOLTZMANN * temperature_k / ELECTRON_CHARGE
}
pub fn thermal_energy_j(temperature_k: f64) -> f64 {
BOLTZMANN * temperature_k
}
pub fn thermal_energy_ev(temperature_k: f64) -> f64 {
thermal_energy_j(temperature_k) * J_TO_EV
}
#[inline]
pub fn deg_to_rad(deg: f64) -> f64 {
deg * PI / 180.0
}
#[inline]
pub fn rad_to_deg(rad: f64) -> f64 {
rad * 180.0 / PI
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn z0_from_constants() {
let z0_calc = (MU_0 / EPSILON_0).sqrt();
assert_relative_eq!(z0_calc, Z0, epsilon = 1e-3);
}
#[test]
fn c_from_mu_eps() {
let c_calc = 1.0 / (MU_0 * EPSILON_0).sqrt();
assert_relative_eq!(c_calc, SPEED_OF_LIGHT, epsilon = 1.0);
}
#[test]
fn wavelength_frequency_roundtrip() {
let lambda = 1550e-9;
let f = wavelength_to_frequency(lambda);
let lambda2 = frequency_to_wavelength(f);
assert_relative_eq!(lambda, lambda2, epsilon = 1e-25);
}
#[test]
fn wavelength_omega_roundtrip() {
let lambda = 800e-9;
let omega = wavelength_to_omega(lambda);
let lambda2 = omega_to_wavelength(omega);
assert_relative_eq!(lambda, lambda2, epsilon = 1e-25);
}
#[test]
fn ev_wavelength_roundtrip() {
let ev = wavelength_nm_to_ev(1550.0);
let nm = ev_to_wavelength_nm(ev);
assert_relative_eq!(nm, 1550.0, epsilon = 1e-4);
}
#[test]
fn dbm_zero_is_one_mw() {
let w = dbm_to_watts(0.0);
assert_relative_eq!(w, 1e-3, epsilon = 1e-15);
}
#[test]
fn one_mw_is_zero_dbm() {
let dbm = watts_to_dbm(1e-3);
assert!(dbm.abs() < 1e-10);
}
#[test]
fn dbm_roundtrip() {
let dbm = 10.0;
let w = dbm_to_watts(dbm);
let dbm2 = watts_to_dbm(w);
assert_relative_eq!(dbm, dbm2, epsilon = 1e-10);
}
#[test]
fn neff_beta_roundtrip() {
let n_eff = 2.5;
let lambda = 1550e-9;
let beta = neff_to_beta(n_eff, lambda);
let n_eff2 = beta_to_neff(beta, lambda);
assert_relative_eq!(n_eff, n_eff2, epsilon = 1e-14);
}
#[test]
fn temperature_c_k_roundtrip() {
let c = 25.0;
let k = temperature_c_to_k(c);
let c2 = temperature_k_to_c(k);
assert_relative_eq!(c, c2, epsilon = 1e-12);
}
#[test]
fn loss_db_cm_roundtrip() {
let loss = 10.0; let db = loss_per_m_to_db_per_cm(loss);
let loss2 = db_per_cm_to_loss_per_m(db);
assert_relative_eq!(loss, loss2, epsilon = 1e-12);
}
#[test]
fn finesse_to_q_basic() {
let q = finesse_to_q(100.0, 100e9, 193e12);
assert_relative_eq!(q, 193_000.0, epsilon = 1.0);
}
#[test]
fn q_to_linewidth_basic() {
let q = 1e6;
let f0 = 200e12;
let lw = q_to_linewidth_hz(q, f0);
assert_relative_eq!(lw, 200e6, epsilon = 1.0);
}
#[test]
fn group_velocity_silicon_ng4() {
let vg = group_index_to_group_velocity(4.0);
assert_relative_eq!(vg, SPEED_OF_LIGHT / 4.0, epsilon = 1.0);
}
#[test]
fn dispersion_roundtrip() {
let d = 17.0; let d_si = dispersion_ps_per_nm_per_km_to_si(d);
let d2 = dispersion_si_to_ps_per_nm_per_km(d_si);
assert_relative_eq!(d, d2, epsilon = 1e-10);
}
#[test]
fn photon_energy_visible() {
let e = photon_energy_ev(550.0);
assert!(e > 2.2 && e < 2.3, "E(550nm)={e:.4} eV");
}
#[test]
fn thermal_voltage_room_temp() {
let vt = thermal_voltage(300.0);
assert_relative_eq!(vt, 0.025_852, epsilon = 1e-5);
}
#[test]
fn deg_rad_roundtrip() {
let deg = 45.0;
let rad = deg_to_rad(deg);
let deg2 = rad_to_deg(rad);
assert_relative_eq!(deg, deg2, epsilon = 1e-13);
}
#[test]
fn hbar_from_planck() {
assert_relative_eq!(HBAR, PLANCK / (2.0 * PI), epsilon = 1e-36);
}
}