Chapter 20: Minimal Realizations and Realization Theory
Lesson 4: Basic Algorithms for Realization Reduction (Concept Only)
This lesson develops the conceptual algorithms used to pass from a nonminimal state-space realization to a minimal one. The emphasis is on exact realization reduction: identifying states that are not reachable from the input or not observable at the output, then constructing a smaller realization with the same transfer matrix. Numerical tolerance selection and ill-conditioning are postponed to the next lesson.
1. Reduction as an Exact Input-Output Preservation Problem
Let a continuous-time LTI realization be \( \Sigma=(\mathbf{A},\mathbf{B},\mathbf{C},\mathbf{D}) \), where \( \mathbf{A}\in\mathbb{R}^{n\times n} \), \( \mathbf{B}\in\mathbb{R}^{n\times m} \), \( \mathbf{C}\in\mathbb{R}^{p\times n} \), and \( \mathbf{D}\in\mathbb{R}^{p\times m} \):
\[ \dot{\mathbf{x} }(t)=\mathbf{A}\mathbf{x}(t)+\mathbf{B}\mathbf{u}(t),\qquad \mathbf{y}(t)=\mathbf{C}\mathbf{x}(t)+\mathbf{D}\mathbf{u}(t). \]
The transfer matrix associated with this realization is
\[ \mathbf{G}(s)=\mathbf{C}(s\mathbf{I}-\mathbf{A})^{-1}\mathbf{B}+ \mathbf{D}. \]
A realization reduction algorithm constructs another realization \( \Sigma_r=(\mathbf{A}_r,\mathbf{B}_r,\mathbf{C}_r,\mathbf{D}) \) of order \( r\le n \) such that the transfer matrix is preserved exactly:
\[ \mathbf{C}_r(s\mathbf{I}_r-\mathbf{A}_r)^{-1}\mathbf{B}_r+ \mathbf{D} = \mathbf{C}(s\mathbf{I}-\mathbf{A})^{-1}\mathbf{B}+ \mathbf{D}. \]
In this chapter, reduction means eliminating dynamically redundant states, not approximating the input-output behavior. Thus the reduced order is the McMillan degree of \( \mathbf{G}(s) \) when the realization is reduced to minimal order.
2. The Two Algebraic Objects Used by the Algorithms
Reduction algorithms use the reachable subspace and the unobservable subspace. The finite-dimensional reachability matrix is
\[ \mathcal{R}=\begin{bmatrix}\mathbf{B}&\mathbf{AB}&\mathbf{A}^2\mathbf{B}&\cdots&\mathbf{A}^{n-1}\mathbf{B}\end{bmatrix},\qquad \mathscr{R}=\operatorname{range}(\mathcal{R}). \]
The finite-dimensional observability matrix is
\[ \mathcal{O}=\begin{bmatrix}\mathbf{C}\\ \mathbf{CA}\\ \mathbf{CA}^2\\ \vdots\\ \mathbf{CA}^{n-1} \end{bmatrix},\qquad \mathscr{N}=\ker(\mathcal{O}). \]
The subspace \( \mathscr{R} \) contains all states that can be generated from zero initial condition by some input. The subspace \( \mathscr{N} \) contains all initial states that produce identically zero free output. Therefore, unreachable states cannot be excited by the input, while unobservable states cannot be detected at the output.
\[ \operatorname{rank}(\mathcal{R})=n \quad\Longleftrightarrow\quad \text{reachable},\qquad \operatorname{rank}(\mathcal{O})=n \quad\Longleftrightarrow\quad \text{observable}. \]
A finite-dimensional LTI realization is minimal exactly when both rank conditions hold. Hence every exact realization reduction algorithm is a constructive method for discarding directions outside these two properties.
3. Algorithm A — Reachability Trimming
The first reduction removes states that cannot be reached from the input. Choose a full-column-rank matrix \( \mathbf{T}_r\in\mathbb{R}^{n\times r} \) whose columns form a basis for \( \mathscr{R} \):
\[ \operatorname{range}(\mathbf{T}_r)=\mathscr{R},\qquad r=\operatorname{rank}(\mathcal{R}). \]
Because \( \mathscr{R} \) is invariant under \( \mathbf{A} \) and contains \( \operatorname{range}(\mathbf{B}) \), there exist matrices \( \mathbf{A}_r \) and \( \mathbf{B}_r \) satisfying
\[ \mathbf{A}\mathbf{T}_r=\mathbf{T}_r\mathbf{A}_r, \qquad \mathbf{B}=\mathbf{T}_r\mathbf{B}_r. \]
With any left inverse \( \mathbf{T}_r^\dagger \) satisfying \( \mathbf{T}_r^\dagger\mathbf{T}_r=\mathbf{I}_r \), the reachable restricted realization is
\[ \mathbf{A}_r=\mathbf{T}_r^\dagger\mathbf{A}\mathbf{T}_r, \qquad \mathbf{B}_r=\mathbf{T}_r^\dagger\mathbf{B}, \qquad \mathbf{C}_r=\mathbf{C}\mathbf{T}_r, \qquad \mathbf{D}_r=\mathbf{D}. \]
If \( \mathbf{T}_r \) is chosen orthonormally, then \( \mathbf{T}_r^\dagger=\mathbf{T}_r^T \). In exact arithmetic, reachability trimming changes internal coordinates but does not alter the transfer matrix because all terms \( \mathbf{A}^k\mathbf{B} \) already lie in \( \mathscr{R} \).
4. Algorithm B — Observability Trimming
After restricting to reachable states, the remaining realization may still contain unobservable internal directions. Let \( \mathscr{N}=\ker(\mathcal{O}) \) for the current reachable realization. Choose a coordinate transformation \( \mathbf{T}=[\mathbf{T}_u\;\mathbf{T}_o] \) such that \( \operatorname{range}(\mathbf{T}_u)=\mathscr{N} \). In transformed coordinates \( \mathbf{x}=\mathbf{T}\begin{bmatrix}\mathbf{x}_u^T&\mathbf{x}_o^T\end{bmatrix}^T \), the realization has the block form
\[ \bar{\mathbf{A} }=\mathbf{T}^{-1}\mathbf{A}\mathbf{T} =\begin{bmatrix} \mathbf{A}_{uu} & \mathbf{A}_{uo}\\ \mathbf{0} & \mathbf{A}_{oo} \end{bmatrix},\qquad \bar{\mathbf{B} }=\mathbf{T}^{-1}\mathbf{B} =\begin{bmatrix}\mathbf{B}_u\\\mathbf{B}_o\end{bmatrix},\qquad \bar{\mathbf{C} }=\mathbf{C}\mathbf{T} =\begin{bmatrix}\mathbf{0}&\mathbf{C}_o\end{bmatrix}. \]
The unobservable coordinate \( \mathbf{x}_u \) has no direct output contribution. Since \( \mathscr{N} \) is \( \mathbf{A} \)-invariant, there is no coupling from \( \mathbf{x}_u \) into the observable quotient dynamics. The reduced observable realization is
\[ \mathbf{A}_{min}=\mathbf{A}_{oo},\qquad \mathbf{B}_{min}=\mathbf{B}_o, \qquad \mathbf{C}_{min}=\mathbf{C}_o, \qquad \mathbf{D}_{min}=\mathbf{D}. \]
The order after both trimming steps is the dimension of the reachable part modulo the unobservable directions that remain inside it.
\[ n_{min}=\dim(\mathscr{R})-\dim(\mathscr{R}\cap\mathscr{N}). \]
5. Algorithmic Flow for Exact Realization Reduction
The complete conceptual procedure is a two-pass trimming algorithm. In exact symbolic work the ranks are exact. In floating-point work the same steps are used, but singular-value thresholds become decisive; that numerical issue is the subject of the next lesson.
flowchart TD
A["Start with realization A, B, C, D"] --> B["Build reachability matrix R"]
B --> C["Find basis for range(R)"]
C --> D["Project onto reachable coordinates"]
D --> E["Build observability matrix of reachable subsystem"]
E --> F["Find basis for null(O)"]
F --> G["Transform so unobservable states come first"]
G --> H["Discard unobservable block"]
H --> I["Return minimal realization with same transfer matrix"]
6. Markov-Parameter and Hankel View (Ho-Kalman Concept)
A second basic route starts not from an existing state-space realization but from input-output data such as Markov parameters. For a strictly proper discrete-time system, the Markov parameters are
\[ \mathbf{H}_0=\mathbf{D},\qquad \mathbf{H}_k=\mathbf{C}\mathbf{A}^{k-1}\mathbf{B},\quad k=1,2,\dots. \]
A block Hankel matrix built from these parameters factors as an observability factor times a reachability factor:
\[ \mathcal{H}_{q,r}=\begin{bmatrix} \mathbf{H}_1 & \mathbf{H}_2 & \cdots & \mathbf{H}_r\\ \mathbf{H}_2 & \mathbf{H}_3 & \cdots & \mathbf{H}_{r+1}\\ \vdots & \vdots & \ddots & \vdots\\ \mathbf{H}_q & \mathbf{H}_{q+1} & \cdots & \mathbf{H}_{q+r-1} \end{bmatrix} = \begin{bmatrix}\mathbf{C}\\\mathbf{CA}\\\vdots\\\mathbf{CA}^{q-1}\end{bmatrix} \begin{bmatrix}\mathbf{B}&\mathbf{AB}&\cdots&\mathbf{A}^{r-1}\mathbf{B}\end{bmatrix}. \]
Therefore the rank of a sufficiently large Hankel matrix gives the minimal state dimension:
\[ n_{min}=\operatorname{rank}(\mathcal{H}_{q,r}) \quad \text{for sufficiently large } q,r. \]
Conceptually, the Ho-Kalman construction factorizes \( \mathcal{H}_{q,r} \) into an observability-like part and a reachability-like part, then extracts \( \mathbf{A} \) from the one-step shifted Hankel matrix. This is realization construction and reduction at the same time: only the rank-revealed dynamic directions are retained.
flowchart TD
M["Markov parameters H0, H1, H2, ..."] --> H["Build block Hankel matrix"]
H --> R["Rank reveals minimal order"]
R --> F["Factor Hankel into observability factor and reachability factor"]
F --> S["Use shifted Hankel matrix to recover A"]
S --> G["Recover B, C, and D"]
7. Proof of Input-Output Preservation
The exactness of the trimming algorithm can be proved by comparing Markov parameters. For the original realization, the strictly proper Markov sequence is \( \mathbf{M}_k=\mathbf{C}\mathbf{A}^k\mathbf{B} \) for \( k=0,1,2,\dots \). Since \( \mathbf{B}=\mathbf{T}_r\mathbf{B}_r \) and \( \mathbf{A}\mathbf{T}_r=\mathbf{T}_r\mathbf{A}_r \), induction gives
\[ \mathbf{A}^k\mathbf{B}=\mathbf{T}_r\mathbf{A}_r^k\mathbf{B}_r, \qquad k=0,1,2,\dots. \]
Thus reachability trimming preserves all Markov parameters:
\[ \mathbf{C}\mathbf{A}^k\mathbf{B} =\mathbf{C}\mathbf{T}_r\mathbf{A}_r^k\mathbf{B}_r =\mathbf{C}_r\mathbf{A}_r^k\mathbf{B}_r. \]
For observability trimming, use the transformed block realization from Section 4. Because \( \bar{\mathbf{C} }=[\mathbf{0}\;\mathbf{C}_o] \) and the lower-left block of \( \bar{\mathbf{A} } \) is zero, the observable quotient gives
\[ \bar{\mathbf{C} }\bar{\mathbf{A} }^k\bar{\mathbf{B} } =\mathbf{C}_o\mathbf{A}_{oo}^k\mathbf{B}_o, \qquad k=0,1,2,\dots. \]
Hence all Markov parameters, and therefore the transfer matrix, remain unchanged. The result is minimal because the final realization is both reachable and observable; by the minimal-realization theorem from Lesson 1, no lower-order realization can realize the same transfer matrix.
8. Worked Symbolic Example
Consider the nonminimal realization
\[ \mathbf{A}=\begin{bmatrix}-1&0&0\\0&-2&0\\0&0&-3\end{bmatrix},\qquad \mathbf{B}=\begin{bmatrix}1\\0\\1\end{bmatrix},\qquad \mathbf{C}=\begin{bmatrix}1&0&0\end{bmatrix},\qquad \mathbf{D}=0. \]
The reachability matrix and observability matrix are
\[ \mathcal{R}=\begin{bmatrix}1&-1&1\\0&0&0\\1&-3&9\end{bmatrix}, \qquad \mathcal{O}=\begin{bmatrix}1&0&0\\-1&0&0\\1&0&0\end{bmatrix}. \]
Hence \( \operatorname{rank}(\mathcal{R})=2 \) and \( \operatorname{rank}(\mathcal{O})=1 \). The state associated with eigenvalue \( -2 \) is not reachable, and the state associated with eigenvalue \( -3 \) is reachable but unobservable. The transfer function is
\[ G(s)=\mathbf{C}(s\mathbf{I}-\mathbf{A})^{-1}\mathbf{B} =\begin{bmatrix}1&0&0\end{bmatrix} \begin{bmatrix}\frac{1}{s+1}&0&0\\0&\frac{1}{s+2}&0\\0&0&\frac{1}{s+3}\end{bmatrix} \begin{bmatrix}1\\0\\1\end{bmatrix} =\frac{1}{s+1}. \]
A minimal realization is therefore
\[ A_{min}=-1, \qquad B_{min}=1, \qquad C_{min}=1, \qquad D_{min}=0. \]
9. Python Implementation
The Python version uses NumPy SVD routines to compute bases for the
reachable column space and the unobservable null space. Related control
libraries include python-control for state-space models and
SciPy for numerical linear algebra.
Chapter20_Lesson4.py
# Chapter20_Lesson4.py
"""
Basic algorithms for exact realization reduction.
This educational script demonstrates the two-stage reduction:
1. restrict the realization to the reachable subspace;
2. quotient out the unobservable subspace of the reachable realization.
Required packages:
pip install numpy scipy
For production control work, compare the result with python-control:
pip install control
"""
from __future__ import annotations
import numpy as np
from numpy.linalg import svd
def controllability_matrix(A: np.ndarray, B: np.ndarray) -> np.ndarray:
"""Return C_R = [B, AB, ..., A^(n-1)B]."""
n = A.shape[0]
blocks = []
Apow = np.eye(n)
for _ in range(n):
blocks.append(Apow @ B)
Apow = Apow @ A
return np.hstack(blocks)
def observability_matrix(A: np.ndarray, C: np.ndarray) -> np.ndarray:
"""Return O = [C; CA; ...; CA^(n-1)]."""
n = A.shape[0]
blocks = []
Apow = np.eye(n)
for _ in range(n):
blocks.append(C @ Apow)
Apow = Apow @ A
return np.vstack(blocks)
def numerical_rank(M: np.ndarray, tol: float | None = 1e-10) -> int:
s = svd(M, compute_uv=False)
if tol is None:
tol = max(M.shape) * np.finfo(float).eps * (s[0] if s.size else 1.0)
return int(np.sum(s > tol))
def column_space_basis(M: np.ndarray, tol: float | None = 1e-10) -> np.ndarray:
"""Orthonormal basis for range(M), returned as columns."""
U, s, _ = svd(M, full_matrices=True)
if tol is None:
tol = max(M.shape) * np.finfo(float).eps * (s[0] if s.size else 1.0)
r = int(np.sum(s > tol))
return U[:, :r]
def null_space_basis(M: np.ndarray, tol: float | None = 1e-10) -> np.ndarray:
"""Orthonormal basis for null(M), returned as columns."""
_, s, Vt = svd(M, full_matrices=True)
if tol is None:
tol = max(M.shape) * np.finfo(float).eps * (s[0] if s.size else 1.0)
r = int(np.sum(s > tol))
return Vt.T[:, r:]
def exact_minimal_reduction(A: np.ndarray, B: np.ndarray, C: np.ndarray, D: np.ndarray):
"""
Return a minimal realization externally equivalent to (A,B,C,D),
assuming exact rank decisions are reliable for the given data.
"""
n = A.shape[0]
# Stage 1: keep only the reachable subspace.
R = controllability_matrix(A, B)
Qr = column_space_basis(R)
A1 = Qr.T @ A @ Qr
B1 = Qr.T @ B
C1 = C @ Qr
# Stage 2: remove the unobservable part of the reachable realization.
O1 = observability_matrix(A1, C1)
Q_unobs = null_space_basis(O1)
q = Q_unobs.shape[1]
if q == 0:
return A1, B1, C1, D, Qr, np.eye(A1.shape[0])
# Orthogonal complement completes the coordinate basis.
Q_obs = null_space_basis(Q_unobs.T)
T = np.hstack([Q_unobs, Q_obs])
Ahat = T.T @ A1 @ T
Bhat = T.T @ B1
Chat = C1 @ T
Amin = Ahat[q:, q:]
Bmin = Bhat[q:, :]
Cmin = Chat[:, q:]
return Amin, Bmin, Cmin, D, Qr, T
def transfer_value(A: np.ndarray, B: np.ndarray, C: np.ndarray, D: np.ndarray, s: complex) -> np.ndarray:
"""Evaluate G(s)=C(sI-A)^(-1)B+D."""
n = A.shape[0]
return C @ np.linalg.solve(s * np.eye(n) - A, B) + D
def main() -> None:
# Nonminimal realization: states 2 and 3 do not affect the input-output map.
A = np.diag([-1.0, -2.0, -3.0])
B = np.array([[1.0], [0.0], [1.0]])
C = np.array([[1.0, 0.0, 0.0]])
D = np.array([[0.0]])
R = controllability_matrix(A, B)
O = observability_matrix(A, C)
print("rank controllability matrix:", numerical_rank(R), "of", A.shape[0])
print("rank observability matrix:", numerical_rank(O), "of", A.shape[0])
Amin, Bmin, Cmin, Dmin, _, _ = exact_minimal_reduction(A, B, C, D)
print("Amin =\n", Amin)
print("Bmin =\n", Bmin)
print("Cmin =\n", Cmin)
print("Dmin =\n", Dmin)
for s in [0.2, 1.0, 2.5]:
g_old = transfer_value(A, B, C, D, s)
g_new = transfer_value(Amin, Bmin, Cmin, Dmin, s)
print(f"s={s:3.1f}: original {g_old.ravel()[0]: .8f}, reduced {g_new.ravel()[0]: .8f}")
if __name__ == "__main__":
main()
10. C++ Implementation
The C++ version uses Eigen for matrix and SVD operations. In industrial C++ control software, Eigen is commonly used because it provides efficient dense linear algebra without requiring a large runtime dependency.
Chapter20_Lesson4.cpp
// Chapter20_Lesson4.cpp
// Basic rank-based realization-reduction diagnostics using Eigen.
// Compile example:
// g++ -std=c++17 Chapter20_Lesson4.cpp -I /path/to/eigen -O2 -o Chapter20_Lesson4
#include <Eigen/Dense>
#include <iostream>
#include <vector>
#include <cmath>
using Eigen::MatrixXd;
using Eigen::VectorXd;
MatrixXd controllabilityMatrix(const MatrixXd& A, const MatrixXd& B) {
const int n = A.rows();
MatrixXd R(n, n * B.cols());
MatrixXd Apow = MatrixXd::Identity(n, n);
for (int k = 0; k < n; ++k) {
R.block(0, k * B.cols(), n, B.cols()) = Apow * B;
Apow = Apow * A;
}
return R;
}
MatrixXd observabilityMatrix(const MatrixXd& A, const MatrixXd& C) {
const int n = A.rows();
MatrixXd O(n * C.rows(), n);
MatrixXd Apow = MatrixXd::Identity(n, n);
for (int k = 0; k < n; ++k) {
O.block(k * C.rows(), 0, C.rows(), n) = C * Apow;
Apow = Apow * A;
}
return O;
}
int svdRank(const MatrixXd& M, double tol = 1e-10) {
Eigen::JacobiSVD<MatrixXd> svd(M, Eigen::ComputeFullU | Eigen::ComputeFullV);
VectorXd s = svd.singularValues();
if (s.size() == 0) return 0;
int r = 0;
for (int i = 0; i < s.size(); ++i) if (s(i) > tol) ++r;
return r;
}
MatrixXd columnSpaceBasis(const MatrixXd& M) {
Eigen::JacobiSVD<MatrixXd> svd(M, Eigen::ComputeFullU | Eigen::ComputeFullV);
VectorXd s = svd.singularValues();
double tol = 1e-10;
int r = 0;
for (int i = 0; i < s.size(); ++i) if (s(i) > tol) ++r;
return svd.matrixU().leftCols(r);
}
MatrixXd nullSpaceBasis(const MatrixXd& M) {
Eigen::JacobiSVD<MatrixXd> svd(M, Eigen::ComputeFullU | Eigen::ComputeFullV);
VectorXd s = svd.singularValues();
double tol = 1e-10;
int r = 0;
for (int i = 0; i < s.size(); ++i) if (s(i) > tol) ++r;
return svd.matrixV().rightCols(M.cols() - r);
}
int main() {
MatrixXd A(3, 3);
A << -1.0, 0.0, 0.0,
0.0,-2.0, 0.0,
0.0, 0.0,-3.0;
MatrixXd B(3, 1);
B << 1.0, 0.0, 1.0;
MatrixXd C(1, 3);
C << 1.0, 0.0, 0.0;
MatrixXd D(1, 1);
D << 0.0;
MatrixXd R = controllabilityMatrix(A, B);
MatrixXd O = observabilityMatrix(A, C);
std::cout << "rank(R) = " << svdRank(R) << " of " << A.rows() << "\n";
std::cout << "rank(O) = " << svdRank(O) << " of " << A.rows() << "\n\n";
// Stage 1: reachable projection.
MatrixXd Qr = columnSpaceBasis(R);
MatrixXd A1 = Qr.transpose() * A * Qr;
MatrixXd B1 = Qr.transpose() * B;
MatrixXd C1 = C * Qr;
// Stage 2: unobservable quotient within the reachable subsystem.
MatrixXd O1 = observabilityMatrix(A1, C1);
MatrixXd Qun = nullSpaceBasis(O1);
int q = Qun.cols();
MatrixXd Amin, Bmin, Cmin;
if (q == 0) {
Amin = A1; Bmin = B1; Cmin = C1;
} else {
MatrixXd Qobs = nullSpaceBasis(Qun.transpose());
MatrixXd T(A1.rows(), A1.rows());
T << Qun, Qobs;
MatrixXd Ahat = T.transpose() * A1 * T;
MatrixXd Bhat = T.transpose() * B1;
MatrixXd Chat = C1 * T;
int m = A1.rows() - q;
Amin = Ahat.block(q, q, m, m);
Bmin = Bhat.block(q, 0, m, Bhat.cols());
Cmin = Chat.block(0, q, Chat.rows(), m);
}
std::cout << "Amin =\n" << Amin << "\n\n";
std::cout << "Bmin =\n" << Bmin << "\n\n";
std::cout << "Cmin =\n" << Cmin << "\n";
return 0;
}
11. Java Implementation
The Java version is deliberately library-free and demonstrates the rank tests using reduced row-echelon elimination. For production Java numerical work, libraries such as EJML, ojAlgo, or Apache Commons Math should be preferred.
Chapter20_Lesson4.java
// Chapter20_Lesson4.java
// Library-free educational implementation of controllability and observability ranks.
// For production Java control computation, use EJML, ojAlgo, or Apache Commons Math.
import java.util.Arrays;
public class Chapter20_Lesson4 {
static double[][] multiply(double[][] A, double[][] B) {
int m = A.length, n = B[0].length, p = B.length;
double[][] C = new double[m][n];
for (int i = 0; i < m; i++) {
for (int k = 0; k < p; k++) {
for (int j = 0; j < n; j++) C[i][j] += A[i][k] * B[k][j];
}
}
return C;
}
static double[][] eye(int n) {
double[][] I = new double[n][n];
for (int i = 0; i < n; i++) I[i][i] = 1.0;
return I;
}
static double[][] controllabilityMatrix(double[][] A, double[][] B) {
int n = A.length, m = B[0].length;
double[][] R = new double[n][n * m];
double[][] Apow = eye(n);
for (int k = 0; k < n; k++) {
double[][] block = multiply(Apow, B);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) R[i][k * m + j] = block[i][j];
}
Apow = multiply(Apow, A);
}
return R;
}
static double[][] observabilityMatrix(double[][] A, double[][] C) {
int n = A.length, p = C.length;
double[][] O = new double[n * p][n];
double[][] Apow = eye(n);
for (int k = 0; k < n; k++) {
double[][] block = multiply(C, Apow);
for (int i = 0; i < p; i++) {
for (int j = 0; j < n; j++) O[k * p + i][j] = block[i][j];
}
Apow = multiply(Apow, A);
}
return O;
}
static int rankRref(double[][] M, double tol) {
int rows = M.length, cols = M[0].length;
double[][] A = new double[rows][cols];
for (int i = 0; i < rows; i++) A[i] = Arrays.copyOf(M[i], cols);
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(A[i][c]) > Math.abs(A[pivot][c])) pivot = i;
}
if (Math.abs(A[pivot][c]) <= tol) continue;
double[] tmp = A[r]; A[r] = A[pivot]; A[pivot] = tmp;
double piv = A[r][c];
for (int j = c; j < cols; j++) A[r][j] /= piv;
for (int i = 0; i < rows; i++) {
if (i == r) continue;
double factor = A[i][c];
for (int j = c; j < cols; j++) A[i][j] -= factor * A[r][j];
}
r++;
}
return r;
}
static void printMatrix(String name, double[][] M) {
System.out.println(name + " =");
for (double[] row : M) System.out.println(Arrays.toString(row));
System.out.println();
}
public static void main(String[] args) {
double[][] A = {
{-1.0, 0.0, 0.0},
{ 0.0,-2.0, 0.0},
{ 0.0, 0.0,-3.0}
};
double[][] B = { {1.0}, {0.0}, {1.0} };
double[][] C = { {1.0, 0.0, 0.0} };
double[][] R = controllabilityMatrix(A, B);
double[][] O = observabilityMatrix(A, C);
printMatrix("Controllability matrix", R);
printMatrix("Observability matrix", O);
int n = A.length;
int rankR = rankRref(R, 1e-10);
int rankO = rankRref(O, 1e-10);
System.out.println("rank(R) = " + rankR + " of " + n);
System.out.println("rank(O) = " + rankO + " of " + n);
System.out.println("Conclusion: this realization is not minimal.");
System.out.println("For this diagonal example, the input-output map is G(s)=1/(s+1), so a minimal realization is A=[-1], B=[1], C=[1], D=[0].");
}
}
12. MATLAB/Simulink Implementation
MATLAB directly supports state-space objects through
ss, reachability and observability matrices through
ctrb and obsv, and exact/minimal
simplification through minreal. The following script also
includes local implementations of the matrices so that the algorithmic
idea is visible. In Simulink, the reduced state-space matrices can be
placed directly in a State-Space block after verification of
the transfer function.
Chapter20_Lesson4.m
% Chapter20_Lesson4.m
% Basic algorithms for exact realization reduction.
% Uses MATLAB functions orth, null, rank. Control System Toolbox functions
% ctrb, obsv, ss, and minreal are also shown for comparison.
clear; clc;
A = diag([-1 -2 -3]);
B = [1; 0; 1];
C = [1 0 0];
D = 0;
R = local_ctrb(A,B);
O = local_obsv(A,C);
fprintf('rank(R) = %d of %d\n', rank(R), size(A,1));
fprintf('rank(O) = %d of %d\n', rank(O), size(A,1));
[Amin,Bmin,Cmin,Dmin] = exact_minimal_reduction(A,B,C,D);
disp('Amin ='); disp(Amin);
disp('Bmin ='); disp(Bmin);
disp('Cmin ='); disp(Cmin);
disp('Dmin ='); disp(Dmin);
% Optional Control System Toolbox comparison:
% sys = ss(A,B,C,D);
% sys_min = minreal(sys);
% disp(sys_min);
function R = local_ctrb(A,B)
n = size(A,1);
R = [];
Apow = eye(n);
for k = 1:n
R = [R, Apow*B]; %#ok<AGROW>
Apow = Apow*A;
end
end
function O = local_obsv(A,C)
n = size(A,1);
O = [];
Apow = eye(n);
for k = 1:n
O = [O; C*Apow]; %#ok<AGROW>
Apow = Apow*A;
end
end
function [Amin,Bmin,Cmin,Dmin] = exact_minimal_reduction(A,B,C,D)
% Stage 1: reachable restriction.
R = local_ctrb(A,B);
Qr = orth(R);
A1 = Qr'*A*Qr;
B1 = Qr'*B;
C1 = C*Qr;
% Stage 2: observable quotient inside reachable part.
O1 = local_obsv(A1,C1);
Qun = null(O1);
q = size(Qun,2);
if q == 0
Amin = A1; Bmin = B1; Cmin = C1; Dmin = D;
return;
end
Qobs = null(Qun');
T = [Qun, Qobs];
Ahat = T'*A1*T;
Bhat = T'*B1;
Chat = C1*T;
Amin = Ahat(q+1:end, q+1:end);
Bmin = Bhat(q+1:end, :);
Cmin = Chat(:, q+1:end);
Dmin = D;
end
13. Wolfram Mathematica Implementation
Mathematica is useful for exact symbolic ranks and for checking whether a cancellation is structural rather than merely numerical. The notebook source below constructs reachability and observability matrices, performs the two trimming stages, and compares transfer-function models.
Chapter20_Lesson4.nb
(* Chapter20_Lesson4.nb *)
(* Wolfram Mathematica educational notebook source. Open as a notebook or paste into Mathematica. *)
ClearAll[controllabilityMatrix, observabilityMatrix, exactMinimalReduction];
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}]
];
exactMinimalReduction[A_, B_, C_, D_] := Module[
{R, Qr, A1, B1, C1, O1, Qun, q, Qobs, T, Ahat, Bhat, Chat},
R = controllabilityMatrix[A, B];
Qr = Orthogonalize[Transpose[RowReduce[Transpose[R]]]];
Qr = Select[Qr, Norm[#] > 10^-10 &] // Transpose;
A1 = Transpose[Qr].A.Qr;
B1 = Transpose[Qr].B;
C1 = C.Qr;
O1 = observabilityMatrix[A1, C1];
Qun = Transpose[NullSpace[O1]];
q = If[MatrixQ[Qun], Dimensions[Qun][[2]], 0];
If[q == 0, Return[{A1, B1, C1, D}]];
Qobs = Transpose[NullSpace[Transpose[Qun]]];
T = ArrayFlatten[{ {Qun, Qobs} }];
Ahat = Transpose[T].A1.T;
Bhat = Transpose[T].B1;
Chat = C1.T;
{Ahat[[q + 1 ;;, q + 1 ;;]], Bhat[[q + 1 ;;, All]], Chat[[All, q + 1 ;;]], D}
];
A = DiagonalMatrix[{-1, -2, -3}];
B = { {1}, {0}, {1} };
Cmat = { {1, 0, 0} };
Dmat = { {0} };
R = controllabilityMatrix[A, B];
O = observabilityMatrix[A, Cmat];
Print["rank(R) = ", MatrixRank[R], " of ", Length[A]];
Print["rank(O) = ", MatrixRank[O], " of ", Length[A]];
{Amin, Bmin, Cmin, Dmin} = exactMinimalReduction[A, B, Cmat, Dmat];
Print["Amin = ", MatrixForm[Amin]];
Print["Bmin = ", MatrixForm[Bmin]];
Print["Cmin = ", MatrixForm[Cmin]];
Print["Dmin = ", MatrixForm[Dmin]];
TransferFunctionModel[StateSpaceModel[{A, B, Cmat, Dmat}], s]
TransferFunctionModel[StateSpaceModel[{Amin, Bmin, Cmin, Dmin}], s]
14. Problems and Solutions
Problem 1 (Reachability Trimming): Let \( \mathbf{A}=\operatorname{diag}(-1,-2) \), \( \mathbf{B}=\begin{bmatrix}1&0\end{bmatrix}^T \), \( \mathbf{C}=\begin{bmatrix}1&1\end{bmatrix} \), and \( \mathbf{D}=0 \). Determine whether the realization is reachable and construct a reduced realization.
Solution: The reachability matrix is
\[ \mathcal{R}=\begin{bmatrix}\mathbf{B}&\mathbf{AB}\end{bmatrix} =\begin{bmatrix}1&-1\\0&0\end{bmatrix},\qquad \operatorname{rank}(\mathcal{R})=1. \]
Only the first state is reachable. Taking \( \mathbf{T}_r=\begin{bmatrix}1&0\end{bmatrix}^T \) gives
\[ A_r=-1, \qquad B_r=1, \qquad C_r=1, \qquad D_r=0. \]
The second state affects neither the response from zero initial condition nor the transfer function.
Problem 2 (Observability Trimming): Let \( \mathbf{A}=\operatorname{diag}(-1,-3) \), \( \mathbf{B}=\begin{bmatrix}1&1\end{bmatrix}^T \), \( \mathbf{C}=\begin{bmatrix}1&0\end{bmatrix} \), and \( \mathbf{D}=0 \). Is the realization minimal?
Solution: The reachability matrix is
\[ \mathcal{R}=\begin{bmatrix}1&-1\\1&-3\end{bmatrix}, \qquad \det(\mathcal{R})=-2, \]
so the realization is reachable. The observability matrix is
\[ \mathcal{O}=\begin{bmatrix}1&0\\-1&0\end{bmatrix}, \qquad \operatorname{rank}(\mathcal{O})=1. \]
Hence the second state is unobservable and the realization is not minimal. The transfer function is \( G(s)=1/(s+1) \), so a minimal realization is \( A_{min}=-1, B_{min}=1, C_{min}=1, D_{min}=0 \).
Problem 3 (Proof by Markov Parameters): Suppose \( \operatorname{range}(\mathbf{T}_r)=\mathscr{R} \) and \( \mathbf{B}=\mathbf{T}_r\mathbf{B}_r \), \( \mathbf{A}\mathbf{T}_r=\mathbf{T}_r\mathbf{A}_r \). Prove that reachability trimming preserves the transfer matrix.
Solution: For \( k=0 \), \( \mathbf{A}^0\mathbf{B}=\mathbf{B}=\mathbf{T}_r\mathbf{B}_r \). Assume \( \mathbf{A}^k\mathbf{B}=\mathbf{T}_r\mathbf{A}_r^k\mathbf{B}_r \). Then
\[ \mathbf{A}^{k+1}\mathbf{B} =\mathbf{A}\mathbf{T}_r\mathbf{A}_r^k\mathbf{B}_r =\mathbf{T}_r\mathbf{A}_r^{k+1}\mathbf{B}_r. \]
Therefore \( \mathbf{C}\mathbf{A}^k\mathbf{B}=\mathbf{C}_r\mathbf{A}_r^k\mathbf{B}_r \) for all \( k \). Since the direct term \( \mathbf{D} \) is unchanged, the transfer matrices are equal.
Problem 4 (Hankel Rank): A SISO discrete-time strictly proper system has Markov parameters \( H_k=2^{k-1}+3^{k-1} \) for \( k=1,2,\dots \). Use the Hankel idea to determine the minimal order.
Solution: Build a two-row Hankel matrix:
\[ \mathcal{H}_{2,2}=\begin{bmatrix} H_1&H_2\\H_2&H_3 \end{bmatrix} =\begin{bmatrix}2&5\\5&13\end{bmatrix}, \qquad \det(\mathcal{H}_{2,2})=26-25=1. \]
Thus \( \operatorname{rank}(\mathcal{H}_{2,2})=2 \), so the minimal order is at least 2. Since the sequence is the sum of two independent exponential modes, the minimal order is exactly 2.
Problem 5 (Dimension Formula): A realization has \( \dim(\mathscr{R})=4 \) and \( \dim(\mathscr{R}\cap\mathscr{N})=1 \). What is the order of the minimal realization obtained by exact trimming?
Solution: Exact trimming first restricts the system to the 4-dimensional reachable subspace. It then removes the 1-dimensional component that is reachable but unobservable. Hence
\[ n_{min}=\dim(\mathscr{R})-\dim(\mathscr{R}\cap\mathscr{N})=4-1=3. \]
15. Summary
Exact realization reduction is based on two algebraic eliminations: remove states outside the reachable subspace and remove states inside the unobservable subspace of the reachable part. Rank-revealing bases obtained from reachability and observability matrices produce the reduced coordinates. The Ho-Kalman/Hankel viewpoint reaches the same conclusion from input-output Markov parameters: the rank of the Hankel matrix reveals the minimal dynamic order. In exact arithmetic, these algorithms preserve the transfer matrix exactly; in floating-point arithmetic, rank tolerance and conditioning become central.
16. References
- 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. Journal of the Society for Industrial and Applied Mathematics, Series A: Control, 1(2), 128–151.
- Ho, B.L., & Kalman, R.E. (1966). Effective construction of linear state-variable models from input/output functions. Regelungstechnik, 14, 545–548.
- Rosenbrock, H.H. (1967). The stability of multivariable systems. IEEE Transactions on Automatic Control, 12(5), 505–512.
- Silverman, L.M. (1971). Realization of linear dynamical systems. IEEE Transactions on Automatic Control, 16(6), 554–567.
- Kung, S.Y. (1978). A new identification and model reduction algorithm via singular value decomposition. Proceedings of the 12th Asilomar Conference on Circuits, Systems and Computers, 705–714.
- Moore, B.C. (1981). Principal component analysis in linear systems: controllability, observability, and model reduction. IEEE Transactions on Automatic Control, 26(1), 17–32.
- Glover, K. (1984). All optimal Hankel-norm approximations of linear multivariable systems and their L-infinity error bounds. International Journal of Control, 39(6), 1115–1193.
- Laub, A.J., Heath, M.T., Paige, C.C., & Ward, R.C. (1987). Computation of system balancing transformations and other applications of simultaneous diagonalization algorithms. IEEE Transactions on Automatic Control, 32(2), 115–122.