Chapter 28: Performance Measures and Quadratic Forms
Lesson 3: State and Control Weighting Matrices (Q, R) as Performance Descriptors
This lesson explains how the matrices \( Q \) and \( R \) encode engineering performance priorities in quadratic state-input measures. We study symmetry, definiteness, scaling, coordinate transformations, geometric interpretation, and practical construction rules before using code to evaluate weighted performance indices for simulated state-space trajectories.
1. Conceptual Role of \( Q \) and \( R \)
In the previous two lessons, quadratic forms and signal-energy ideas were introduced as ways of assigning a scalar measure to vectors and signals. Here we specialize those ideas to a continuous-time state-space system with state \( x(t)\in\mathbb{R}^n \) and input \( u(t)\in\mathbb{R}^m \). A weighted performance descriptor over a finite horizon \( [0,T] \) is
\[ J_T(x,u)=\int_0^T \left(x(t)^\top Qx(t)+u(t)^\top Ru(t)\right)dt. \]
The matrix \( Q \) assigns relative importance to state deviations, while \( R \) assigns relative importance to control usage. At this stage, we do not yet solve an optimal-control problem. Instead, we treat \( Q \) and \( R \) as precise mathematical descriptions of what a designer means by a “large state error” and a “large input effort.”
flowchart TD
A["Engineering priorities"] --> B["State limits and state importance"]
A --> C["Actuator limits and input cost"]
B --> D["Choose Q"]
C --> E["Choose R"]
D --> F["Weighted state term: xT Q x"]
E --> G["Weighted input term: uT R u"]
F --> H["Performance descriptor J"]
G --> H
H --> I["Compare trajectories and feedback designs"]
2. Mathematical Admissibility: Symmetry and Definiteness
For real-valued quadratic measures, the usual assumptions are \( Q=Q^\top\succeq 0 \) and \( R=R^\top\succ 0 \). The positive semidefinite requirement on \( Q \) permits some state directions to be unpenalized. The positive definite requirement on \( R \) means every nonzero input has a strictly positive instantaneous cost.
\[ Q\in\mathbb{S}_+^n,\qquad R\in\mathbb{S}_{++}^m,\qquad x^\top Qx\ge 0,\qquad u^\top Ru>0\;\text{for}\;u\ne 0. \]
The expression above uses the cone notation \( \mathbb{S}_+^n \) for symmetric positive semidefinite matrices and \( \mathbb{S}_{++}^m \) for symmetric positive definite matrices. If a designer writes a nonsymmetric matrix in a quadratic form, only its symmetric part matters:
\[ x^\top Qx=x^\top\left(\frac{Q+Q^\top}{2}\right)x. \]
Proof. Decompose \( Q \) into its symmetric and skew-symmetric parts:
\[ Q=\frac{Q+Q^\top}{2}+\frac{Q-Q^\top}{2}=Q_s+Q_a, \qquad Q_a^\top=-Q_a. \]
For any real vector \( x \), the scalar \( x^\top Q_ax \) equals its own transpose:
\[ x^\top Q_ax=(x^\top Q_ax)^\top=x^\top Q_a^\top x=-x^\top Q_ax. \]
Hence \( x^\top Q_ax=0 \), proving that the skew-symmetric part has no effect on the quadratic performance measure.
3. Geometry of Weighted State and Input Magnitudes
If \( Q\succ 0 \), the set of states with equal weighted magnitude is an ellipsoid:
\[ \mathcal{E}_Q(c)=\left\{x\in\mathbb{R}^n\;:\;x^\top Qx=c\right\}. \]
Let the spectral decomposition of \( Q \) be \( Q=V\Lambda V^\top \), with orthonormal eigenvectors in \( V \) and nonnegative eigenvalues in \( \Lambda \). In modal coordinates \( z=V^\top x \), the quadratic form becomes
\[ x^\top Qx=z^\top\Lambda z=\sum_{i=1}^n \lambda_i z_i^2. \]
Large eigenvalues compress the ellipsoid along the corresponding directions, meaning the performance descriptor regards those directions as expensive. A diagonal \( Q \) penalizes individual coordinates independently, while a nondiagonal \( Q \) introduces cross-weighting between state coordinates.
The same interpretation applies to \( R \) in the input space. For multi-input systems, off-diagonal terms in \( R \) can represent coupled actuator usage, shared power supplies, or a preference against simultaneous use of certain channels.
4. Constructing \( Q \) from Physical Performance Variables
The state vector may contain variables with different physical units: position, velocity, current, angle, angular velocity, pressure, or temperature. A good \( Q \) should therefore be built from physical performance variables rather than arbitrary coordinate magnitudes. Suppose the variables of interest are \( z=C_zx \), where \( z \) collects physically meaningful errors. If \( W_z\succeq 0 \) weights those errors, then
\[ z^\top W_zz=(C_zx)^\top W_z(C_zx)=x^\top(C_z^\top W_zC_z)x. \]
Therefore an induced state weighting matrix is
\[ Q=C_z^\top W_zC_z. \]
This construction is useful when the raw state is not itself the performance output. For example, in a mechanical system, the state might contain both positions and velocities, while the designer might care mainly about selected displacements and a limited set of velocities.
A common first-pass normalization is Bryson-style weighting. If \( x_i^{\max} \) is the largest acceptable magnitude of state component \( x_i \), then the diagonal choice
\[ Q=\operatorname{diag}\left(\frac{1}{(x_1^{\max})^2}, \frac{1}{(x_2^{\max})^2},\dots, \frac{1}{(x_n^{\max})^2}\right) \]
makes a state component near its acceptable limit contribute approximately one unit to \( x^\top Qx \).
5. Constructing \( R \) from Actuator and Energy Considerations
The matrix \( R \) describes how expensive control signals are. If all actuators are independent and the acceptable input magnitudes are \( u_j^{\max} \), a normalized diagonal choice is
\[ R=\operatorname{diag}\left(\frac{1}{(u_1^{\max})^2}, \frac{1}{(u_2^{\max})^2},\dots, \frac{1}{(u_m^{\max})^2}\right). \]
If actuator channels are coupled, use a full symmetric positive definite matrix. For example, with two inputs,
\[ u^\top Ru=r_1u_1^2+2r_{12}u_1u_2+r_2u_2^2, \qquad R=\begin{bmatrix}r_1&r_{12}\\r_{12}&r_2\end{bmatrix}\succ 0. \]
The cross-term coefficient \( r_{12} \) changes the cost of using the two inputs together. Positive definiteness is essential: otherwise the performance descriptor could assign zero or negative cost to a nonzero actuator command, which is physically inappropriate for an effort penalty.
6. Scaling and Coordinate Transformations
State coordinates in modern control are not unique. If \( x=Tz \), with nonsingular \( T \), the same physical quadratic state measure must satisfy
\[ x^\top Q_xx=z^\top Q_zz. \]
Substituting \( x=Tz \) gives
\[ (Tz)^\top Q_x(Tz)=z^\top(T^\top Q_xT)z. \]
Therefore the coordinate-transformed weighting matrix is
\[ Q_z=T^\top Q_xT. \]
This formula is important because a diagonal matrix in one coordinate system does not generally remain diagonal after a change of coordinates. Arbitrary diagonal choices can therefore unintentionally weight coordinate artifacts rather than physical performance variables.
If the input is transformed by \( u=Sv \), then the corresponding input weighting becomes
\[ R_v=S^\top R_uS. \]
7. Comparing Designs with a Fixed Performance Descriptor
Consider two feedback gains \( K_1 \) and \( K_2 \) applied to the same plant \( \dot{x}=Ax+Bu \) through \( u=-Kx \). For the same initial condition, the closed-loop trajectories satisfy
\[ \dot{x}_i=(A-BK_i)x_i, \qquad u_i=-K_ix_i, \qquad i=1,2. \]
The performance descriptor ranks the two designs through
\[ J_T(K_i)=\int_0^T\left(x_i(t)^\top Qx_i(t)+u_i(t)^\top Ru_i(t)\right)dt. \]
It is crucial that \( Q \) and \( R \) remain fixed during the comparison. Changing the weights changes the meaning of performance itself, so it cannot be used to make a fair comparison between designs.
flowchart TD
A["Start with physical limits"] --> B["Normalize states and inputs"]
B --> C["Select initial Q and R"]
C --> D["Simulate candidate feedback designs"]
D --> E["Compute same J for every design"]
E --> F["Inspect state peaks and input peaks"]
F --> G["Weights reflect priorities?"]
G -->|"yes"| H["Use descriptor for comparison"]
G -->|"no"| I["Revise Q or R from engineering requirements"]
I --> C
8. Convexity and Lower-Bound Properties
The instantaneous function \( \ell(x,u)=x^\top Qx+u^\top Ru \) is convex in \( (x,u) \) when \( Q\succeq 0 \) and \( R\succeq 0 \). If \( R\succ 0 \), it is strictly convex in \( u \). In block form,
\[ \ell(x,u)=\begin{bmatrix}x\\u\end{bmatrix}^\top \begin{bmatrix}Q&0\\0&R\end{bmatrix} \begin{bmatrix}x\\u\end{bmatrix}. \]
Since a block-diagonal matrix with positive semidefinite diagonal blocks is positive semidefinite, \( \ell \) is a convex quadratic function. Moreover, if \( \lambda_{\min}(R) \) is the smallest eigenvalue of \( R \), then
\[ u^\top Ru\ge \lambda_{\min}(R)\|u\|_2^2. \]
This lower bound shows why a positive definite \( R \) prevents arbitrarily large input actions from being cost-free.
9. Python Implementation
This script checks definiteness, constructs Bryson-style weights, simulates a closed-loop trajectory, evaluates the finite-horizon weighted cost, and verifies coordinate-transformation consistency.
Chapter28_Lesson3.py
"""
Chapter28_Lesson3.py
Modern Control — Chapter 28, Lesson 3
State and control weighting matrices Q and R as performance descriptors.
This script demonstrates:
1. Symmetry and definiteness checks for Q and R.
2. Bryson-style diagonal weight selection.
3. Finite-horizon weighted performance integral for a simulated state/input record.
4. Coordinate-transformation consistency of a quadratic state cost.
"""
from __future__ import annotations
import numpy as np
from numpy.linalg import eigvalsh
from scipy.integrate import solve_ivp
def symmetrize(M: np.ndarray) -> np.ndarray:
"""Return the symmetric part of a square matrix."""
return 0.5 * (M + M.T)
def is_psd(M: np.ndarray, tol: float = 1e-10) -> bool:
"""Check positive semidefiniteness through symmetric eigenvalues."""
Ms = symmetrize(M)
return bool(np.min(eigvalsh(Ms)) >= -tol)
def is_pd(M: np.ndarray, tol: float = 1e-10) -> bool:
"""Check positive definiteness through symmetric eigenvalues."""
Ms = symmetrize(M)
return bool(np.min(eigvalsh(Ms)) > tol)
def bryson_weights(max_abs_values: np.ndarray) -> np.ndarray:
"""
Bryson-style diagonal weighting:
weight_i = 1 / allowed_i^2.
The vector contains acceptable maximum magnitudes of variables.
"""
max_abs_values = np.asarray(max_abs_values, dtype=float)
if np.any(max_abs_values <= 0.0):
raise ValueError("All allowed magnitudes must be positive.")
return np.diag(1.0 / (max_abs_values**2))
def simulate_closed_loop(A: np.ndarray, B: np.ndarray, K: np.ndarray, x0: np.ndarray, tf: float = 8.0):
"""Simulate xdot = (A - B K) x and u = -K x."""
Acl = A - B @ K
def rhs(_t, x):
return Acl @ x
sol = solve_ivp(rhs, (0.0, tf), x0, dense_output=False, max_step=0.01, rtol=1e-8, atol=1e-10)
X = sol.y.T
U = -(K @ X.T).T
return sol.t, X, U
def weighted_cost(t: np.ndarray, X: np.ndarray, U: np.ndarray, Q: np.ndarray, R: np.ndarray) -> float:
"""Approximate integral of x'Qx + u'Ru using the trapezoidal rule."""
state_terms = np.einsum("bi,ij,bj->b", X, Q, X)
input_terms = np.einsum("bi,ij,bj->b", U, R, U)
return float(np.trapz(state_terms + input_terms, t))
def main() -> None:
# A stable feedback example for a second-order plant.
A = np.array([[0.0, 1.0], [-2.0, -0.4]])
B = np.array([[0.0], [1.0]])
K = np.array([[3.0, 2.2]])
x0 = np.array([1.0, 0.0])
# Performance-descriptor weights from engineering tolerances.
# State 1 allowed magnitude: 1.0; state 2 allowed magnitude: 2.0.
Q = bryson_weights(np.array([1.0, 2.0]))
# Input allowed magnitude: 0.5.
R = bryson_weights(np.array([0.5]))
print("Q =\n", Q)
print("R =\n", R)
print("Q is PSD:", is_psd(Q))
print("R is PD:", is_pd(R))
t, X, U = simulate_closed_loop(A, B, K, x0)
J = weighted_cost(t, X, U, Q, R)
print(f"Finite-horizon weighted cost J_T = {J:.6f}")
# Coordinate transformation: x = T z.
T = np.array([[2.0, 0.5], [0.0, 1.5]])
Z = np.linalg.solve(T, X.T).T
Qz = T.T @ Q @ T
J_state_x = float(np.trapz(np.einsum("bi,ij,bj->b", X, Q, X), t))
J_state_z = float(np.trapz(np.einsum("bi,ij,bj->b", Z, Qz, Z), t))
print(f"State cost in x-coordinates = {J_state_x:.6f}")
print(f"State cost in z-coordinates = {J_state_z:.6f}")
print("Coordinate consistency error:", abs(J_state_x - J_state_z))
if __name__ == "__main__":
main()
10. C++ Implementation
The C++ example uses only the standard library and implements RK4 integration from scratch for a two-state closed-loop system.
Chapter28_Lesson3.cpp
/*
Chapter28_Lesson3.cpp
Modern Control — Chapter 28, Lesson 3
State and control weighting matrices Q and R as performance descriptors.
This standalone C++ example computes a finite-horizon weighted cost
for xdot = (A - B K)x, u = -Kx using RK4 integration.
*/
#include <array>
#include <cmath>
#include <iostream>
#include <stdexcept>
using Vec2 = std::array<double, 2>;
using Mat2 = std::array<std::array<double, 2>, 2>;
Vec2 mat_vec(const Mat2& A, const Vec2& x) {
return {A[0][0] * x[0] + A[0][1] * x[1],
A[1][0] * x[0] + A[1][1] * x[1]};
}
Vec2 add(const Vec2& a, const Vec2& b) {
return {a[0] + b[0], a[1] + b[1]};
}
Vec2 scale(double c, const Vec2& x) {
return {c * x[0], c * x[1]};
}
double quad2(const Vec2& x, const Mat2& Q) {
return x[0] * (Q[0][0] * x[0] + Q[0][1] * x[1]) +
x[1] * (Q[1][0] * x[0] + Q[1][1] * x[1]);
}
double input_value(const std::array<double, 2>& K, const Vec2& x) {
return -(K[0] * x[0] + K[1] * x[1]);
}
Vec2 rhs(const Mat2& Acl, const Vec2& x) {
return mat_vec(Acl, x);
}
Vec2 rk4_step(const Mat2& Acl, const Vec2& x, double h) {
Vec2 k1 = rhs(Acl, x);
Vec2 k2 = rhs(Acl, add(x, scale(0.5 * h, k1)));
Vec2 k3 = rhs(Acl, add(x, scale(0.5 * h, k2)));
Vec2 k4 = rhs(Acl, add(x, scale(h, k3)));
return add(x, scale(h / 6.0, add(add(k1, scale(2.0, k2)), add(scale(2.0, k3), k4))));
}
bool is_pd_1x1(double r) {
return r > 0.0;
}
bool is_psd_2x2(const Mat2& Q) {
// Sylvester condition for 2x2 symmetric PSD:
// q11 >= 0, q22 >= 0, det(Q) >= 0.
const double det = Q[0][0] * Q[1][1] - Q[0][1] * Q[1][0];
return Q[0][0] >= -1e-12 && Q[1][1] >= -1e-12 && det >= -1e-12;
}
int main() {
// Plant and feedback: xdot = (A - B K)x.
Mat2 A = { { {0.0, 1.0}, {-2.0, -0.4} } };
std::array<double, 2> B = {0.0, 1.0};
std::array<double, 2> K = {3.0, 2.2};
Mat2 Acl = A;
Acl[0][0] -= B[0] * K[0];
Acl[0][1] -= B[0] * K[1];
Acl[1][0] -= B[1] * K[0];
Acl[1][1] -= B[1] * K[1];
// Bryson-style tolerances: x1_max=1, x2_max=2, u_max=0.5.
Mat2 Q = { { {1.0, 0.0}, {0.0, 1.0 / 4.0} } };
double R = 1.0 / (0.5 * 0.5);
if (!is_psd_2x2(Q)) {
throw std::runtime_error("Q must be positive semidefinite.");
}
if (!is_pd_1x1(R)) {
throw std::runtime_error("R must be positive definite.");
}
Vec2 x = {1.0, 0.0};
double h = 0.001;
double tf = 8.0;
int steps = static_cast<int>(tf / h);
double J = 0.0;
auto integrand = [&](const Vec2& xv) {
double u = input_value(K, xv);
return quad2(xv, Q) + R * u * u;
};
double f_old = integrand(x);
for (int k = 0; k < steps; ++k) {
Vec2 x_next = rk4_step(Acl, x, h);
double f_new = integrand(x_next);
J += 0.5 * h * (f_old + f_new);
x = x_next;
f_old = f_new;
}
std::cout << "Q = [[1, 0], [0, 0.25]]\n";
std::cout << "R = " << R << "\n";
std::cout << "Finite-horizon weighted cost J_T = " << J << "\n";
return 0;
}
11. Java Implementation
The Java implementation mirrors the C++ version and keeps all linear algebra explicit so students can see how the quadratic cost is computed.
Chapter28_Lesson3.java
/*
Chapter28_Lesson3.java
Modern Control — Chapter 28, Lesson 3
State and control weighting matrices Q and R as performance descriptors.
This standalone Java example computes a finite-horizon weighted cost
for xdot = (A - B K)x, u = -Kx using RK4 integration.
*/
public class Chapter28_Lesson3 {
static double[] matVec(double[][] A, double[] x) {
return new double[] {
A[0][0] * x[0] + A[0][1] * x[1],
A[1][0] * x[0] + A[1][1] * x[1]
};
}
static double[] add(double[] a, double[] b) {
return new double[] {a[0] + b[0], a[1] + b[1]};
}
static double[] scale(double c, double[] x) {
return new double[] {c * x[0], c * x[1]};
}
static double[] rhs(double[][] Acl, double[] x) {
return matVec(Acl, x);
}
static double[] rk4Step(double[][] Acl, double[] x, double h) {
double[] k1 = rhs(Acl, x);
double[] k2 = rhs(Acl, add(x, scale(0.5 * h, k1)));
double[] k3 = rhs(Acl, add(x, scale(0.5 * h, k2)));
double[] k4 = rhs(Acl, add(x, scale(h, k3)));
return add(x, scale(h / 6.0, add(add(k1, scale(2.0, k2)), add(scale(2.0, k3), k4))));
}
static double quad(double[] x, double[][] Q) {
return x[0] * (Q[0][0] * x[0] + Q[0][1] * x[1])
+ x[1] * (Q[1][0] * x[0] + Q[1][1] * x[1]);
}
static double input(double[] K, double[] x) {
return -(K[0] * x[0] + K[1] * x[1]);
}
static boolean isPsd2x2(double[][] Q) {
double det = Q[0][0] * Q[1][1] - Q[0][1] * Q[1][0];
return Q[0][0] >= -1e-12 && Q[1][1] >= -1e-12 && det >= -1e-12;
}
public static void main(String[] args) {
double[][] A = { {0.0, 1.0}, {-2.0, -0.4} };
double[] B = {0.0, 1.0};
double[] K = {3.0, 2.2};
double[][] Acl = new double[2][2];
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 2; ++j) {
Acl[i][j] = A[i][j] - B[i] * K[j];
}
}
// Bryson-style tolerances: x1_max=1, x2_max=2, u_max=0.5.
double[][] Q = { {1.0, 0.0}, {0.0, 1.0 / 4.0} };
double R = 1.0 / (0.5 * 0.5);
if (!isPsd2x2(Q)) {
throw new IllegalArgumentException("Q must be positive semidefinite.");
}
if (R <= 0.0) {
throw new IllegalArgumentException("R must be positive definite.");
}
double[] x = {1.0, 0.0};
double h = 0.001;
double tf = 8.0;
int steps = (int) Math.round(tf / h);
double J = 0.0;
double fOld = quad(x, Q) + R * input(K, x) * input(K, x);
for (int k = 0; k < steps; ++k) {
double[] xNext = rk4Step(Acl, x, h);
double uNext = input(K, xNext);
double fNew = quad(xNext, Q) + R * uNext * uNext;
J += 0.5 * h * (fOld + fNew);
x = xNext;
fOld = fNew;
}
System.out.println("Q = [[1, 0], [0, 0.25]]");
System.out.println("R = " + R);
System.out.println("Finite-horizon weighted cost J_T = " + J);
}
}
12. MATLAB and Simulink Implementation
The MATLAB script uses ode45 for simulation and, when
Simulink is available, programmatically creates a small model that
computes the state quadratic term \( x^\top Qx \).
Chapter28_Lesson3.m
% Chapter28_Lesson3.m
% Modern Control — Chapter 28, Lesson 3
% State and control weighting matrices Q and R as performance descriptors.
%
% This script demonstrates:
% 1. Bryson-style weight construction.
% 2. Finite-horizon weighted cost for a closed-loop state trajectory.
% 3. Coordinate-transformation consistency.
% 4. Optional programmatic creation of a small Simulink model.
clear; clc;
A = [0 1; -2 -0.4];
B = [0; 1];
K = [3.0 2.2];
x0 = [1; 0];
% Bryson-style tolerances.
xMax = [1; 2];
uMax = 0.5;
Q = diag(1 ./ (xMax.^2));
R = 1 / (uMax^2);
fprintf('eig(Q) = '); disp(eig((Q + Q')/2)');
fprintf('eig(R) = %.6f\n', R);
Acl = A - B*K;
[t, X] = ode45(@(t,x) Acl*x, [0 8], x0);
U = -(K * X')';
stateTerms = sum((X*Q).*X, 2);
inputTerms = (U.^2) * R;
J = trapz(t, stateTerms + inputTerms);
fprintf('Finite-horizon weighted cost J_T = %.6f\n', J);
% Coordinate transformation x = T z. Then Qz = T' Q T.
T = [2 0.5; 0 1.5];
Z = (T \ X')';
Qz = T' * Q * T;
Jx = trapz(t, sum((X*Q).*X, 2));
Jz = trapz(t, sum((Z*Qz).*Z, 2));
fprintf('State cost in x-coordinates = %.6f\n', Jx);
fprintf('State cost in z-coordinates = %.6f\n', Jz);
fprintf('Coordinate consistency error = %.3e\n', abs(Jx - Jz));
% Optional Simulink model: run only when Simulink is available.
if license('test', 'Simulink')
modelName = 'Chapter28_Lesson3_Simulink_QR_Cost';
if bdIsLoaded(modelName)
close_system(modelName, 0);
end
new_system(modelName);
open_system(modelName);
add_block('simulink/Sources/Constant', [modelName '/x_vector'], ...
'Value', '[1; 0]', 'Position', [80 80 150 120]);
add_block('simulink/Math Operations/Gain', [modelName '/Q_gain'], ...
'Gain', mat2str(Q), 'Multiplication', 'Matrix(K*u)', 'Position', [220 70 300 130]);
add_block('simulink/Math Operations/Dot Product', [modelName '/xTQx'], ...
'Position', [380 70 460 130]);
add_block('simulink/Sinks/Display', [modelName '/Display_xTQx'], ...
'Position', [540 80 650 120]);
add_line(modelName, 'x_vector/1', 'Q_gain/1');
add_line(modelName, 'x_vector/1', 'xTQx/1');
add_line(modelName, 'Q_gain/1', 'xTQx/2');
add_line(modelName, 'xTQx/1', 'Display_xTQx/1');
save_system(modelName);
fprintf('Created optional Simulink model: %s.slx\n', modelName);
end
13. Wolfram Mathematica Implementation
The Mathematica notebook expression evaluates the same weighted-cost example and symbolically verifies the coordinate-transformation formula.
Chapter28_Lesson3.nb
Notebook[{Cell["Chapter28_Lesson3.nb", "Title"],
Cell["Modern Control — Chapter 28, Lesson 3: State and control weighting matrices Q and R as performance descriptors.", "Text"],
Cell[BoxData[RowBox[{"ClearAll", "[", "\"Global`*\"", "]"}]], "Input"],
Cell[BoxData[RowBox[{RowBox[{"A", "=", RowBox[{"{ {", RowBox[{RowBox[{"0", ",", "1"}], ",", RowBox[{RowBox[{"-", "2"}], ",", RowBox[{"-", "0.4"}]}]}], "} }"}]}], ";"}]], "Input"],
Cell[BoxData[RowBox[{RowBox[{"B", "=", RowBox[{"{ {", RowBox[{"0"}], "},{", RowBox[{"1"}], "} }"}]}], ";", RowBox[{"K", "=", RowBox[{"{ {", RowBox[{"3.0", ",", "2.2"}], "} }"}]}], ";"}]], "Input"],
Cell[BoxData[RowBox[{RowBox[{"xMax", "=", RowBox[{"{", RowBox[{"1", ",", "2"}], "}"}]}], ";", RowBox[{"uMax", "=", "0.5"}], ";"}]], "Input"],
Cell[BoxData[RowBox[{RowBox[{"Q", "=", RowBox[{"DiagonalMatrix", "[", RowBox[{"1", "/", RowBox[{"xMax", "^", "2"}]}], "]"}]}], ";", RowBox[{"R", "=", RowBox[{"{ {", RowBox[{"1", "/", RowBox[{"uMax", "^", "2"}]}], "} }"}]}], ";"}]], "Input"],
Cell[BoxData[RowBox[{"{", RowBox[{RowBox[{"Eigenvalues", "[", "Q", "]"}], ",", RowBox[{"Eigenvalues", "[", "R", "]"}]}], "}"}]], "Input"],
Cell[BoxData[RowBox[{RowBox[{"Acl", "=", RowBox[{"A", "-", RowBox[{"B", ".", "K"}]}]}], ";"}]], "Input"],
Cell[BoxData[RowBox[{"sol", "=", RowBox[{"NDSolveValue", "[", RowBox[{RowBox[{"{", RowBox[{RowBox[{RowBox[{"x", "'"}], "[", "t", "]"}], "==", RowBox[{"Acl", ".", RowBox[{"x", "[", "t", "]"}]}]}], ",", RowBox[{RowBox[{"x", "[", "0", "]"}], "==", RowBox[{"{", RowBox[{"1", ",", "0"}], "}"}]}]}], "}"}], ",", "x", ",", RowBox[{"{", RowBox[{"t", ",", "0", ",", "8"}], "}"}]}], "]"}]}]], "Input"],
Cell[BoxData[RowBox[{"J", "=", RowBox[{"NIntegrate", "[", RowBox[{RowBox[{RowBox[{RowBox[{"sol", "[", "t", "]"}], ".", "Q", ".", RowBox[{"sol", "[", "t", "]"}]}], "+", RowBox[{RowBox[{"(", RowBox[{RowBox[{"-", "K"}], ".", RowBox[{"sol", "[", "t", "]"}]}], ")"}], ".", "R", ".", RowBox[{"(", RowBox[{RowBox[{"-", "K"}], ".", RowBox[{"sol", "[", "t", "]"}]}], ")"}]}]}], ",", RowBox[{"{", RowBox[{"t", ",", "0", ",", "8"}], "}"}]}], "]"}]}]], "Input"],
Cell[BoxData[RowBox[{RowBox[{"Tmat", "=", RowBox[{"{ {", RowBox[{RowBox[{"2", ",", "0.5"}], ",", RowBox[{"0", ",", "1.5"}]}], "} }"}]}], ";", RowBox[{"Qz", "=", RowBox[{RowBox[{"Transpose", "[", "Tmat", "]"}], ".", "Q", ".", "Tmat"}]}], ";"}]], "Input"],
Cell[BoxData[RowBox[{"Simplify", "[", RowBox[{RowBox[{RowBox[{"x", ".", "Q", ".", "x"}], "/.", RowBox[{"x", "->", RowBox[{"Tmat", ".", "z"}]}]}], "==", RowBox[{"z", ".", "Qz", ".", "z"}]}], "]"}]], "Input"]
}]
14. Problems and Solutions
Problem 1 (Symmetric Part): Let \( Q\in\mathbb{R}^{n\times n} \) be any real square matrix. Prove that the quadratic form \( x^\top Qx \) depends only on the symmetric part of \( Q \).
Solution: Define
\[ Q_s=\frac{Q+Q^\top}{2},\qquad Q_a=\frac{Q-Q^\top}{2}. \]
Then \( Q=Q_s+Q_a \) and \( Q_a^\top=-Q_a \). For any real vector \( x \),
\[ x^\top Q_ax=(x^\top Q_ax)^\top=x^\top Q_a^\top x=-x^\top Q_ax. \]
Therefore \( x^\top Q_ax=0 \), so \( x^\top Qx=x^\top Q_sx \).
Problem 2 (Bryson-Style Weights): A state vector is \( x=[x_1,x_2,x_3]^\top \). The acceptable magnitudes are \( x_1^{\max}=2 \), \( x_2^{\max}=0.5 \), and \( x_3^{\max}=10 \). Construct a diagonal \( Q \) using normalized squared penalties.
Solution:
\[ Q=\operatorname{diag}\left(\frac{1}{2^2}, \frac{1}{0.5^2},\frac{1}{10^2}\right) =\operatorname{diag}(0.25,4,0.01). \]
The second state receives the largest weight because its acceptable magnitude is smallest.
Problem 3 (Coordinate Transformation): Suppose \( x=Tz \) and a state cost is \( x^\top Q_xx \). Derive the weighting matrix \( Q_z \) that gives the same scalar cost in \( z \)-coordinates.
Solution:
\[ x^\top Q_xx=(Tz)^\top Q_x(Tz)=z^\top T^\top Q_xTz. \]
Hence \( Q_z=T^\top Q_xT \). This transformed matrix preserves the physical meaning of the original cost.
Problem 4 (Induced Output Weight): Let the performance output be \( z=C_zx \), and suppose the desired output penalty is \( z^\top W_zz \). Find the equivalent state weighting matrix.
Solution:
\[ z^\top W_zz=(C_zx)^\top W_z(C_zx)=x^\top C_z^\top W_zC_zx. \]
Therefore \( Q=C_z^\top W_zC_z \). If \( W_z\succeq 0 \), then \( Q\succeq 0 \) because \( x^\top Qx=(C_zx)^\top W_z(C_zx)\ge 0 \).
Problem 5 (Positive Definiteness of a Two-Input R): Consider \( R=\begin{bmatrix}4&1\\1&2\end{bmatrix} \). Decide whether it is positive definite.
Solution: For a symmetric two-by-two matrix, positive definiteness follows from positive leading principal minors:
\[ 4>0, \qquad \det(R)=4\cdot 2-1\cdot 1=7>0. \]
Thus \( R\succ 0 \), so every nonzero two-input vector has strictly positive input cost.
15. Summary
The matrices \( Q \) and \( R \) are not arbitrary tuning symbols; they are mathematical encodings of state importance, actuator effort, units, physical tolerances, and coordinate choices. A valid quadratic performance descriptor normally uses \( Q\succeq 0 \) and \( R\succ 0 \). Diagonal weights are useful for normalized first designs, while full matrices capture coupled variables or coupled actuators. Coordinate transformations require congruence transformations such as \( Q_z=T^\top Q_xT \), preserving the physical meaning of the quadratic cost. These ideas prepare students for the qualitative weight-behavior discussion in Lesson 4 and the optimal-feedback preview in Lesson 5.
16. References
- Kalman, R.E. (1960). Contributions to the theory of optimal control. Boletin de la Sociedad Matematica Mexicana, 5, 102–119.
- Kalman, R.E. (1963). Lyapunov functions for the problem of Lur'e in automatic control. Proceedings of the National Academy of Sciences, 49(2), 201–205.
- Letov, A.M. (1960). The analytical design of control systems. Automation and Remote Control, 21, 303–306.
- Wonham, W.M. (1968). On a matrix Riccati equation of stochastic control. SIAM Journal on Control, 6(4), 681–697.
- Willems, J.C. (1971). Least squares stationary optimal control and the algebraic Riccati equation. IEEE Transactions on Automatic Control, 16(6), 621–634.
- Anderson, B.D.O. and Moore, J.B. (1968). Linear optimal control. Prentice-Hall technical report and related journal-era developments.
- Kučera, V. (1972). A contribution to matrix quadratic equations. IEEE Transactions on Automatic Control, 17(3), 344–347.
- Laub, A.J. (1979). A Schur method for solving algebraic Riccati equations. IEEE Transactions on Automatic Control, 24(6), 913–921.