use core::convert::From;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PidParameterAdditive {
pub proportional: f32,
pub integral: f32,
pub differential: f32,
}
impl PidParameterAdditive {
pub fn new(proportional: f32) -> Self {
if proportional <= 0.0 {
panic!("Positive proportional coefficient required");
}
Self {
proportional,
integral: 0.0,
differential: 0.0,
}
}
pub fn set_integral(&self, integral: f32) -> Self {
if integral <= 0.0 {
panic!("Positive integral coefficient required");
}
Self { integral, ..*self }
}
pub fn set_differential(&self, differential: f32) -> Self {
if differential <= 0.0 {
panic!("Positive differential coefficient required");
}
Self {
differential,
..*self
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PidParameterStandard {
pub amplification: f32,
pub integral_time: Option<f32>,
pub differential_time: f32,
}
impl PidParameterStandard {
pub fn new(amplification: f32) -> Self {
if amplification <= 0.0 {
panic!("Positive amplification required");
}
Self {
amplification,
integral_time: None,
differential_time: 0.0,
}
}
pub fn set_integral_time(&self, integral_time: f32) -> Self {
if integral_time <= 0.0 {
panic!("Positive integral time required");
}
Self {
integral_time: Some(integral_time),
..*self
}
}
pub fn set_differential_time(&self, differential_time: f32) -> Self {
if differential_time <= 0.0 {
panic!("Positive differential time required");
}
Self {
differential_time,
..*self
}
}
}
impl From<PidParameterAdditive> for PidParameterStandard {
fn from(item: PidParameterAdditive) -> Self {
Self {
amplification: item.proportional,
integral_time: if item.integral == 0.0 {
None
} else {
Some(item.proportional / item.integral)
},
differential_time: item.differential / item.proportional,
}
}
}
impl From<PidParameterStandard> for PidParameterAdditive {
fn from(item: PidParameterStandard) -> Self {
Self {
proportional: item.amplification,
integral: match item.integral_time {
Some(time) => item.amplification / time,
None => 0.0,
},
differential: item.differential_time * item.amplification,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn new_standard_should_panic_on_zero() {
PidParameterStandard::new(0.0);
}
#[test]
#[should_panic]
fn new_standard_should_panic_on_negative() {
PidParameterStandard::new(-1.0);
}
#[test]
#[should_panic]
fn set_integral_time_should_panic_on_negative() {
PidParameterStandard::new(1.0).set_integral_time(-1.0);
}
#[test]
#[should_panic]
fn set_integral_time_should_panic_on_zero() {
PidParameterStandard::new(1.0).set_integral_time(0.0);
}
#[test]
#[should_panic]
fn set_differential_time_should_panic_on_negative() {
PidParameterStandard::new(1.0).set_differential_time(-1.0);
}
#[test]
#[should_panic]
fn set_differential_time_should_panic_on_zero() {
PidParameterStandard::new(1.0).set_differential_time(0.0);
}
#[test]
#[should_panic]
fn new_additive_should_panic_on_zero() {
PidParameterAdditive::new(0.0);
}
#[test]
#[should_panic]
fn new_additive_should_panic_on_negative() {
PidParameterAdditive::new(-1.0);
}
#[test]
#[should_panic]
fn set_integral_should_panic_on_negative() {
PidParameterAdditive::new(1.0).set_integral(-1.0);
}
#[test]
#[should_panic]
fn set_integral_should_panic_on_zero() {
PidParameterAdditive::new(1.0).set_integral(0.0);
}
#[test]
#[should_panic]
fn set_differential_should_panic_on_negative() {
PidParameterAdditive::new(1.0).set_differential(-1.0);
}
#[test]
#[should_panic]
fn set_differential_should_panic_on_zero() {
PidParameterAdditive::new(1.0).set_differential(0.0);
}
#[test]
fn convert_standard_to_additive_ok() {
let s = PidParameterStandard::new(2.0)
.set_differential_time(1.0)
.set_integral_time(0.5);
let a = PidParameterAdditive::new(2.0)
.set_differential(2.0)
.set_integral(4.0);
assert_eq!(a, s.into());
let s = PidParameterStandard::new(1.0).set_integral_time(0.25);
let a = PidParameterAdditive::new(1.0).set_integral(4.0);
assert_eq!(a, s.into());
let s = PidParameterStandard::new(1.0).set_differential_time(2.0);
let a = PidParameterAdditive::new(1.0).set_differential(2.0);
assert_eq!(a, s.into());
let s = PidParameterStandard::new(1.0);
let a = PidParameterAdditive::new(1.0);
assert_eq!(a, s.into());
}
#[test]
fn convert_additive_to_standard_ok() {
let s = PidParameterStandard::new(2.0)
.set_differential_time(1.0)
.set_integral_time(0.5);
let a = PidParameterAdditive::new(2.0)
.set_differential(2.0)
.set_integral(4.0);
assert_eq!(s, a.into());
let s = PidParameterStandard::new(1.0).set_integral_time(0.25);
let a = PidParameterAdditive::new(1.0).set_integral(4.0);
assert_eq!(s, a.into());
let s = PidParameterStandard::new(1.0).set_differential_time(2.0);
let a = PidParameterAdditive::new(1.0).set_differential(2.0);
assert_eq!(s, a.into());
let s = PidParameterStandard::new(1.0);
let a = PidParameterAdditive::new(1.0);
assert_eq!(s, a.into());
}
}