#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub struct ThermistorParams {
pub r0: f64,
pub beta: f64,
pub t0: f64,
}
impl ThermistorParams {
pub fn ntc_10k() -> Self {
Self {
r0: 10_000.0,
beta: 3950.0,
t0: 298.15,
}
}
}
impl Default for ThermistorParams {
fn default() -> Self {
Self::ntc_10k()
}
}
pub fn thermistor_resistance(temperature_k: f64, params: &ThermistorParams) -> f64 {
let t = temperature_k.max(1.0);
params.r0 * (params.beta * (1.0 / t - 1.0 / params.t0)).exp()
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn ntc_at_reference_temperature_equals_r0() {
let params = ThermistorParams::ntc_10k();
let r = thermistor_resistance(298.15, ¶ms);
assert_relative_eq!(r, 10_000.0, max_relative = 1e-10);
}
#[test]
fn ntc_increases_as_temperature_drops() {
let params = ThermistorParams::ntc_10k();
let r_25c = thermistor_resistance(298.15, ¶ms);
let r_10c = thermistor_resistance(283.15, ¶ms);
let r_50c = thermistor_resistance(323.15, ¶ms);
assert!(
r_10c > r_25c,
"NTC resistance should increase as temp drops"
);
assert!(
r_50c < r_25c,
"NTC resistance should decrease as temp rises"
);
}
#[test]
fn ntc_0c_reasonable_value() {
let params = ThermistorParams::ntc_10k();
let r_0c = thermistor_resistance(273.15, ¶ms);
assert!(
r_0c > 20_000.0 && r_0c < 40_000.0,
"R at 0°C = {} (expected 20-40 kΩ)",
r_0c
);
}
}