use super::Extrapolator;
#[derive(Debug, Clone, Copy, Default)]
pub struct LinearExtrapolator;
impl LinearExtrapolator {
#[must_use]
pub fn new() -> Self {
Self
}
}
impl Extrapolator for LinearExtrapolator {
fn extrapolate(&self, t: f64, last_t: f64, last_value: f64, last_derivative: f64) -> f64 {
last_value + last_derivative * (t - last_t)
}
fn name(&self) -> &'static str {
"Linear"
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_linear_extrapolation() {
let extrap = LinearExtrapolator::new();
let last_t = 10.0;
let last_value = 0.05;
let last_deriv = 0.001;
let value = extrap.extrapolate(15.0, last_t, last_value, last_deriv);
assert_relative_eq!(value, 0.055, epsilon = 1e-10);
let value = extrap.extrapolate(20.0, last_t, last_value, last_deriv);
assert_relative_eq!(value, 0.06, epsilon = 1e-10);
}
#[test]
fn test_linear_with_negative_slope() {
let extrap = LinearExtrapolator;
let last_t = 20.0;
let last_value = 0.04;
let last_deriv = -0.0005;
let value = extrap.extrapolate(30.0, last_t, last_value, last_deriv);
assert_relative_eq!(value, 0.035, epsilon = 1e-10);
}
#[test]
fn test_linear_at_boundary() {
let extrap = LinearExtrapolator;
let last_t = 10.0;
let last_value = 0.05;
let last_deriv = 0.001;
let value = extrap.extrapolate(last_t, last_t, last_value, last_deriv);
assert_relative_eq!(value, last_value, epsilon = 1e-15);
}
#[test]
fn test_linear_with_zero_slope() {
let extrap = LinearExtrapolator;
let last_t = 10.0;
let last_value = 0.03;
let last_deriv = 0.0;
for t in [15.0, 20.0, 50.0, 100.0] {
let value = extrap.extrapolate(t, last_t, last_value, last_deriv);
assert_relative_eq!(value, last_value, epsilon = 1e-15);
}
}
#[test]
fn test_linear_name() {
let extrap = LinearExtrapolator;
assert_eq!(extrap.name(), "Linear");
}
}