Chapter 24: Pole Placement for Multi-Input Systems
Lesson 1: Existence Conditions for MIMO Pole Assignment
This lesson establishes the exact algebraic conditions under which a continuous-time multi-input state-feedback law can assign closed-loop poles. The central result is that arbitrary pole assignment is possible exactly when the pair \( (\mathbf{A},\mathbf{B}) \) is controllable. If the pair is only stabilizable, then the controllable poles can be moved, but stable uncontrollable poles remain fixed.
1. Problem Formulation
Consider the continuous-time LTI multi-input system \( \dot{\mathbf{x} }=\mathbf{A}\mathbf{x}+\mathbf{B}\mathbf{u} \), where \( \mathbf{x}\in\mathbb{R}^n \), \( \mathbf{u}\in\mathbb{R}^m \), \( \mathbf{A}\in\mathbb{R}^{n\times n} \), and \( \mathbf{B}\in\mathbb{R}^{n\times m} \). Full-state feedback has the form
\[ \mathbf{u}=-\mathbf{K}\mathbf{x},\qquad \mathbf{K}\in\mathbb{R}^{m\times n}. \]
The closed-loop state matrix is \( \mathbf{A}_c=\mathbf{A}-\mathbf{B}\mathbf{K} \). Given a desired monic polynomial of degree \( n \),
\[ p_d(s)=\prod_{i=1}^{n}(s-\lambda_i), \]
the MIMO pole-assignment problem asks whether there exists a matrix \( \mathbf{K} \) such that
\[ \det\left(s\mathbf{I}-\mathbf{A}+\mathbf{B}\mathbf{K}\right)=p_d(s). \]
In the SISO case, the gain is essentially determined by the desired characteristic polynomial. In the MIMO case, the condition for existence is still controllability, but the gain matrix is generally nonunique.
flowchart TD
A["Start with xdot = A x + B u"] --> B["Apply state feedback u = -K x"]
B --> C["Closed-loop matrix Acl = A - B K"]
C --> D["Choose desired polynomial p_d(s)"]
D --> E["Check controllability rank"]
E -->|rank is n| F["Arbitrary poles are assignable"]
E -->|rank is less than n| G["Some modes are fixed"]
G --> H["Only controllable-subspace poles can move"]
2. Kalman Controllability Condition
The multi-input controllability matrix is
\[ \mathcal{C}(\mathbf{A},\mathbf{B})= \begin{bmatrix} \mathbf{B} & \mathbf{A}\mathbf{B} & \mathbf{A}^2\mathbf{B} & \cdots & \mathbf{A}^{n-1}\mathbf{B} \end{bmatrix}\in\mathbb{R}^{n\times nm}. \]
The pair \( (\mathbf{A},\mathbf{B}) \) is controllable if and only if
\[ \operatorname{rank}\mathcal{C}(\mathbf{A},\mathbf{B})=n. \]
The fundamental existence theorem for full-state MIMO pole placement is:
\[ \boxed{ \text{Arbitrary pole assignment by } \mathbf{u}=-\mathbf{K}\mathbf{x} \text{ is possible} \Longleftrightarrow \operatorname{rank}\mathcal{C}(\mathbf{A},\mathbf{B})=n. } \]
The word arbitrary means that every monic polynomial \( p_d(s) \) of degree \( n \) can be realized as the closed-loop characteristic polynomial.
3. PBH Test and Modal Interpretation
The Popov–Belevitch–Hautus condition gives an eigenvalue-level characterization of controllability:
\[ \operatorname{rank} \begin{bmatrix} \lambda\mathbf{I}-\mathbf{A} & \mathbf{B} \end{bmatrix}=n, \qquad \forall \lambda\in\sigma(\mathbf{A}). \]
Equivalently, there must not exist a nonzero left eigenvector \( \mathbf{q} \) of \( \mathbf{A} \) satisfying
\[ \mathbf{q}^{*}\mathbf{A}=\lambda\mathbf{q}^{*},\qquad \mathbf{q}^{*}\mathbf{B}=\mathbf{0}. \]
If such a vector exists, then the input matrix has no authority over that mode. This immediately explains why uncontrollable modes cannot be moved by state feedback.
4. Necessity Proof: Uncontrollable Modes Are Invariant
Suppose there exists a nonzero left eigenvector \( \mathbf{q} \) such that
\[ \mathbf{q}^{*}\mathbf{A}=\lambda\mathbf{q}^{*},\qquad \mathbf{q}^{*}\mathbf{B}=\mathbf{0}. \]
For any feedback gain \( \mathbf{K} \),
\[ \mathbf{q}^{*}(\mathbf{A}-\mathbf{B}\mathbf{K}) = \mathbf{q}^{*}\mathbf{A}-\mathbf{q}^{*}\mathbf{B}\mathbf{K} = \lambda\mathbf{q}^{*}. \]
Therefore \( \lambda \) remains a closed-loop eigenvalue for every possible feedback gain. Hence arbitrary pole assignment is impossible unless every open-loop mode is controllable.
5. Sufficiency Proof: Controllability Guarantees Pole Assignment
If \( (\mathbf{A},\mathbf{B}) \) is controllable, there exists a nonsingular transformation \( \mathbf{x}=\mathbf{T}\mathbf{z} \) that brings the system into a controllability staircase or multi-input Brunovsky form:
\[ \dot{\mathbf{z} }=\bar{\mathbf{A} }\mathbf{z} +\bar{\mathbf{B} }\mathbf{u},\qquad \bar{\mathbf{A} }=\mathbf{T}^{-1}\mathbf{A}\mathbf{T},\qquad \bar{\mathbf{B} }=\mathbf{T}^{-1}\mathbf{B}. \]
In that form, the states are arranged into input-driven controllability chains. The chain lengths are the controllability indices \( \nu_1,\nu_2,\ldots,\nu_m \), satisfying
\[ \nu_1+\nu_2+\cdots+\nu_m=n. \]
Feedback changes the terminal rows of these controllability chains. As a result, the coefficients of the closed-loop characteristic polynomial can be chosen to match any desired monic polynomial \( p_d(s) \). Transforming the gain back to the original coordinates gives
\[ \mathbf{K}=\bar{\mathbf{K} }\mathbf{T}^{-1}. \]
Therefore controllability is sufficient for arbitrary pole placement.
6. Stabilizability and Fixed Uncontrollable Poles
Full controllability is required for arbitrary pole assignment. Stabilization only requires the weaker condition of stabilizability:
\[ \operatorname{rank} \begin{bmatrix} \lambda\mathbf{I}-\mathbf{A} & \mathbf{B} \end{bmatrix}=n, \qquad \forall \lambda\in\sigma(\mathbf{A}) \text{ with } \operatorname{Re}(\lambda)\ge 0. \]
In the controllable/uncontrollable decomposition,
\[ \bar{\mathbf{A} }= \begin{bmatrix} \mathbf{A}_c & \mathbf{A}_{12}\\ \mathbf{0} & \mathbf{A}_u \end{bmatrix},\qquad \bar{\mathbf{B} }= \begin{bmatrix} \mathbf{B}_c\\ \mathbf{0} \end{bmatrix}, \]
where \( (\mathbf{A}_c,\mathbf{B}_c) \) is controllable and \( \mathbf{A}_u \) contains the uncontrollable modes. Under feedback,
\[ \bar{\mathbf{A} }-\bar{\mathbf{B} }\bar{\mathbf{K} }= \begin{bmatrix} \mathbf{A}_c-\mathbf{B}_c\mathbf{K}_c & \mathbf{A}_{12}-\mathbf{B}_c\mathbf{K}_u\\ \mathbf{0} & \mathbf{A}_u \end{bmatrix}. \]
Hence
\[ \sigma(\mathbf{A}-\mathbf{B}\mathbf{K}) = \sigma(\mathbf{A}_c-\mathbf{B}_c\mathbf{K}_c) \cup \sigma(\mathbf{A}_u). \]
flowchart TD
A["Original pair A, B"] --> B["Coordinate transformation"]
B --> C["Controllable block Ac, Bc"]
B --> D["Uncontrollable block Au"]
C --> E["Feedback moves poles of Ac - Bc Kc"]
D --> F["Poles of Au are fixed"]
E --> G["Closed-loop spectrum"]
F --> G
7. MIMO-Specific Degrees of Freedom
In MIMO pole assignment, the gain matrix contains \( mn \) scalar entries, while the characteristic polynomial imposes only \( n \) scalar coefficient constraints. Thus, if the system is controllable and \( m>1 \), the solution set is generally infinite:
\[ \mathcal{S}(p_d)= \left\{ \mathbf{K}\in\mathbb{R}^{m\times n}: \det(s\mathbf{I}-\mathbf{A}+\mathbf{B}\mathbf{K})=p_d(s) \right\}. \]
This nonuniqueness is useful. Later lessons will use these extra degrees of freedom for eigenstructure assignment, partial pole placement, robustness improvement, and gain-size management.
For an assigned eigenpair, the equation \( (\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{v}=\lambda\mathbf{v} \) can be written as
\[ (\mathbf{A}-\lambda\mathbf{I})\mathbf{v} = \mathbf{B}\mathbf{g},\qquad \mathbf{g}=\mathbf{K}\mathbf{v}. \]
Therefore possible closed-loop eigenvectors are constrained by the nullspace of
\[ \begin{bmatrix} \mathbf{A}-\lambda\mathbf{I} & -\mathbf{B} \end{bmatrix} \begin{bmatrix} \mathbf{v}\\ \mathbf{g} \end{bmatrix} = \mathbf{0}. \]
8. Numerical Tests and Libraries
In exact mathematics, rank is exact. In numerical computation, rank is determined using singular values and a tolerance:
\[ \operatorname{rank}(\mathbf{M}) = \#\left\{ \sigma_i(\mathbf{M}): \sigma_i(\mathbf{M}) \text{ is numerically nonzero} \right\}. \]
Useful libraries for this lesson include NumPy, SciPy, and python-control in Python; Eigen, Armadillo, LAPACK, and SLICOT bindings in C++; EJML, ojAlgo, and Apache Commons Math in Java; Control System Toolbox and Simulink in MATLAB; and symbolic/numeric matrix tools in Wolfram Mathematica.
9. Python Implementation
Chapter24_Lesson1.py
import numpy as np
from scipy.signal import place_poles
def ctrb(A, B):
n = A.shape[0]
return np.hstack([np.linalg.matrix_power(A, k) @ B for k in range(n)])
def rank(M, tol=1e-10):
return np.sum(np.linalg.svd(M, compute_uv=False) > tol)
def pbh_rank(A, B, lam):
n = A.shape[0]
M = np.hstack((lam * np.eye(n, dtype=complex) - A, B))
return rank(M)
def controllable(A, B):
return rank(ctrb(A, B)) == A.shape[0]
def stabilizable(A, B):
n = A.shape[0]
for lam in np.linalg.eigvals(A):
if np.real(lam) >= 0 and pbh_rank(A, B, lam) < n:
return False
return True
A = np.array([[0., 1., 0.],
[0., 0., 1.],
[-1., -5., -6.]])
B = np.array([[0., 0.],
[1., 0.],
[0., 1.]])
print("rank(C) =", rank(ctrb(A, B)))
print("controllable =", controllable(A, B))
print("stabilizable =", stabilizable(A, B))
desired_poles = np.array([-2., -3., -4.])
result = place_poles(A, B, desired_poles, method="YT")
K = result.gain_matrix
print("K =")
print(K)
print("closed-loop poles =", np.linalg.eigvals(A - B @ K))
A_bad = np.diag([1., -2., -3.])
B_bad = np.array([[0.], [1.], [1.]])
print("bad rank =", rank(ctrb(A_bad, B_bad)))
print("bad stabilizable =", stabilizable(A_bad, B_bad))
10. C++ Implementation
Chapter24_Lesson1.cpp
#include <Eigen/Dense>
#include <Eigen/Eigenvalues>
#include <iostream>
#include <complex>
using Matrix = Eigen::MatrixXd;
using CMatrix = Eigen::MatrixXcd;
int rank(const Matrix& M, double tol = 1e-10) {
Eigen::JacobiSVD<Matrix> svd(M);
int r = 0;
for (int i = 0; i < svd.singularValues().size(); ++i)
if (svd.singularValues()(i) > tol) ++r;
return r;
}
int rankComplex(const CMatrix& M, double tol = 1e-10) {
Eigen::JacobiSVD<CMatrix> svd(M);
int r = 0;
for (int i = 0; i < svd.singularValues().size(); ++i)
if (svd.singularValues()(i) > tol) ++r;
return r;
}
Matrix ctrb(const Matrix& A, const Matrix& B) {
int n = A.rows(), m = B.cols();
Matrix C(n, n * m);
Matrix Apow = Matrix::Identity(n, n);
for (int k = 0; k < n; ++k) {
C.block(0, k * m, n, m) = Apow * B;
Apow = A * Apow;
}
return C;
}
int pbhRank(const Matrix& A, const Matrix& B, std::complex<double> lam) {
int n = A.rows(), m = B.cols();
CMatrix M(n, n + m);
M.leftCols(n) = lam * CMatrix::Identity(n, n) - A.cast<std::complex<double>>();
M.rightCols(m) = B.cast<std::complex<double>>();
return rankComplex(M);
}
int main() {
Matrix A(3,3);
A << 0, 1, 0,
0, 0, 1,
-1,-5,-6;
Matrix B(3,2);
B << 0,0,
1,0,
0,1;
std::cout << "rank(C) = " << rank(ctrb(A,B)) << "\n";
Eigen::EigenSolver<Matrix> es(A);
for (int i = 0; i < A.rows(); ++i)
std::cout << "PBH rank = " << pbhRank(A, B, es.eigenvalues()(i)) << "\n";
Matrix K(2,3);
K << 8, 6, 1,
-1,-5,-3;
Matrix Acl = A - B * K;
Eigen::EigenSolver<Matrix> es2(Acl);
std::cout << "Closed-loop eigenvalues:\n" << es2.eigenvalues() << "\n";
}
11. Java Implementation
Chapter24_Lesson1.java
public class Chapter24_Lesson1 {
static double[][] mul(double[][] A, double[][] B) {
int n = A.length, p = A[0].length, m = B[0].length;
double[][] C = new double[n][m];
for (int i = 0; i < n; i++)
for (int k = 0; k < p; k++)
for (int j = 0; j < m; 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[][] ctrb(double[][] A, double[][] B) {
int n = A.length, m = B[0].length;
double[][] C = new double[n][n * m];
double[][] Apow = eye(n);
for (int block = 0; block < n; block++) {
double[][] AB = mul(Apow, B);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
C[i][block * m + j] = AB[i][j];
Apow = mul(A, Apow);
}
return C;
}
static int rank(double[][] X, double tol) {
double[][] A = new double[X.length][X[0].length];
for (int i = 0; i < X.length; i++)
A[i] = java.util.Arrays.copyOf(X[i], X[i].length);
int rows = A.length, cols = A[0].length, 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 div = A[r][c];
for (int j = c; j < cols; j++) A[r][j] /= div;
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;
}
public static void main(String[] args) {
double[][] A = { {0,1,0}, {0,0,1}, {-1,-5,-6} };
double[][] B = { {0,0}, {1,0}, {0,1} };
double[][] C = ctrb(A, B);
System.out.println("rank(C) = " + rank(C, 1e-10));
System.out.println("controllable = " + (rank(C, 1e-10) == A.length));
double[][] K = { {8,6,1}, {-1,-5,-3} };
double[][] Acl = sub(A, mul(B, K));
System.out.println("A-BK:");
print(Acl);
}
static double[][] sub(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 void print(double[][] M) {
for (double[] row : M)
System.out.println(java.util.Arrays.toString(row));
}
}
12. MATLAB/Simulink Implementation
Chapter24_Lesson1.m
% Chapter24_Lesson1.m
clear; clc;
A = [ 0 1 0;
0 0 1;
-1 -5 -6 ];
B = [0 0;
1 0;
0 1];
n = size(A, 1);
C = ctrb(A, B);
fprintf('rank(ctrb(A,B)) = %d\n', rank(C));
fprintf('controllable = %d\n', rank(C) == n);
lambdaA = eig(A);
for k = 1:length(lambdaA)
M = [lambdaA(k) * eye(n) - A, B];
fprintf('PBH rank at lambda %g%+gi = %d\n', ...
real(lambdaA(k)), imag(lambdaA(k)), rank(M));
end
desired_poles = [-2 -3 -4];
K = place(A, B, desired_poles);
Acl = A - B * K;
disp('K ='); disp(K);
disp('closed-loop poles ='); disp(eig(Acl));
sys_cl = ss(Acl, zeros(n,1), eye(n), zeros(n,1));
t = linspace(0, 6, 400);
x0 = [1; -0.5; 0.75];
[y, t, x] = initial(sys_cl, x0, t);
figure;
plot(t, x, 'LineWidth', 1.5);
grid on;
xlabel('Time (s)');
ylabel('States');
title('Closed-loop response after MIMO pole assignment');
legend('x_1','x_2','x_3');
% Optional Simulink model creation if Simulink is installed.
if exist('simulink', 'file') == 4
model = 'Chapter24_Lesson1_Simulink';
new_system(model);
open_system(model);
add_block('simulink/Continuous/State-Space', ...
[model '/closed_loop_ss'], 'Position', [100 70 280 150]);
set_param([model '/closed_loop_ss'], ...
'A', 'Acl', 'B', 'zeros(3,1)', ...
'C', 'eye(3)', 'D', 'zeros(3,1)', ...
'X0', '[1; -0.5; 0.75]');
save_system(model);
end
13. Wolfram Mathematica Implementation
Chapter24_Lesson1.nb
A = { {0, 1, 0}, {0, 0, 1}, {-1, -5, -6} };
B = { {0, 0}, {1, 0}, {0, 1} };
n = Length[A];
ControllabilityMatrix[A_, B_] :=
ArrayFlatten[{Table[MatrixPower[A, k].B, {k, 0, Length[A] - 1}]}];
MatrixRank[ControllabilityMatrix[A, B]]
PBHRank[A_, B_, lambda_] :=
MatrixRank[Join[lambda IdentityMatrix[Length[A]] - A, B, 2]];
Table[{lambda, PBHRank[A, B, lambda]}, {lambda, Eigenvalues[A]}]
K = { {8, 6, 1}, {-1, -5, -3} };
Acl = A - B.K;
Eigenvalues[Acl]
ABad = DiagonalMatrix[{1, -2, -3}];
BBad = { {0}, {1}, {1} };
{MatrixRank[ControllabilityMatrix[ABad, BBad]], PBHRank[ABad, BBad, 1]}
14. Problems and Solutions
Problem 1: Let \( \mathbf{A}=\begin{bmatrix}0&1\\-2&-3\end{bmatrix} \) and \( \mathbf{B}=\begin{bmatrix}0\\1\end{bmatrix} \). Determine whether arbitrary pole assignment is possible.
Solution: The controllability matrix is
\[ \mathcal{C}= \begin{bmatrix} \mathbf{B} & \mathbf{A}\mathbf{B} \end{bmatrix} = \begin{bmatrix} 0 & 1\\ 1 & -3 \end{bmatrix}. \]
\[ \det(\mathcal{C})=0(-3)-1(1)=-1\ne 0. \]
Hence \( \operatorname{rank}\mathcal{C}=2 \). Since \( n=2 \), the pair is controllable, so arbitrary assignment of two closed-loop poles is possible.
Problem 2: Consider \( \mathbf{A}=\operatorname{diag}(1,-2) \) and \( \mathbf{B}=\begin{bmatrix}0\\1\end{bmatrix} \). Is the system stabilizable?
Solution: The unstable eigenvalue is \( \lambda=1 \). The PBH matrix at this eigenvalue is
\[ \begin{bmatrix} \lambda\mathbf{I}-\mathbf{A} & \mathbf{B} \end{bmatrix}_{\lambda=1} = \begin{bmatrix} 0 & 0 & 0\\ 0 & 3 & 1 \end{bmatrix}. \]
Its rank is \( 1<2 \). Therefore the unstable mode is uncontrollable. The pair is not stabilizable, and no state feedback can move the pole at \( +1 \).
Problem 3: Suppose \( (\mathbf{A},\mathbf{B}) \) is controllable with \( n=4 \) and \( m=2 \). Are the repeated desired poles \( \{-2,-2,-2,-2\} \) algebraically assignable?
Solution: Yes. Controllability is sufficient for arbitrary algebraic pole placement, including repeated poles. However, assigning four independent eigenvectors at the same eigenvalue is a stronger eigenstructure-assignment requirement and may be limited by the number of inputs and the nullspace structure of \( \begin{bmatrix}\mathbf{A}-\lambda\mathbf{I}&-\mathbf{B}\end{bmatrix} \).
Problem 4: Prove that if a pair is stabilizable, then some feedback gain can make the closed-loop system asymptotically stable.
Solution: In the controllability decomposition, the uncontrollable block \( \mathbf{A}_u \) contains all uncontrollable modes. Stabilizability means every eigenvalue of \( \mathbf{A}_u \) satisfies \( \operatorname{Re}(\lambda)<0 \). Since \( (\mathbf{A}_c,\mathbf{B}_c) \) is controllable, choose \( \mathbf{K}_c \) so that \( \mathbf{A}_c-\mathbf{B}_c\mathbf{K}_c \) has all poles in the open left-half plane. The closed-loop spectrum is the union of these assigned stable poles and the already stable uncontrollable poles.
Problem 5: Explain why MIMO pole placement usually has infinitely many feedback gains assigning the same pole set.
Solution: The feedback matrix has \( mn \) entries, but the desired monic characteristic polynomial imposes only \( n \) scalar coefficient constraints. For \( m>1 \), this leaves extra degrees of freedom. These degrees of freedom can later be used for eigenvector shaping, robustness, gain reduction, or actuator allocation.
15. Summary
Arbitrary MIMO pole assignment by full-state feedback is possible if and only if \( (\mathbf{A},\mathbf{B}) \) is controllable. The Kalman rank test and the PBH test give equivalent existence conditions. If the pair is not controllable, uncontrollable modes are invariant under feedback. If the pair is stabilizable, the controllable poles can be moved to stabilize the system while stable uncontrollable poles remain fixed. Multi-input systems also introduce nonuniqueness, which later becomes useful for eigenstructure and robustness-oriented design.
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.
- Popov, V.M. (1964). Hyperstability of control systems. Automation and Remote Control, 25, 903–917.
- Rosenbrock, H.H. (1970). State-Space and Multivariable Theory. Nelson.
- Wonham, W.M. (1967). On pole assignment in multi-input controllable linear systems. IEEE Transactions on Automatic Control, 12(6), 660–665.
- Davison, E.J. (1968). On pole assignment in linear systems with incomplete state feedback. IEEE Transactions on Automatic Control, 13(3), 348–351.
- Moore, B.C. (1976). On the flexibility offered by state feedback in multivariable systems beyond closed-loop eigenvalue assignment. IEEE Transactions on Automatic Control, 21(5), 689–692.
- Kautsky, J., Nichols, N.K., & Van Dooren, P. (1985). Robust pole assignment in linear state feedback. International Journal of Control, 41(5), 1129–1155.
- Tits, A.L., & Yang, Y. (1996). Globally convergent algorithms for robust pole assignment by state feedback. IEEE Transactions on Automatic Control, 41(10), 1432–1452.