Chapter 23: Pole Placement for Single-Input Systems
Lesson 2: Pole Assignment via Controllable Canonical Form
This lesson develops the most transparent algebraic method for assigning closed-loop poles in a single-input controllable system: transform the system to controllable canonical form, apply state feedback, and match the coefficients of the desired characteristic polynomial. The method reveals why controllability is the exact structural condition behind arbitrary pole placement.
1. Problem Setting and Design Objective
Consider the continuous-time single-input LTI system \( \dot{\mathbf{x}}=\mathbf{A}\mathbf{x}+\mathbf{b}u \), where \( \mathbf{x}\in\mathbb{R}^n \), \( u\in\mathbb{R} \), \( \mathbf{A}\in\mathbb{R}^{n\times n} \), and \( \mathbf{b}\in\mathbb{R}^{n} \). In state-feedback pole placement, the input is chosen as
\[ u=-\mathbf{K}\mathbf{x}+r,\qquad \mathbf{K}=\begin{bmatrix}k_1&k_2&\cdots&k_n\end{bmatrix}. \]
The closed-loop state matrix is therefore \( \mathbf{A}_{cl}=\mathbf{A}-\mathbf{b}\mathbf{K} \). The pole assignment problem is to choose \( \mathbf{K} \) so that
\[ \det(s\mathbf{I}-\mathbf{A}+\mathbf{b}\mathbf{K}) =\phi_d(s), \]
where the desired monic polynomial is
\[ \phi_d(s)=s^n+\alpha_{n-1}s^{n-1}+\alpha_{n-2}s^{n-2} +\cdots+\alpha_1s+\alpha_0. \]
In this lesson we solve the problem first in controllable canonical coordinates, where the feedback gains appear directly as characteristic polynomial coefficients.
2. Controllable Canonical Form Convention
A single-input system is in controllable canonical form if its state equation can be written as
\[ \dot{\mathbf{z}}=\mathbf{A}_c\mathbf{z}+\mathbf{b}_cu, \]
with
\[ \mathbf{A}_c= \begin{bmatrix} 0 & 1 & 0 & \cdots & 0\\ 0 & 0 & 1 & \cdots & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 0 & 0 & 0 & \cdots & 1\\ -a_0 & -a_1 & -a_2 & \cdots & -a_{n-1} \end{bmatrix},\qquad \mathbf{b}_c= \begin{bmatrix} 0\\0\\ \vdots\\0\\1 \end{bmatrix}. \]
The open-loop characteristic polynomial of \( \mathbf{A}_c \) is
\[ p_c(s)=\det(s\mathbf{I}-\mathbf{A}_c) =s^n+a_{n-1}s^{n-1}+\cdots+a_1s+a_0. \]
The coefficients \( a_0,a_1,\ldots,a_{n-1} \) appear only in the last row of \( \mathbf{A}_c \). This is why pole assignment becomes especially simple in this coordinate system.
3. Feedback in Controllable Canonical Coordinates
In canonical coordinates, choose \( u=-\mathbf{K}_c\mathbf{z}+r \), where
\[ \mathbf{K}_c= \begin{bmatrix} k_0 & k_1 & \cdots & k_{n-1} \end{bmatrix}. \]
The closed-loop matrix becomes
\[ \mathbf{A}_{c,cl} =\mathbf{A}_c-\mathbf{b}_c\mathbf{K}_c = \begin{bmatrix} 0 & 1 & 0 & \cdots & 0\\ 0 & 0 & 1 & \cdots & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 0 & 0 & 0 & \cdots & 1\\ -(a_0+k_0) & -(a_1+k_1) & -(a_2+k_2) & \cdots & -(a_{n-1}+k_{n-1}) \end{bmatrix}. \]
Therefore its characteristic polynomial is
\[ \det(s\mathbf{I}-\mathbf{A}_{c,cl}) =s^n+(a_{n-1}+k_{n-1})s^{n-1} +\cdots+(a_1+k_1)s+(a_0+k_0). \]
Matching this polynomial with \( \phi_d(s) \) gives the canonical feedback gain directly:
\[ \boxed{ \mathbf{K}_c= \begin{bmatrix} \alpha_0-a_0 & \alpha_1-a_1 & \cdots & \alpha_{n-1}-a_{n-1} \end{bmatrix}.} \]
4. Proof by Coefficient Matching
The proof follows from the companion structure. Since \( \mathbf{b}_c\mathbf{K}_c \) has all rows zero except the last row,
\[ \mathbf{b}_c\mathbf{K}_c = \begin{bmatrix} 0 & 0 & \cdots & 0\\ 0 & 0 & \cdots & 0\\ \vdots & \vdots & \ddots & \vdots\\ k_0 & k_1 & \cdots & k_{n-1} \end{bmatrix}. \]
Thus feedback changes only the final row of the companion matrix. For a companion matrix with last row \( -c_0,-c_1,\ldots,-c_{n-1} \), the characteristic polynomial is
\[ s^n+c_{n-1}s^{n-1}+\cdots+c_1s+c_0. \]
In the closed-loop matrix, the effective coefficients are \( c_i=a_i+k_i \). Hence requiring \( c_i=\alpha_i \) for every \( i=0,1,\ldots,n-1 \) yields \( k_i=\alpha_i-a_i \). This establishes the coefficient-matching pole assignment formula in controllable canonical form.
5. Design Workflow in Canonical Coordinates
For a system already in controllable canonical form, the design procedure is purely algebraic.
flowchart TD
A["Start with SISO system in CCF"] --> B["Read open-loop coefficients a0,...,a(n-1)"]
B --> C["Choose desired closed-loop poles"]
C --> D["Build desired polynomial coefficients alpha0,...,alpha(n-1)"]
D --> E["Compute Kc = alpha - a"]
E --> F["Form Acl = Ac - bc Kc"]
F --> G["Verify eigenvalues of Acl"]
If the desired poles are \( \lambda_1,\lambda_2,\ldots,\lambda_n \), then
\[ \phi_d(s)=\prod_{i=1}^{n}(s-\lambda_i). \]
Expanding the product gives the coefficients \( \alpha_0,\alpha_1,\ldots,\alpha_{n-1} \).
6. Transformation from a General Controllable Pair to CCF
Suppose the original coordinates are \( \mathbf{x} \), while the controllable canonical coordinates are \( \mathbf{z} \). Let
\[ \mathbf{x}=\mathbf{T}\mathbf{z}. \]
Then
\[ \dot{\mathbf{z}} =\mathbf{T}^{-1}\mathbf{A}\mathbf{T}\mathbf{z} +\mathbf{T}^{-1}\mathbf{b}u. \]
To obtain CCF, choose \( \mathbf{T} \) so that
\[ \mathbf{A}_c=\mathbf{T}^{-1}\mathbf{A}\mathbf{T},\qquad \mathbf{b}_c=\mathbf{T}^{-1}\mathbf{b}. \]
Define the controllability matrices
\[ \mathcal{C}= \begin{bmatrix} \mathbf{b}&\mathbf{A}\mathbf{b}&\cdots &\mathbf{A}^{n-1}\mathbf{b} \end{bmatrix},\qquad \mathcal{C}_c= \begin{bmatrix} \mathbf{b}_c&\mathbf{A}_c\mathbf{b}_c&\cdots &\mathbf{A}_c^{n-1}\mathbf{b}_c \end{bmatrix}. \]
Since \( \mathbf{x}=\mathbf{T}\mathbf{z} \), the columns generated by reachability satisfy \( \mathcal{C}=\mathbf{T}\mathcal{C}_c \). Therefore,
\[ \boxed{\mathbf{T}=\mathcal{C}\mathcal{C}_c^{-1}.} \]
The physical-coordinate gain is not \( \mathbf{K}_c \). Because \( \mathbf{z}=\mathbf{T}^{-1}\mathbf{x} \),
\[ u=-\mathbf{K}_c\mathbf{z}+r =-\mathbf{K}_c\mathbf{T}^{-1}\mathbf{x}+r. \]
Hence
\[ \boxed{\mathbf{K}=\mathbf{K}_c\mathbf{T}^{-1}.} \]
flowchart TD
X["Original coordinates x"] --> T["x = T z"]
T --> Z["Canonical coordinates z"]
Z --> KC["Design Kc by coefficient matching"]
KC --> KX["Map back: K = Kc T inverse"]
KX --> CL["Closed-loop matrix: A - b K"]
7. Controllability as the Existence Condition
The transformation above requires \( \mathcal{C}^{-1} \) implicitly through \( \mathbf{T}=\mathcal{C}\mathcal{C}_c^{-1} \). Therefore the original system must satisfy
\[ \operatorname{rank}\mathcal{C}=n. \]
This is exactly the Kalman controllability condition. If the pair \( (\mathbf{A},\mathbf{b}) \) is controllable, the coordinates can be transformed to CCF and arbitrary closed-loop pole assignment is possible. If it is not controllable, some modes are not affected by the input and their poles cannot be moved by state feedback.
Thus, for single-input systems, the following statement is fundamental:
\[ (\mathbf{A},\mathbf{b})\text{ controllable} \quad\Longleftrightarrow\quad \text{arbitrary assignment of }n\text{ closed-loop poles is possible}. \]
8. Worked Third-Order Example
Consider the CCF system with open-loop characteristic polynomial
\[ p_c(s)=s^3+6s^2+11s+6. \]
Therefore \( a_0=6,\;a_1=11,\;a_2=6 \), and
\[ \mathbf{A}_c= \begin{bmatrix} 0&1&0\\ 0&0&1\\ -6&-11&-6 \end{bmatrix},\qquad \mathbf{b}_c= \begin{bmatrix} 0\\0\\1 \end{bmatrix}. \]
Suppose the desired closed-loop poles are \( -4,-5,-6 \). Then
\[ \phi_d(s)=(s+4)(s+5)(s+6)=s^3+15s^2+74s+120. \]
Thus \( \alpha_0=120,\;\alpha_1=74,\;\alpha_2=15 \). The canonical feedback gain is
\[ \mathbf{K}_c= \begin{bmatrix} 120-6 & 74-11 & 15-6 \end{bmatrix} = \begin{bmatrix} 114 & 63 & 9 \end{bmatrix}. \]
The closed-loop matrix is
\[ \mathbf{A}_{c,cl}= \begin{bmatrix} 0&1&0\\ 0&0&1\\ -120&-74&-15 \end{bmatrix}, \]
whose characteristic polynomial is \( s^3+15s^2+74s+120 \), as required.
9. Implementation: Python
Chapter23_Lesson2.py
"""
Chapter23_Lesson2.py
Pole Assignment via Controllable Canonical Form (CCF)
"""
import numpy as np
def companion_pair_from_coefficients(a_ascending):
a = np.asarray(a_ascending, dtype=float)
n = len(a)
A = np.zeros((n, n))
if n > 1:
A[:-1, 1:] = np.eye(n - 1)
A[-1, :] = -a
b = np.zeros((n, 1))
b[-1, 0] = 1.0
return A, b
def controllability_matrix(A, b):
A = np.asarray(A, dtype=float)
b = np.asarray(b, dtype=float).reshape((-1, 1))
n = A.shape[0]
cols = []
v = b.copy()
for _ in range(n):
cols.append(v)
v = A @ v
return np.hstack(cols)
def desired_coefficients_from_poles(poles):
coeff_desc = np.poly(np.asarray(poles, dtype=complex))
coeff_desc = np.real_if_close(coeff_desc, tol=1000)
return np.asarray(coeff_desc[1:][::-1], dtype=float)
def ccf_gain(open_coeffs_ascending, desired_poles):
a = np.asarray(open_coeffs_ascending, dtype=float)
alpha = desired_coefficients_from_poles(desired_poles)
if len(a) != len(alpha):
raise ValueError("Number of desired poles must match system order.")
return alpha - a
def transform_to_ccf_gain(A, b, open_coeffs_ascending, desired_poles):
A = np.asarray(A, dtype=float)
b = np.asarray(b, dtype=float).reshape((-1, 1))
Ac, bc = companion_pair_from_coefficients(open_coeffs_ascending)
M = controllability_matrix(A, b)
Mc = controllability_matrix(Ac, bc)
if np.linalg.matrix_rank(M) < A.shape[0]:
raise ValueError("The pair (A,b) is not controllable.")
T = M @ np.linalg.inv(Mc)
Kc = ccf_gain(open_coeffs_ascending, desired_poles).reshape((1, -1))
Kx = Kc @ np.linalg.inv(T)
return Kx, Kc, T, Ac, bc
def main():
a = np.array([6.0, 11.0, 6.0])
desired_poles = np.array([-4.0, -5.0, -6.0])
Ac, bc = companion_pair_from_coefficients(a)
Kc = ccf_gain(a, desired_poles)
Acl = Ac - bc @ Kc.reshape(1, -1)
print("A_c =\n", Ac)
print("b_c =\n", bc)
print("K_c =", Kc)
print("Closed-loop eigenvalues =", np.linalg.eigvals(Acl))
T_true = np.array([[1.0, 2.0, 0.0],
[0.0, 1.0, 1.0],
[2.0, 0.0, 1.0]])
A = T_true @ Ac @ np.linalg.inv(T_true)
b = T_true @ bc
Kx, Kc2, T, _, _ = transform_to_ccf_gain(A, b, a, desired_poles)
print("\nK_x =", Kx)
print("Recovered T =\n", T)
print("Eigenvalues of A-bK_x =", np.linalg.eigvals(A - b @ Kx))
if __name__ == "__main__":
main()
10. Implementation: C++
Chapter23_Lesson2.cpp
/*
Chapter23_Lesson2.cpp
Pole Assignment via Controllable Canonical Form (CCF)
*/
#include <cmath>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <vector>
using Matrix = std::vector<std::vector<double>>;
using Vector = std::vector<double>;
Matrix companionMatrix(const Vector& aAscending) {
const int n = static_cast<int>(aAscending.size());
Matrix A(n, Vector(n, 0.0));
for (int i = 0; i < n - 1; ++i) {
A[i][i + 1] = 1.0;
}
for (int j = 0; j < n; ++j) {
A[n - 1][j] = -aAscending[j];
}
return A;
}
Vector inputVector(int n) {
Vector b(n, 0.0);
b[n - 1] = 1.0;
return b;
}
Vector polynomialFromRealRoots(const Vector& roots) {
Vector coeff(1, 1.0);
for (double r : roots) {
Vector next(coeff.size() + 1, 0.0);
for (std::size_t i = 0; i < coeff.size(); ++i) {
next[i] += coeff[i];
next[i + 1] += -r * coeff[i];
}
coeff = next;
}
return coeff;
}
Vector desiredCoefficientsAscending(const Vector& desiredPoles) {
Vector desc = polynomialFromRealRoots(desiredPoles);
const int n = static_cast<int>(desiredPoles.size());
Vector asc(n);
for (int i = 0; i < n; ++i) {
asc[i] = desc[n - i];
}
return asc;
}
Vector ccfGain(const Vector& openCoeffsAscending, const Vector& desiredPoles) {
Vector alpha = desiredCoefficientsAscending(desiredPoles);
if (alpha.size() != openCoeffsAscending.size()) {
throw std::runtime_error("System order and number of desired poles differ.");
}
Vector K(alpha.size());
for (std::size_t i = 0; i < alpha.size(); ++i) {
K[i] = alpha[i] - openCoeffsAscending[i];
}
return K;
}
Matrix closedLoopMatrix(const Matrix& A, const Vector& b, const Vector& K) {
const int n = static_cast<int>(A.size());
Matrix Acl = A;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
Acl[i][j] -= b[i] * K[j];
}
}
return Acl;
}
void printMatrix(const Matrix& A, const std::string& name) {
std::cout << name << " =\n";
for (const auto& row : A) {
for (double v : row) {
std::cout << std::setw(12) << std::setprecision(6) << v << " ";
}
std::cout << "\n";
}
}
void printVector(const Vector& v, const std::string& name) {
std::cout << name << " = [ ";
for (double x : v) {
std::cout << std::setprecision(6) << x << " ";
}
std::cout << "]\n";
}
int main() {
Vector a = {6.0, 11.0, 6.0};
Vector desiredPoles = {-4.0, -5.0, -6.0};
Matrix Ac = companionMatrix(a);
Vector bc = inputVector(static_cast<int>(a.size()));
Vector Kc = ccfGain(a, desiredPoles);
Matrix Acl = closedLoopMatrix(Ac, bc, Kc);
printMatrix(Ac, "A_c");
printVector(bc, "b_c");
printVector(Kc, "K_c");
printMatrix(Acl, "A_c - b_c K_c");
std::cout << "\nExpected closed-loop characteristic polynomial:\n";
std::cout << "s^3 + 15 s^2 + 74 s + 120 = (s+4)(s+5)(s+6)\n";
return 0;
}
11. Implementation: Java
Chapter23_Lesson2.java
/*
Chapter23_Lesson2.java
Pole Assignment via Controllable Canonical Form (CCF)
*/
import java.util.Arrays;
public class Chapter23_Lesson2 {
static double[][] companionMatrix(double[] aAscending) {
int n = aAscending.length;
double[][] A = new double[n][n];
for (int i = 0; i < n - 1; i++) {
A[i][i + 1] = 1.0;
}
for (int j = 0; j < n; j++) {
A[n - 1][j] = -aAscending[j];
}
return A;
}
static double[] inputVector(int n) {
double[] b = new double[n];
b[n - 1] = 1.0;
return b;
}
static double[] polynomialFromRealRoots(double[] roots) {
double[] coeff = {1.0};
for (double r : roots) {
double[] next = new double[coeff.length + 1];
for (int i = 0; i < coeff.length; i++) {
next[i] += coeff[i];
next[i + 1] += -r * coeff[i];
}
coeff = next;
}
return coeff;
}
static double[] desiredCoefficientsAscending(double[] desiredPoles) {
double[] desc = polynomialFromRealRoots(desiredPoles);
int n = desiredPoles.length;
double[] asc = new double[n];
for (int i = 0; i < n; i++) {
asc[i] = desc[n - i];
}
return asc;
}
static double[] ccfGain(double[] openCoeffsAscending, double[] desiredPoles) {
double[] alpha = desiredCoefficientsAscending(desiredPoles);
if (alpha.length != openCoeffsAscending.length) {
throw new IllegalArgumentException("System order and number of desired poles differ.");
}
double[] K = new double[alpha.length];
for (int i = 0; i < alpha.length; i++) {
K[i] = alpha[i] - openCoeffsAscending[i];
}
return K;
}
static double[][] closedLoopMatrix(double[][] A, double[] b, double[] K) {
int n = A.length;
double[][] Acl = new double[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
Acl[i][j] = A[i][j] - b[i] * K[j];
}
}
return Acl;
}
static void printMatrix(double[][] A, String name) {
System.out.println(name + " =");
for (double[] row : A) {
System.out.println(Arrays.toString(row));
}
}
static void printVector(double[] v, String name) {
System.out.println(name + " = " + Arrays.toString(v));
}
public static void main(String[] args) {
double[] a = {6.0, 11.0, 6.0};
double[] desiredPoles = {-4.0, -5.0, -6.0};
double[][] Ac = companionMatrix(a);
double[] bc = inputVector(a.length);
double[] Kc = ccfGain(a, desiredPoles);
double[][] Acl = closedLoopMatrix(Ac, bc, Kc);
printMatrix(Ac, "A_c");
printVector(bc, "b_c");
printVector(Kc, "K_c");
printMatrix(Acl, "A_c - b_c K_c");
System.out.println("\nExpected closed-loop polynomial:");
System.out.println("s^3 + 15 s^2 + 74 s + 120 = (s+4)(s+5)(s+6)");
}
}
12. Implementation: MATLAB / Simulink
Chapter23_Lesson2.m
% Chapter23_Lesson2.m
% Pole Assignment via Controllable Canonical Form (CCF)
clear; clc;
a = [6 11 6];
desiredPoles = [-4 -5 -6];
[Ac, bc] = companion_pair_from_coefficients(a);
Kc = ccf_gain(a, desiredPoles);
Acl = Ac - bc*Kc;
disp('A_c ='); disp(Ac);
disp('b_c ='); disp(bc);
disp('K_c ='); disp(Kc);
disp('eig(A_c-b_c*K_c) ='); disp(eig(Acl).');
if exist('place', 'file') == 2
K_place = place(Ac, bc, desiredPoles);
disp('K from MATLAB place(Ac,bc,desiredPoles) =');
disp(K_place);
end
C = eye(size(Ac,1));
D = zeros(size(Ac,1),1);
sys_cl = ss(Acl, bc, C, D);
t = linspace(0, 5, 300);
r = ones(size(t));
[y, t, x] = lsim(sys_cl, r, t);
figure('Name','Chapter23 Lesson2 CCF Pole Assignment');
plot(t, x, 'LineWidth', 1.5);
grid on;
xlabel('Time (s)');
ylabel('States');
title('Closed-loop response in controllable canonical coordinates');
legend('z_1','z_2','z_3');
if exist('new_system', 'file') == 2
model = 'Chapter23_Lesson2_Simulink_CCF';
if bdIsLoaded(model)
close_system(model, 0);
end
new_system(model);
open_system(model);
add_block('simulink/Sources/Step', [model '/reference_step'], ...
'Position', [50 80 90 110]);
add_block('simulink/Continuous/State-Space', [model '/closed_loop_ss'], ...
'Position', [160 65 300 125], ...
'A', mat2str(Acl), ...
'B', mat2str(bc), ...
'C', mat2str(C), ...
'D', mat2str(D));
add_block('simulink/Sinks/Scope', [model '/state_scope'], ...
'Position', [370 70 410 120]);
add_line(model, 'reference_step/1', 'closed_loop_ss/1');
add_line(model, 'closed_loop_ss/1', 'state_scope/1');
set_param(model, 'StopTime', '5');
save_system(model);
disp(['Created Simulink model: ' model '.slx']);
end
function [A, b] = companion_pair_from_coefficients(aAscending)
n = numel(aAscending);
A = zeros(n);
if n > 1
A(1:n-1,2:n) = eye(n-1);
end
A(n,:) = -aAscending(:).';
b = zeros(n,1);
b(n) = 1;
end
function alphaAscending = desired_coefficients_from_poles(poles)
desc = poly(poles);
alphaAscending = fliplr(desc(2:end));
end
function K = ccf_gain(aAscending, desiredPoles)
alpha = desired_coefficients_from_poles(desiredPoles);
if numel(alpha) ~= numel(aAscending)
error('Number of desired poles must match system order.');
end
K = alpha - aAscending;
end
13. Implementation: Wolfram Mathematica
Chapter23_Lesson2.nb
ClearAll[companionPair, desiredCoeffsAscending, ccfGain];
companionPair[aAscending_List] := Module[{n, A, b},
n = Length[aAscending];
A = ConstantArray[0, {n, n}];
Do[A[[i, i + 1]] = 1, {i, 1, n - 1}];
A[[n]] = -aAscending;
b = UnitVector[n, n];
{A, b}
];
desiredCoeffsAscending[poles_List] := Module[{poly},
poly = Expand[Times @@ (s - poles)];
Reverse[Rest[CoefficientList[poly, s]]]
];
ccfGain[aAscending_List, desiredPoles_List] := Module[{alpha},
alpha = desiredCoeffsAscending[desiredPoles];
alpha - aAscending
];
a = {6, 11, 6};
desiredPoles = {-4, -5, -6};
{Ac, bc} = companionPair[a];
Kc = ccfGain[a, desiredPoles];
Acl = Ac - Outer[Times, bc, Kc];
Ac
bc
Kc
Eigenvalues[Acl]
CharacteristicPolynomial[Acl, s]
14. Problems and Solutions
Problem 1: A second-order CCF system has
\[ \mathbf{A}_c= \begin{bmatrix} 0&1\\ -2&-3 \end{bmatrix},\qquad \mathbf{b}_c= \begin{bmatrix} 0\\1 \end{bmatrix}. \]
Assign the closed-loop poles to \( -4 \) and \( -5 \).
Solution:
\[ p_c(s)=s^2+3s+2,\qquad \phi_d(s)=(s+4)(s+5)=s^2+9s+20. \]
Thus \( a_0=2,\;a_1=3 \) and \( \alpha_0=20,\;\alpha_1=9 \). Therefore
\[ \mathbf{K}_c= \begin{bmatrix} 20-2 & 9-3 \end{bmatrix} = \begin{bmatrix} 18 & 6 \end{bmatrix}. \]
Problem 2: For the CCF system
\[ p_c(s)=s^3+4s^2+5s+2, \]
find \( \mathbf{K}_c \) if the desired polynomial is \( \phi_d(s)=s^3+10s^2+31s+30 \).
Solution:
\[ a_0=2,\quad a_1=5,\quad a_2=4,\qquad \alpha_0=30,\quad \alpha_1=31,\quad \alpha_2=10. \]
\[ \mathbf{K}_c= \begin{bmatrix} 30-2 & 31-5 & 10-4 \end{bmatrix} = \begin{bmatrix} 28 & 26 & 6 \end{bmatrix}. \]
Problem 3: Suppose \( \mathbf{x}=\mathbf{T}\mathbf{z} \) and \( \mathbf{K}_c \) has already been designed in CCF coordinates. Derive the feedback gain in the original coordinates.
Solution:
\[ \mathbf{z}=\mathbf{T}^{-1}\mathbf{x}. \]
Since the canonical feedback law is \( u=-\mathbf{K}_c\mathbf{z}+r \), substitution gives
\[ u=-\mathbf{K}_c\mathbf{T}^{-1}\mathbf{x}+r. \]
Therefore the physical-coordinate gain is
\[ \boxed{\mathbf{K}=\mathbf{K}_c\mathbf{T}^{-1}.} \]
Problem 4: Explain why the CCF pole assignment method fails if \( \operatorname{rank}\mathcal{C}\neq n \).
Solution:
The transformation to controllable canonical form requires an invertible coordinate transformation. Since \( \mathbf{T}=\mathcal{C}\mathcal{C}_c^{-1} \), the matrix \( \mathcal{C} \) must have full rank. If \( \operatorname{rank}\mathcal{C}\neq n \), the input cannot excite every state-space direction. Hence some modes are uncontrollable and their eigenvalues remain fixed under state feedback. Arbitrary assignment of all closed-loop poles is therefore impossible.
Problem 5: A fourth-order CCF system has \( p_c(s)=s^4+2s^3+3s^2+4s+5 \). Desired poles are \( -1,-2,-3,-4 \). Compute \( \mathbf{K}_c \).
Solution:
\[ \phi_d(s)=(s+1)(s+2)(s+3)(s+4) =s^4+10s^3+35s^2+50s+24. \]
The open-loop coefficients in ascending order are \( a_0=5,\;a_1=4,\;a_2=3,\;a_3=2 \). The desired coefficients are \( \alpha_0=24,\;\alpha_1=50,\;\alpha_2=35,\;\alpha_3=10 \). Thus
\[ \mathbf{K}_c= \begin{bmatrix} 24-5 & 50-4 & 35-3 & 10-2 \end{bmatrix} = \begin{bmatrix} 19 & 46 & 32 & 8 \end{bmatrix}. \]
15. Summary
Pole assignment in controllable canonical form is based on a simple but powerful fact: state feedback changes only the final row of the companion matrix, and that row directly determines the characteristic polynomial coefficients. Therefore the canonical gain is obtained by subtracting the open-loop coefficients from the desired coefficients. For a general controllable single-input pair, one first maps the system into CCF, designs \( \mathbf{K}_c \), and maps the gain back using \( \mathbf{K}=\mathbf{K}_c\mathbf{T}^{-1} \).
16. References
- Kalman, R.E. (1960). Contributions to the theory of optimal control. Boletin de la Sociedad Matematica 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.
- Wonham, W.M. (1967). On pole assignment in multi-input controllable linear systems. IEEE Transactions on Automatic Control, 12(6), 660–665.
- Bass, R.W., & Gura, I. (1965). High-order system design via state space considerations. Proceedings of the Joint Automatic Control Conference, 311–318.
- Luenberger, D.G. (1967). Canonical forms for linear multivariable systems. IEEE Transactions on Automatic Control, 12(3), 290–293.
- Davison, E.J. (1968). On pole assignment in linear systems with incomplete state feedback. IEEE Transactions on Automatic Control, 13(3), 348–351.
- Kailath, T. (1980). Linear systems. Although a textbook, its treatment of canonical forms and controllability follows the theoretical development established in the systems literature.