Hey folks! Jumping to Rust from a predominately C++ and Python background. I'm diving in by creating my own DSP library (starting with a basic PID controller). In C++, I would build libraries like this using templates for the obvious benefit of being able to define my type on an as needed basis. When it comes to operations such as multiplying or dividing by a discrete time step, the auto
keyword was very helpful for working around this ambiguous type definition.
In Rust, however, I'm a little stumped. I have defined a Number
trait (duplicated from an example) as follows:
pub trait Number: PartialOrd + num_traits::Signed + Copy {}
impl<T: PartialOrd + num_traits::Signed + Copy> Number for T {}
With the Generic I was able to define my PID struct
and impl
appropriately (I believe):
struct PIDController<T: Number> {
pub setpoint: T,
pub output_limits: Limits<T>,
pub kp: T,
pub ki: T,
pub kd: T,
pub p_limits: Limits<T>,
pub i_limits: Limits<T>,
pub d_limits: Limits<T>,
band_limit_i: T,
prev_time: SystemTime,
prev_error: T,
first_sample: bool,
ei: T,
}
impl<T> PIDController<T>
where T: Number,
T: From<f32> {
// Create+Initialize new PIDController
pub fn new() -> Self {
Self {
setpoint: T::zero(),
output_limits: Limits {
lower_limit: T::zero(),
upper_limit: T::zero(),
},
kp: T::zero(),
ki: T::zero(),
kd: T::zero(),
p_limits: Limits {
lower_limit: (T::zero()),
upper_limit: (T::zero()),
},
i_limits: Limits {
lower_limit: (T::zero()),
upper_limit: (T::zero()),
},
d_limits: Limits {
lower_limit: (T::zero()),
upper_limit: (T::zero()),
},
band_limit_i: T::zero(),
prev_time: SystemTime::now(),
prev_error: T::zero(),
first_sample: true,
ei: T::zero(),
}
}
The issue I'm running into is in my update
function I will want to divide or multiply my Generic by a Duration, which has the ability to return as various "number" types (u32, u64, f32, etc...).
// Division
let mut ed = (error - self.prev_error) / T::from(dt.as_secs_f32());
// Multiplication
self.ei.clone() + error * T::from(dt.as_secs_f32()) * self.ki
How can I implement a multiplication or division operation (or any mathematical operation) where I want to evaluate a Generic with a value of known type? I ca
You can see in the example I added the From
trait(?) for the f32
type but that obviously breaks if I use any type other than f32
or f64
. I assume there's a better way than adding a From
variation for every type I want to support:
T: From<u8>,
T: From<u16>,
T: From<u32>,
T: From<f32>,
etc ...
I tried doing my due-diligence to find the answer on my own but am maybe missing a key piece of terminology to find what I'm looking for. Any help/feedback is appreciated. Thanks in advance!