Chapter 24: Pole Placement for Multi-Input Systems
Lesson 2: Degrees of Freedom and Closed-Loop Eigenstructure
This lesson explains why multi-input pole placement is not a unique design problem. After the desired closed-loop poles are fixed, a multi-input feedback matrix still contains additional degrees of freedom. These degrees of freedom can be used to shape closed-loop eigenvectors, modal directions, numerical conditioning, and input distribution.
1. MIMO Pole Placement Is Not Unique
Consider the continuous-time LTI system \( \dot{\mathbf{x} }=\mathbf{A}\mathbf{x}+\mathbf{B}\mathbf{u} \), where \( \mathbf{x}\in\mathbb{R}^{n} \) and \( \mathbf{u}\in\mathbb{R}^{m} \). With full-state feedback
\[ \mathbf{u}=-\mathbf{K}\mathbf{x},\qquad \mathbf{K}\in\mathbb{R}^{m\times n}, \]
the closed-loop matrix is \( \mathbf{A}_{cl}=\mathbf{A}-\mathbf{B}\mathbf{K} \). The pole placement problem asks us to choose \( \mathbf{K} \) so that
\[ \sigma(\mathbf{A}-\mathbf{B}\mathbf{K}) =\{\lambda_1,\lambda_2,\dots,\lambda_n\}. \]
In a single-input system, the feedback row \( \mathbf{K}\in\mathbb{R}^{1\times n} \) has exactly \( n \) scalar entries, and assigning \( n \) characteristic-polynomial coefficients usually determines a unique feedback row. In a multi-input system, \( \mathbf{K} \) has \( mn \) scalar entries, while the characteristic polynomial still has only \( n \) independent coefficients. Thus, generically,
\[ \text{remaining feedback degrees of freedom} =mn-n=n(m-1). \]
These extra degrees of freedom are not mathematical redundancy. They represent genuine design freedom: different matrices \( \mathbf{K} \) can produce the same pole set but very different closed-loop eigenvectors and transient responses.
2. Closed-Loop Eigenstructure
A pole is only part of a mode. A complete closed-loop mode consists of an eigenvalue-eigenvector pair \( (\lambda_i,\mathbf{v}_i) \) satisfying
\[ (\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{v}_i =\lambda_i\mathbf{v}_i. \]
Rearranging gives the central eigenstructure assignment equation:
\[ (\mathbf{A}-\lambda_i\mathbf{I})\mathbf{v}_i =\mathbf{B}\mathbf{z}_i,\qquad \mathbf{z}_i=\mathbf{K}\mathbf{v}_i. \]
Equivalently,
\[ \begin{bmatrix} \mathbf{A}-\lambda_i\mathbf{I} & -\mathbf{B} \end{bmatrix} \begin{bmatrix} \mathbf{v}_i\\ \mathbf{z}_i \end{bmatrix} =\mathbf{0}. \]
Therefore, for every assigned pole \( \lambda_i \), the designer may choose a vector \( [\mathbf{v}_i^T\;\mathbf{z}_i^T]^T \) from the null space of \( [\mathbf{A}-\lambda_i\mathbf{I}\;-\mathbf{B}] \). The state part \( \mathbf{v}_i \) becomes the desired closed-loop eigenvector, and the input part \( \mathbf{z}_i \) determines how the feedback gain maps that mode into the input channels.
3. Null-Space Parameterization and Degrees of Freedom
Suppose the pair \( (\mathbf{A},\mathbf{B}) \) is controllable and \( \lambda_i \) is not an uncontrollable eigenvalue. By the PBH condition,
\[ \operatorname{rank} \begin{bmatrix} \lambda_i\mathbf{I}-\mathbf{A} & \mathbf{B} \end{bmatrix} =n. \]
Since the matrix has \( n+m \) columns and rank \( n \), its null space has dimension \( m \):
\[ \dim\mathcal{N} \left( \begin{bmatrix} \mathbf{A}-\lambda_i\mathbf{I} & -\mathbf{B} \end{bmatrix} \right)=m. \]
Let \( \mathbf{N}_i \) be a basis matrix for this null space. Then
\[ \begin{bmatrix} \mathbf{v}_i\\ \mathbf{z}_i \end{bmatrix} =\mathbf{N}_i\boldsymbol{\alpha}_i,\qquad \boldsymbol{\alpha}_i\in\mathbb{C}^{m}. \]
The parameter vector \( \boldsymbol{\alpha}_i \) is the local eigenstructure-design freedom for pole \( \lambda_i \). Since eigenvectors are unchanged by nonzero scalar multiplication, one scalar degree is lost to scaling. Hence, for simple assigned poles, each pole contributes approximately \( m-1 \) eigenvector-shaping degrees of freedom, and all poles together contribute
\[ n(m-1) \]
degrees of freedom, matching the generic algebraic count \( mn-n \).
flowchart TD
A["Choose desired pole lambda_i"] --> B["Build matrix: A - lambda_i I and -B"]
B --> C["Compute null space basis N_i"]
C --> D["Choose parameter alpha_i"]
D --> E["Extract eigenvector v_i and input image z_i"]
E --> F["Repeat for all poles"]
F --> G["Assemble V and Z"]
G --> H["If V invertible, compute K = Z V inverse"]
4. Constructing the Feedback Matrix from Eigenvectors
Collect the desired closed-loop eigenvectors and their input images as
\[ \mathbf{V}= \begin{bmatrix} \mathbf{v}_1 & \mathbf{v}_2 & \cdots & \mathbf{v}_n \end{bmatrix},\qquad \mathbf{Z}= \begin{bmatrix} \mathbf{z}_1 & \mathbf{z}_2 & \cdots & \mathbf{z}_n \end{bmatrix}. \]
The eigenstructure equations for all modes can be written compactly as
\[ \mathbf{A}\mathbf{V}-\mathbf{B}\mathbf{Z} =\mathbf{V}\boldsymbol{\Lambda},\qquad \boldsymbol{\Lambda}=\operatorname{diag}(\lambda_1,\dots,\lambda_n). \]
If \( \mathbf{V} \) is nonsingular, define
\[ \boxed{\mathbf{K}=\mathbf{Z}\mathbf{V}^{-1} }. \]
Then \( \mathbf{K}\mathbf{V}=\mathbf{Z} \), so
\[ (\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{V} =\mathbf{A}\mathbf{V}-\mathbf{B}\mathbf{K}\mathbf{V} =\mathbf{A}\mathbf{V}-\mathbf{B}\mathbf{Z} =\mathbf{V}\boldsymbol{\Lambda}. \]
Because \( \mathbf{V} \) is invertible, this implies
\[ \mathbf{A}-\mathbf{B}\mathbf{K} =\mathbf{V}\boldsymbol{\Lambda}\mathbf{V}^{-1}. \]
Therefore, the assigned eigenvalues are exactly the closed-loop poles, and the columns of \( \mathbf{V} \) are the corresponding closed-loop eigenvectors.
5. Why Eigenvectors Matter
The eigenvalues determine exponential rates and oscillation frequencies, but the eigenvectors determine how each mode appears in the state coordinates. For the modal expansion
\[ \mathbf{x}(t)= \sum_{i=1}^{n} c_i e^{\lambda_i t}\mathbf{v}_i, \]
changing \( \mathbf{v}_i \) changes which physical states participate strongly in mode \( i \). In MIMO state-feedback design, eigenvector shaping can be used to:
- reduce undesirable coupling between state variables,
- avoid placing sensitive modes along poorly measured coordinates,
- distribute control action among multiple actuators,
- improve numerical conditioning of the modal matrix, and
- obtain a feedback gain with smaller or more balanced entries.
A useful conditioning indicator is
\[ \kappa(\mathbf{V})= \|\mathbf{V}\|\,\|\mathbf{V}^{-1}\|. \]
If \( \kappa(\mathbf{V}) \) is large, the eigenvectors are nearly linearly dependent. Then the closed-loop system may become sensitive to modeling errors and numerical roundoff, even if the pole locations appear acceptable.
6. Repeated and Complex Poles
For real feedback matrices, complex poles must be assigned in conjugate pairs. If \( \lambda=a+jb \) is assigned with eigenvector \( \mathbf{v}=\mathbf{p}+j\mathbf{q} \), then \( \bar{\lambda}=a-jb \) must be assigned with \( \bar{\mathbf{v} }=\mathbf{p}-j\mathbf{q} \). The real invariant subspace is represented by
\[ \mathbf{V}_{r}= \begin{bmatrix} \mathbf{p} & \mathbf{q} \end{bmatrix},\qquad \boldsymbol{\Lambda}_{r}= \begin{bmatrix} a & b\\ -b & a \end{bmatrix}. \]
For repeated poles, one must distinguish between assigning several independent eigenvectors and assigning a Jordan chain. For a chain associated with repeated pole \( \lambda \),
\[ (\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{v}_1 =\lambda\mathbf{v}_1, \]
\[ (\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{v}_j =\lambda\mathbf{v}_j+\mathbf{v}_{j-1},\qquad j=2,\dots,r. \]
Therefore, repeated-pole eigenstructure assignment requires careful control of eigenvector independence and Jordan-chain length. In engineering practice, designers often avoid unnecessary repeated poles because they can increase sensitivity and produce polynomial factors multiplying the exponential response.
7. Design Workflow
A practical multi-input pole-placement workflow does not stop after pole selection. It also checks whether the chosen eigenvectors produce a usable feedback matrix.
flowchart TD
S["Start with controllable pair A, B"] --> P["Choose desired closed-loop poles"]
P --> N["For each pole, compute null-space choices"]
N --> V["Select modal directions using design objectives"]
V --> C["Check V invertible and well conditioned"]
C -->|bad| V
C -->|good| K["Compute K = Z V inverse"]
K --> T["Verify eigenvalues, gain size, and simulation response"]
8. Worked Numerical Example
Consider the two-input system
\[ \mathbf{A}= \begin{bmatrix} 0&1&0\\ 0&0&1\\ -2&-3&-4 \end{bmatrix},\qquad \mathbf{B}= \begin{bmatrix} 0&0\\ 1&0\\ 0&1 \end{bmatrix}. \]
We assign the poles \( \{-1,-2,-5\} \). For each pole \( \lambda \), choose a free shaping parameter \( \gamma \) and set
\[ \mathbf{v}(\lambda,\gamma)= \begin{bmatrix} 1\\ \lambda\\ \lambda^2+\gamma \end{bmatrix},\qquad \mathbf{z}(\lambda,\gamma)= \begin{bmatrix} \gamma\\ -2-3\lambda+(-4-\lambda)(\lambda^2+\gamma) \end{bmatrix}. \]
Direct substitution verifies
\[ (\mathbf{A}-\lambda\mathbf{I})\mathbf{v}(\lambda,\gamma) =\mathbf{B}\mathbf{z}(\lambda,\gamma). \]
Choosing \( \gamma_1=0.2,\gamma_2=-0.4,\gamma_3=0.8 \) gives a nonsingular \( \mathbf{V} \). Then \( \mathbf{K}=\mathbf{Z}\mathbf{V}^{-1} \) assigns the desired poles. Changing the values of \( \gamma_i \) can keep the same poles while changing the eigenvectors and feedback gain.
9. Python Implementation
Chapter24_Lesson2.py
# Chapter24_Lesson2.py
# Degrees of freedom and closed-loop eigenstructure for MIMO pole placement.
# Model: x_dot = A x + B u, u = -K x, so A_cl = A - B K.
#
# Dependencies:
# pip install numpy
import numpy as np
def eigenstructure_column(lam: float, gamma: float):
"""
For the example system
A = [[0, 1, 0],
[0, 0, 1],
[-2, -3, -4]], B = [[0, 0],
[1, 0],
[0, 1]]
solve (A - lam I) v = B z, where z = K v.
The second input gives one free shaping parameter gamma = z1.
We set v1 = 1 and z1 = gamma, then solve the three scalar equations.
"""
v1 = 1.0
v2 = lam
v3 = lam * lam + gamma
z1 = gamma
z2 = -2.0 - 3.0 * lam + (-4.0 - lam) * v3
return np.array([v1, v2, v3], dtype=float), np.array([z1, z2], dtype=float)
def design_gain(lambdas, gammas):
A = np.array([[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
[-2.0, -3.0, -4.0]])
B = np.array([[0.0, 0.0],
[1.0, 0.0],
[0.0, 1.0]])
V_cols = []
Z_cols = []
for lam, gamma in zip(lambdas, gammas):
v, z = eigenstructure_column(lam, gamma)
V_cols.append(v)
Z_cols.append(z)
V = np.column_stack(V_cols)
Z = np.column_stack(Z_cols)
if abs(np.linalg.det(V)) < 1e-10:
raise ValueError("Chosen eigenvectors are nearly singular. Change gammas.")
K = Z @ np.linalg.inv(V)
Acl = A - B @ K
return A, B, V, Z, K, Acl
def main():
desired_poles = np.array([-1.0, -2.0, -5.0])
# These gamma values are the extra eigenvector-shaping degrees of freedom.
# Keeping the same poles but changing gamma changes K and the eigenvectors.
gammas = np.array([0.2, -0.4, 0.8])
A, B, V, Z, K, Acl = design_gain(desired_poles, gammas)
residual = A @ V - B @ Z - V @ np.diag(desired_poles)
print("A =\n", A)
print("B =\n", B)
print("Desired poles =", desired_poles)
print("Eigenvector-shaping gammas =", gammas)
print("V =\n", V)
print("Z = K V =\n", Z)
print("K =\n", K)
print("eig(A - B K) =", np.linalg.eigvals(Acl))
print("condition number of V =", np.linalg.cond(V))
print("max eigenstructure residual =", np.max(np.abs(residual)))
if __name__ == "__main__":
main()
10. C++ Implementation
Chapter24_Lesson2.cpp
// Chapter24_Lesson2.cpp
// Degrees of freedom and closed-loop eigenstructure for MIMO pole placement.
// No external linear algebra library is required for this small 3-state example.
//
// Compile:
// g++ Chapter24_Lesson2.cpp -O2 -std=c++17 -o Chapter24_Lesson2
//
// Run:
// ./Chapter24_Lesson2
#include <cmath>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <vector>
using Matrix = std::vector<std::vector<double>>;
void printMatrix(const std::string& name, const Matrix& M) {
std::cout << name << " =\n";
for (const auto& row : M) {
for (double x : row) {
std::cout << std::setw(14) << std::setprecision(8) << x << " ";
}
std::cout << "\n";
}
}
Matrix multiply(const Matrix& A, const Matrix& B) {
const int r = static_cast<int>(A.size());
const int c = static_cast<int>(B[0].size());
const 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 k = 0; k < inner; ++k) {
for (int j = 0; j < c; ++j) {
C[i][j] += A[i][k] * B[k][j];
}
}
}
return C;
}
double det3(const Matrix& M) {
return M[0][0] * (M[1][1] * M[2][2] - M[1][2] * M[2][1])
- M[0][1] * (M[1][0] * M[2][2] - M[1][2] * M[2][0])
+ M[0][2] * (M[1][0] * M[2][1] - M[1][1] * M[2][0]);
}
Matrix inverse3(const Matrix& M) {
double d = det3(M);
if (std::abs(d) < 1e-12) {
throw std::runtime_error("Singular or nearly singular V matrix.");
}
Matrix Inv(3, std::vector<double>(3, 0.0));
Inv[0][0] = (M[1][1] * M[2][2] - M[1][2] * M[2][1]) / d;
Inv[0][1] = -(M[0][1] * M[2][2] - M[0][2] * M[2][1]) / d;
Inv[0][2] = (M[0][1] * M[1][2] - M[0][2] * M[1][1]) / d;
Inv[1][0] = -(M[1][0] * M[2][2] - M[1][2] * M[2][0]) / d;
Inv[1][1] = (M[0][0] * M[2][2] - M[0][2] * M[2][0]) / d;
Inv[1][2] = -(M[0][0] * M[1][2] - M[0][2] * M[1][0]) / d;
Inv[2][0] = (M[1][0] * M[2][1] - M[1][1] * M[2][0]) / d;
Inv[2][1] = -(M[0][0] * M[2][1] - M[0][1] * M[2][0]) / d;
Inv[2][2] = (M[0][0] * M[1][1] - M[0][1] * M[1][0]) / d;
return Inv;
}
void eigenstructureColumn(double lambda, double gamma,
std::vector<double>& v,
std::vector<double>& z) {
const double v1 = 1.0;
const double v2 = lambda;
const double v3 = lambda * lambda + gamma;
const double z1 = gamma;
const double z2 = -2.0 - 3.0 * lambda + (-4.0 - lambda) * v3;
v = {v1, v2, v3};
z = {z1, z2};
}
int main() {
Matrix A = { {0.0, 1.0, 0.0},
{0.0, 0.0, 1.0},
{-2.0, -3.0, -4.0} };
Matrix B = { {0.0, 0.0},
{1.0, 0.0},
{0.0, 1.0} };
std::vector<double> lambdas = {-1.0, -2.0, -5.0};
std::vector<double> gammas = {0.2, -0.4, 0.8};
Matrix V(3, std::vector<double>(3, 0.0));
Matrix Z(2, std::vector<double>(3, 0.0));
for (int j = 0; j < 3; ++j) {
std::vector<double> v, z;
eigenstructureColumn(lambdas[j], gammas[j], v, z);
for (int i = 0; i < 3; ++i) V[i][j] = v[i];
for (int i = 0; i < 2; ++i) Z[i][j] = z[i];
}
Matrix K = multiply(Z, inverse3(V));
printMatrix("A", A);
printMatrix("B", B);
printMatrix("V", V);
printMatrix("Z = K V", Z);
printMatrix("K", K);
std::cout << "\nThe desired eigenvalues are: ";
for (double x : lambdas) std::cout << x << " ";
std::cout << "\n";
std::cout << "For this construction, A V - B Z = V Lambda by design.\n";
std::cout << "Closed-loop matrix is A - B K.\n";
return 0;
}
11. Java Implementation
Chapter24_Lesson2.java
// Chapter24_Lesson2.java
// Degrees of freedom and closed-loop eigenstructure for MIMO pole placement.
// No external library is required for this small 3-state example.
//
// Compile:
// javac Chapter24_Lesson2.java
//
// Run:
// java Chapter24_Lesson2
public class Chapter24_Lesson2 {
static void printMatrix(String name, double[][] M) {
System.out.println(name + " =");
for (double[] row : M) {
for (double x : row) {
System.out.printf("%14.8f ", x);
}
System.out.println();
}
}
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 k = 0; k < inner; k++) {
for (int j = 0; j < c; j++) {
C[i][j] += A[i][k] * B[k][j];
}
}
}
return C;
}
static double det3(double[][] M) {
return M[0][0] * (M[1][1] * M[2][2] - M[1][2] * M[2][1])
- M[0][1] * (M[1][0] * M[2][2] - M[1][2] * M[2][0])
+ M[0][2] * (M[1][0] * M[2][1] - M[1][1] * M[2][0]);
}
static double[][] inverse3(double[][] M) {
double d = det3(M);
if (Math.abs(d) < 1e-12) {
throw new IllegalArgumentException("Singular or nearly singular V matrix.");
}
double[][] Inv = new double[3][3];
Inv[0][0] = (M[1][1] * M[2][2] - M[1][2] * M[2][1]) / d;
Inv[0][1] = -(M[0][1] * M[2][2] - M[0][2] * M[2][1]) / d;
Inv[0][2] = (M[0][1] * M[1][2] - M[0][2] * M[1][1]) / d;
Inv[1][0] = -(M[1][0] * M[2][2] - M[1][2] * M[2][0]) / d;
Inv[1][1] = (M[0][0] * M[2][2] - M[0][2] * M[2][0]) / d;
Inv[1][2] = -(M[0][0] * M[1][2] - M[0][2] * M[1][0]) / d;
Inv[2][0] = (M[1][0] * M[2][1] - M[1][1] * M[2][0]) / d;
Inv[2][1] = -(M[0][0] * M[2][1] - M[0][1] * M[2][0]) / d;
Inv[2][2] = (M[0][0] * M[1][1] - M[0][1] * M[1][0]) / d;
return Inv;
}
static double[] eigenvector(double lambda, double gamma) {
return new double[] {1.0, lambda, lambda * lambda + gamma};
}
static double[] zColumn(double lambda, double gamma) {
double v3 = lambda * lambda + gamma;
double z1 = gamma;
double z2 = -2.0 - 3.0 * lambda + (-4.0 - lambda) * v3;
return new double[] {z1, z2};
}
public static void main(String[] args) {
double[][] A = {
{0.0, 1.0, 0.0},
{0.0, 0.0, 1.0},
{-2.0, -3.0, -4.0}
};
double[][] B = {
{0.0, 0.0},
{1.0, 0.0},
{0.0, 1.0}
};
double[] lambdas = {-1.0, -2.0, -5.0};
double[] gammas = {0.2, -0.4, 0.8};
double[][] V = new double[3][3];
double[][] Z = new double[2][3];
for (int j = 0; j < 3; j++) {
double[] v = eigenvector(lambdas[j], gammas[j]);
double[] z = zColumn(lambdas[j], gammas[j]);
for (int i = 0; i < 3; i++) V[i][j] = v[i];
for (int i = 0; i < 2; i++) Z[i][j] = z[i];
}
double[][] K = multiply(Z, inverse3(V));
printMatrix("A", A);
printMatrix("B", B);
printMatrix("V", V);
printMatrix("Z = K V", Z);
printMatrix("K", K);
System.out.print("\nThe desired eigenvalues are: ");
for (double x : lambdas) System.out.print(x + " ");
System.out.println("\nFor this construction, A V - B Z = V Lambda by design.");
System.out.println("Closed-loop matrix is A - B K.");
}
}
12. MATLAB / Simulink Implementation
In MATLAB, the constructive eigenstructure calculation can be done using
only core matrix operations. The Control System Toolbox function
place is useful for comparison, but it does not expose the
same explicit eigenvector-shaping parameter used below.
Chapter24_Lesson2.m
% Chapter24_Lesson2.m
% Degrees of freedom and closed-loop eigenstructure for MIMO pole placement.
% Model: x_dot = A x + B u, u = -K x, so A_cl = A - B K.
%
% Toolboxes:
% - No toolbox is required for the constructive eigenstructure part.
% - Control System Toolbox can be used for place(A,B,poles) comparison.
clear; clc;
A = [0 1 0;
0 0 1;
-2 -3 -4];
B = [0 0;
1 0;
0 1];
desired_poles = [-1 -2 -5];
gammas = [0.2 -0.4 0.8]; % extra MIMO eigenvector-shaping degrees of freedom
V = zeros(3, 3);
Z = zeros(2, 3);
for j = 1:3
lambda = desired_poles(j);
gamma = gammas(j);
v = [1;
lambda;
lambda^2 + gamma];
z = [gamma;
-2 - 3*lambda + (-4 - lambda)*(lambda^2 + gamma)];
V(:, j) = v;
Z(:, j) = z;
end
if abs(det(V)) < 1e-10
error('Chosen eigenvectors are nearly singular. Change gammas.');
end
K = Z / V; % same as Z * inv(V), but numerically preferable
Acl = A - B*K;
residual = A*V - B*Z - V*diag(desired_poles);
disp('A ='); disp(A);
disp('B ='); disp(B);
disp('V ='); disp(V);
disp('Z = K V ='); disp(Z);
disp('K ='); disp(K);
disp('eig(A - B*K) ='); disp(eig(Acl).');
disp('cond(V) ='); disp(cond(V));
disp('max eigenstructure residual ='); disp(max(abs(residual), [], 'all'));
% Optional comparison:
% K_place = place(A, B, desired_poles);
% disp('K from MATLAB place ='); disp(K_place);
% disp('eig(A - B*K_place) ='); disp(eig(A - B*K_place).');
In Simulink, implement the closed-loop system by connecting a
State-Space block with matrices
\( \mathbf{A} \) and
\( \mathbf{B} \) to a feedback gain block
\( -\mathbf{K} \). The equivalent closed-loop state
matrix is \( \mathbf{A}-\mathbf{B}\mathbf{K} \).
13. Wolfram Mathematica Implementation
Chapter24_Lesson2.nb
(* Chapter24_Lesson2.nb *)
(* Degrees of freedom and closed-loop eigenstructure for MIMO pole placement. *)
(* This is Wolfram Language code saved with .nb extension for easy copy/import. *)
ClearAll["Global`*"];
A = { {0, 1, 0}, {0, 0, 1}, {-2, -3, -4} };
B = { {0, 0}, {1, 0}, {0, 1} };
desiredPoles = {-1, -2, -5};
gammas = {0.2, -0.4, 0.8};
eigenstructureColumn[lambda_, gamma_] := Module[{v, z},
v = {1, lambda, lambda^2 + gamma};
z = {gamma, -2 - 3 lambda + (-4 - lambda) (lambda^2 + gamma)};
{v, z}
];
cols = MapThread[eigenstructureColumn, {desiredPoles, gammas}];
V = Transpose[cols[[All, 1]]];
Z = Transpose[cols[[All, 2]]];
K = Z . Inverse[V];
Acl = A - B . K;
residual = A . V - B . Z - V . DiagonalMatrix[desiredPoles];
Print["A = ", MatrixForm[A]];
Print["B = ", MatrixForm[B]];
Print["V = ", MatrixForm[V]];
Print["Z = K V = ", MatrixForm[Z]];
Print["K = ", MatrixForm[N[K]]];
Print["Eigenvalues of A - B K = ", Eigenvalues[N[Acl]]];
Print["Condition number of V = ", N[ConditionNumber[V]]];
Print["Max eigenstructure residual = ", Max[Abs[N[residual]]]];
14. Problems and Solutions
Problem 1 (Degree-of-Freedom Count): A controllable system has \( n=6 \) states and \( m=3 \) inputs. After assigning six distinct closed-loop poles, how many generic feedback degrees of freedom remain?
Solution: The gain matrix \( \mathbf{K}\in\mathbb{R}^{3\times 6} \) has \( mn=18 \) scalar entries. Pole assignment imposes \( n=6 \) characteristic-polynomial constraints. Therefore,
\[ mn-n=18-6=12. \]
Equivalently, each simple pole contributes approximately \( m-1=2 \) eigenvector-shaping degrees of freedom, and six poles give \( 6\cdot 2=12 \).
Problem 2 (Eigenstructure Verification): Suppose matrices \( \mathbf{V} \) and \( \mathbf{Z} \) satisfy \( \mathbf{A}\mathbf{V}-\mathbf{B}\mathbf{Z} =\mathbf{V}\boldsymbol{\Lambda} \), and \( \mathbf{V} \) is nonsingular. Prove that \( \mathbf{K}=\mathbf{Z}\mathbf{V}^{-1} \) assigns the eigenvalues in \( \boldsymbol{\Lambda} \).
Solution: Since \( \mathbf{K}\mathbf{V}=\mathbf{Z} \),
\[ (\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{V} =\mathbf{A}\mathbf{V}-\mathbf{B}\mathbf{K}\mathbf{V} =\mathbf{A}\mathbf{V}-\mathbf{B}\mathbf{Z} =\mathbf{V}\boldsymbol{\Lambda}. \]
Multiplying on the right by \( \mathbf{V}^{-1} \) gives
\[ \mathbf{A}-\mathbf{B}\mathbf{K} =\mathbf{V}\boldsymbol{\Lambda}\mathbf{V}^{-1}. \]
Hence the closed-loop matrix is similar to \( \boldsymbol{\Lambda} \), so it has the same eigenvalues.
Problem 3 (Null-Space Dimension): Let \( (\mathbf{A},\mathbf{B}) \) be controllable with \( \mathbf{A}\in\mathbb{R}^{n\times n} \) and \( \mathbf{B}\in\mathbb{R}^{n\times m} \). Show that for any assignable pole \( \lambda \), \( [\mathbf{A}-\lambda\mathbf{I}\;-\mathbf{B}] \) has nullity \( m \).
Solution: By the PBH controllability condition,
\[ \operatorname{rank} \begin{bmatrix} \lambda\mathbf{I}-\mathbf{A} & \mathbf{B} \end{bmatrix} =n. \]
Multiplying some columns by \( -1 \) does not change rank, so
\[ \operatorname{rank} \begin{bmatrix} \mathbf{A}-\lambda\mathbf{I} & -\mathbf{B} \end{bmatrix} =n. \]
This matrix has \( n+m \) columns. By the rank-nullity theorem,
\[ \operatorname{nullity}=n+m-n=m. \]
Problem 4 (Feedback Reconstruction): For the numerical example in Section 8, explain why changing \( \gamma_1,\gamma_2,\gamma_3 \) may change \( \mathbf{K} \) without changing the desired poles.
Solution: Each \( \gamma_i \) selects a different vector in the two-dimensional null space associated with pole \( \lambda_i \). This changes \( \mathbf{v}_i \) and \( \mathbf{z}_i \). If the resulting \( \mathbf{V} \) remains nonsingular, the gain \( \mathbf{K}=\mathbf{Z}\mathbf{V}^{-1} \) still satisfies \( (\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{V} =\mathbf{V}\boldsymbol{\Lambda} \). Therefore, the poles are unchanged, but the modal directions and feedback gain generally change.
Problem 5 (Conditioning): Why is it undesirable to choose eigenvectors that make \( \mathbf{V} \) nearly singular?
Solution: If \( \mathbf{V} \) is nearly singular, then \( \mathbf{V}^{-1} \) has large entries and the feedback \( \mathbf{K}=\mathbf{Z}\mathbf{V}^{-1} \) may become large or sensitive. Also, the modal decomposition \( \mathbf{A}_{cl}=\mathbf{V}\boldsymbol{\Lambda}\mathbf{V}^{-1} \) becomes ill-conditioned. Small perturbations in \( \mathbf{A} \), \( \mathbf{B} \), or \( \mathbf{K} \) can then cause large changes in the computed eigenstructure.
15. Summary
In multi-input pole placement, assigning closed-loop poles does not uniquely determine the feedback matrix. The extra degrees of freedom can be interpreted through the null space of \( [\mathbf{A}-\lambda_i\mathbf{I}\;-\mathbf{B}] \). By choosing vectors in these null spaces, the designer shapes closed-loop eigenvectors as well as eigenvalues. If the assembled modal matrix \( \mathbf{V} \) is nonsingular, the feedback matrix is recovered from \( \mathbf{K}=\mathbf{Z}\mathbf{V}^{-1} \). This eigenstructure viewpoint explains why MIMO pole placement is more flexible, but also more numerically delicate, than SISO pole placement.
16. References
- Wonham, W.M. (1967). On pole assignment in multi-input controllable linear systems. IEEE Transactions on Automatic Control, 12(6), 660–665.
- 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.
- Andry, A.N., Shapiro, E.Y., & Chung, J.C. (1983). Eigenstructure assignment for linear systems. IEEE Transactions on Automatic Control, 28(7), 711–729.
- Kautsky, J., Nichols, N.K., & Van Dooren, P. (1985). Robust pole assignment in linear state feedback. International Journal of Control, 41(5), 1129–1155.
- Varga, A. (1981). A Schur method for pole assignment. IEEE Transactions on Automatic Control, 26(2), 517–519.
- 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.