Chapter 20: Minimal Realizations and Realization Theory
Lesson 1: Definition of Minimal Realization (Order, Reachability, Observability)
This lesson defines a minimal state-space realization of a transfer function or transfer matrix, relates minimal order to reachability and observability, and proves the central theorem: a finite-dimensional LTI realization is minimal if and only if it is both reachable and observable. We also connect this theorem to the Hankel matrix, cancelled modes, and practical rank tests used in computational control.
1. Realization and Order
A continuous-time, finite-dimensional, linear time-invariant system is represented by \( \dot{\mathbf{x} }(t)=\mathbf{A}\mathbf{x}(t)+\mathbf{B}\mathbf{u}(t) \), \( \mathbf{y}(t)=\mathbf{C}\mathbf{x}(t)+\mathbf{D}\mathbf{u}(t) \), where \( \mathbf{x}\in\mathbb{R}^n \), \( \mathbf{u}\in\mathbb{R}^m \), and \( \mathbf{y}\in\mathbb{R}^p \). The quadruple \( (\mathbf{A},\mathbf{B},\mathbf{C},\mathbf{D}) \) is called a realization of the transfer matrix \( \mathbf{G}(s) \) if
\[ \mathbf{G}(s)=\mathbf{C}(s\mathbf{I}-\mathbf{A})^{-1}\mathbf{B}+\mathbf{D}. \]
The order of the realization is the dimension \( n \) of the state vector. Many different state coordinate choices may realize the same input-output map. Therefore, order is not a property of a coordinate basis alone; it is a property of how many internal coordinates are needed to reproduce the same external transfer behavior.
A realization of order \( n \) is called minimal if no realization of the same \( \mathbf{G}(s) \) exists with smaller order. Equivalently, it has no redundant internal state coordinate that is invisible from the input-output behavior.
\[ (\mathbf{A},\mathbf{B},\mathbf{C},\mathbf{D})\text{ is minimal} \quad\Longleftrightarrow\quad n = \min\{ r:\exists (\mathbf{A}_r,\mathbf{B}_r,\mathbf{C}_r,\mathbf{D}) \text{ realizing }\mathbf{G}(s)\}. \]
The feedthrough matrix \( \mathbf{D} \) affects the instantaneous input-output term, but it does not add dynamic state order. Minimal order is determined by the dynamic part \( \mathbf{C}(s\mathbf{I}-\mathbf{A})^{-1}\mathbf{B} \).
2. Reachability and Observability Conditions
A state direction is dynamically useful in a realization only if it can be excited by the input and can influence the output. For the LTI realization above, the finite-dimensional reachability and observability matrices are
\[ \mathcal{R}_n = \begin{bmatrix} \mathbf{B} & \mathbf{A}\mathbf{B} & \mathbf{A}^2\mathbf{B} & \cdots & \mathbf{A}^{n-1}\mathbf{B} \end{bmatrix}, \]
\[ \mathcal{O}_n = \begin{bmatrix} \mathbf{C} \\ \mathbf{C}\mathbf{A} \\ \mathbf{C}\mathbf{A}^2 \\ \vdots \\ \mathbf{C}\mathbf{A}^{n-1} \end{bmatrix}. \]
The pair \( (\mathbf{A},\mathbf{B}) \) is reachable if \( \operatorname{rank}(\mathcal{R}_n)=n \). The pair \( (\mathbf{C},\mathbf{A}) \) is observable if \( \operatorname{rank}(\mathcal{O}_n)=n \). Minimality is exactly the simultaneous satisfaction of these two rank conditions.
\[ \boxed{ (\mathbf{A},\mathbf{B},\mathbf{C},\mathbf{D})\text{ minimal} \quad\Longleftrightarrow\quad \operatorname{rank}(\mathcal{R}_n)=n \text{ and } \operatorname{rank}(\mathcal{O}_n)=n }. \]
flowchart TD
A["State-space realization"] --> B["Check reachable directions"]
A --> C["Check observable directions"]
B --> D{"rank(R_n) = n ?"}
C --> E{"rank(O_n) = n ?"}
D -->|"no"| F["Redundant \ninput-unreachable \ndynamics"]
E -->|"no"| G["Redundant \noutput-invisible \ndynamics"]
D -->|"yes"| H["No unreachable \nstate direction"]
E -->|"yes"| I["No unobservable \nstate direction"]
H --> J{"both conditions true?"}
I --> J
J -->|"yes"| K["minimal realization"]
J -->|"no"| L["nonminimal realization"]
3. Main Minimality Theorem
Theorem: Let \( (\mathbf{A},\mathbf{B},\mathbf{C},\mathbf{D}) \) be a finite-dimensional realization of \( \mathbf{G}(s) \). The realization is minimal if and only if \( (\mathbf{A},\mathbf{B}) \) is reachable and \( (\mathbf{C},\mathbf{A}) \) is observable.
Proof, nonminimal direction: Suppose the realization is not reachable. Then the reachable subspace \( \mathcal{X}_r=\operatorname{im}(\mathcal{R}_n) \) has dimension \( r<n \). Choose a nonsingular coordinate transformation \( \mathbf{T} \) whose first \( r \) columns span \( \mathcal{X}_r \). In the transformed coordinates \( \bar{\mathbf{x} }=\mathbf{T}^{-1}\mathbf{x} \), the system has the form
\[ \bar{\mathbf{A} }= \begin{bmatrix} \mathbf{A}_r & \mathbf{A}_{12} \\ \mathbf{0} & \mathbf{A}_u \end{bmatrix}, \quad \bar{\mathbf{B} }= \begin{bmatrix} \mathbf{B}_r \\ \mathbf{0} \end{bmatrix}, \quad \bar{\mathbf{C} }= \begin{bmatrix} \mathbf{C}_r & \mathbf{C}_u \end{bmatrix}. \]
With zero initial condition, the lower block is never excited by any input. Hence the transfer matrix is
\[ \mathbf{G}(s)= \mathbf{C}_r(s\mathbf{I}-\mathbf{A}_r)^{-1}\mathbf{B}_r +\mathbf{D}, \]
so a lower-order realization exists. Therefore a nonreachable realization cannot be minimal. The same argument by duality applies if the realization is unobservable: an unobservable state component cannot influence the output, so it can be removed without changing \( \mathbf{G}(s) \).
Proof, minimal direction: Suppose the realization is reachable and observable. Define the Markov parameters by expanding the transfer matrix about infinity:
\[ \mathbf{G}(s)=\mathbf{D}+ \sum_{k=1}^\infty \frac{\mathbf{C}\mathbf{A}^{k-1}\mathbf{B} }{s^k}, \quad \mathbf{H}_k=\mathbf{C}\mathbf{A}^{k-1}\mathbf{B}. \]
Form a block Hankel matrix from these parameters:
\[ \mathcal{H}= \begin{bmatrix} \mathbf{H}_1 & \mathbf{H}_2 & \cdots \\ \mathbf{H}_2 & \mathbf{H}_3 & \cdots \\ \vdots & \vdots & \ddots \end{bmatrix} = \begin{bmatrix} \mathbf{C} \\ \mathbf{C}\mathbf{A} \\ \vdots \end{bmatrix} \begin{bmatrix} \mathbf{B} & \mathbf{A}\mathbf{B} & \cdots \end{bmatrix} =\mathcal{O}_\infty\mathcal{R}_\infty. \]
Since the realization is reachable and observable, the finite sections \( \mathcal{R}_n \) and \( \mathcal{O}_n \) have rank \( n \). Thus the Hankel matrix has rank \( n \). Any other realization of order \( m \) of the same transfer matrix produces the same Markov parameters and therefore the same Hankel matrix, but its Hankel factorization has rank at most \( m \). Hence \( n\le m \). No smaller realization exists, so the reachable and observable realization is minimal.
4. Minimal Order, Hankel Rank, and McMillan Degree
The proof above shows that the minimal state dimension is equal to the rank of the Hankel matrix built from the Markov parameters. For a proper rational transfer matrix, this number is also called the McMillan degree.
\[ n_{\min} = \operatorname{rank}(\mathcal{H}) = \deg_M \mathbf{G}(s). \]
In SISO transfer functions, the same idea appears as pole-zero cancellation. For example,
\[ G(s)=\frac{s+1}{(s+1)(s+2)}=\frac{1}{s+2}. \]
A two-state realization may contain a mode at \( s=-1 \), but if that mode is cancelled in the external transfer function, then the external behavior needs only one dynamic state. Minimality therefore rejects internally stored modes that do not appear in the input-output map.
In MIMO systems, cancellations are not always visible by looking at one scalar denominator. The rank tests \( \operatorname{rank}(\mathcal{R}_n)=n \) and \( \operatorname{rank}(\mathcal{O}_n)=n \) remain the coordinate-invariant way to test minimality.
5. Coordinate Invariance and Uniqueness up to Similarity
Minimality is independent of the coordinate basis used to describe the state. If \( \mathbf{T} \) is nonsingular and \( \bar{\mathbf{x} }=\mathbf{T}^{-1}\mathbf{x} \), then
\[ \bar{\mathbf{A} }=\mathbf{T}^{-1}\mathbf{A}\mathbf{T}, \quad \bar{\mathbf{B} }=\mathbf{T}^{-1}\mathbf{B}, \quad \bar{\mathbf{C} }=\mathbf{C}\mathbf{T}, \quad \bar{\mathbf{D} }=\mathbf{D}. \]
The transfer matrix is unchanged because
\[ \bar{\mathbf{C} }(s\mathbf{I}-\bar{\mathbf{A} })^{-1} \bar{\mathbf{B} }+\bar{\mathbf{D} } = \mathbf{C}(s\mathbf{I}-\mathbf{A})^{-1}\mathbf{B}+\mathbf{D}. \]
Reachability and observability ranks are also invariant under this transformation:
\[ \bar{\mathcal{R} }_n =\mathbf{T}^{-1}\mathcal{R}_n, \quad \bar{\mathcal{O} }_n=\mathcal{O}_n\mathbf{T}. \]
A stronger fact is true: any two minimal realizations of the same transfer matrix are similar. Thus minimal realization is unique up to a nonsingular change of state coordinates, not unique as a literal numerical quadruple.
\[ \mathbf{A}_2=\mathbf{T}^{-1}\mathbf{A}_1\mathbf{T}, \quad \mathbf{B}_2=\mathbf{T}^{-1}\mathbf{B}_1, \quad \mathbf{C}_2=\mathbf{C}_1\mathbf{T}, \quad \mathbf{D}_2=\mathbf{D}_1. \]
6. How Nonminimal Realizations Appear
Nonminimal realizations appear when modeling introduces internal states that are not present in the final external map. Common causes include algebraic pole-zero cancellation, unnecessary cascaded filters, states added during augmentation, and coordinate choices that retain both useful and redundant directions.
The Kalman decomposition from the previous chapter separates the state space into reachable-observable, reachable-unobservable, unreachable-observable, and unreachable-unobservable components. Only the reachable-observable block is required for a minimal realization.
flowchart LR
X["Full state space"] --> RO["reachable and observable"]
X --> RU["reachable but unobservable"]
X --> UO["unreachable but observable"]
X --> UU["unreachable and unobservable"]
RO --> M["kept in minimal realization"]
RU --> R1["remove: output-invisible"]
UO --> R2["remove: input-unreachable"]
UU --> R3["remove: neither excited \nnor measured"]
In transformed Kalman coordinates, the transfer matrix depends only on the reachable-observable portion. Symbolically,
\[ \mathbf{G}(s) =\mathbf{C}_{ro}(s\mathbf{I}-\mathbf{A}_{ro})^{-1} \mathbf{B}_{ro}+\mathbf{D}. \]
7. Worked Example: A Cancelled Internal Mode
Consider the two-state realization
\[ \mathbf{A}= \begin{bmatrix} -1 & 0 \\ 0 & -2 \end{bmatrix}, \quad \mathbf{B}= \begin{bmatrix} 1 \\ 1 \end{bmatrix}, \quad \mathbf{C}= \begin{bmatrix} 0 & 1 \end{bmatrix}, \quad \mathbf{D}=0. \]
Its transfer function is
\[ G(s)= \begin{bmatrix}0&1\end{bmatrix} \begin{bmatrix} \frac{1}{s+1} & 0 \\ 0 & \frac{1}{s+2} \end{bmatrix} \begin{bmatrix} 1 \\ 1 \end{bmatrix} = \frac{1}{s+2}. \]
The reachability matrix is full rank:
\[ \mathcal{R}_2 = \begin{bmatrix} 1 & -1 \\ 1 & -2 \end{bmatrix}, \quad \operatorname{rank}(\mathcal{R}_2)=2. \]
But the observability matrix is rank deficient:
\[ \mathcal{O}_2 = \begin{bmatrix} 0 & 1 \\ 0 & -2 \end{bmatrix}, \quad \operatorname{rank}(\mathcal{O}_2)=1. \]
Therefore this realization is not minimal. The one-state minimal realization of the same transfer function is
\[ \dot{x}=-2x+u, \quad y=x, \quad A_m=-2,\; B_m=1,\; C_m=1,\; D_m=0. \]
8. Computational Implementation
The following implementations compute reachability and observability matrices, evaluate minimality by rank tests, and compare a nonminimal two-state realization with a one-state minimal realization of the same transfer function.
Chapter20_Lesson1.py
# Chapter20_Lesson1.py
# Minimal realization tests for continuous-time LTI systems.
# Requires: numpy
#
# The transfer matrix is G(s) = C (sI - A)^(-1) B + D.
# A realization is minimal iff (A,B) is reachable and (C,A) is observable.
import numpy as np
def matrix_rank(M, tol=1e-10):
"""Numerical rank using singular values."""
s = np.linalg.svd(np.asarray(M, dtype=float), compute_uv=False)
return int(np.sum(s > tol))
def reachability_matrix(A, B):
"""R_n = [B, AB, ..., A^(n-1)B]."""
A = np.asarray(A, dtype=float)
B = np.asarray(B, dtype=float)
n = A.shape[0]
blocks = []
Ak = np.eye(n)
for _ in range(n):
blocks.append(Ak @ B)
Ak = A @ Ak
return np.hstack(blocks)
def observability_matrix(A, C):
"""O_n = [C; CA; ...; CA^(n-1)]."""
A = np.asarray(A, dtype=float)
C = np.asarray(C, dtype=float)
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 is_reachable(A, B, tol=1e-10):
A = np.asarray(A, dtype=float)
return matrix_rank(reachability_matrix(A, B), tol) == A.shape[0]
def is_observable(A, C, tol=1e-10):
A = np.asarray(A, dtype=float)
return matrix_rank(observability_matrix(A, C), tol) == A.shape[0]
def is_minimal(A, B, C, tol=1e-10):
"""Kalman minimality test."""
return is_reachable(A, B, tol) and is_observable(A, C, tol)
def markov_parameters(A, B, C, D, count=8):
"""
Returns h_0, h_1, ..., h_count where
h_0 = D and h_k = C A^(k-1) B for k >= 1.
"""
A = np.asarray(A, dtype=float)
B = np.asarray(B, dtype=float)
C = np.asarray(C, dtype=float)
D = np.asarray(D, dtype=float)
params = [D]
Ak = np.eye(A.shape[0])
for _ in range(1, count + 1):
params.append(C @ Ak @ B)
Ak = A @ Ak
return params
def block_hankel_from_markov(h, rows, cols):
"""
Builds the block Hankel matrix
H = [h_{i+j+1}] for i=0,...,rows-1 and j=0,...,cols-1.
This uses strictly proper Markov parameters h_1, h_2, ...
"""
return np.block([[h[i + j + 1] for j in range(cols)] for i in range(rows)])
def transfer_value(A, B, C, D, s):
"""Evaluate G(s) at a scalar complex frequency s."""
A = np.asarray(A, dtype=float)
B = np.asarray(B, dtype=float)
C = np.asarray(C, dtype=float)
D = np.asarray(D, dtype=float)
n = A.shape[0]
return C @ np.linalg.solve(s * np.eye(n) - A, B) + D
def report(name, A, B, C, D):
R = reachability_matrix(A, B)
O = observability_matrix(A, C)
h = markov_parameters(A, B, C, D, count=10)
H = block_hankel_from_markov(h, rows=3, cols=3)
print(f"\n{name}")
print("-" * len(name))
print("A =\n", np.asarray(A, dtype=float))
print("B =\n", np.asarray(B, dtype=float))
print("C =\n", np.asarray(C, dtype=float))
print("D =\n", np.asarray(D, dtype=float))
print("rank(R_n) =", matrix_rank(R), "of n =", np.asarray(A).shape[0])
print("rank(O_n) =", matrix_rank(O), "of n =", np.asarray(A).shape[0])
print("minimal? =", is_minimal(A, B, C))
print("estimated Hankel rank =", matrix_rank(H))
if __name__ == "__main__":
# Nonminimal realization: one unobservable mode at -1 is present internally,
# but the transfer function is only G(s) = 1/(s+2).
A_nonmin = np.array([[-1.0, 0.0],
[ 0.0,-2.0]])
B_nonmin = np.array([[1.0],
[1.0]])
C_nonmin = np.array([[0.0, 1.0]])
D_nonmin = np.array([[0.0]])
# Minimal realization of the same external behavior G(s) = 1/(s+2).
A_min = np.array([[-2.0]])
B_min = np.array([[1.0]])
C_min = np.array([[1.0]])
D_min = np.array([[0.0]])
report("Two-state nonminimal realization", A_nonmin, B_nonmin, C_nonmin, D_nonmin)
report("One-state minimal realization", A_min, B_min, C_min, D_min)
for s in [1.0, 2.0, 3.0]:
g1 = transfer_value(A_nonmin, B_nonmin, C_nonmin, D_nonmin, s)
g2 = transfer_value(A_min, B_min, C_min, D_min, s)
print(f"G_nonminimal({s}) = {g1[0,0]:.6f}, G_minimal({s}) = {g2[0,0]:.6f}")
Chapter20_Lesson1.cpp
// Chapter20_Lesson1.cpp
// Minimal realization tests for continuous-time LTI systems.
// Compile: g++ -std=c++17 Chapter20_Lesson1.cpp -O2 -o Chapter20_Lesson1
//
// The transfer matrix is G(s) = C (sI - A)^(-1) B + D.
// A realization is minimal iff (A,B) is reachable and (C,A) is observable.
#include <cmath>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
using Matrix = std::vector<std::vector<double>>;
Matrix zeros(int r, int c) {
return Matrix(r, std::vector<double>(c, 0.0));
}
Matrix identity(int n) {
Matrix I = zeros(n, n);
for (int i = 0; i < n; ++i) I[i][i] = 1.0;
return I;
}
Matrix multiply(const Matrix& A, const Matrix& B) {
int r = static_cast<int>(A.size());
int k = static_cast<int>(A[0].size());
int c = static_cast<int>(B[0].size());
if (static_cast<int>(B.size()) != k) throw std::runtime_error("Dimension mismatch.");
Matrix M = zeros(r, c);
for (int i = 0; i < r; ++i)
for (int j = 0; j < c; ++j)
for (int t = 0; t < k; ++t)
M[i][j] += A[i][t] * B[t][j];
return M;
}
Matrix hstack(const std::vector<Matrix>& blocks) {
int r = static_cast<int>(blocks[0].size());
int totalCols = 0;
for (const auto& B : blocks) totalCols += static_cast<int>(B[0].size());
Matrix M = zeros(r, totalCols);
int col0 = 0;
for (const auto& B : blocks) {
int c = static_cast<int>(B[0].size());
for (int i = 0; i < r; ++i)
for (int j = 0; j < c; ++j)
M[i][col0 + j] = B[i][j];
col0 += c;
}
return M;
}
Matrix vstack(const std::vector<Matrix>& blocks) {
int c = static_cast<int>(blocks[0][0].size());
int totalRows = 0;
for (const auto& B : blocks) totalRows += static_cast<int>(B.size());
Matrix M = zeros(totalRows, c);
int row0 = 0;
for (const auto& B : blocks) {
int r = static_cast<int>(B.size());
for (int i = 0; i < r; ++i)
for (int j = 0; j < c; ++j)
M[row0 + i][j] = B[i][j];
row0 += r;
}
return M;
}
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 reachabilityMatrix(const Matrix& A, const Matrix& B) {
int n = static_cast<int>(A.size());
std::vector<Matrix> blocks;
Matrix Ak = identity(n);
for (int k = 0; k < n; ++k) {
blocks.push_back(multiply(Ak, B));
Ak = multiply(A, Ak);
}
return hstack(blocks);
}
Matrix observabilityMatrix(const Matrix& A, const Matrix& C) {
int n = static_cast<int>(A.size());
std::vector<Matrix> blocks;
Matrix Ak = identity(n);
for (int k = 0; k < n; ++k) {
blocks.push_back(multiply(C, Ak));
Ak = multiply(Ak, A);
}
return vstack(blocks);
}
bool isReachable(const Matrix& A, const Matrix& B) {
return rank(reachabilityMatrix(A, B)) == static_cast<int>(A.size());
}
bool isObservable(const Matrix& A, const Matrix& C) {
return rank(observabilityMatrix(A, C)) == static_cast<int>(A.size());
}
bool isMinimal(const Matrix& A, const Matrix& B, const Matrix& C) {
return isReachable(A, B) && isObservable(A, C);
}
void report(const std::string& name, const Matrix& A, const Matrix& B, const Matrix& C) {
std::cout << "\n" << name << "\n";
std::cout << std::string(name.size(), '-') << "\n";
std::cout << "rank(R_n) = " << rank(reachabilityMatrix(A, B))
<< " of n = " << A.size() << "\n";
std::cout << "rank(O_n) = " << rank(observabilityMatrix(A, C))
<< " of n = " << A.size() << "\n";
std::cout << "minimal? = " << (isMinimal(A, B, C) ? "yes" : "no") << "\n";
}
int main() {
Matrix A_nonmin = { {-1.0, 0.0},
{ 0.0,-2.0} };
Matrix B_nonmin = { {1.0},
{1.0} };
Matrix C_nonmin = { {0.0, 1.0} };
Matrix A_min = { {-2.0} };
Matrix B_min = { {1.0} };
Matrix C_min = { {1.0} };
report("Two-state nonminimal realization", A_nonmin, B_nonmin, C_nonmin);
report("One-state minimal realization", A_min, B_min, C_min);
std::cout << "\nBoth realizations have external transfer behavior G(s)=1/(s+2),\n";
std::cout << "but the first realization contains one unobservable internal mode.\n";
return 0;
}
Chapter20_Lesson1.java
// Chapter20_Lesson1.java
// Minimal realization tests for continuous-time LTI systems.
// Compile: javac Chapter20_Lesson1.java
// Run: java Chapter20_Lesson1
//
// The transfer matrix is G(s) = C (sI - A)^(-1) B + D.
// A realization is minimal iff (A,B) is reachable and (C,A) is observable.
public class Chapter20_Lesson1 {
static double[][] zeros(int r, int c) {
return new double[r][c];
}
static double[][] identity(int n) {
double[][] I = zeros(n, n);
for (int i = 0; i < n; i++) I[i][i] = 1.0;
return I;
}
static double[][] multiply(double[][] A, double[][] B) {
int r = A.length;
int k = A[0].length;
int c = B[0].length;
if (B.length != k) throw new IllegalArgumentException("Dimension mismatch.");
double[][] M = zeros(r, c);
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
for (int t = 0; t < k; t++) {
M[i][j] += A[i][t] * B[t][j];
}
}
}
return M;
}
static double[][] hstack(double[][][] blocks) {
int r = blocks[0].length;
int totalCols = 0;
for (double[][] B : blocks) totalCols += B[0].length;
double[][] M = zeros(r, totalCols);
int col0 = 0;
for (double[][] B : blocks) {
for (int i = 0; i < r; i++) {
for (int j = 0; j < B[0].length; j++) {
M[i][col0 + j] = B[i][j];
}
}
col0 += B[0].length;
}
return M;
}
static double[][] vstack(double[][][] blocks) {
int c = blocks[0][0].length;
int totalRows = 0;
for (double[][] B : blocks) totalRows += B.length;
double[][] M = zeros(totalRows, c);
int row0 = 0;
for (double[][] B : blocks) {
for (int i = 0; i < B.length; i++) {
for (int j = 0; j < c; j++) {
M[row0 + i][j] = B[i][j];
}
}
row0 += B.length;
}
return M;
}
static int rank(double[][] input, double tol) {
int rows = input.length;
int cols = input[0].length;
double[][] M = new double[rows][cols];
for (int i = 0; i < rows; i++) System.arraycopy(input[i], 0, M[i], 0, 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(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[][] reachabilityMatrix(double[][] A, double[][] B) {
int n = A.length;
double[][][] blocks = new double[n][][];
double[][] Ak = identity(n);
for (int k = 0; k < n; k++) {
blocks[k] = multiply(Ak, B);
Ak = multiply(A, Ak);
}
return hstack(blocks);
}
static double[][] observabilityMatrix(double[][] A, double[][] C) {
int n = A.length;
double[][][] blocks = new double[n][][];
double[][] Ak = identity(n);
for (int k = 0; k < n; k++) {
blocks[k] = multiply(C, Ak);
Ak = multiply(Ak, A);
}
return vstack(blocks);
}
static boolean isReachable(double[][] A, double[][] B) {
return rank(reachabilityMatrix(A, B), 1e-10) == A.length;
}
static boolean isObservable(double[][] A, double[][] C) {
return rank(observabilityMatrix(A, C), 1e-10) == A.length;
}
static boolean isMinimal(double[][] A, double[][] B, double[][] C) {
return isReachable(A, B) && isObservable(A, C);
}
static void report(String name, double[][] A, double[][] B, double[][] C) {
System.out.println("\n" + name);
System.out.println("-".repeat(name.length()));
System.out.println("rank(R_n) = " + rank(reachabilityMatrix(A, B), 1e-10) + " of n = " + A.length);
System.out.println("rank(O_n) = " + rank(observabilityMatrix(A, C), 1e-10) + " of n = " + A.length);
System.out.println("minimal? = " + (isMinimal(A, B, C) ? "yes" : "no"));
}
public static void main(String[] args) {
double[][] A_nonmin = { {-1.0, 0.0},
{ 0.0,-2.0} };
double[][] B_nonmin = { {1.0},
{1.0} };
double[][] C_nonmin = { {0.0, 1.0} };
double[][] A_min = { {-2.0} };
double[][] B_min = { {1.0} };
double[][] C_min = { {1.0} };
report("Two-state nonminimal realization", A_nonmin, B_nonmin, C_nonmin);
report("One-state minimal realization", A_min, B_min, C_min);
System.out.println("\nBoth realizations have external transfer behavior G(s)=1/(s+2),");
System.out.println("but the first realization contains one unobservable internal mode.");
}
}
Chapter20_Lesson1.m
% Chapter20_Lesson1.m
% Minimal realization tests for continuous-time LTI systems.
% Requires: MATLAB. Control System Toolbox is optional but recommended for ss,
% tf, minreal, ctrb, and obsv.
%
% The transfer matrix is G(s) = C*(sI - A)^(-1)*B + D.
% A realization is minimal iff (A,B) is reachable and (C,A) is observable.
clear; clc;
A_nonmin = [-1 0;
0 -2];
B_nonmin = [1;
1];
C_nonmin = [0 1];
D_nonmin = 0;
A_min = -2;
B_min = 1;
C_min = 1;
D_min = 0;
fprintf('\nTwo-state nonminimal realization\n');
reportMinimality(A_nonmin, B_nonmin, C_nonmin);
fprintf('\nOne-state minimal realization\n');
reportMinimality(A_min, B_min, C_min);
% Optional Control System Toolbox verification.
if exist('ss', 'file') == 2
sys_nonmin = ss(A_nonmin, B_nonmin, C_nonmin, D_nonmin);
sys_min = ss(A_min, B_min, C_min, D_min);
fprintf('\nTransfer functions:\n');
disp(tf(sys_nonmin));
disp(tf(sys_min));
fprintf('\nMATLAB minreal result for the nonminimal model:\n');
disp(minreal(sys_nonmin));
% Simulink workflow note:
% 1. Build or open a Simulink model.
% 2. Define linear analysis input/output points.
% 3. Use linearize(modelName) to obtain an ss object.
% 4. Apply minreal(sys) and compare rank(ctrb(sys)) and rank(obsv(sys)).
end
function R = reachabilityMatrix(A, B)
n = size(A, 1);
R = [];
Ak = eye(n);
for k = 1:n
R = [R, Ak*B]; %#ok<AGROW>
Ak = A*Ak;
end
end
function O = observabilityMatrix(A, C)
n = size(A, 1);
O = [];
Ak = eye(n);
for k = 1:n
O = [O; C*Ak]; %#ok<AGROW>
Ak = Ak*A;
end
end
function reportMinimality(A, B, C)
n = size(A, 1);
R = reachabilityMatrix(A, B);
O = observabilityMatrix(A, C);
fprintf('rank(R_n) = %d of n = %d\n', rank(R), n);
fprintf('rank(O_n) = %d of n = %d\n', rank(O), n);
fprintf('minimal? = %s\n', string(rank(R) == n && rank(O) == n));
end
Chapter20_Lesson1.nb
(* Chapter20_Lesson1.nb *)
(* Minimal realization tests for continuous-time LTI systems in Wolfram Language. *)
(* The transfer matrix is G(s) = C . Inverse[s I - A] . B + D. *)
(* A realization is minimal iff (A,B) is reachable and (C,A) is observable. *)
ClearAll[reachabilityMatrix, observabilityMatrix, minimalQ, transferValue, report];
reachabilityMatrix[A_, B_] := Module[{n = Length[A], Ak = IdentityMatrix[Length[A]]},
ArrayFlatten[{Table[(Ak = If[k == 1, IdentityMatrix[n], A . Ak]; If[k == 1, B, Ak . B]), {k, 1, n}]}]
];
observabilityMatrix[A_, C_] := Module[{n = Length[A], Ak = IdentityMatrix[Length[A]], blocks},
blocks = Table[
If[k == 1, C, Ak = Ak . A; C . Ak],
{k, 1, n}
];
Join @@ blocks
];
minimalQ[A_, B_, C_] := Module[{n = Length[A], R, O},
R = reachabilityMatrix[A, B];
O = observabilityMatrix[A, C];
MatrixRank[R] == n && MatrixRank[O] == n
];
transferValue[A_, B_, C_, D_, s_] := C . Inverse[s IdentityMatrix[Length[A]] - A] . B + D;
report[name_, A_, B_, C_] := Module[{R, O, n},
n = Length[A];
R = reachabilityMatrix[A, B];
O = observabilityMatrix[A, C];
Print["\n", name];
Print["rank(R_n) = ", MatrixRank[R], " of n = ", n];
Print["rank(O_n) = ", MatrixRank[O], " of n = ", n];
Print["minimal? = ", minimalQ[A, B, C]];
];
A_nonmin = { {-1, 0}, {0, -2} };
B_nonmin = { {1}, {1} };
C_nonmin = { {0, 1} };
D_nonmin = { {0} };
A_min = { {-2} };
B_min = { {1} };
C_min = { {1} };
D_min = { {0} };
report["Two-state nonminimal realization", A_nonmin, B_nonmin, C_nonmin];
report["One-state minimal realization", A_min, B_min, C_min];
FullSimplify[transferValue[A_nonmin, B_nonmin, C_nonmin, D_nonmin, s]]
FullSimplify[transferValue[A_min, B_min, C_min, D_min, s]]
9. Problems and Solutions
Problem 1: Let \( G(s)=\frac{s+3}{(s+1)(s+3)} \). What is the minimal order of a realization of \( G(s) \)?
Solution: The transfer function simplifies to \( G(s)=\frac{1}{s+1} \) after cancellation of \( s+3 \). The remaining dynamic denominator has degree one, so a minimal realization has order one. A possible minimal realization is
\[ A=-1,\quad B=1,\quad C=1,\quad D=0. \]
Problem 2: For \( \mathbf{A}=\begin{bmatrix}0&1\\-2&-3\end{bmatrix} \), \( \mathbf{B}=\begin{bmatrix}0\\1\end{bmatrix} \), and \( \mathbf{C}=\begin{bmatrix}1&0\end{bmatrix} \), decide whether the realization is minimal.
Solution: Compute
\[ \mathcal{R}_2= \begin{bmatrix} \mathbf{B} & \mathbf{A}\mathbf{B} \end{bmatrix} = \begin{bmatrix} 0 & 1 \\ 1 & -3 \end{bmatrix}, \quad \det(\mathcal{R}_2)=-1\ne0. \]
\[ \mathcal{O}_2= \begin{bmatrix} \mathbf{C} \\ \mathbf{C}\mathbf{A} \end{bmatrix} = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}, \quad \operatorname{rank}(\mathcal{O}_2)=2. \]
Both rank conditions hold, so the realization is minimal.
Problem 3: Show that a nonreachable realization cannot be minimal.
Solution: Let \( \mathcal{X}_r=\operatorname{im}(\mathcal{R}_n) \) and suppose \( \dim(\mathcal{X}_r)=r<n \). In a basis whose first \( r \) vectors span \( \mathcal{X}_r \), the transformed input matrix has zero components outside the reachable block:
\[ \bar{\mathbf{B} }= \begin{bmatrix} \mathbf{B}_r \\ \mathbf{0} \end{bmatrix}. \]
Starting from zero initial condition, the unreachable coordinates are never excited by any input. Removing them leaves the same transfer matrix with smaller order, contradicting minimality.
Problem 4: Prove that similarity transformations do not affect minimality.
Solution: For nonsingular \( \mathbf{T} \), the transformed reachability and observability matrices satisfy
\[ \bar{\mathcal{R} }_n=\mathbf{T}^{-1}\mathcal{R}_n, \quad \bar{\mathcal{O} }_n=\mathcal{O}_n\mathbf{T}. \]
Multiplication by a nonsingular matrix does not change rank. Therefore the rank conditions for reachability and observability are unchanged, and minimality is invariant.
Problem 5: Suppose a realization has \( \operatorname{rank}(\mathcal{R}_n)=n \) but \( \operatorname{rank}(\mathcal{O}_n)=q<n \). What can be concluded?
Solution: The realization is reachable but not observable. Hence every state direction can be excited by the input, but at least one nonzero state direction is invisible at the output. The realization is not minimal; a lower-order realization exists after removing the unobservable component. The minimal order is at most \( q \), although the exact minimal order must be computed after accounting for the reachable-observable intersection.
10. Summary
A minimal realization is the lowest-order state-space representation that produces a given transfer matrix. The dynamic order equals the number of state directions that are both reachable from the input and observable at the output. The central test is therefore simple and powerful: compute the reachability and observability matrices and check that both have full rank. Minimal realizations are unique up to similarity transformation, and their order equals the Hankel rank, also known as the McMillan degree for rational transfer matrices.
11. 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.
- Ho, B.L., & Kalman, R.E. (1966). Effective construction of linear state-variable models from input/output functions. Regelungstechnik, 14, 545–548.
- 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.
- Rosenbrock, H.H. (1968). State-space and multivariable theory. Proceedings of the Institution of Electrical Engineers, 115(6), 775–783.
- Silverman, L.M. (1971). Realization of linear dynamical systems. IEEE Transactions on Automatic Control, 16(6), 554–567.
- Wonham, W.M. (1968). On pole assignment in multi-input controllable linear systems. IEEE Transactions on Automatic Control, 12(6), 660–665.
- Zeiger, H.P., & McEwen, A.J. (1974). Approximate linear realizations of given dimension via Ho's algorithm. IEEE Transactions on Automatic Control, 19(2), 153–153.
- De Schutter, B. (2000). Minimal state-space realization in linear system theory: an overview. Journal of Computational and Applied Mathematics, 121(1–2), 331–354.