use crate::constants;
pub fn er_eff_static(u: f64, er: f64) -> f64 {
let f = if u <= 1.0 {
(1.0 + 12.0 / u).powf(-0.5) + 0.04 * (1.0 - u).powi(2)
} else {
(1.0 + 12.0 / u).powf(-0.5)
};
(er + 1.0) / 2.0 + (er - 1.0) / 2.0 * f
}
pub fn effective_width(w: f64, h: f64, t: f64) -> f64 {
if t <= 0.0 {
return w;
}
let u = w / h;
let dw = if u >= std::f64::consts::FRAC_PI_2 {
(t / std::f64::consts::PI) * (1.0 + (2.0 * h / t).ln())
} else {
(t / std::f64::consts::PI) * (1.0 + (4.0 * std::f64::consts::PI * w / t).ln())
};
w + dw
}
pub fn propagation_delay(er_eff: f64) -> f64 {
er_eff.sqrt() / constants::SPEED_OF_LIGHT_IN_NS * 1000.0
}
pub fn inductance_per_length(zo: f64, tpd_ps_per_in: f64) -> f64 {
zo * tpd_ps_per_in / 1000.0
}
pub fn capacitance_per_length(zo: f64, tpd_ps_per_in: f64) -> f64 {
(tpd_ps_per_in / 1000.0) / zo * 1000.0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn er_eff_fr4_wide_trace() {
let er_eff = er_eff_static(2.0, 4.6);
assert!(er_eff > 3.0 && er_eff < 4.6, "er_eff = {er_eff}");
}
#[test]
fn er_eff_narrow_trace() {
let narrow = er_eff_static(0.5, 4.6);
let wide = er_eff_static(2.0, 4.6);
assert!(narrow < wide, "narrow {narrow} should be < wide {wide}");
}
#[test]
fn thickness_correction_increases_width() {
let w = 5.0; let h = 4.0;
let t = 1.4; let we = effective_width(w, h, t);
assert!(we > w, "effective width {we} should be > original {w}");
}
}