WPILibC++ 2023.4.3
MathUtil.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <numbers>
8
9#include <wpi/SymbolExports.h>
10
11#include "units/angle.h"
12#include "units/base.h"
13#include "units/math.h"
14
15namespace frc {
16
17/**
18 * Returns 0.0 if the given value is within the specified range around zero. The
19 * remaining range between the deadband and the maximum magnitude is scaled from
20 * 0.0 to the maximum magnitude.
21 *
22 * @param value Value to clip.
23 * @param deadband Range around zero.
24 * @param maxMagnitude The maximum magnitude of the input (defaults to 1). Can
25 * be infinite.
26 * @return The value after the deadband is applied.
27 */
28template <typename T,
29 typename = std::enable_if_t<std::disjunction_v<
30 std::is_floating_point<T>, units::traits::is_unit_t<T>>>>
31T ApplyDeadband(T value, T deadband, T maxMagnitude = T{1.0}) {
32 T magnitude;
33 if constexpr (std::is_floating_point_v<T>) {
34 magnitude = std::abs(value);
35 } else {
36 magnitude = units::math::abs(value);
37 }
38
39 if (magnitude > deadband) {
40 if (maxMagnitude / deadband > 1.0E12) {
41 // If max magnitude is sufficiently large, the implementation encounters
42 // roundoff error. Implementing the limiting behavior directly avoids
43 // the problem.
44 return value > T{0.0} ? value - deadband : value + deadband;
45 }
46 if (value > T{0.0}) {
47 // Map deadband to 0 and map max to max.
48 //
49 // y - y₁ = m(x - x₁)
50 // y - y₁ = (y₂ - y₁)/(x₂ - x₁) (x - x₁)
51 // y = (y₂ - y₁)/(x₂ - x₁) (x - x₁) + y₁
52 //
53 // (x₁, y₁) = (deadband, 0) and (x₂, y₂) = (max, max).
54 // x₁ = deadband
55 // y₁ = 0
56 // x₂ = max
57 // y₂ = max
58 //
59 // y = (max - 0)/(max - deadband) (x - deadband) + 0
60 // y = max/(max - deadband) (x - deadband)
61 // y = max (x - deadband)/(max - deadband)
62 return maxMagnitude * (value - deadband) / (maxMagnitude - deadband);
63 } else {
64 // Map -deadband to 0 and map -max to -max.
65 //
66 // y - y₁ = m(x - x₁)
67 // y - y₁ = (y₂ - y₁)/(x₂ - x₁) (x - x₁)
68 // y = (y₂ - y₁)/(x₂ - x₁) (x - x₁) + y₁
69 //
70 // (x₁, y₁) = (-deadband, 0) and (x₂, y₂) = (-max, -max).
71 // x₁ = -deadband
72 // y₁ = 0
73 // x₂ = -max
74 // y₂ = -max
75 //
76 // y = (-max - 0)/(-max + deadband) (x + deadband) + 0
77 // y = max/(max - deadband) (x + deadband)
78 // y = max (x + deadband)/(max - deadband)
79 return maxMagnitude * (value + deadband) / (maxMagnitude - deadband);
80 }
81 } else {
82 return T{0.0};
83 }
84}
85
86/**
87 * Returns modulus of input.
88 *
89 * @param input Input value to wrap.
90 * @param minimumInput The minimum value expected from the input.
91 * @param maximumInput The maximum value expected from the input.
92 */
93template <typename T>
94constexpr T InputModulus(T input, T minimumInput, T maximumInput) {
95 T modulus = maximumInput - minimumInput;
96
97 // Wrap input if it's above the maximum input
98 int numMax = (input - minimumInput) / modulus;
99 input -= numMax * modulus;
100
101 // Wrap input if it's below the minimum input
102 int numMin = (input - maximumInput) / modulus;
103 input -= numMin * modulus;
104
105 return input;
106}
107
108/**
109 * Wraps an angle to the range -pi to pi radians (-180 to 180 degrees).
110 *
111 * @param angle Angle to wrap.
112 */
114constexpr units::radian_t AngleModulus(units::radian_t angle) {
115 return InputModulus<units::radian_t>(angle,
116 units::radian_t{-std::numbers::pi},
117 units::radian_t{std::numbers::pi});
118}
119
120} // namespace frc
#define WPILIB_DLLEXPORT
Definition: SymbolExports.h:36
Definition: core.h:1240
typename std::enable_if< B, T >::type enable_if_t
Definition: core.h:298
UnitType abs(const UnitType x) noexcept
Compute absolute value.
Definition: math.h:721
Definition: AprilTagFieldLayout.h:22
WPILIB_DLLEXPORT constexpr units::radian_t AngleModulus(units::radian_t angle)
Wraps an angle to the range -pi to pi radians (-180 to 180 degrees).
Definition: MathUtil.h:114
T ApplyDeadband(T value, T deadband, T maxMagnitude=T{1.0})
Returns 0.0 if the given value is within the specified range around zero.
Definition: MathUtil.h:31
constexpr T InputModulus(T input, T minimumInput, T maximumInput)
Returns modulus of input.
Definition: MathUtil.h:94
static constexpr const unit_t< PI > pi(1)
Ratio of a circle's circumference to its diameter.
Traits which tests if a class is a unit
Definition: base.h:1864