use crate::error::EstimationError;
use crate::linear_algebra::Vector;
use crate::scalar::{Numeric, VectorFn};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ConstantTurnAndSpeed {
pub timestep: f64,
}
impl VectorFn<5, 5> for ConstantTurnAndSpeed {
fn eval<S: Numeric>(&self, state: &[S; 5]) -> [S; 5] {
let [x, y, heading, speed, turn_rate] = *state;
let dt = S::from_f64(self.timestep);
let next_heading = heading + turn_rate * dt;
let (next_x, next_y) = if turn_rate.abs() > S::from_f64(1e-6) {
let radius = speed / turn_rate;
(
x + radius * (next_heading.sin() - heading.sin()),
y + radius * (heading.cos() - next_heading.cos()),
)
} else {
(
x + speed * heading.cos() * dt,
y + speed * heading.sin() * dt,
)
};
[next_x, next_y, next_heading.wrap_to_pi(), speed, turn_rate]
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DirectMeasurement<const STATE_DIMENSION: usize, const MEASUREMENT_DIMENSION: usize> {
indices: [usize; MEASUREMENT_DIMENSION],
}
impl<const STATE_DIMENSION: usize, const MEASUREMENT_DIMENSION: usize>
DirectMeasurement<STATE_DIMENSION, MEASUREMENT_DIMENSION>
{
pub fn try_new(indices: [usize; MEASUREMENT_DIMENSION]) -> Result<Self, EstimationError> {
for index in indices {
if index >= STATE_DIMENSION {
return Err(EstimationError::StateIndexOutOfRange);
}
}
Ok(DirectMeasurement { indices })
}
#[must_use]
pub fn indices(&self) -> [usize; MEASUREMENT_DIMENSION] {
self.indices
}
}
impl<const STATE_DIMENSION: usize, const MEASUREMENT_DIMENSION: usize>
VectorFn<STATE_DIMENSION, MEASUREMENT_DIMENSION>
for DirectMeasurement<STATE_DIMENSION, MEASUREMENT_DIMENSION>
{
fn eval<S: Numeric>(&self, state: &[S; STATE_DIMENSION]) -> [S; MEASUREMENT_DIMENSION] {
core::array::from_fn(|position| {
self.indices
.get(position)
.and_then(|&index| state.get(index))
.copied()
.unwrap_or(S::ZERO)
})
}
}
pub fn residual_with_wrapped_angles<const MEASUREMENT_DIMENSION: usize, T: Numeric>(
measured: Vector<MEASUREMENT_DIMENSION, T>,
predicted: Vector<MEASUREMENT_DIMENSION, T>,
angular_components: &[usize],
) -> Vector<MEASUREMENT_DIMENSION, T> {
Vector::from_fn(|component| {
let difference = measured[component] - predicted[component];
if angular_components.contains(&component) {
difference.wrap_to_pi()
} else {
difference
}
})
}