blob: 1bf99a2ff0ac63637f5650e3a1cf01d90ede31b4 [file] [log] [blame]
Austin Schuh9b881ae2019-01-04 07:29:20 +11001#ifndef FRC971_CONTROL_LOOPS_C2D_H_
2#define FRC971_CONTROL_LOOPS_C2D_H_
3
4#include <chrono>
5
6#include <Eigen/Dense>
James Kuszmaul59a5c612019-01-22 07:56:08 -08007// We need to include MatrixFunctions for the matrix exponential.
8#include "unsupported/Eigen/MatrixFunctions"
Austin Schuh9b881ae2019-01-04 07:29:20 +11009
10namespace frc971 {
11namespace controls {
12
13template <typename Scalar, int num_states, int num_inputs>
14void C2D(const ::Eigen::Matrix<Scalar, num_states, num_states> &A_continuous,
15 const ::Eigen::Matrix<Scalar, num_states, num_inputs> &B_continuous,
16 ::std::chrono::nanoseconds dt,
17 ::Eigen::Matrix<Scalar, num_states, num_states> *A,
18 ::Eigen::Matrix<Scalar, num_states, num_inputs> *B) {
19 // Trick from
20 // https://en.wikipedia.org/wiki/Discretization#Discretization_of_linear_state_space_models
21 // to solve for A and B more efficiently.
22 Eigen::Matrix<Scalar, num_states + num_inputs, num_states + num_inputs>
23 M_state_continuous;
24 M_state_continuous.setZero();
25 M_state_continuous.template block<num_states, num_states>(0, 0) =
26 A_continuous *
27 ::std::chrono::duration_cast<::std::chrono::duration<Scalar>>(dt).count();
28 M_state_continuous.template block<num_states, num_inputs>(0, num_states) =
29 B_continuous *
30 ::std::chrono::duration_cast<::std::chrono::duration<Scalar>>(dt).count();
31
32 Eigen::Matrix<Scalar, num_states + num_inputs, num_states + num_inputs>
33 M_state = M_state_continuous.exp();
34 *A = M_state.template block<num_states, num_states>(0, 0);
35 *B = M_state.template block<num_states, num_inputs>(0, num_states);
36}
37
James Kuszmaul59a5c612019-01-22 07:56:08 -080038template <typename Scalar, int num_states>
39void DiscretizeQ(
40 const Eigen::Matrix<Scalar, num_states, num_states> &Q_continuous,
41 const Eigen::Matrix<Scalar, num_states, num_states> &A_continuous,
42 ::std::chrono::nanoseconds dt,
43 Eigen::Matrix<Scalar, num_states, num_states> *Q_d) {
44 Eigen::Matrix<Scalar, num_states, num_states> Qtemp =
45 (Q_continuous + Q_continuous.transpose()) / static_cast<Scalar>(2.0);
46 Eigen::Matrix<Scalar, 2 * num_states, 2 * num_states> M_gain;
47 M_gain.setZero();
48 // Set up the matrix M = [[-A, Q], [0, A.T]]
49 M_gain.template block<num_states, num_states>(0, 0) = -A_continuous;
50 M_gain.template block<num_states, num_states>(0, num_states) = Qtemp;
51 M_gain.template block<num_states, num_states>(num_states, num_states) =
52 A_continuous.transpose();
53
54 Eigen::Matrix<Scalar, 2 * num_states, 2 *num_states> phi =
55 (M_gain *
56 ::std::chrono::duration_cast<::std::chrono::duration<Scalar>>(dt)
57 .count()).exp();
58
59 // Phi12 = phi[0:num_states, num_states:2*num_states]
60 // Phi22 = phi[num_states:2*num_states,
61 // num_states:2*num_states]
62 Eigen::Matrix<Scalar, num_states, num_states> phi12 =
63 phi.block(0, num_states, num_states, num_states);
64 Eigen::Matrix<Scalar, num_states, num_states> phi22 =
65 phi.block(num_states, num_states, num_states, num_states);
66
67 *Q_d = phi22.transpose() * phi12;
68 *Q_d = (*Q_d + Q_d->transpose()) / static_cast<Scalar>(2.0);
69}
70
Austin Schuh9b881ae2019-01-04 07:29:20 +110071} // namespace controls
72} // namespace frc971
73
74#endif // FRC971_CONTROL_LOOPS_C2D_H_