use crate::CalcError;
use crate::impedance::{common, types::ImpedanceResult};
pub struct StriplineInput {
pub width: f64,
pub height: f64,
pub thickness: f64,
pub er: f64,
}
pub fn calculate(input: &StriplineInput) -> Result<ImpedanceResult, CalcError> {
let StriplineInput { width, height, thickness, er } = *input;
if width <= 0.0 {
return Err(CalcError::NegativeDimension { name: "width", value: width });
}
if height <= 0.0 {
return Err(CalcError::NegativeDimension { name: "height", value: height });
}
if er < 1.0 {
return Err(CalcError::OutOfRange {
name: "er",
value: er,
expected: ">= 1.0",
});
}
let zo = (60.0 / er.sqrt()) * (1.9 * (2.0 * height + thickness) / (0.8 * width + thickness)).ln();
let er_eff = er;
let tpd = common::propagation_delay(er_eff);
let lo = common::inductance_per_length(zo, tpd);
let co = common::capacitance_per_length(zo, tpd);
Ok(ImpedanceResult {
zo,
er_eff,
tpd_ps_per_in: tpd,
lo_nh_per_in: lo,
co_pf_per_in: co,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic_stripline() {
let result = calculate(&StriplineInput {
width: 10.0,
height: 10.0,
thickness: 1.4,
er: 4.6,
})
.unwrap();
assert!(result.zo > 20.0 && result.zo < 100.0, "Zo = {}", result.zo);
assert!((result.er_eff - 4.6).abs() < 1e-10);
assert!(result.tpd_ps_per_in > 0.0);
assert!(result.lo_nh_per_in > 0.0);
assert!(result.co_pf_per_in > 0.0);
}
#[test]
fn narrow_trace_higher_impedance() {
let narrow = calculate(&StriplineInput {
width: 3.0,
height: 10.0,
thickness: 1.4,
er: 4.6,
})
.unwrap();
let wide = calculate(&StriplineInput {
width: 20.0,
height: 10.0,
thickness: 1.4,
er: 4.6,
})
.unwrap();
assert!(
narrow.zo > wide.zo,
"narrow Zo {} should be > wide Zo {}",
narrow.zo,
wide.zo
);
}
#[test]
fn higher_er_lower_impedance() {
let low_er = calculate(&StriplineInput {
width: 10.0,
height: 10.0,
thickness: 1.4,
er: 2.2,
})
.unwrap();
let high_er = calculate(&StriplineInput {
width: 10.0,
height: 10.0,
thickness: 1.4,
er: 4.6,
})
.unwrap();
assert!(
low_er.zo > high_er.zo,
"low Er Zo {} should be > high Er Zo {}",
low_er.zo,
high_er.zo
);
}
#[test]
fn rejects_negative_width() {
let result = calculate(&StriplineInput {
width: -1.0,
height: 10.0,
thickness: 1.4,
er: 4.6,
});
assert!(result.is_err());
}
#[test]
fn rejects_low_er() {
let result = calculate(&StriplineInput {
width: 10.0,
height: 10.0,
thickness: 1.4,
er: 0.5,
});
assert!(result.is_err());
}
}