#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum LinalgError {
Singular,
IllConditioned,
NotPositiveDefinite,
Underdetermined,
NonFinite,
NotSymmetric,
InvalidTimestep,
DidNotConverge {
iters: usize,
},
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum DiffError {
OrderZero,
OrderUnsupported,
StepSizeZero,
IndexOutOfRange,
EmptyFunctionSet,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum IntegrateError {
IterationsZero,
LimitsIllDefined,
QuadratureOrderOutOfRange,
StepSizeTooSmall,
DidNotConverge {
steps: usize,
},
NonFinite,
IndexOutOfRange,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum SolveError {
DidNotConverge {
iters: usize,
},
NonFinite,
InvalidBracket,
Linalg(LinalgError),
Diff(DiffError),
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum KinematicsError {
NonPositiveParameter,
NonFinite,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum SpatialError {
NonPositiveMass,
NonFinite,
NotSymmetric,
NonPositiveInertia,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum EstimationError {
NotPositiveDefinite,
NonFinite,
Diff(DiffError),
WeightsDegenerate,
InvalidTuning,
StateIndexOutOfRange,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum SignalError {
NonFinite,
NonPositiveTimestep,
CoefficientOutOfRange,
FrequencyOutOfRange,
NonPositiveQualityFactor,
NegativeThreshold,
ThresholdsOutOfOrder,
NonPositiveRate,
WindowTooShort,
WindowEvenLength,
PolynomialOrderTooHigh,
SectionIndexOutOfRange,
Linalg(LinalgError),
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum ControlError {
NonFinite,
NonPositiveTimestep,
InvalidOutputLimits,
#[deprecated(
since = "0.10.0",
note = "filters now report SignalError::CoefficientOutOfRange"
)]
FilterCoefficientOutOfRange,
NonPositiveLookaheadDistance,
InvalidBeamCount,
InvalidFieldOfView,
NonPositiveRange,
NonPositiveChassisWidth,
NonPositiveSpeed,
InvalidSpeedScaling,
NegativeGoalBias,
NonPositiveGain,
NotSymmetricInertia,
NonPositiveInertia,
UndefinedThrustDirection,
UndefinedHeadingDirection,
Linalg(LinalgError),
Signal(SignalError),
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum DynamicsError {
NonFinite,
NonPositiveInertia,
Linalg(LinalgError),
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum PlantError {
NonFinite,
NonPositiveArmLength,
NonPositiveTorqueRatio,
InvalidThrustLimits,
RotorLayoutNotIndependent,
NonPositiveTimeConstant,
NonPositiveTimestep,
Linalg(LinalgError),
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum MappingError {
NonFinite,
NonPositiveResolution,
EmptyGrid,
GridTooLarge,
TooFewBeams,
InvalidFieldOfView,
NonPositiveRange,
InvalidRangeLimits,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum MotionError {
NonFinite,
CapacityExceeded,
PathTooShort,
SegmentCountMismatch,
DurationNotPositive,
WorkspaceTooSmall,
Linalg(LinalgError),
Polynomial(PolynomialError),
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum PolynomialError {
NonFinite,
LeadingCoefficientZero,
DegreeOverflow,
CapacityExceeded,
Empty,
VariableOutOfRange,
DuplicateNode,
TooFewSamples,
SpanNotPositive,
DidNotConverge {
steps: usize,
},
Linalg(LinalgError),
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum CalcError {
Linalg(LinalgError),
Solve(SolveError),
Integrate(IntegrateError),
Differentiate(DiffError),
Kinematics(KinematicsError),
Spatial(SpatialError),
Estimation(EstimationError),
Signal(SignalError),
Control(ControlError),
Dynamics(DynamicsError),
Plant(PlantError),
Mapping(MappingError),
Motion(MotionError),
Polynomial(PolynomialError),
}
impl From<LinalgError> for SolveError {
fn from(e: LinalgError) -> Self {
SolveError::Linalg(e)
}
}
impl From<DiffError> for SolveError {
fn from(e: DiffError) -> Self {
SolveError::Diff(e)
}
}
impl From<DiffError> for EstimationError {
fn from(e: DiffError) -> Self {
EstimationError::Diff(e)
}
}
impl From<LinalgError> for SignalError {
fn from(e: LinalgError) -> Self {
SignalError::Linalg(e)
}
}
impl From<LinalgError> for PolynomialError {
fn from(e: LinalgError) -> Self {
PolynomialError::Linalg(e)
}
}
impl From<LinalgError> for MotionError {
fn from(e: LinalgError) -> Self {
MotionError::Linalg(e)
}
}
impl From<PolynomialError> for MotionError {
fn from(e: PolynomialError) -> Self {
MotionError::Polynomial(e)
}
}
impl From<SignalError> for ControlError {
fn from(e: SignalError) -> Self {
ControlError::Signal(e)
}
}
impl From<LinalgError> for ControlError {
fn from(e: LinalgError) -> Self {
ControlError::Linalg(e)
}
}
impl From<LinalgError> for DynamicsError {
fn from(e: LinalgError) -> Self {
DynamicsError::Linalg(e)
}
}
impl From<LinalgError> for PlantError {
fn from(e: LinalgError) -> Self {
PlantError::Linalg(e)
}
}
impl From<LinalgError> for CalcError {
fn from(e: LinalgError) -> Self {
CalcError::Linalg(e)
}
}
impl From<DiffError> for CalcError {
fn from(e: DiffError) -> Self {
CalcError::Differentiate(e)
}
}
impl From<IntegrateError> for CalcError {
fn from(e: IntegrateError) -> Self {
CalcError::Integrate(e)
}
}
impl From<SolveError> for CalcError {
fn from(e: SolveError) -> Self {
CalcError::Solve(e)
}
}
impl From<KinematicsError> for CalcError {
fn from(e: KinematicsError) -> Self {
CalcError::Kinematics(e)
}
}
impl From<SpatialError> for CalcError {
fn from(e: SpatialError) -> Self {
CalcError::Spatial(e)
}
}
impl From<EstimationError> for CalcError {
fn from(e: EstimationError) -> Self {
CalcError::Estimation(e)
}
}
impl From<SignalError> for CalcError {
fn from(e: SignalError) -> Self {
CalcError::Signal(e)
}
}
impl From<ControlError> for CalcError {
fn from(e: ControlError) -> Self {
CalcError::Control(e)
}
}
impl From<DynamicsError> for CalcError {
fn from(e: DynamicsError) -> Self {
CalcError::Dynamics(e)
}
}
impl From<PlantError> for CalcError {
fn from(e: PlantError) -> Self {
CalcError::Plant(e)
}
}
impl From<MappingError> for CalcError {
fn from(e: MappingError) -> Self {
CalcError::Mapping(e)
}
}
impl From<MotionError> for CalcError {
fn from(e: MotionError) -> Self {
CalcError::Motion(e)
}
}
impl From<PolynomialError> for CalcError {
fn from(e: PolynomialError) -> Self {
CalcError::Polynomial(e)
}
}
impl core::fmt::Display for LinalgError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
LinalgError::Singular => f.write_str("matrix is singular or rank-deficient"),
LinalgError::IllConditioned => {
f.write_str("matrix is too ill-conditioned to solve reliably")
}
LinalgError::NotPositiveDefinite => f.write_str("matrix is not positive definite"),
LinalgError::Underdetermined => f.write_str("system is underdetermined (M < N)"),
LinalgError::NonFinite => f.write_str("matrix contained a non-finite value"),
LinalgError::NotSymmetric => {
f.write_str("matrix must read the same across the diagonal")
}
LinalgError::InvalidTimestep => f.write_str("timestep must be finite and non-negative"),
LinalgError::DidNotConverge { iters } => {
write!(f, "matrix equation did not settle after {iters} iterations")
}
}
}
}
impl core::fmt::Display for DiffError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(match self {
DiffError::OrderZero => "derivative order cannot be zero",
DiffError::OrderUnsupported => "derivative order is not supported",
DiffError::StepSizeZero => "step size cannot be zero",
DiffError::IndexOutOfRange => "variable index out of range",
DiffError::EmptyFunctionSet => "function set cannot be empty",
})
}
}
impl core::fmt::Display for IntegrateError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
IntegrateError::IterationsZero => f.write_str("number of iterations cannot be zero"),
IntegrateError::LimitsIllDefined => {
f.write_str("lower limit must be strictly less than upper limit")
}
IntegrateError::QuadratureOrderOutOfRange => {
f.write_str("quadrature order is out of supported range")
}
IntegrateError::StepSizeTooSmall => {
f.write_str("adaptive step size fell below the minimum")
}
IntegrateError::DidNotConverge { steps } => {
write!(f, "integrator did not converge within {steps} steps")
}
IntegrateError::NonFinite => {
f.write_str("integrand or state contained a non-finite value")
}
IntegrateError::IndexOutOfRange => f.write_str("variable index out of range"),
}
}
}
impl core::fmt::Display for SolveError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
SolveError::DidNotConverge { iters } => {
write!(f, "solver did not converge after {iters} iterations")
}
SolveError::NonFinite => {
f.write_str("residual or Jacobian contained a non-finite value")
}
SolveError::InvalidBracket => {
f.write_str("bracket endpoints must enclose a sign change")
}
SolveError::Linalg(e) => write!(f, "{e}"),
SolveError::Diff(e) => write!(f, "{e}"),
}
}
}
impl core::fmt::Display for KinematicsError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(match self {
KinematicsError::NonPositiveParameter => {
"geometric parameter must be strictly positive"
}
KinematicsError::NonFinite => "geometric parameter was not finite",
})
}
}
impl core::fmt::Display for SpatialError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(match self {
SpatialError::NonPositiveMass => "body mass must be strictly positive",
SpatialError::NonFinite => "mass, centre of mass, or inertia was not finite",
SpatialError::NotSymmetric => {
"rotational inertia must read the same across the diagonal"
}
SpatialError::NonPositiveInertia => {
"rotational inertia diagonal entries must be strictly positive"
}
})
}
}
impl core::fmt::Display for EstimationError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
EstimationError::NotPositiveDefinite => {
f.write_str("innovation covariance is not positive definite")
}
EstimationError::NonFinite => f.write_str("filter value was not finite"),
EstimationError::Diff(e) => write!(f, "{e}"),
EstimationError::WeightsDegenerate => f.write_str("all particle weights were zero"),
EstimationError::InvalidTuning => f.write_str("invalid filter tuning"),
EstimationError::StateIndexOutOfRange => {
f.write_str("measurement model refers to a state component that does not exist")
}
}
}
}
impl core::fmt::Display for SignalError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
SignalError::NonFinite => f.write_str("filter parameter contained a non-finite value"),
SignalError::NonPositiveTimestep => f.write_str("timestep must be strictly positive"),
SignalError::CoefficientOutOfRange => {
f.write_str("smoothing coefficient must lie in [0, 1]")
}
SignalError::FrequencyOutOfRange => {
f.write_str("frequency must be above zero and below half the sampling rate")
}
SignalError::NonPositiveQualityFactor => {
f.write_str("quality factor must be strictly positive")
}
SignalError::NegativeThreshold => f.write_str("deadband threshold cannot be negative"),
SignalError::ThresholdsOutOfOrder => {
f.write_str("lower switching threshold must be below the upper one")
}
SignalError::NonPositiveRate => f.write_str("rate limit must be strictly positive"),
SignalError::WindowTooShort => f.write_str("window length cannot be zero"),
SignalError::WindowEvenLength => f.write_str("window length must be odd"),
SignalError::PolynomialOrderTooHigh => {
f.write_str("window is too short for the number of polynomial terms")
}
SignalError::SectionIndexOutOfRange => {
f.write_str("cascade section index out of range")
}
SignalError::Linalg(e) => write!(f, "filter setup failed: {e}"),
}
}
}
impl core::fmt::Display for ControlError {
#[allow(deprecated)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(match self {
ControlError::NonFinite => {
"gain, timestep, limit, or filter coefficient was not finite"
}
ControlError::NonPositiveTimestep => "control timestep must be strictly positive",
ControlError::InvalidOutputLimits => "output minimum must not exceed output maximum",
ControlError::FilterCoefficientOutOfRange => {
"low-pass smoothing coefficient must lie in [0, 1]"
}
ControlError::NonPositiveLookaheadDistance => {
"lookahead distance must be strictly positive"
}
ControlError::InvalidBeamCount => "gap-follower needs at least two beams",
ControlError::InvalidFieldOfView => {
"field of view must lie in (0, 2π] and the frontal half-angle within half of it"
}
ControlError::NonPositiveRange => {
"maximum range and gap threshold must be strictly positive, with the threshold no larger than the range"
}
ControlError::NonPositiveChassisWidth => {
"chassis width must be strictly positive and less than twice the maximum range"
}
ControlError::NonPositiveSpeed => {
"cruise speed and turn gain must be strictly positive"
}
ControlError::InvalidSpeedScaling => {
"stopping distance must be non-negative and strictly less than the clear distance"
}
ControlError::NegativeGoalBias => "goal bias must not be negative",
ControlError::NonPositiveGain => "controller gain must be strictly positive",
ControlError::NotSymmetricInertia => {
"rotational inertia must read the same across the diagonal"
}
ControlError::NonPositiveInertia => "rotational inertia must be positive definite",
ControlError::UndefinedThrustDirection => {
"wanted acceleration cancels gravity, leaving no direction to push in"
}
ControlError::UndefinedHeadingDirection => {
"the push is straight along the wanted heading, so the heading cannot be set"
}
ControlError::Linalg(e) => return write!(f, "{e}"),
ControlError::Signal(e) => return write!(f, "{e}"),
})
}
}
impl core::fmt::Display for DynamicsError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
DynamicsError::NonFinite => f.write_str("body property was not finite"),
DynamicsError::NonPositiveInertia => {
f.write_str("rotational inertia is not positive definite")
}
DynamicsError::Linalg(e) => write!(f, "rotational inertia could not be inverted: {e}"),
}
}
}
impl core::fmt::Display for PlantError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
PlantError::NonFinite => f.write_str("rotor property was not finite"),
PlantError::NonPositiveArmLength => f.write_str("arm length must be strictly positive"),
PlantError::NonPositiveTorqueRatio => {
f.write_str("turning force per unit of push must be strictly positive")
}
PlantError::InvalidThrustLimits => {
f.write_str("smallest thrust must be below the largest")
}
PlantError::RotorLayoutNotIndependent => {
f.write_str("rotor layout cannot produce every wanted push and turn")
}
PlantError::NonPositiveTimeConstant => {
f.write_str("rotor lag time must be strictly positive")
}
PlantError::NonPositiveTimestep => f.write_str("tick length must be strictly positive"),
PlantError::Linalg(e) => write!(f, "rotor layout could not be inverted: {e}"),
}
}
}
impl core::fmt::Display for MappingError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
MappingError::NonFinite => f.write_str("map value contained a non-finite value"),
MappingError::NonPositiveResolution => {
f.write_str("cell size must be strictly positive")
}
MappingError::EmptyGrid => {
f.write_str("grid must have at least one column and one row")
}
MappingError::GridTooLarge => f.write_str("grid has more cells than can be counted"),
MappingError::TooFewBeams => f.write_str("a scan needs at least two beams"),
MappingError::InvalidFieldOfView => f.write_str("field of view must lie in (0, 2π]"),
MappingError::NonPositiveRange => {
f.write_str("sensing range must be strictly positive")
}
MappingError::InvalidRangeLimits => f.write_str(
"closest visible range must be non-negative and below the sensing range",
),
}
}
}
impl core::fmt::Display for MotionError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
MotionError::NonFinite => f.write_str("waypoint coordinate was not finite"),
MotionError::CapacityExceeded => {
f.write_str("more waypoints than the path capacity allows")
}
MotionError::PathTooShort => {
f.write_str("query required more waypoints than the path contains")
}
MotionError::SegmentCountMismatch => {
f.write_str("one duration is needed for each pair of waypoints")
}
MotionError::DurationNotPositive => {
f.write_str("segment duration was zero or negative")
}
MotionError::WorkspaceTooSmall => {
f.write_str("more segments than the planner's free-derivative capacity holds")
}
MotionError::Linalg(e) => write!(f, "trajectory system could not be solved: {e}"),
MotionError::Polynomial(e) => write!(f, "trajectory piece could not be formed: {e}"),
}
}
}
impl core::fmt::Display for PolynomialError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
PolynomialError::NonFinite => f.write_str("polynomial value was not finite"),
PolynomialError::LeadingCoefficientZero => {
f.write_str("highest polynomial coefficient is zero")
}
PolynomialError::DegreeOverflow => {
f.write_str("result needs more coefficients than the polynomial holds")
}
PolynomialError::CapacityExceeded => {
f.write_str("more terms than the polynomial holds")
}
PolynomialError::Empty => f.write_str("there is nothing to evaluate"),
PolynomialError::VariableOutOfRange => {
f.write_str("variable index past the number of variables")
}
PolynomialError::DuplicateNode => {
f.write_str("two interpolation points share the same position")
}
PolynomialError::TooFewSamples => f.write_str("fewer samples than coefficients to fit"),
PolynomialError::SpanNotPositive => f.write_str("piece span was zero or negative"),
PolynomialError::DidNotConverge { steps } => {
write!(f, "root isolation stopped after {steps} steps")
}
PolynomialError::Linalg(e) => {
write!(f, "polynomial system could not be solved: {e}")
}
}
}
}
impl core::fmt::Display for CalcError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
CalcError::Linalg(e) => write!(f, "{e}"),
CalcError::Solve(e) => write!(f, "{e}"),
CalcError::Integrate(e) => write!(f, "{e}"),
CalcError::Differentiate(e) => write!(f, "{e}"),
CalcError::Kinematics(e) => write!(f, "{e}"),
CalcError::Spatial(e) => write!(f, "{e}"),
CalcError::Estimation(e) => write!(f, "{e}"),
CalcError::Signal(e) => write!(f, "{e}"),
CalcError::Control(e) => write!(f, "{e}"),
CalcError::Dynamics(e) => write!(f, "{e}"),
CalcError::Plant(e) => write!(f, "{e}"),
CalcError::Mapping(e) => write!(f, "{e}"),
CalcError::Motion(e) => write!(f, "{e}"),
CalcError::Polynomial(e) => write!(f, "{e}"),
}
}
}
impl core::error::Error for LinalgError {}
impl core::error::Error for DiffError {}
impl core::error::Error for IntegrateError {}
impl core::error::Error for KinematicsError {}
impl core::error::Error for SpatialError {}
impl core::error::Error for MappingError {}
impl core::error::Error for DynamicsError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
DynamicsError::Linalg(e) => Some(e),
_ => None,
}
}
}
impl core::error::Error for PlantError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
PlantError::Linalg(e) => Some(e),
_ => None,
}
}
}
impl core::error::Error for MotionError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
MotionError::Linalg(e) => Some(e),
MotionError::Polynomial(e) => Some(e),
_ => None,
}
}
}
impl core::error::Error for PolynomialError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
PolynomialError::Linalg(e) => Some(e),
_ => None,
}
}
}
impl core::error::Error for SignalError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
SignalError::Linalg(e) => Some(e),
_ => None,
}
}
}
impl core::error::Error for ControlError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
ControlError::Signal(e) => Some(e),
ControlError::Linalg(e) => Some(e),
_ => None,
}
}
}
impl core::error::Error for EstimationError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
EstimationError::Diff(e) => Some(e),
_ => None,
}
}
}
impl core::error::Error for SolveError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
SolveError::Linalg(e) => Some(e),
SolveError::Diff(e) => Some(e),
_ => None,
}
}
}
impl core::error::Error for CalcError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
CalcError::Linalg(e) => Some(e),
CalcError::Solve(e) => Some(e),
CalcError::Integrate(e) => Some(e),
CalcError::Differentiate(e) => Some(e),
CalcError::Kinematics(e) => Some(e),
CalcError::Spatial(e) => Some(e),
CalcError::Estimation(e) => Some(e),
CalcError::Signal(e) => Some(e),
CalcError::Control(e) => Some(e),
CalcError::Dynamics(e) => Some(e),
CalcError::Plant(e) => Some(e),
CalcError::Mapping(e) => Some(e),
CalcError::Motion(e) => Some(e),
CalcError::Polynomial(e) => Some(e),
}
}
}