use crate::linear_algebra::Vector3D;
use crate::ode::ExponentialMap;
use crate::scalar::Numeric;
use crate::spatial::SO3;
#[inline]
pub(super) fn upward_reference<T: Numeric>() -> Vector3D<T> {
Vector3D::new([T::ZERO, T::ZERO, T::ONE])
}
#[inline]
pub(super) fn north_reference<T: Numeric>() -> Vector3D<T> {
Vector3D::new([T::ONE, T::ZERO, T::ZERO])
}
#[inline]
pub(super) fn readings_are_finite<T: Numeric>(
gyroscope_reading: Vector3D<T>,
accelerometer_reading: Vector3D<T>,
magnetometer_reading: Option<Vector3D<T>>,
timestep: T,
) -> bool {
gyroscope_reading.is_finite()
&& accelerometer_reading.is_finite()
&& timestep.is_finite()
&& magnetometer_reading.is_none_or(Vector3D::is_finite)
}
#[inline]
pub(super) fn orientation_is_finite<T: Numeric>(orientation: SO3<T>) -> bool {
let [w, x, y, z] = orientation.quaternion().as_array();
w.is_finite() && x.is_finite() && y.is_finite() && z.is_finite()
}
#[inline]
pub(super) fn correction<T: Numeric>(
orientation: SO3<T>,
accelerometer_reading: Vector3D<T>,
magnetometer_reading: Option<Vector3D<T>>,
upward_reference: Vector3D<T>,
north_reference: Vector3D<T>,
) -> Vector3D<T> {
let mut total = Vector3D::zeros();
if let Some(measured) = accelerometer_reading.try_normalized() {
total += measured.cross(orientation.inverse().act(upward_reference));
}
if let Some(measured) = magnetometer_reading.and_then(Vector3D::try_normalized) {
let in_world = orientation.act(measured);
let vertical = in_world.dot(upward_reference);
let across = T::ONE - vertical * vertical;
let horizontal = if across > T::ZERO {
across.sqrt()
} else {
T::ZERO
};
let reference = north_reference * horizontal + upward_reference * vertical;
total += measured.cross(orientation.inverse().act(reference));
}
total
}
#[inline]
pub(super) fn stepped_orientation<T: Numeric>(
orientation: SO3<T>,
corrected_rate: Vector3D<T>,
timestep: T,
) -> SO3<T> {
ExponentialMap::attitude_step(orientation, corrected_rate, timestep).normalized()
}