// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.math;
import org.ejml.simple.SimpleMatrix;
public final class DARE {
private DARE() {
throw new UnsupportedOperationException("This is a utility class!");
}
/**
* Computes the unique stabilizing solution X to the discrete-time algebraic Riccati equation.
*
*
AᵀXA − X − AᵀXB(BᵀXB + R)⁻¹BᵀXA + Q = 0
*
*
This internal function skips expensive precondition checks for increased performance. The
* solver may hang if any of the following occur:
*
*
* - Q isn't symmetric positive semidefinite
*
- R isn't symmetric positive definite
*
- The (A, B) pair isn't stabilizable
*
- The (A, C) pair where Q = CᵀC isn't detectable
*
*
* Only use this function if you're sure the preconditions are met.
*
* @param Number of states.
* @param Number of inputs.
* @param A System matrix.
* @param B Input matrix.
* @param Q State cost matrix.
* @param R Input cost matrix.
* @return Solution of DARE.
*/
public static Matrix dareDetail(
Matrix A,
Matrix B,
Matrix Q,
Matrix R) {
var S = new Matrix(new SimpleMatrix(A.getNumRows(), A.getNumCols()));
WPIMathJNI.dareDetailABQR(
A.getStorage().getDDRM().getData(),
B.getStorage().getDDRM().getData(),
Q.getStorage().getDDRM().getData(),
R.getStorage().getDDRM().getData(),
A.getNumCols(),
B.getNumCols(),
S.getStorage().getDDRM().getData());
return S;
}
/**
* Computes the unique stabilizing solution X to the discrete-time algebraic Riccati equation.
*
* AᵀXA − X − (AᵀXB + N)(BᵀXB + R)⁻¹(BᵀXA + Nᵀ) + Q = 0
*
*
This overload of the DARE is useful for finding the control law uₖ that minimizes the
* following cost function subject to xₖ₊₁ = Axₖ + Buₖ.
*
*
* ∞ [xₖ]ᵀ[Q N][xₖ]
* J = Σ [uₖ] [Nᵀ R][uₖ] ΔT
* k=0
*
*
* This is a more general form of the following. The linear-quadratic regulator is the feedback
* control law uₖ that minimizes the following cost function subject to xₖ₊₁ = Axₖ + Buₖ:
*
*
* ∞
* J = Σ (xₖᵀQxₖ + uₖᵀRuₖ) ΔT
* k=0
*
*
* This can be refactored as:
*
*
* ∞ [xₖ]ᵀ[Q 0][xₖ]
* J = Σ [uₖ] [0 R][uₖ] ΔT
* k=0
*
*
* This internal function skips expensive precondition checks for increased performance. The
* solver may hang if any of the following occur:
*
*
* - Q − NR⁻¹Nᵀ isn't symmetric positive semidefinite
*
- R isn't symmetric positive definite
*
- The (A, B) pair isn't stabilizable
*
- The (A, C) pair where Q = CᵀC isn't detectable
*
*
* Only use this function if you're sure the preconditions are met.
*
* @param Number of states.
* @param Number of inputs.
* @param A System matrix.
* @param B Input matrix.
* @param Q State cost matrix.
* @param R Input cost matrix.
* @param N State-input cross-term cost matrix.
* @return Solution of DARE.
*/
public static Matrix dareDetail(
Matrix A,
Matrix B,
Matrix Q,
Matrix R,
Matrix N) {
var S = new Matrix(new SimpleMatrix(A.getNumRows(), A.getNumCols()));
WPIMathJNI.dareDetailABQRN(
A.getStorage().getDDRM().getData(),
B.getStorage().getDDRM().getData(),
Q.getStorage().getDDRM().getData(),
R.getStorage().getDDRM().getData(),
N.getStorage().getDDRM().getData(),
A.getNumCols(),
B.getNumCols(),
S.getStorage().getDDRM().getData());
return S;
}
/**
* Computes the unique stabilizing solution X to the discrete-time algebraic Riccati equation.
*
* AᵀXA − X − AᵀXB(BᵀXB + R)⁻¹BᵀXA + Q = 0
*
* @param Number of states.
* @param Number of inputs.
* @param A System matrix.
* @param B Input matrix.
* @param Q State cost matrix.
* @param R Input cost matrix.
* @return Solution of DARE.
* @throws IllegalArgumentException if Q isn't symmetric positive semidefinite.
* @throws IllegalArgumentException if R isn't symmetric positive definite.
* @throws IllegalArgumentException if the (A, B) pair isn't stabilizable.
* @throws IllegalArgumentException if the (A, C) pair where Q = CᵀC isn't detectable.
*/
public static Matrix dare(
Matrix A,
Matrix B,
Matrix Q,
Matrix R) {
var S = new Matrix(new SimpleMatrix(A.getNumRows(), A.getNumCols()));
WPIMathJNI.dareABQR(
A.getStorage().getDDRM().getData(),
B.getStorage().getDDRM().getData(),
Q.getStorage().getDDRM().getData(),
R.getStorage().getDDRM().getData(),
A.getNumCols(),
B.getNumCols(),
S.getStorage().getDDRM().getData());
return S;
}
/**
* Computes the unique stabilizing solution X to the discrete-time algebraic Riccati equation.
*
* AᵀXA − X − (AᵀXB + N)(BᵀXB + R)⁻¹(BᵀXA + Nᵀ) + Q = 0
*
*
This overload of the DARE is useful for finding the control law uₖ that minimizes the
* following cost function subject to xₖ₊₁ = Axₖ + Buₖ.
*
*
* ∞ [xₖ]ᵀ[Q N][xₖ]
* J = Σ [uₖ] [Nᵀ R][uₖ] ΔT
* k=0
*
*
* This is a more general form of the following. The linear-quadratic regulator is the feedback
* control law uₖ that minimizes the following cost function subject to xₖ₊₁ = Axₖ + Buₖ:
*
*
* ∞
* J = Σ (xₖᵀQxₖ + uₖᵀRuₖ) ΔT
* k=0
*
*
* This can be refactored as:
*
*
* ∞ [xₖ]ᵀ[Q 0][xₖ]
* J = Σ [uₖ] [0 R][uₖ] ΔT
* k=0
*
*
* @param Number of states.
* @param Number of inputs.
* @param A System matrix.
* @param B Input matrix.
* @param Q State cost matrix.
* @param R Input cost matrix.
* @param N State-input cross-term cost matrix.
* @return Solution of DARE.
* @throws IllegalArgumentException if Q − NR⁻¹Nᵀ isn't symmetric positive semidefinite.
* @throws IllegalArgumentException if R isn't symmetric positive definite.
* @throws IllegalArgumentException if the (A, B) pair isn't stabilizable.
* @throws IllegalArgumentException if the (A, C) pair where Q = CᵀC isn't detectable.
*/
public static Matrix dare(
Matrix A,
Matrix B,
Matrix Q,
Matrix R,
Matrix N) {
var S = new Matrix(new SimpleMatrix(A.getNumRows(), A.getNumCols()));
WPIMathJNI.dareABQRN(
A.getStorage().getDDRM().getData(),
B.getStorage().getDDRM().getData(),
Q.getStorage().getDDRM().getData(),
R.getStorage().getDDRM().getData(),
N.getStorage().getDDRM().getData(),
A.getNumCols(),
B.getNumCols(),
S.getStorage().getDDRM().getData());
return S;
}
}