Chapter 24: Pole Placement for Multi-Input Systems
Lesson 4: Partial Pole Placement and Restricted Eigenstructure
This lesson develops partial pole placement for multi-input state-feedback systems and then extends it to restricted eigenstructure assignment. The central idea is to assign only selected closed-loop modes while preserving or constraining other modes through invariant subspaces, eigenvector equations, and linear algebraic compatibility conditions.
1. Motivation and Problem Statement
In the previous lessons, the closed-loop state matrix under full-state feedback was written as \( \mathbf{A}_{cl}=\mathbf{A}-\mathbf{B}\mathbf{K} \) for the law \( \mathbf{u}=-\mathbf{K}\mathbf{x} \). Full pole placement asks us to prescribe all eigenvalues of \( \mathbf{A}_{cl} \). In many engineering designs, however, only part of the spectrum must be relocated. Stable, fast, or physically desirable modes may be left unchanged. This leads to partial pole placement.
Let \( \mathbf{A}\in\mathbb{R}^{n\times n} \) and \( \mathbf{B}\in\mathbb{R}^{n\times m} \). Suppose we want to assign \( r \) selected modes \( \lambda_1,\dots,\lambda_r \), where \( r\le n \), and preserve an unassigned subspace \( \mathcal{N} \) of dimension \( n-r \). The desired spectral split is
\[ \sigma(\mathbf{A}-\mathbf{B}\mathbf{K}) = \Lambda_a \cup \Lambda_p, \quad \Lambda_a=\{\lambda_1,\dots, \lambda_r\}, \quad \Lambda_p=\text{preserved or weakly affected modes}. \]
The design problem is no longer just which poles to assign; it is also which eigenvectors and invariant subspaces should be associated with them. This is why MIMO pole placement naturally leads to eigenstructure assignment.
flowchart TD
A["Open-loop pair (A,B)"] --> B["Choose modes to assign"]
B --> C["Choose modes/subspace to preserve"]
C --> D["Solve mode equations: (A-lambda I)v = B g"]
D --> E["Build X = [assigned eigenvectors, preserved basis]"]
E --> F["Solve K X = [G, 0]"]
F --> G["Closed-loop matrix A - B K"]
G --> H["Verify assigned poles and preserved modes"]
2. Closed-Loop Eigenvector Equation
A vector \( \mathbf{v}_i\ne\mathbf{0} \) is a right eigenvector of the closed-loop matrix associated with \( \lambda_i \) if
\[ (\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{v}_i= \lambda_i\mathbf{v}_i. \]
Rearranging gives the fundamental MIMO eigenstructure equation:
\[ (\mathbf{A}-\lambda_i\mathbf{I})\mathbf{v}_i = \mathbf{B}\mathbf{g}_i, \quad \mathbf{g}_i=\mathbf{K}\mathbf{v}_i. \]
For a fixed desired pole \( \lambda_i \), the input direction \( \mathbf{g}_i\in\mathbb{R}^{m} \) is a degree of freedom. If \( \lambda_i \) is not already an eigenvalue of \( \mathbf{A} \), then
\[ \mathbf{v}_i=(\mathbf{A}-\lambda_i\mathbf{I})^{-1}\mathbf{B} \mathbf{g}_i. \]
Thus every nonzero admissible input direction generates a candidate closed-loop eigenvector. This freedom does not exist in the same way in single-input pole placement, and it is the mathematical source of restricted eigenstructure design.
For repeated poles, generalized eigenvectors may be required. In this lesson we focus on distinct assigned poles because the main goal is to understand partial placement and linear eigenvector restrictions before treating Jordan-chain assignment.
3. Partial Pole Placement with a Preserved Subspace
Let the assigned eigenvectors be collected in \( \mathbf{V}_a=[\mathbf{v}_1\;\cdots\;\mathbf{v}_r] \) and the corresponding input-direction matrix be \( \mathbf{G}_a=[\mathbf{g}_1\;\cdots\;\mathbf{g}_r] \). Then the feedback gain must satisfy
\[ \mathbf{K}\mathbf{V}_a=\mathbf{G}_a. \]
Suppose the preserved subspace has basis \( \mathbf{N}\in\mathbb{R}^{n\times(n-r)} \). To preserve it as an open-loop invariant subspace, impose
\[ \mathbf{K}\mathbf{N}=\mathbf{0}. \]
Combining the assigned and preserved constraints gives a single linear equation for \( \mathbf{K} \):
\[ \mathbf{K}\underbrace{[\mathbf{V}_a\;\mathbf{N}]}_{\mathbf{X} } = \underbrace{[\mathbf{G}_a\;\mathbf{0}]}_{\mathbf{Y} }. \]
If \( \mathbf{X}\in\mathbb{R}^{n\times n} \) is nonsingular, the feedback is unique under these constraints:
\[ \boxed{\mathbf{K}=\mathbf{Y}\mathbf{X}^{-1} }. \]
If \( \mathbf{X} \) has more columns than rows or is numerically ill-conditioned, a least-squares or minimum-norm solution can be used, but exact preservation may be lost if the constraints are incompatible.
4. Proof of the Partial Placement Construction
Assume that \( \mathbf{X}=[\mathbf{V}_a\;\mathbf{N}] \) is nonsingular and that \( \mathbf{K}\mathbf{X}=\mathbf{Y} \). For every assigned column \( \mathbf{v}_i \), we have \( \mathbf{K}\mathbf{v}_i=\mathbf{g}_i \). Therefore,
\[ (\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{v}_i = \mathbf{A}\mathbf{v}_i-\mathbf{B}\mathbf{g}_i. \]
From the mode equation \( (\mathbf{A}-\lambda_i\mathbf{I})\mathbf{v}_i=\mathbf{B}\mathbf{g}_i \), it follows that
\[ \mathbf{A}\mathbf{v}_i-\mathbf{B}\mathbf{g}_i= \lambda_i\mathbf{v}_i, \]
so \( \lambda_i \) is a closed-loop eigenvalue. For the preserved basis \( \mathbf{N} \), if \( \mathbf{A}\mathbf{N}=\mathbf{N}\mathbf{M} \) for some matrix \( \mathbf{M} \), then
\[ (\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{N}= \mathbf{A}\mathbf{N}-\mathbf{B}\mathbf{K}\mathbf{N}= \mathbf{N}\mathbf{M}. \]
Hence the subspace \( \operatorname{span}(\mathbf{N}) \) remains closed-loop invariant and its internal eigenvalues are preserved as the eigenvalues of \( \mathbf{M} \).
5. Restricted Eigenstructure Assignment
Pole placement controls decay rates and oscillation frequencies, but the eigenvectors determine how modes appear in individual states and outputs. In MIMO systems, we can impose linear restrictions such as modal localization, output decoupling, or actuator-direction constraints.
A general linear eigenvector restriction is written as \( \mathbf{H}_i\mathbf{v}_i=\mathbf{0} \). Combining it with the mode equation gives
\[ (\mathbf{A}-\lambda_i\mathbf{I})\mathbf{v}_i = \mathbf{B}\mathbf{g}_i, \quad \mathbf{H}_i\mathbf{v}_i=\mathbf{0}. \]
If \( \lambda_i\notin\sigma(\mathbf{A}) \), substitute \( \mathbf{v}_i=(\mathbf{A}-\lambda_i\mathbf{I})^{-1}\mathbf{B}\mathbf{g}_i \). The restriction becomes a homogeneous equation in the input direction:
\[ \mathbf{H}_i(\mathbf{A}-\lambda_i\mathbf{I})^{-1}\mathbf{B} \mathbf{g}_i=\mathbf{0}. \]
Therefore, a nontrivial restricted eigenvector exists if and only if
\[ \operatorname{null}\left(\mathbf{H}_i(\mathbf{A}-\lambda_i\mathbf{I})^{-1} \mathbf{B}\right) \ne \{\mathbf{0}\}. \]
If the null space has dimension greater than one, the remaining freedom may be used to reduce feedback norm, reduce sensitivity, or improve the conditioning of the eigenvector matrix.
flowchart TD
A["Choose lambda_i"] --> B["Specify eigenvector restriction H_i v_i = 0"]
B --> C["Compute S_i = H_i inv(A-lambda_i I) B"]
C --> D{"Does null(S_i) contain \nnonzero g_i?"}
D -->|"yes"| E["Set v_i = inv(A-lambda_i I) B g_i"]
D -->|"no"| F["Restriction is incompatible with \nthis pole/input pair"]
E --> G["Assemble K using K V = G and \npreservation constraints"]
6. Compatibility and Degrees of Freedom
The unrestricted admissible eigenvectors for a desired pole can be described by the null space of a block matrix:
\[ \begin{bmatrix} \mathbf{A}-\lambda_i\mathbf{I} & -\mathbf{B} \end{bmatrix} \begin{bmatrix} \mathbf{v}_i \\ \mathbf{g}_i \end{bmatrix} =\mathbf{0}. \]
Adding the restriction \( \mathbf{H}_i\mathbf{v}_i=\mathbf{0} \) gives
\[ \begin{bmatrix} \mathbf{A}-\lambda_i\mathbf{I} & -\mathbf{B} \\ \mathbf{H}_i & \mathbf{0} \end{bmatrix} \begin{bmatrix} \mathbf{v}_i \\ \mathbf{g}_i \end{bmatrix} =\mathbf{0}. \]
A feasible assigned mode requires a nonzero solution with \( \mathbf{v}_i\ne\mathbf{0} \). The multi-input case is favorable because increasing \( m \) increases the dimension of possible \( \mathbf{g}_i \) directions. However, too many restrictions may eliminate all feasible modes.
Numerically, the important matrix is not only the feedback gain \( \mathbf{K} \) but also the modal matrix \( \mathbf{X} \). A poorly conditioned \( \mathbf{X} \) implies high sensitivity of assigned eigenvalues to perturbations in \( \mathbf{A} \), \( \mathbf{B} \), and \( \mathbf{K} \).
\[ \kappa(\mathbf{X})=\|\mathbf{X}\|\,\|\mathbf{X}^{-1}\|. \]
7. Numerical Example
Consider the four-state, two-input system
\[ \mathbf{A}=\operatorname{diag}(0.2,0.6,-0.5,-1.0),\quad \mathbf{B}=\begin{bmatrix} 1&0\\0.3&1\\0.2&0.4\\0.1&0.2 \end{bmatrix}. \]
We assign two closed-loop poles to \( -2 \) and \( -3 \), while preserving the stable modes associated with \( -0.5 \) and \( -1.0 \). Choose
\[ \mathbf{g}_1=\begin{bmatrix}1\\0\end{bmatrix},\quad \mathbf{g}_2=\begin{bmatrix}0\\1\end{bmatrix},\quad \mathbf{N}=\begin{bmatrix}0&0\\0&0\\1&0\\0&1\end{bmatrix}. \]
The assigned eigenvectors are
\[ \mathbf{v}_i=(\mathbf{A}-\lambda_i\mathbf{I})^{-1}\mathbf{B}\mathbf{g}_i, \quad i=1,2. \]
Then \( \mathbf{X}=[\mathbf{v}_1\;\mathbf{v}_2\;\mathbf{N}] \) and \( \mathbf{Y}=[\mathbf{g}_1\;\mathbf{g}_2\;\mathbf{0}\;\mathbf{0}] \) give
\[ \mathbf{K}=\begin{bmatrix} 2.2&0&0&0\\ -0.913846&3.6&0&0 \end{bmatrix}. \]
The closed-loop eigenvalues are \( \{-3,-2,-1,-0.5\} \). The last two modes are preserved because \( \mathbf{K}\mathbf{N}=\mathbf{0} \).
8. Python Implementation
Chapter24_Lesson4.py
# Chapter24_Lesson4.py
# Partial Pole Placement and Restricted Eigenstructure
# Dependencies: numpy, scipy
# Install: pip install numpy scipy
import numpy as np
from scipy.linalg import eig, null_space
np.set_printoptions(precision=6, suppress=True)
def partial_pole_placement(A, B, assigned_lambdas, input_directions, keep_basis):
"""Construct K for u = -Kx.
Assigned eigenpairs satisfy
(A - lambda_i I) v_i = B g_i,
K v_i = g_i.
Kept open-loop modes satisfy
K n_j = 0.
Therefore, with X = [V_assigned, N_keep] and Y = [G_assigned, 0],
K X = Y.
If X is square nonsingular, K = Y X^{-1}; otherwise use a least-squares
right solve.
"""
n = A.shape[0]
V_cols = []
G_cols = []
for lam, g in zip(assigned_lambdas, input_directions):
v = np.linalg.solve(A - lam * np.eye(n), B @ g)
V_cols.append(v)
G_cols.append(g)
V = np.column_stack(V_cols)
G = np.column_stack(G_cols)
X = np.column_stack((V, keep_basis))
Y = np.column_stack((G, np.zeros((B.shape[1], keep_basis.shape[1]))))
if X.shape[0] == X.shape[1] and abs(np.linalg.det(X)) > 1e-12:
K = Y @ np.linalg.inv(X)
else:
K = Y @ np.linalg.pinv(X)
return K, V, G, X, Y
def restricted_mode(A, B, lam, H):
"""Find one mode satisfying H v = 0 and (A-lambda I)v = B g.
Since v = (A-lambda I)^{-1} B g, the restriction becomes
H (A-lambda I)^{-1} B g = 0.
"""
n = A.shape[0]
M = np.linalg.solve(A - lam * np.eye(n), B)
S = H @ M
Gnull = null_space(S)
if Gnull.size == 0:
raise ValueError("No nonzero input direction satisfies the restriction.")
g = Gnull[:, 0]
v = M @ g
return v, g, S
# Example system: four states, two independent actuators.
A = np.diag([0.2, 0.6, -0.5, -1.0])
B = np.array([
[1.0, 0.0],
[0.3, 1.0],
[0.2, 0.4],
[0.1, 0.2]
])
# Assign two unstable/slow modes and keep two stable modes unchanged.
assigned_lambdas = [-2.0, -3.0]
input_directions = [np.array([1.0, 0.0]), np.array([0.0, 1.0])]
keep_basis = np.eye(4)[:, 2:4]
K, V, G, X, Y = partial_pole_placement(
A, B, assigned_lambdas, input_directions, keep_basis
)
Acl = A - B @ K
print("K =")
print(K)
print("Closed-loop eigenvalues =", np.sort_complex(eig(Acl, left=False, right=False)))
print("Condition number of X =", np.linalg.cond(X))
print("Assigned-mode residual ||Acl V - V Lambda|| =",
np.linalg.norm(Acl @ V - V @ np.diag(assigned_lambdas)))
print("Preservation residual ||K N_keep|| =", np.linalg.norm(K @ keep_basis))
# Restricted eigenstructure example: force the assigned eigenvector to satisfy x3 = x4.
H = np.array([[0.0, 0.0, 1.0, -1.0]])
v_restricted, g_restricted, S = restricted_mode(A, B, -2.0, H)
print("\nRestriction matrix S = H (A-lambda I)^(-1) B =")
print(S)
print("Restricted input direction g =", g_restricted)
print("Restricted eigenvector v =", v_restricted)
print("H v =", H @ v_restricted)
9. C++ Implementation
Chapter24_Lesson4.cpp
// Chapter24_Lesson4.cpp
// Partial Pole Placement and Restricted Eigenstructure
// Dependency: Eigen 3
// Build example: g++ -std=c++17 Chapter24_Lesson4.cpp -I /path/to/eigen -O2 -o Chapter24_Lesson4
#include <Eigen/Dense>
#include <Eigen/Eigenvalues>
#include <iostream>
#include <vector>
using Eigen::MatrixXd;
using Eigen::VectorXd;
int main() {
const int n = 4;
const int m = 2;
MatrixXd A = MatrixXd::Zero(n, n);
A(0,0) = 0.2;
A(1,1) = 0.6;
A(2,2) = -0.5;
A(3,3) = -1.0;
MatrixXd B(n, m);
B << 1.0, 0.0,
0.3, 1.0,
0.2, 0.4,
0.1, 0.2;
std::vector<double> lambdas = {-2.0, -3.0};
std::vector<VectorXd> gList;
VectorXd g1(m), g2(m);
g1 << 1.0, 0.0;
g2 << 0.0, 1.0;
gList.push_back(g1);
gList.push_back(g2);
MatrixXd V(n, 2);
MatrixXd G(m, 2);
for (int i = 0; i < 2; ++i) {
MatrixXd M = A - lambdas[i] * MatrixXd::Identity(n, n);
VectorXd v = M.fullPivLu().solve(B * gList[i]);
V.col(i) = v;
G.col(i) = gList[i];
}
MatrixXd Nkeep = MatrixXd::Zero(n, 2);
Nkeep(2,0) = 1.0;
Nkeep(3,1) = 1.0;
MatrixXd X(n, n);
X << V, Nkeep;
MatrixXd Y = MatrixXd::Zero(m, n);
Y.block(0, 0, m, 2) = G;
MatrixXd K = Y * X.inverse();
MatrixXd Acl = A - B * K;
Eigen::EigenSolver<MatrixXd> solver(Acl);
std::cout << "K =\n" << K << "\n\n";
std::cout << "Closed-loop eigenvalues =\n" << solver.eigenvalues() << "\n\n";
std::cout << "Assigned-mode residual norm = "
<< (Acl * V - V * (VectorXd(2) << lambdas[0], lambdas[1]).finished().asDiagonal()).norm()
<< "\n";
std::cout << "Preservation residual ||K Nkeep|| = " << (K * Nkeep).norm() << "\n\n";
// Restricted eigenstructure: require x3 = x4 for lambda = -2.
MatrixXd H(1, n);
H << 0.0, 0.0, 1.0, -1.0;
double lam = -2.0;
MatrixXd M = (A - lam * MatrixXd::Identity(n, n)).inverse() * B;
MatrixXd S = H * M;
// For a 1-by-2 row S = [a b], a null vector is [b, -a]^T.
VectorXd grest(m);
grest << S(0,1), -S(0,0);
VectorXd vrest = M * grest;
std::cout << "S = H(A-lambda I)^(-1)B =\n" << S << "\n";
std::cout << "Restricted g =\n" << grest << "\n";
std::cout << "Restricted v =\n" << vrest << "\n";
std::cout << "H v =\n" << H * vrest << "\n";
return 0;
}
10. Java Implementation
Chapter24_Lesson4.java
// Chapter24_Lesson4.java
// Partial Pole Placement and Restricted Eigenstructure
// Dependency: Apache Commons Math 3
// Compile example:
// javac -cp commons-math3-3.6.1.jar Chapter24_Lesson4.java
// java -cp .:commons-math3-3.6.1.jar Chapter24_Lesson4
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.linear.EigenDecomposition;
import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.linear.RealVector;
import org.apache.commons.math3.linear.ArrayRealVector;
public class Chapter24_Lesson4 {
static void printMatrix(String name, RealMatrix M) {
System.out.println(name + " =");
for (int i = 0; i < M.getRowDimension(); i++) {
for (int j = 0; j < M.getColumnDimension(); j++) {
System.out.printf("%12.6f ", M.getEntry(i, j));
}
System.out.println();
}
System.out.println();
}
static RealMatrix hstack(RealMatrix left, RealMatrix right) {
int rows = left.getRowDimension();
int cols = left.getColumnDimension() + right.getColumnDimension();
RealMatrix out = MatrixUtils.createRealMatrix(rows, cols);
out.setSubMatrix(left.getData(), 0, 0);
out.setSubMatrix(right.getData(), 0, left.getColumnDimension());
return out;
}
public static void main(String[] args) {
int n = 4;
double[][] Adata = {
{0.2, 0.0, 0.0, 0.0},
{0.0, 0.6, 0.0, 0.0},
{0.0, 0.0, -0.5, 0.0},
{0.0, 0.0, 0.0, -1.0}
};
double[][] Bdata = {
{1.0, 0.0},
{0.3, 1.0},
{0.2, 0.4},
{0.1, 0.2}
};
RealMatrix A = new Array2DRowRealMatrix(Adata);
RealMatrix B = new Array2DRowRealMatrix(Bdata);
double[] lambdas = {-2.0, -3.0};
double[][] Gdata = {
{1.0, 0.0},
{0.0, 1.0}
};
RealMatrix G = new Array2DRowRealMatrix(Gdata);
RealMatrix V = MatrixUtils.createRealMatrix(n, 2);
for (int i = 0; i < 2; i++) {
RealMatrix M = A.subtract(MatrixUtils.createRealIdentityMatrix(n).scalarMultiply(lambdas[i]));
RealVector g = G.getColumnVector(i);
RealVector v = MatrixUtils.inverse(M).operate(B.operate(g));
V.setColumnVector(i, v);
}
RealMatrix Nkeep = MatrixUtils.createRealMatrix(n, 2);
Nkeep.setEntry(2, 0, 1.0);
Nkeep.setEntry(3, 1, 1.0);
RealMatrix X = hstack(V, Nkeep);
RealMatrix zeros = MatrixUtils.createRealMatrix(2, 2);
RealMatrix Y = hstack(G, zeros);
RealMatrix K = Y.multiply(MatrixUtils.inverse(X));
RealMatrix Acl = A.subtract(B.multiply(K));
printMatrix("K", K);
EigenDecomposition eig = new EigenDecomposition(Acl);
System.out.println("Closed-loop eigenvalues:");
for (double val : eig.getRealEigenvalues()) {
System.out.printf("%12.6f ", val);
}
System.out.println("\n");
RealMatrix Lambda = MatrixUtils.createRealDiagonalMatrix(lambdas);
double assignedResidual = Acl.multiply(V).subtract(V.multiply(Lambda)).getFrobeniusNorm();
double keepResidual = K.multiply(Nkeep).getFrobeniusNorm();
System.out.printf("Assigned-mode residual = %.6e\n", assignedResidual);
System.out.printf("Preservation residual ||K Nkeep|| = %.6e\n\n", keepResidual);
// Restricted eigenstructure: require x3 = x4 for lambda = -2.
RealMatrix H = new Array2DRowRealMatrix(new double[][] { {0.0, 0.0, 1.0, -1.0} });
double lam = -2.0;
RealMatrix M = MatrixUtils.inverse(
A.subtract(MatrixUtils.createRealIdentityMatrix(n).scalarMultiply(lam))
).multiply(B);
RealMatrix S = H.multiply(M);
double a = S.getEntry(0, 0);
double b = S.getEntry(0, 1);
RealVector grest = new ArrayRealVector(new double[] {b, -a});
RealVector vrest = M.operate(grest);
printMatrix("S", S);
System.out.println("Restricted g = " + grest);
System.out.println("Restricted v = " + vrest);
System.out.println("H v = " + H.operate(vrest));
}
}
11. MATLAB and Simulink Implementation
Chapter24_Lesson4.m
% Chapter24_Lesson4.m
% Partial Pole Placement and Restricted Eigenstructure
% Requires: base MATLAB. Control System Toolbox is used only for ss/eig display.
clear; clc;
A = diag([0.2, 0.6, -0.5, -1.0]);
B = [1.0 0.0;
0.3 1.0;
0.2 0.4;
0.1 0.2];
assigned_lambdas = [-2.0, -3.0];
G = [1.0 0.0;
0.0 1.0];
V = zeros(4,2);
for i = 1:2
lam = assigned_lambdas(i);
g = G(:,i);
V(:,i) = (A - lam*eye(4)) \ (B*g);
end
Nkeep = [0 0;
0 0;
1 0;
0 1];
X = [V Nkeep];
Y = [G zeros(2,2)];
K = Y / X; % K X = Y
Acl = A - B*K;
fprintf('K =\n'); disp(K);
fprintf('Closed-loop eigenvalues =\n'); disp(eig(Acl).');
fprintf('cond(X) = %.6f\n', cond(X));
fprintf('Assigned-mode residual = %.6e\n', norm(Acl*V - V*diag(assigned_lambdas)));
fprintf('Preservation residual ||K*Nkeep|| = %.6e\n', norm(K*Nkeep));
% Restricted eigenstructure: require x3 = x4 for lambda = -2.
H = [0 0 1 -1];
lam = -2.0;
M = (A - lam*eye(4)) \ B;
S = H*M;
g_restricted = null(S);
g_restricted = g_restricted(:,1);
v_restricted = M*g_restricted;
fprintf('\nS = H*(A-lambda*I)^(-1)*B =\n'); disp(S);
fprintf('Restricted g =\n'); disp(g_restricted);
fprintf('Restricted v =\n'); disp(v_restricted);
fprintf('H*v =\n'); disp(H*v_restricted);
% Optional Simulink model creation for the closed-loop matrix.
% This creates a compact state-space simulation model if Simulink is installed.
if exist('new_system', 'file') == 2
model = 'Chapter24_Lesson4_simulink';
if bdIsLoaded(model)
close_system(model, 0);
end
new_system(model);
open_system(model);
add_block('simulink/Sources/Step', [model '/StepInput'], 'Position', [60 90 90 120]);
add_block('simulink/Continuous/State-Space', [model '/ClosedLoopSS'], 'Position', [160 70 310 150]);
add_block('simulink/Sinks/Scope', [model '/Scope'], 'Position', [380 85 430 135]);
set_param([model '/ClosedLoopSS'], ...
'A', 'Acl', 'B', 'B(:,1)', 'C', 'eye(4)', 'D', 'zeros(4,1)');
add_line(model, 'StepInput/1', 'ClosedLoopSS/1');
add_line(model, 'ClosedLoopSS/1', 'Scope/1');
set_param(model, 'StopTime', '8');
save_system(model);
fprintf('Created optional Simulink model: %s.slx\n', model);
end
12. Wolfram Mathematica Implementation
Chapter24_Lesson4.nb
(* Chapter24_Lesson4.nb *)
(* Partial Pole Placement and Restricted Eigenstructure *)
ClearAll["Global`*"];
A = DiagonalMatrix[{0.2, 0.6, -0.5, -1.0}];
B = { {1.0, 0.0}, {0.3, 1.0}, {0.2, 0.4}, {0.1, 0.2} };
assignedLambdas = {-2.0, -3.0};
G = { {1.0, 0.0}, {0.0, 1.0} };
vFor[lambda_, g_] := LinearSolve[A - lambda IdentityMatrix[4], B.g];
V = Transpose[{vFor[assignedLambdas[[1]], G[[All, 1]]],
vFor[assignedLambdas[[2]], G[[All, 2]]]}];
Nkeep = { {0, 0}, {0, 0}, {1, 0}, {0, 1} };
X = ArrayFlatten[{ {V, Nkeep} }];
Y = ArrayFlatten[{ {G, ConstantArray[0, {2, 2}]} }];
K = Y.Inverse[X];
Acl = A - B.K;
Print["K = ", MatrixForm[K]];
Print["Closed-loop eigenvalues = ", Eigenvalues[Acl]];
Print["Condition number of X = ", ConditionNumber[X]];
Print["Assigned-mode residual = ", Norm[Acl.V - V.DiagonalMatrix[assignedLambdas]]];
Print["Preservation residual = ", Norm[K.Nkeep]];
(* Restricted eigenstructure: require x3 = x4 for lambda = -2. *)
H = { {0, 0, 1, -1} };
lambda = -2.0;
M = LinearSolve[A - lambda IdentityMatrix[4], B];
S = H.M;
gRestricted = First[NullSpace[S]];
vRestricted = M.gRestricted;
Print["S = ", MatrixForm[S]];
Print["Restricted g = ", gRestricted];
Print["Restricted v = ", vRestricted];
Print["H v = ", H.vRestricted];
13. Problems and Solutions
Problem 1 (Mode Equation): Let \( \mathbf{u}=-\mathbf{K}\mathbf{x} \). Show that if \( (\mathbf{A}-\lambda\mathbf{I})\mathbf{v}=\mathbf{B}\mathbf{g} \) and \( \mathbf{K}\mathbf{v}=\mathbf{g} \), then \( \lambda \) is a closed-loop eigenvalue.
Solution:
\[ (\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{v}= \mathbf{A}\mathbf{v}-\mathbf{B}\mathbf{g}= \mathbf{A}\mathbf{v}-(\mathbf{A}-\lambda\mathbf{I})\mathbf{v}= \lambda\mathbf{v}. \]
Since \( \mathbf{v}\ne\mathbf{0} \), this is precisely the eigenvalue equation.
Problem 2 (Preserved Subspace): Suppose \( \mathbf{A}\mathbf{N}=\mathbf{N}\mathbf{M} \) and \( \mathbf{K}\mathbf{N}=\mathbf{0} \). Prove that \( \operatorname{span}(\mathbf{N}) \) remains invariant under \( \mathbf{A}-\mathbf{B}\mathbf{K} \).
Solution:
\[ (\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{N}= \mathbf{A}\mathbf{N}-\mathbf{B}\mathbf{K}\mathbf{N}= \mathbf{N}\mathbf{M}. \]
Therefore every vector in \( \operatorname{span}(\mathbf{N}) \) is mapped back into the same subspace. The eigenvalues internal to this subspace are the eigenvalues of \( \mathbf{M} \).
Problem 3 (Restricted Eigenvector Feasibility): Let \( \lambda\notin\sigma(\mathbf{A}) \) and require \( \mathbf{H}\mathbf{v}=\mathbf{0} \). Derive a condition for existence of a nonzero restricted eigenvector.
Solution: Since
\[ \mathbf{v}=(\mathbf{A}-\lambda\mathbf{I})^{-1}\mathbf{B}\mathbf{g}, \]
the restriction becomes
\[ \mathbf{H}(\mathbf{A}-\lambda\mathbf{I})^{-1}\mathbf{B}\mathbf{g}=\mathbf{0}. \]
A nonzero feasible direction exists exactly when the null space of this matrix contains a nonzero vector \( \mathbf{g} \). If no such vector exists, that pole and restriction are incompatible.
Problem 4 (Numerical Construction): For the example in Section 7, compute \( \mathbf{v}_1 \) for \( \lambda_1=-2 \) and \( \mathbf{g}_1=[1\;0]^T \).
Solution: Since
\[ \mathbf{A}+2\mathbf{I}=\operatorname{diag}(2.2,2.6,1.5,1.0), \]
we obtain
\[ \mathbf{v}_1=(\mathbf{A}+2\mathbf{I})^{-1}\mathbf{B} \begin{bmatrix}1\\0\end{bmatrix} =\begin{bmatrix} 1/2.2\\0.3/2.6\\0.2/1.5\\0.1/1.0 \end{bmatrix} =\begin{bmatrix}0.454545\\0.115385\\0.133333\\0.1\end{bmatrix}. \]
Problem 5 (Conditioning): Explain why two nearly parallel assigned eigenvectors can make partial pole placement numerically fragile.
Solution: The gain is computed from \( \mathbf{K}=\mathbf{Y}\mathbf{X}^{-1} \). If the columns of \( \mathbf{X} \) are nearly linearly dependent, then \( \kappa(\mathbf{X}) \) is large. A small perturbation in the model or in the computed eigenvectors can produce a large perturbation in \( \mathbf{K} \) and in the closed-loop eigenvalues. Therefore, when MIMO design freedom exists, the input directions \( \mathbf{g}_i \) should be chosen to keep \( \mathbf{X} \) well-conditioned.
14. Summary
Partial pole placement assigns selected closed-loop modes without unnecessarily changing the entire spectrum. The core construction uses the equations \( (\mathbf{A}-\lambda_i\mathbf{I})\mathbf{v}_i= \mathbf{B}\mathbf{g}_i \) and \( \mathbf{K}\mathbf{V}_a=\mathbf{G}_a \). Preserved modes are enforced by \( \mathbf{K}\mathbf{N}=\mathbf{0} \). Restricted eigenstructure assignment adds constraints such as \( \mathbf{H}_i\mathbf{v}_i=\mathbf{0} \), converting modal-shape requirements into null-space conditions on the input directions.
15. 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(6), 689–692.
- Klein, G., & Moore, B. C. (1977). Eigenvalue-generalized eigenvector assignment with state feedback. IEEE Transactions on Automatic Control, 22(1), 140–141.
- Fahmy, M. M., & O'Reilly, J. (1982). On eigenstructure assignment in linear multivariable systems. IEEE Transactions on Automatic Control, 27(3), 690–693.
- Bhattacharyya, S. P., & de Souza, E. (1982). Pole assignment via Sylvester's equation. Systems & Control Letters, 1(4), 261–263.
- Andry, A. N., Shapiro, E. Y., & Chung, J. C. (1983). Eigenstructure assignment for linear systems. IEEE Transactions on Aerospace and Electronic Systems, AES-19(5), 711–729.
- Fahmy, M. M., & O'Reilly, J. (1984). Eigenstructure assignment via linear state-feedback control. International Journal of Control, 40(1), 161–168.
- Kautsky, J., Nichols, N. K., & Van Dooren, P. (1985). Robust pole assignment in linear state feedback. International Journal of Control, 41(5), 1129–1155.
- Byers, R., & Nash, S. G. (1989). Approaches to robust pole assignment. International Journal of Control, 49(1), 97–117.
- Varga, A. (2000). Robust pole assignment techniques via state feedback. Proceedings of the IEEE Conference on Decision and Control, 4655–4660.