WPILibC++ 2027.0.0-alpha-4
Loading...
Searching...
No Matches
StateSpaceUtil.hpp
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 <algorithm>
8#include <array>
9#include <concepts>
10#include <limits>
11#include <span>
12
13#include <Eigen/Core>
14
17
18namespace wpi::math {
19
20/**
21 * Creates a cost matrix from the given vector for use with LQR.
22 *
23 * The cost matrix is constructed using Bryson's rule. The inverse square of
24 * each tolerance is placed on the cost matrix diagonal. If a tolerance is
25 * infinity, its cost matrix entry is set to zero.
26 *
27 * @param tolerances An array. For a Q matrix, its elements are the maximum
28 * allowed excursions of the states from the reference. For an R matrix, its
29 * elements are the maximum allowed excursions of the control inputs from no
30 * actuation.
31 * @return State excursion or control effort cost matrix.
32 */
33template <std::same_as<double>... Ts>
34constexpr Eigen::Matrix<double, sizeof...(Ts), sizeof...(Ts)> CostMatrix(
35 Ts... tolerances) {
36 Eigen::Matrix<double, sizeof...(Ts), sizeof...(Ts)> result;
37
38 for (int row = 0; row < result.rows(); ++row) {
39 for (int col = 0; col < result.cols(); ++col) {
40 if (row != col) {
41 result(row, col) = 0.0;
42 }
43 }
44 }
45
47 [&](int i, double tolerance) {
48 if (tolerance == std::numeric_limits<double>::infinity()) {
49 result(i, i) = 0.0;
50 } else {
51 result(i, i) = 1.0 / (tolerance * tolerance);
52 }
53 },
54 tolerances...);
55
56 return result;
57}
58
59/**
60 * Creates a cost matrix from the given vector for use with LQR.
61 *
62 * The cost matrix is constructed using Bryson's rule. The inverse square of
63 * each element in the input is placed on the cost matrix diagonal. If a
64 * tolerance is infinity, its cost matrix entry is set to zero.
65 *
66 * @param costs An array. For a Q matrix, its elements are the maximum allowed
67 * excursions of the states from the reference. For an R matrix, its
68 * elements are the maximum allowed excursions of the control inputs from no
69 * actuation.
70 * @return State excursion or control effort cost matrix.
71 */
72template <size_t N>
73constexpr Eigen::Matrix<double, N, N> CostMatrix(
74 const std::array<double, N>& costs) {
75 Eigen::Matrix<double, N, N> result;
76
77 for (int row = 0; row < result.rows(); ++row) {
78 for (int col = 0; col < result.cols(); ++col) {
79 if (row == col) {
80 if (costs[row] == std::numeric_limits<double>::infinity()) {
81 result(row, col) = 0.0;
82 } else {
83 result(row, col) = 1.0 / (costs[row] * costs[row]);
84 }
85 } else {
86 result(row, col) = 0.0;
87 }
88 }
89 }
90
91 return result;
92}
93
94/**
95 * Creates a cost matrix from the given vector for use with LQR.
96 *
97 * The cost matrix is constructed using Bryson's rule. The inverse square of
98 * each element in the input is placed on the cost matrix diagonal. If a
99 * tolerance is infinity, its cost matrix entry is set to zero.
100 *
101 * @param costs A possibly variable length container. For a Q matrix, its
102 * elements are the maximum allowed excursions of the states from the
103 * reference. For an R matrix, its elements are the maximum allowed
104 * excursions of the control inputs from no actuation.
105 * @return State excursion or control effort cost matrix.
106 */
108 const std::span<const double> costs);
109
110/**
111 * Creates a covariance matrix from the given vector for use with Kalman
112 * filters.
113 *
114 * Each element is squared and placed on the covariance matrix diagonal.
115 *
116 * @param stdDevs An array. For a Q matrix, its elements are the standard
117 * deviations of each state from how the model behaves. For an R matrix, its
118 * elements are the standard deviations for each output measurement.
119 * @return Process noise or measurement noise covariance matrix.
120 */
121template <std::same_as<double>... Ts>
122constexpr Eigen::Matrix<double, sizeof...(Ts), sizeof...(Ts)> CovarianceMatrix(
123 Ts... stdDevs) {
124 Eigen::Matrix<double, sizeof...(Ts), sizeof...(Ts)> result;
125
126 for (int row = 0; row < result.rows(); ++row) {
127 for (int col = 0; col < result.cols(); ++col) {
128 if (row != col) {
129 result(row, col) = 0.0;
130 }
131 }
132 }
133
135 [&](int i, double stdDev) { result(i, i) = stdDev * stdDev; },
136 stdDevs...);
137
138 return result;
139}
140
141/**
142 * Creates a covariance matrix from the given vector for use with Kalman
143 * filters.
144 *
145 * Each element is squared and placed on the covariance matrix diagonal.
146 *
147 * @param stdDevs An array. For a Q matrix, its elements are the standard
148 * deviations of each state from how the model behaves. For an R matrix, its
149 * elements are the standard deviations for each output measurement.
150 * @return Process noise or measurement noise covariance matrix.
151 */
152template <size_t N>
153constexpr Eigen::Matrix<double, N, N> CovarianceMatrix(
154 const std::array<double, N>& stdDevs) {
155 Eigen::Matrix<double, N, N> result;
156
157 for (int row = 0; row < result.rows(); ++row) {
158 for (int col = 0; col < result.cols(); ++col) {
159 if (row == col) {
160 result(row, col) = stdDevs[row] * stdDevs[row];
161 } else {
162 result(row, col) = 0.0;
163 }
164 }
165 }
166
167 return result;
168}
169
170/**
171 * Creates a covariance matrix from the given vector for use with Kalman
172 * filters.
173 *
174 * Each element is squared and placed on the covariance matrix diagonal.
175 *
176 * @param stdDevs A possibly variable length container. For a Q matrix, its
177 * elements are the standard deviations of each state from how the model
178 * behaves. For an R matrix, its elements are the standard deviations for
179 * each output measurement.
180 * @return Process noise or measurement noise covariance matrix.
181 */
183 const std::span<const double> stdDevs);
184
185/**
186 * Renormalize all inputs if any exceeds the maximum magnitude. Useful for
187 * systems such as differential drivetrains.
188 *
189 * @tparam Inputs Number of inputs.
190 * @param u The input vector.
191 * @param maxMagnitude The maximum magnitude any input can have.
192 * @return The normalizedInput
193 */
194template <int Inputs>
195Eigen::Vector<double, Inputs> DesaturateInputVector(
196 const Eigen::Vector<double, Inputs>& u, double maxMagnitude) {
197 return u * std::min(1.0, maxMagnitude / u.template lpNorm<Eigen::Infinity>());
198}
199
200extern template WPILIB_DLLEXPORT Eigen::VectorXd
201DesaturateInputVector<Eigen::Dynamic>(const Eigen::VectorXd& u,
202 double maxMagnitude);
203
204} // namespace wpi::math
#define WPILIB_DLLEXPORT
Definition SymbolExports.hpp:36
Definition LinearSystem.hpp:20
constexpr Eigen::Matrix< double, sizeof...(Ts), sizeof...(Ts)> CovarianceMatrix(Ts... stdDevs)
Creates a covariance matrix from the given vector for use with Kalman filters.
Definition StateSpaceUtil.hpp:122
template WPILIB_DLLEXPORT Eigen::VectorXd DesaturateInputVector< Eigen::Dynamic >(const Eigen::VectorXd &u, double maxMagnitude)
constexpr Eigen::Matrix< double, sizeof...(Ts), sizeof...(Ts)> CostMatrix(Ts... tolerances)
Creates a cost matrix from the given vector for use with LQR.
Definition StateSpaceUtil.hpp:34
Eigen::Vector< double, Inputs > DesaturateInputVector(const Eigen::Vector< double, Inputs > &u, double maxMagnitude)
Renormalize all inputs if any exceeds the maximum magnitude.
Definition StateSpaceUtil.hpp:195
constexpr void for_each(F &&f, Ts &&... elems)
Calls f(i, elem) for each element of elems where i is the index of the element in elems and elem is t...
Definition Algorithm.hpp:29