Chapter 22: Fundamentals of State-Feedback Control
Lesson 4: Requirements for Implementing State Feedback
This lesson studies the conditions that must hold before the state-feedback law \( u(t)=-Kx(t)+r(t) \) can be implemented on a real or simulated system. We distinguish mathematical design possibility from practical implementation readiness: state availability, model consistency, controllability or stabilizability, actuator authority, coordinate consistency, sampling, computation, and verification of the resulting closed-loop matrix.
1. Why Implementation Requirements Matter
In Lessons 1--3 of this chapter, state feedback was introduced in the form \( u(t)=-Kx(t)+r(t) \), giving the closed-loop state equation
\[ \dot{x}(t)=Ax(t)+Bu(t) =Ax(t)+B[-Kx(t)+r(t)] =(A-BK)x(t)+Br(t). \]
Therefore the closed-loop dynamics are governed by \( A_{\mathrm{cl} }=A-BK \). Mathematically, this looks simple. Implementation, however, requires more than writing down \( K \). The controller must have access to a usable state vector, the matrices must represent the same coordinates and units as the measurements, the input must physically realize \( -Kx+r \), and all unstable modes that need control must be reachable through the actuators.
\[ \boxed{ \begin{aligned} \text{Implementability} &= \text{state availability} + \text{model compatibility} + \text{stabilizability} \\ &\quad + \text{actuator feasibility} + \text{real-time realizability}. \end{aligned} } \]
flowchart TD
A["Start with plant model A, B, C, D"] --> B["Check matrix dimensions and coordinate units"]
B --> C["Can the full state be measured or reconstructed?"]
C -->|yes| D["Check controllability or stabilizability"]
C -->|no| E["Need observer or state estimator \nin later chapters"]
D --> F["Choose or verify gain K"]
F --> G["Compute Acl = A - B K"]
G --> H["Verify closed-loop eigenvalues and input levels"]
H --> I["Discretize or implement in real time"]
2. Dimensional and Algebraic Compatibility
Consider the continuous-time LTI model
\[ \dot{x}=Ax+Bu,\qquad y=Cx+Du, \]
where \( x\in\mathbb{R}^{n} \), \( u\in\mathbb{R}^{m} \), and \( y\in\mathbb{R}^{p} \). The state-feedback gain must satisfy
\[ K\in\mathbb{R}^{m\times n},\qquad Kx\in\mathbb{R}^{m},\qquad u=-Kx+r\in\mathbb{R}^{m}. \]
The product \( BK \) has dimension \( n\times n \), so the closed-loop matrix \( A-BK \) is well-defined only when \( B\in\mathbb{R}^{n\times m} \) and \( K\in\mathbb{R}^{m\times n} \).
\[ A-BK\in\mathbb{R}^{n\times n}. \]
A common implementation error is to compute a gain using a transformed state but apply it to a physical state. Suppose \( x=Tz \), where \( T \) is nonsingular. If the intended feedback in the physical coordinates is \( u=-K_xx \), then in the \( z \)-coordinates it must be
\[ u=-K_xTz=-K_zz,\qquad K_z=K_xT. \]
Conversely, if a gain \( K_z \) is designed for the transformed state \( z=T^{-1}x \), then the equivalent physical-coordinate gain is
\[ u=-K_zz=-K_zT^{-1}x,\qquad K_x=K_zT^{-1}. \]
Thus, implementation requires that the numerical state used by the controller must be exactly the same state representation used in gain design.
3. Availability of the State Vector
State feedback is not output feedback. The law \( u=-Kx+r \) requires the controller to know \( x(t) \), not merely the output \( y(t) \). If the measured signal is \( y_m=C_mx \), direct algebraic recovery of the full state is possible only if the measurement map contains \( n \) independent state directions:
\[ \operatorname{rank}(C_m)=n. \]
If \( C_m\in\mathbb{R}^{p\times n} \) and \( \operatorname{rank}(C_m)=n \), then \( p\ge n \) and there exists a left inverse \( L \) such that
\[ LC_m=I_n,\qquad x=Ly_m. \]
If \( \operatorname{rank}(C_m)<n \), then at least one nonzero state direction lies in the null space of \( C_m \). In that case, different states can generate the same measured output, so direct full-state feedback cannot be implemented from \( y_m \) alone.
\[ \operatorname{rank}(C_m)<n \quad\Longrightarrow\quad \exists v\neq 0 \text{ such that } C_mv=0. \]
Then \( x \) and \( x+v \) produce the same measurement:
\[ C_m(x+v)=C_mx+C_mv=C_mx. \]
Therefore no static function of the measurement alone can distinguish \( x \) from \( x+v \). If not all states are directly measured, an observer or estimator is required; the detailed observer design is treated later, but the important prerequisite is already known from earlier chapters: the relevant state information must be observable or at least detectable.
flowchart TD
X["Plant state x"] --> P["Plant dynamics"]
P --> Y["Measured output y"]
X --> S["State sensors or estimator"]
S --> XH["Available state signal"]
XH --> FB["Compute u = -K x + r"]
FB --> P
4. Controllability and Stabilizability Requirements
State feedback can only move modes that the input can influence. The Kalman controllability matrix is
\[ \mathcal{C} = \begin{bmatrix} B & AB & A^2B & \cdots & A^{n-1}B \end{bmatrix}. \]
Full arbitrary eigenvalue assignment by static state feedback requires
\[ \operatorname{rank}(\mathcal{C})=n. \]
For the weaker requirement of closed-loop stabilization, full controllability is not necessary. It is enough that all nondecaying open-loop modes be controllable. This property is called stabilizability. The PBH stabilizability condition is
\[ \operatorname{rank} \begin{bmatrix} \lambda I-A & B \end{bmatrix} =n \quad \text{for every } \lambda\in\sigma(A) \text{ with } \operatorname{Re}(\lambda)\ge 0. \]
Equivalently, every uncontrollable mode must already be strictly stable:
\[ \lambda \text{ uncontrollable} \quad\Longrightarrow\quad \operatorname{Re}(\lambda)<0. \]
This condition is fundamental for implementation. If an unstable mode is uncontrollable, no numerical gain \( K \) can stabilize it because the actuator has no authority over that mode.
Proof of the unassignable-mode obstruction.
Suppose there exists a nonzero left eigenvector \( q^\ast \) such that
\[ q^\ast A=\lambda q^\ast,\qquad q^\ast B=0. \]
Then for any state-feedback gain \( K \),
\[ q^\ast(A-BK)=q^\ast A-q^\ast BK =\lambda q^\ast-0\cdot K =\lambda q^\ast. \]
Thus \( \lambda \) remains an eigenvalue of \( A-BK \) for every possible feedback gain. Hence this mode is unassignable. If \( \operatorname{Re}(\lambda)\ge 0 \), closed-loop asymptotic stability is impossible.
5. Actuator Authority and Saturation
Even when \( (A,B) \) is controllable, the actuator may not be able to realize the demanded signal \( u=-Kx+r \). For a componentwise saturated actuator,
\[ u_{\min,i}\le u_i(t)\le u_{\max,i},\qquad i=1,\dots,m. \]
The commanded input must satisfy
\[ u_{\min}\le -Kx(t)+r(t)\le u_{\max}. \]
If the gain is very large, the closed-loop eigenvalues may move far to the left, but the demanded input can become physically infeasible. For a norm-bounded estimate, assume \( \|x(t)\|_2\le \rho \) and \( \|r(t)\|_2\le r_{\max} \). Then
\[ \|u(t)\|_2 = \|-Kx(t)+r(t)\|_2 \le \|K\|_2\|x(t)\|_2+\|r(t)\|_2 \le \|K\|_2\rho+r_{\max}. \]
Therefore a sufficient condition for respecting an input magnitude bound \( \|u(t)\|_2\le u_{\max} \) over the operating set is
\[ \|K\|_2\rho+r_{\max}\le u_{\max}. \]
This inequality is conservative, but it shows the implementation trade-off: aggressive feedback usually increases control effort. In practice, input constraints must be checked before deploying the controller.
6. Sampling, Computation, and Real-Time Execution
Most digital controllers implement the feedback at sample instants \( t_k=kT_s \). If the continuous plant is held by a zero-order hold, the exact sampled model is
\[ x_{k+1}=A_dx_k+B_du_k, \]
where
\[ A_d=e^{AT_s},\qquad B_d=\int_0^{T_s}e^{A\tau}B\,d\tau. \]
A digital implementation of state feedback has the form
\[ u_k=-K_dx_k+r_k. \]
If a continuous-time gain \( K \) is simply inserted into a sampled system without checking the resulting discrete-time dynamics, the implementation can behave differently from the intended continuous-time design. The discrete closed-loop matrix is
\[ A_{d,\mathrm{cl} }=A_d-B_dK_d. \]
Discrete-time asymptotic stability requires all eigenvalues of \( A_{d,\mathrm{cl} } \) to lie inside the unit disk:
\[ |\mu_i(A_{d,\mathrm{cl} })|<1,\qquad i=1,\dots,n. \]
The implementation also requires that computation, measurement, communication, and actuation finish inside each sampling period. A simple timing requirement is
\[ T_{\mathrm{measure} }+T_{\mathrm{compute} }+T_{\mathrm{actuate} } <T_s. \]
7. Software Libraries and Implementation Roles
Modern control software implementation usually separates four tasks: matrix analysis, controller design, simulation, and deployment. For this lesson, the main task is not to design \( K \) from scratch, but to verify whether a supplied state-feedback law is implementable.
-
Python:
NumPyfor matrix algebra,SciPyfor simulation and matrix exponentials, andpython-controlfor state-space utilities. -
C++:
EigenorArmadillofor linear algebra; embedded implementations often use fixed-size arrays for deterministic memory behavior. -
Java:
EJML,la4j, orApache Commons Mathfor matrix operations. -
MATLAB/Simulink: Control System Toolbox for
ctrb,obsv,ss, andinitial; Simulink for block-level implementation and real-time testing. - Wolfram Mathematica: symbolic and numerical eigenvalue analysis, matrix rank checks, and differential-equation simulation.
8. Python Implementation
Chapter22_Lesson4.py
"""
Chapter22_Lesson4.py
Requirements for Implementing State Feedback
This script checks the minimum implementation requirements for a continuous-time
state-feedback law u(t) = -K x(t) + r(t).
Libraries used:
- NumPy for linear algebra
No pole-placement algorithm is used here; the gain K is assumed to be supplied
by a later design step.
"""
import numpy as np
def controllability_matrix(A, B):
"""Return Wc = [B AB ... A^(n-1)B]."""
n = A.shape[0]
blocks = []
Ak = np.eye(n)
for _ in range(n):
blocks.append(Ak @ B)
Ak = Ak @ A
return np.hstack(blocks)
def observability_matrix(A, C):
"""Return Wo = [C; CA; ...; CA^(n-1)]."""
n = A.shape[0]
blocks = []
Ak = np.eye(n)
for _ in range(n):
blocks.append(C @ Ak)
Ak = Ak @ A
return np.vstack(blocks)
def rank(M, tol=1e-9):
"""Numerical matrix rank wrapper."""
return int(np.linalg.matrix_rank(M, tol=tol))
def stabilizability_pbh(A, B, tol=1e-8):
"""
PBH stabilizability test for continuous-time systems.
The pair (A,B) is stabilizable iff every eigenvalue lambda of A with
Re(lambda) >= 0 satisfies rank([lambda I - A, B]) = n.
"""
n = A.shape[0]
failed = []
for lam in np.linalg.eigvals(A):
if lam.real >= -tol:
pbh = np.hstack((lam * np.eye(n) - A, B))
if rank(pbh, tol) < n:
failed.append(lam)
return len(failed) == 0, failed
def full_state_is_directly_measured(C, n, tol=1e-9):
"""
A necessary condition for direct implementation without observer is that
the measurement map y = Cx contains enough independent information to
reconstruct x algebraically.
"""
return rank(C, tol) == n
def simulate_closed_loop(A, B, K, x0, dt=0.01, tf=5.0):
"""
From-scratch forward-Euler simulation of x_dot = (A - BK)x.
This is intentionally simple; production simulation should use solve_ivp
or a validated real-time integration/discretization method.
"""
Acl = A - B @ K
steps = int(tf / dt)
xs = np.zeros((steps + 1, len(x0)))
ts = np.linspace(0.0, tf, steps + 1)
xs[0, :] = x0
for k in range(steps):
xs[k + 1, :] = xs[k, :] + dt * (Acl @ xs[k, :])
return ts, xs
def main():
# Example plant: second-order stable open-loop system.
A = np.array([[0.0, 1.0],
[-2.0, -3.0]])
B = np.array([[0.0],
[1.0]])
# Position-only measurement is not enough for direct full-state feedback.
C_position_only = np.array([[1.0, 0.0]])
# Full-state measurement means both states are measured or reconstructed.
C_full = np.eye(2)
# K is assumed to come from a design step; this lesson checks implementation readiness.
K = np.array([[4.0, 2.0]])
n = A.shape[0]
print("=== Requirement checks for u = -Kx + r ===")
print("State dimension n:", n)
print("Input dimension m:", B.shape[1])
Wc = controllability_matrix(A, B)
print("\nControllability matrix Wc:\n", Wc)
print("rank(Wc) =", rank(Wc), "required =", n)
ok_stab, bad_modes = stabilizability_pbh(A, B)
print("PBH stabilizable?", ok_stab)
if bad_modes:
print("Unstabilizable nondecaying modes:", bad_modes)
print("\nFull state measured with C_position_only?",
full_state_is_directly_measured(C_position_only, n))
print("Full state measured with C_full?",
full_state_is_directly_measured(C_full, n))
Acl = A - B @ K
print("\nClosed-loop matrix Acl = A - BK:\n", Acl)
print("closed-loop eigenvalues:", np.linalg.eigvals(Acl))
cond_Wc = np.linalg.cond(Wc)
print("condition number of Wc:", cond_Wc)
if cond_Wc > 1e6:
print("Warning: controllability calculation is ill-conditioned.")
x0 = np.array([1.0, 0.0])
t, x = simulate_closed_loop(A, B, K, x0)
print("\nFinal simulated state at t =", t[-1], "is", x[-1, :])
if __name__ == "__main__":
main()
9. C++ Implementation
Chapter22_Lesson4.cpp
/*
Chapter22_Lesson4.cpp
Requirements for Implementing State Feedback
This standalone C++ example checks rank controllability, computes closed-loop
eigenvalues for a supplied gain K, and simulates x_dot = (A - BK)x.
Compile:
g++ -std=c++17 Chapter22_Lesson4.cpp -o Chapter22_Lesson4
*/
#include <cmath>
#include <complex>
#include <iomanip>
#include <iostream>
#include <vector>
using Matrix = std::vector<std::vector<double>>;
Matrix multiply(const Matrix& A, const Matrix& B) {
int r = static_cast<int>(A.size());
int c = static_cast<int>(B[0].size());
int inner = static_cast<int>(B.size());
Matrix C(r, std::vector<double>(c, 0.0));
for (int i = 0; i < r; ++i) {
for (int j = 0; j < c; ++j) {
for (int k = 0; k < inner; ++k) {
C[i][j] += A[i][k] * B[k][j];
}
}
}
return C;
}
Matrix subtract(const Matrix& A, const Matrix& B) {
Matrix C = A;
for (size_t i = 0; i < A.size(); ++i) {
for (size_t j = 0; j < A[0].size(); ++j) {
C[i][j] -= B[i][j];
}
}
return C;
}
int rank(Matrix M, double tol = 1e-10) {
int rows = static_cast<int>(M.size());
int cols = static_cast<int>(M[0].size());
int r = 0;
for (int c = 0; c < cols && r < rows; ++c) {
int pivot = r;
for (int i = r + 1; i < rows; ++i) {
if (std::fabs(M[i][c]) > std::fabs(M[pivot][c])) pivot = i;
}
if (std::fabs(M[pivot][c]) <= tol) continue;
std::swap(M[pivot], M[r]);
double piv = M[r][c];
for (int j = c; j < cols; ++j) M[r][j] /= piv;
for (int i = 0; i < rows; ++i) {
if (i == r) continue;
double factor = M[i][c];
for (int j = c; j < cols; ++j) M[i][j] -= factor * M[r][j];
}
++r;
}
return r;
}
Matrix controllabilityMatrix2x2(const Matrix& A, const Matrix& B) {
Matrix AB = multiply(A, B);
return { {B[0][0], AB[0][0]},
{B[1][0], AB[1][0]} };
}
std::pair<std::complex<double>, std::complex<double>> eigenvalues2x2(const Matrix& A) {
double tr = A[0][0] + A[1][1];
double det = A[0][0] * A[1][1] - A[0][1] * A[1][0];
std::complex<double> disc = std::complex<double>(tr * tr - 4.0 * det, 0.0);
std::complex<double> root = std::sqrt(disc);
return {(tr + root) / 2.0, (tr - root) / 2.0};
}
void printMatrix(const std::string& name, const Matrix& M) {
std::cout << name << "\n";
for (const auto& row : M) {
for (double v : row) std::cout << std::setw(12) << v << " ";
std::cout << "\n";
}
}
int main() {
Matrix A = { {0.0, 1.0},
{-2.0, -3.0} };
Matrix B = { {0.0},
{1.0} };
Matrix K = { {4.0, 2.0} };
Matrix Wc = controllabilityMatrix2x2(A, B);
printMatrix("Controllability matrix Wc:", Wc);
std::cout << "rank(Wc) = " << rank(Wc) << " required = 2\n";
Matrix BK = multiply(B, K);
Matrix Acl = subtract(A, BK);
printMatrix("\nClosed-loop matrix Acl = A - BK:", Acl);
auto eigs = eigenvalues2x2(Acl);
std::cout << "closed-loop eigenvalues: " << eigs.first << ", " << eigs.second << "\n";
std::vector<double> x = {1.0, 0.0};
double dt = 0.01;
double tf = 5.0;
int steps = static_cast<int>(tf / dt);
for (int k = 0; k < steps; ++k) {
std::vector<double> dx = {
Acl[0][0] * x[0] + Acl[0][1] * x[1],
Acl[1][0] * x[0] + Acl[1][1] * x[1]
};
x[0] += dt * dx[0];
x[1] += dt * dx[1];
}
std::cout << "Final simulated state: [" << x[0] << ", " << x[1] << "]\n";
return 0;
}
10. Java Implementation
Chapter22_Lesson4.java
/*
Chapter22_Lesson4.java
Requirements for Implementing State Feedback
Compile:
javac Chapter22_Lesson4.java
Run:
java Chapter22_Lesson4
*/
public class Chapter22_Lesson4 {
static double[][] multiply(double[][] A, double[][] B) {
int r = A.length;
int c = B[0].length;
int inner = B.length;
double[][] C = new double[r][c];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
for (int k = 0; k < inner; k++) {
C[i][j] += A[i][k] * B[k][j];
}
}
}
return C;
}
static double[][] subtract(double[][] A, double[][] B) {
double[][] C = new double[A.length][A[0].length];
for (int i = 0; i < A.length; i++) {
for (int j = 0; j < A[0].length; j++) {
C[i][j] = A[i][j] - B[i][j];
}
}
return C;
}
static int rank(double[][] input, double tol) {
double[][] M = copy(input);
int rows = M.length;
int cols = M[0].length;
int r = 0;
for (int c = 0; c < cols && r < rows; c++) {
int pivot = r;
for (int i = r + 1; i < rows; i++) {
if (Math.abs(M[i][c]) > Math.abs(M[pivot][c])) pivot = i;
}
if (Math.abs(M[pivot][c]) <= tol) continue;
double[] tmp = M[pivot];
M[pivot] = M[r];
M[r] = tmp;
double piv = M[r][c];
for (int j = c; j < cols; j++) M[r][j] /= piv;
for (int i = 0; i < rows; i++) {
if (i == r) continue;
double factor = M[i][c];
for (int j = c; j < cols; j++) M[i][j] -= factor * M[r][j];
}
r++;
}
return r;
}
static double[][] copy(double[][] A) {
double[][] C = new double[A.length][A[0].length];
for (int i = 0; i < A.length; i++) {
System.arraycopy(A[i], 0, C[i], 0, A[0].length);
}
return C;
}
static double[][] controllabilityMatrix2x2(double[][] A, double[][] B) {
double[][] AB = multiply(A, B);
return new double[][]{
{B[0][0], AB[0][0]},
{B[1][0], AB[1][0]}
};
}
static double[] eigenvalues2x2Real(double[][] A) {
double tr = A[0][0] + A[1][1];
double det = A[0][0] * A[1][1] - A[0][1] * A[1][0];
double disc = tr * tr - 4.0 * det;
if (disc < 0.0) {
throw new IllegalArgumentException("This simple demo expects real eigenvalues.");
}
double root = Math.sqrt(disc);
return new double[]{(tr + root) / 2.0, (tr - root) / 2.0};
}
static void printMatrix(String name, double[][] M) {
System.out.println(name);
for (double[] row : M) {
for (double v : row) System.out.printf("%12.6f ", v);
System.out.println();
}
}
public static void main(String[] args) {
double[][] A = { {0.0, 1.0}, {-2.0, -3.0} };
double[][] B = { {0.0}, {1.0} };
double[][] K = { {4.0, 2.0} };
double[][] Wc = controllabilityMatrix2x2(A, B);
printMatrix("Controllability matrix Wc:", Wc);
System.out.println("rank(Wc) = " + rank(Wc, 1e-10) + " required = 2");
double[][] Acl = subtract(A, multiply(B, K));
printMatrix("\nClosed-loop matrix Acl = A - BK:", Acl);
double[] eigs = eigenvalues2x2Real(Acl);
System.out.printf("closed-loop eigenvalues: %.6f, %.6f%n", eigs[0], eigs[1]);
double[] x = {1.0, 0.0};
double dt = 0.01;
int steps = (int)(5.0 / dt);
for (int k = 0; k < steps; k++) {
double dx0 = Acl[0][0] * x[0] + Acl[0][1] * x[1];
double dx1 = Acl[1][0] * x[0] + Acl[1][1] * x[1];
x[0] += dt * dx0;
x[1] += dt * dx1;
}
System.out.printf("Final simulated state: [%.6f, %.6f]%n", x[0], x[1]);
}
}
11. MATLAB and Simulink Implementation
Chapter22_Lesson4.m
% Chapter22_Lesson4.m
% Requirements for Implementing State Feedback
%
% This script checks direct state availability, controllability,
% PBH stabilizability, closed-loop eigenvalues, and optionally creates
% a minimal Simulink model for x_dot = (A - B*K)x.
%
% Toolboxes:
% - Base MATLAB is enough for the custom controllability/observability code.
% - Control System Toolbox provides ctrb/obsv/ss/initial conveniences.
% - Simulink is optional for model construction.
clear; clc;
A = [0 1; -2 -3];
B = [0; 1];
% Position-only measurement cannot directly implement u = -Kx.
C_position_only = [1 0];
% Full-state measurement or reconstructed full state.
C_full = eye(2);
% Gain K is assumed to be supplied by a design step.
K = [4 2];
n = size(A,1);
Wc = local_ctrb(A,B);
Wo_position = local_obsv(A,C_position_only);
Wo_full = local_obsv(A,C_full);
fprintf("=== Requirement checks for u = -Kx + r ===\n");
fprintf("rank(Wc) = %d, required = %d\n", rank(Wc), n);
fprintf("rank(C_position_only) = %d, required for direct full-state measurement = %d\n", ...
rank(C_position_only), n);
fprintf("rank(C_full) = %d, required for direct full-state measurement = %d\n", ...
rank(C_full), n);
fprintf("rank(Wo_position) = %d, required for observer-based reconstruction = %d\n", ...
rank(Wo_position), n);
fprintf("rank(Wo_full) = %d, required for observer-based reconstruction = %d\n", ...
rank(Wo_full), n);
[pbh_ok, bad_modes] = local_pbh_stabilizable(A,B);
fprintf("PBH stabilizable? %d\n", pbh_ok);
if ~isempty(bad_modes)
disp("Unstabilizable nondecaying modes:");
disp(bad_modes);
end
Acl = A - B*K;
disp("Closed-loop matrix Acl = A - BK:");
disp(Acl);
disp("Closed-loop eigenvalues:");
disp(eig(Acl));
x0 = [1; 0];
[t,x] = ode45(@(t,x) Acl*x, [0 5], x0);
fprintf("Final simulated state at t = %.2f: [%g, %g]^T\n", t(end), x(end,1), x(end,2));
% Optional: create a minimal Simulink model if Simulink is available.
if exist("simulink", "file") == 4
model = "Chapter22_Lesson4_Simulink";
if bdIsLoaded(model)
close_system(model,0);
end
new_system(model);
open_system(model);
assignin("base","Acl",Acl);
assignin("base","Bzero",zeros(2,1));
assignin("base","Cout",eye(2));
assignin("base","Dzero",zeros(2,1));
add_block("simulink/Sources/Constant", model + "/ZeroInput", ...
"Value", "0", "Position", [80 90 130 120]);
add_block("simulink/Continuous/State-Space", model + "/ClosedLoopPlant", ...
"A", "Acl", "B", "Bzero", "C", "Cout", "D", "Dzero", ...
"X0", "[1;0]", "Position", [200 70 360 140]);
add_block("simulink/Sinks/Scope", model + "/StateScope", ...
"Position", [440 75 500 135]);
add_line(model, "ZeroInput/1", "ClosedLoopPlant/1");
add_line(model, "ClosedLoopPlant/1", "StateScope/1");
save_system(model);
fprintf("Created optional Simulink model: %s.slx\n", model);
end
function Wc = local_ctrb(A,B)
n = size(A,1);
Wc = [];
Ak = eye(n);
for k = 1:n
Wc = [Wc, Ak*B]; %#ok<AGROW>
Ak = Ak*A;
end
end
function Wo = local_obsv(A,C)
n = size(A,1);
Wo = [];
Ak = eye(n);
for k = 1:n
Wo = [Wo; C*Ak]; %#ok<AGROW>
Ak = Ak*A;
end
end
function [ok,bad_modes] = local_pbh_stabilizable(A,B)
n = size(A,1);
ev = eig(A);
bad_modes = [];
tol = 1e-9;
for k = 1:length(ev)
lam = ev(k);
if real(lam) >= -tol
M = [lam*eye(n)-A, B];
if rank(M) < n
bad_modes = [bad_modes; lam]; %#ok<AGROW>
end
end
end
ok = isempty(bad_modes);
end
12. Wolfram Mathematica Implementation
Chapter22_Lesson4.nb
(* Chapter22_Lesson4.nb *)
(* Requirements for Implementing State Feedback *)
ClearAll["Global`*"];
A = { {0, 1}, {-2, -3} };
B = { {0}, {1} };
CPositionOnly = { {1, 0} };
CFull = IdentityMatrix[2];
(* K is assumed to be supplied by a design step. *)
K = { {4, 2} };
ControllabilityMatrix[A_, B_] := Module[
{n = Length[A]},
ArrayFlatten[{Table[MatrixPower[A, k].B, {k, 0, n - 1}]}]
];
ObservabilityMatrix[A_, C_] := Module[
{n = Length[A]},
Join @@ Table[C.MatrixPower[A, k], {k, 0, n - 1}]
];
PBHStabilizableQ[A_, B_] := Module[
{n = Length[A], evals = Eigenvalues[A], bad},
bad = Select[
evals,
Re[#] >= 0 && MatrixRank[ArrayFlatten[{ { #.IdentityMatrix[n] - A, B} }]] < n &
];
{Length[bad] == 0, bad}
];
Wc = ControllabilityMatrix[A, B];
WoPosition = ObservabilityMatrix[A, CPositionOnly];
WoFull = ObservabilityMatrix[A, CFull];
Print["=== Requirement checks for u = -K x + r ==="];
Print["Wc = ", MatrixForm[Wc]];
Print["rank(Wc) = ", MatrixRank[Wc], ", required = ", Length[A]];
Print["rank(CPositionOnly) = ", MatrixRank[CPositionOnly],
", required for direct full-state measurement = ", Length[A]];
Print["rank(CFull) = ", MatrixRank[CFull],
", required for direct full-state measurement = ", Length[A]];
Print["rank(WoPosition) = ", MatrixRank[WoPosition],
", required for observer-based reconstruction = ", Length[A]];
Print["rank(WoFull) = ", MatrixRank[WoFull],
", required for observer-based reconstruction = ", Length[A]];
Print["PBH stabilizable? ", PBHStabilizableQ[A, B]];
Acl = A - B.K;
Print["Acl = ", MatrixForm[Acl]];
Print["Closed-loop eigenvalues = ", Eigenvalues[Acl]];
x0 = {1, 0};
sol = NDSolveValue[
{x'[t] == Acl.x[t], x[0] == x0},
x,
{t, 0, 5}
];
Print["Final simulated state = ", sol[5]];
Plot[Evaluate[sol[t]], {t, 0, 5},
PlotLegends -> {"x1(t)", "x2(t)"},
AxesLabel -> {"t", "states"},
PlotLabel -> "Closed-loop state response"
]
13. Implementation Checklist
Before implementing \( u=-Kx+r \), verify the following conditions.
- Model compatibility: \( A \), \( B \), and \( K \) have compatible dimensions and use the same state coordinates.
- State availability: either the full state is directly measured, or an observer/estimator is available.
- Stabilizability: every unstable or marginal open-loop mode is controllable through \( B \).
- Closed-loop verification: eigenvalues of \( A-BK \) satisfy the intended stability condition.
- Actuator feasibility: the demanded input stays within physical limits over the expected operating region.
- Sampling feasibility: digital implementation uses an appropriate sampling period and verifies discrete-time closed-loop stability.
- Numerical reliability: rank tests and gain calculations are not dominated by ill-conditioning.
14. Problems and Solutions
Problem 1 (Direct State Availability): Let \( x=[x_1\;x_2]^T \) and suppose the only measured signal is \( y=x_1 \). Can the feedback \( u=-[k_1\;k_2]x \) be directly implemented from \( y \) alone?
Solution:
Here \( C_m=[1\;0] \), so \( \operatorname{rank}(C_m)=1<2 \). Therefore \( C_m \) does not contain enough independent information to reconstruct \( x\in\mathbb{R}^2 \). In fact,
\[ C_m \begin{bmatrix} 0\\1 \end{bmatrix} =0. \]
Thus \( [x_1\;x_2]^T \) and \( [x_1\;x_2+\alpha]^T \) produce the same measured output for any \( \alpha \). Direct full-state feedback cannot be implemented from \( y=x_1 \) alone. A sensor for \( x_2 \) or an observer is required.
Problem 2 (Unstabilizable Mode): Consider
\[ A= \begin{bmatrix} 1 & 0\\ 0 & -2 \end{bmatrix}, \qquad B= \begin{bmatrix} 0\\ 1 \end{bmatrix}. \]
Determine whether the system is stabilizable.
Solution:
The eigenvalues of \( A \) are \( 1 \) and \( -2 \). The nondecaying eigenvalue is \( \lambda=1 \). The PBH matrix is
\[ \begin{bmatrix} \lambda I-A & B \end{bmatrix}_{\lambda=1} = \begin{bmatrix} 0 & 0 & 0\\ 0 & 3 & 1 \end{bmatrix}. \]
Its rank is \( 1<2 \). Therefore the unstable mode \( \lambda=1 \) is uncontrollable. The pair \( (A,B) \) is not stabilizable, and no static state feedback gain \( K \) can make \( A-BK \) asymptotically stable.
Problem 3 (Coordinate Consistency): Suppose \( x=Tz \),
\[ T= \begin{bmatrix} 2 & 0\\ 0 & 5 \end{bmatrix}, \qquad K_x= \begin{bmatrix} 3 & 4 \end{bmatrix}. \]
Find the gain that must be applied to the transformed state \( z \).
Solution:
Since \( x=Tz \),
\[ u=-K_xx=-K_xTz. \]
Therefore
\[ K_z=K_xT = \begin{bmatrix} 3 & 4 \end{bmatrix} \begin{bmatrix} 2 & 0\\ 0 & 5 \end{bmatrix} = \begin{bmatrix} 6 & 20 \end{bmatrix}. \]
Applying \( K_x \) directly to \( z \) would implement the wrong controller.
Problem 4 (Input Bound Check): Let \( u=-Kx \), where \( K=[4\;2] \). Suppose \( \|x\|_2\le 0.5 \). Find a sufficient upper bound for \( |u| \).
Solution:
Since the input is scalar,
\[ |u|=|Kx|\le \|K\|_2\|x\|_2. \]
The gain norm is
\[ \|K\|_2=\sqrt{4^2+2^2}=\sqrt{20}. \]
Therefore
\[ |u|\le \sqrt{20}(0.5)\approx 2.236. \]
Thus an actuator with magnitude limit below approximately \( 2.236 \) may saturate over this operating region.
Problem 5 (Discrete-Time Stability Check): A sampled-data implementation has
\[ A_d= \begin{bmatrix} 1 & 0.1\\ 0 & 1 \end{bmatrix}, \qquad B_d= \begin{bmatrix} 0\\ 0.1 \end{bmatrix}, \qquad K_d= \begin{bmatrix} 2 & 3 \end{bmatrix}. \]
Compute \( A_{d,\mathrm{cl} } \) and state the stability test.
Solution:
First compute
\[ B_dK_d= \begin{bmatrix} 0\\ 0.1 \end{bmatrix} \begin{bmatrix} 2 & 3 \end{bmatrix} = \begin{bmatrix} 0 & 0\\ 0.2 & 0.3 \end{bmatrix}. \]
Hence
\[ A_{d,\mathrm{cl} } = A_d-B_dK_d = \begin{bmatrix} 1 & 0.1\\ -0.2 & 0.7 \end{bmatrix}. \]
The digital closed loop is asymptotically stable if every eigenvalue \( \mu_i \) of this matrix satisfies \( |\mu_i|<1 \). Unlike continuous-time stability, the discrete-time stability region is the open unit disk.
15. Summary
State feedback requires more than a gain matrix. A valid implementation must have compatible matrix dimensions, a state signal available to the controller, stabilizable plant dynamics, actuator authority, consistent coordinates and units, and a verified real-time or sampled-data execution path. The essential mathematical checks are \( \operatorname{rank}(\mathcal{C})=n \) for full pole assignability, the PBH stabilizability condition for stabilization, and eigenvalue verification of \( A-BK \) or \( A_d-B_dK_d \). These requirements prepare us for the next lesson, where practical limitations of state feedback are studied in more detail.
16. References
- Kalman, R.E. (1960). Contributions to the theory of optimal control. Boletín de la Sociedad Matemática Mexicana, 5, 102--119.
- Kalman, R.E. (1963). Mathematical description of linear dynamical systems. Journal of the Society for Industrial and Applied Mathematics, Series A: Control, 1(2), 152--192.
- Gilbert, E.G. (1963). Controllability and observability in multivariable control systems. SIAM Journal on Control, 1(2), 128--151.
- Luenberger, D.G. (1964). Observing the state of a linear system. IEEE Transactions on Military Electronics, 8(2), 74--80.
- Luenberger, D.G. (1966). Observers for multivariable systems. IEEE Transactions on Automatic Control, 11(2), 190--197.
- Wonham, W.M. (1967). On pole assignment in multi-input controllable linear systems. IEEE Transactions on Automatic Control, 12(6), 660--665.
- Hautus, M.L.J. (1969). Controllability and observability conditions of linear autonomous systems. Proceedings of the Koninklijke Nederlandse Akademie van Wetenschappen, Series A, 72, 443--448.
- Davison, E.J. (1970). On pole assignment in linear systems with incomplete state feedback. IEEE Transactions on Automatic Control, 15(3), 348--351.
- Rosenbrock, H.H. (1970). Structural properties of linear dynamical systems. International Journal of Control, 12(4), 591--604.
- Kailath, T. (1980). Linear systems and state-space methods. IEEE-related foundational contributions in linear systems theory.