@@ -35,7 +35,7 @@ namespace wpi::math {
3535 * @return The value after the deadband is applied.
3636 */
3737template <typename T>
38- requires std::is_arithmetic_v<T> || wpi::units::traits::is_unit_v <T>
38+ requires std::is_arithmetic_v<T> || wpi::units::DimensionedUnitType <T>
3939constexpr T ApplyDeadband (T value, T deadband, T maxMagnitude = T{1.0 }) {
4040 T magnitude;
4141 if constexpr (std::is_arithmetic_v<T>) {
@@ -95,6 +95,24 @@ constexpr T ApplyDeadband(T value, T deadband, T maxMagnitude = T{1.0}) {
9595 }
9696}
9797
98+ /* *
99+ * Returns 0.0 if the given value is within the specified range around zero. The
100+ * remaining range between the deadband and the maximum magnitude is scaled from
101+ * 0.0 to the maximum magnitude.
102+ *
103+ * @param value Value to clip.
104+ * @param deadband Range around zero.
105+ * @param maxMagnitude The maximum magnitude of the input (defaults to 1). Can
106+ * be infinite.
107+ * @return The value after the deadband is applied.
108+ */
109+ template <typename T>
110+ requires wpi::units::DimensionlessUnitType<T>
111+ constexpr T ApplyDeadband (T value, T deadband,
112+ T maxMagnitude = wpi::units::dimensionless<>{1.0 }) {
113+ return ApplyDeadband (value.raw (), deadband.raw (), maxMagnitude.raw ());
114+ }
115+
98116/* *
99117 * Returns a zero vector if the given vector is within the specified
100118 * distance from the origin. The remaining distance between the deadband and the
@@ -107,7 +125,7 @@ constexpr T ApplyDeadband(T value, T deadband, T maxMagnitude = T{1.0}) {
107125 * @return The value after the deadband is applied.
108126 */
109127template <typename T, int N>
110- requires std::is_arithmetic_v<T> || wpi::units::traits::is_unit_v <T>
128+ requires std::is_arithmetic_v<T> || wpi::units::DimensionedUnitType <T>
111129Eigen::Vector<T, N> ApplyDeadband (const Eigen::Vector<T, N>& value, T deadband,
112130 T maxMagnitude = T{1.0 }) {
113131 if constexpr (std::is_arithmetic_v<T>) {
@@ -143,7 +161,7 @@ Eigen::Vector<T, N> ApplyDeadband(const Eigen::Vector<T, N>& value, T deadband,
143161 * range.
144162 */
145163template <typename T>
146- requires std::is_arithmetic_v<T> || wpi::units::traits::is_unit_v <T>
164+ requires std::is_arithmetic_v<T> || wpi::units::DimensionedUnitType <T>
147165constexpr T CopyDirectionPow (T value, double exponent,
148166 T maxMagnitude = T{1.0 }) {
149167 if constexpr (std::is_arithmetic_v<T>) {
@@ -152,12 +170,37 @@ constexpr T CopyDirectionPow(T value, double exponent,
152170 value);
153171 } else {
154172 return wpi::units::copysign (
155- gcem::pow ((wpi::units::abs (value) / maxMagnitude).value (), exponent) *
173+ gcem::pow ((wpi::units::abs (value) / maxMagnitude).raw (), exponent) *
156174 maxMagnitude,
157175 value);
158176 }
159177}
160178
179+ /* *
180+ * Raises the input to the power of the given exponent while preserving its
181+ * sign.
182+ *
183+ * The function normalizes the input value to the range [0, 1] based on the
184+ * maximum magnitude so that the output stays in the range.
185+ *
186+ * This is useful for applying smoother or more aggressive control response
187+ * curves (e.g. joystick input shaping).
188+ *
189+ * @param value The input value to transform.
190+ * @param exponent The exponent to apply (e.g. 1.0 = linear, 2.0 = squared
191+ * curve). Must be positive.
192+ * @param maxMagnitude The maximum expected absolute value of input (defaults to
193+ * 1). Must be positive.
194+ * @return The transformed value with the same sign and scaled to the input
195+ * range.
196+ */
197+ template <typename T>
198+ requires wpi::units::DimensionlessUnitType<T>
199+ constexpr T CopyDirectionPow (T value, double exponent,
200+ T maxMagnitude = wpi::units::dimensionless{1.0 }) {
201+ return CopyDirectionPow (value.raw (), exponent, maxMagnitude.raw ());
202+ }
203+
161204/* *
162205 * Raises the norm of the input to the power of the given exponent while
163206 * preserving its direction.
@@ -177,7 +220,7 @@ constexpr T CopyDirectionPow(T value, double exponent,
177220 * the input range.
178221 */
179222template <typename T, int N>
180- requires std::is_arithmetic_v<T> || wpi::units::traits::is_unit_v <T>
223+ requires std::is_arithmetic_v<T> || wpi::units::DimensionedUnitType <T>
181224Eigen::Vector<T, N> CopyDirectionPow (const Eigen::Vector<T, N>& value,
182225 double exponent, T maxMagnitude = T{1.0 }) {
183226 if constexpr (std::is_arithmetic_v<T>) {
0 commit comments