Chapter 22: Fundamentals of State-Feedback Control

Lesson 2: Closed-Loop State Matrix and Mode Relocation

This lesson studies how full-state feedback changes the internal dynamics of a linear state-space system. Starting from \( \dot{\mathbf{x} }=\mathbf{A}\mathbf{x}+\mathbf{B}\mathbf{u} \) and the feedback law \( \mathbf{u}=-\mathbf{K}\mathbf{x}+\mathbf{r} \), we derive the closed-loop state matrix \( \mathbf{A}_{cl}=\mathbf{A}-\mathbf{B}\mathbf{K} \), interpret its eigenvalues as relocated closed-loop modes, and prove which modes can and cannot be moved by state feedback.

1. From Open-Loop Dynamics to Closed-Loop Dynamics

Consider the continuous-time LTI system \( \dot{\mathbf{x} }(t)=\mathbf{A}\mathbf{x}(t)+\mathbf{B}\mathbf{u}(t) \), where \( \mathbf{x}(t)\in\mathbb{R}^{n} \), \( \mathbf{u}(t)\in\mathbb{R}^{m} \), \( \mathbf{A}\in\mathbb{R}^{n\times n} \), and \( \mathbf{B}\in\mathbb{R}^{n\times m} \). Under full-state feedback,

\[ \mathbf{u}(t)=-\mathbf{K}\mathbf{x}(t)+\mathbf{r}(t),\qquad \mathbf{K}\in\mathbb{R}^{m\times n}. \]

Substitution gives

\[ \dot{\mathbf{x} }(t)= \mathbf{A}\mathbf{x}(t)+\mathbf{B}\big(-\mathbf{K}\mathbf{x}(t)+\mathbf{r}(t)\big) =(\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{x}(t)+\mathbf{B}\mathbf{r}(t). \]

Therefore, the autonomous part of the closed-loop system is governed by the matrix

\[ \boxed{\mathbf{A}_{cl}=\mathbf{A}-\mathbf{B}\mathbf{K} }. \]

The reference input \( \mathbf{r}(t) \) affects the forced response, but the internal closed-loop modes are determined by \( \mathbf{A}_{cl} \).

flowchart TD
  R["reference r"] --> SUM["sum: r minus Kx"]
  X["state x"] --> FB["gain K"]
  FB --> SUM
  SUM --> U["control input u"]
  U --> PLANT["plant: x_dot = A x + B u"]
  PLANT --> X
  PLANT --> ACL["closed-loop matrix: Acl = A - B K"]
        

2. Closed-Loop Modes

The open-loop modes are the eigenvalues of \( \mathbf{A} \). The closed-loop modes are the eigenvalues of \( \mathbf{A}_{cl}=\mathbf{A}-\mathbf{B}\mathbf{K} \). Thus the closed-loop characteristic polynomial is

\[ p_{cl}(s)=\det\!\left(s\mathbf{I}-\mathbf{A}_{cl}\right) =\det\!\left(s\mathbf{I}-\mathbf{A}+\mathbf{B}\mathbf{K}\right). \]

The homogeneous closed-loop solution is

\[ \mathbf{x}(t)=e^{(\mathbf{A}-\mathbf{B}\mathbf{K})t}\mathbf{x}(0). \]

Hence, if all eigenvalues of \( \mathbf{A}-\mathbf{B}\mathbf{K} \) satisfy \( \operatorname{Re}(\lambda_i)<0 \), then the closed-loop origin is asymptotically stable. More generally, the qualitative response is shaped by the spectral data of \( \mathbf{A}_{cl} \): real modes yield exponential decay or growth, complex modes yield oscillatory exponentials, and repeated defective modes may introduce polynomial factors multiplying exponentials.

\[ \lambda_i(\mathbf{A}) \quad \text{open-loop modes},\qquad \lambda_i(\mathbf{A}-\mathbf{B}\mathbf{K}) \quad \text{closed-loop modes}. \]

3. Meaning of Mode Relocation

Mode relocation means modifying the eigenvalues of the autonomous state matrix by choosing the feedback gain \( \mathbf{K} \). In classical transfer-function language, one often speaks of moving closed-loop poles. In state-space language, the same idea is expressed as relocating the eigenvalues of \( \mathbf{A}_{cl} \).

For a desired set of closed-loop modes \( \{\mu_1,\mu_2,\dots,\mu_n\} \), the desired characteristic polynomial is

\[ p_d(s)=\prod_{i=1}^{n}(s-\mu_i) =s^n+\alpha_{n-1}s^{n-1}+\cdots+\alpha_1s+\alpha_0. \]

The design goal is to choose \( \mathbf{K} \) such that

\[ \det\!\left(s\mathbf{I}-\mathbf{A}+\mathbf{B}\mathbf{K}\right) =p_d(s). \]

In later lessons, we will study systematic pole-placement algorithms. In this lesson, the emphasis is conceptual: feedback replaces the internal generator \( \mathbf{A} \) by \( \mathbf{A}-\mathbf{B}\mathbf{K} \), and this changes the state-transition matrix from \( e^{\mathbf{A}t} \) to \( e^{(\mathbf{A}-\mathbf{B}\mathbf{K})t} \).

4. Mode Relocation Workflow

A practical state-feedback design workflow separates analysis from gain computation. First, inspect the open-loop modes and controllability. Then choose desired closed-loop modes based on stability and transient response. Finally, compute and verify \( \mathbf{A}_{cl}=\mathbf{A}-\mathbf{B}\mathbf{K} \).

flowchart TD
  A["Model: A and B"] --> B["Compute open-loop modes"]
  B --> C["Check controllability or controllable subspace"]
  C --> D["Select desired closed-loop modes"]
  D --> E["Choose feedback gain K"]
  E --> F["Form Acl = A - B K"]
  F --> G["Verify eigenvalues of Acl"]
  G --> H["Simulate x_dot = Acl x"]
        

5. Second-Order SISO Example by Coefficient Matching

Consider the controllable second-order SISO system in phase-variable form:

\[ \dot{\mathbf{x} }= \begin{bmatrix}0 & 1\\ -a_0 & -a_1\end{bmatrix}\mathbf{x} +\begin{bmatrix}0\\1\end{bmatrix}u. \]

Let \( \mathbf{K}=\begin{bmatrix}k_1 & k_2\end{bmatrix} \). Then

\[ \mathbf{A}_{cl}= \begin{bmatrix}0 & 1\\ -a_0 & -a_1\end{bmatrix} -\begin{bmatrix}0\\1\end{bmatrix} \begin{bmatrix}k_1 & k_2\end{bmatrix} = \begin{bmatrix}0 & 1\\ -(a_0+k_1) & -(a_1+k_2)\end{bmatrix}. \]

The closed-loop characteristic polynomial is

\[ p_{cl}(s)=\det(s\mathbf{I}-\mathbf{A}_{cl}) =s^2+(a_1+k_2)s+(a_0+k_1). \]

Suppose the desired modes are \( \mu_1 \) and \( \mu_2 \). Then

\[ p_d(s)=(s-\mu_1)(s-\mu_2) =s^2-\left(\mu_1+\mu_2\right)s+\mu_1\mu_2. \]

Matching coefficients gives

\[ a_1+k_2=-(\mu_1+\mu_2),\qquad a_0+k_1=\mu_1\mu_2. \]

Therefore,

\[ \boxed{k_1=\mu_1\mu_2-a_0},\qquad \boxed{k_2=-(\mu_1+\mu_2)-a_1}. \]

For example, if

\[ \mathbf{A}=\begin{bmatrix}0 & 1\\ -2 & -0.4\end{bmatrix}, \qquad \mathbf{B}=\begin{bmatrix}0\\1\end{bmatrix}, \]

and the desired modes are \( -2 \) and \( -3 \), then

\[ p_d(s)=(s+2)(s+3)=s^2+5s+6. \]

Since \( a_0=2 \) and \( a_1=0.4 \),

\[ k_1=6-2=4,\qquad k_2=5-0.4=4.6. \]

Thus

\[ \mathbf{K}=\begin{bmatrix}4 & 4.6\end{bmatrix},\qquad \mathbf{A}_{cl}= \begin{bmatrix}0 & 1\\ -6 & -5\end{bmatrix}. \]

Its characteristic polynomial is

\[ \det(s\mathbf{I}-\mathbf{A}_{cl})=s^2+5s+6, \]

so the closed-loop modes are exactly \( -2 \) and \( -3 \).

6. Which Modes Can Be Moved?

State feedback can relocate modes only through directions influenced by the input matrix \( \mathbf{B} \). This is why controllability, studied earlier, is fundamental for state-feedback design.

Theorem: Suppose there exists a nonzero left eigenvector \( \mathbf{q}^{T} \) such that

\[ \mathbf{q}^{T}\mathbf{A}=\lambda\mathbf{q}^{T}, \qquad \mathbf{q}^{T}\mathbf{B}=\mathbf{0}. \]

Then \( \lambda \) is an eigenvalue of \( \mathbf{A}-\mathbf{B}\mathbf{K} \) for every feedback gain \( \mathbf{K} \).

Proof:

\[ \mathbf{q}^{T}(\mathbf{A}-\mathbf{B}\mathbf{K}) =\mathbf{q}^{T}\mathbf{A}-\mathbf{q}^{T}\mathbf{B}\mathbf{K} =\lambda\mathbf{q}^{T}-\mathbf{0}\mathbf{K} =\lambda\mathbf{q}^{T}. \]

Hence \( \mathbf{q}^{T} \) remains a left eigenvector of the closed-loop matrix with the same eigenvalue \( \lambda \). Therefore this mode is unaltered by any state-feedback gain. This proves that uncontrollable modes are unassignable by state feedback.

In contrast, if the pair \( (\mathbf{A},\mathbf{B}) \) is controllable, then all modes of the finite-dimensional LTI system can be assigned by a suitable full-state feedback gain. The constructive algorithms for doing this systematically are introduced in the next chapter.

7. Stability and Transient Interpretation

Once \( \mathbf{K} \) has been selected, stability is assessed from \( \mathbf{A}_{cl} \), not from \( \mathbf{A} \). The closed-loop equilibrium at the origin for the homogeneous system is asymptotically stable if and only if

\[ \operatorname{Re}\left(\lambda_i(\mathbf{A}-\mathbf{B}\mathbf{K})\right)<0, \qquad i=1,\dots,n. \]

If \( \mathbf{A}_{cl} \) is diagonalizable, then

\[ \mathbf{A}_{cl}=\mathbf{V}\boldsymbol{\Lambda}\mathbf{V}^{-1}, \qquad e^{\mathbf{A}_{cl}t} =\mathbf{V}e^{\boldsymbol{\Lambda}t}\mathbf{V}^{-1}. \]

Therefore the closed-loop response is a superposition of modal terms \( e^{\lambda_i t} \). Moving eigenvalues farther left generally increases decay rate, but also usually requires larger control effort because the control signal \( \mathbf{u}=-\mathbf{K}\mathbf{x}+\mathbf{r} \) becomes more aggressive. Thus mode relocation is not merely a stability operation; it is also a performance and actuator-demand decision.

8. Effect of Reference Input on Modes

With reference input, the closed-loop system is

\[ \dot{\mathbf{x} }(t)=\mathbf{A}_{cl}\mathbf{x}(t)+\mathbf{B}\mathbf{r}(t). \]

For a constant reference \( \mathbf{r}(t)=\mathbf{r}_0 \), if \( \mathbf{A}_{cl} \) is nonsingular, the equilibrium satisfies

\[ \mathbf{0}=\mathbf{A}_{cl}\mathbf{x}_{e}+\mathbf{B}\mathbf{r}_0, \qquad \mathbf{x}_{e}=-\mathbf{A}_{cl}^{-1}\mathbf{B}\mathbf{r}_0. \]

Define \( \tilde{\mathbf{x} }=\mathbf{x}-\mathbf{x}_{e} \). Then

\[ \dot{\tilde{\mathbf{x} } }=\mathbf{A}_{cl}\tilde{\mathbf{x} }. \]

Thus the reference changes the equilibrium and forced response, but it does not change the modal matrix \( \mathbf{A}_{cl} \). Closed-loop modes remain the eigenvalues of \( \mathbf{A}-\mathbf{B}\mathbf{K} \).

9. Python Implementation — Closed-Loop Modes

Chapter22_Lesson2.py

"""
Chapter22_Lesson2.py
Closed-Loop State Matrix and Mode Relocation
"""

from __future__ import annotations

import numpy as np
from numpy.typing import NDArray

try:
    from scipy.linalg import expm
    from scipy.signal import place_poles
    SCIPY_AVAILABLE = True
except Exception:
    SCIPY_AVAILABLE = False


def closed_loop_matrix(A: NDArray[np.float64],
                       B: NDArray[np.float64],
                       K: NDArray[np.float64]) -> NDArray[np.float64]:
    """Return Acl = A - B K."""
    return A - B @ K


def characteristic_coefficients_2x2(A: NDArray[np.float64]) -> tuple[float, float]:
    """
    For a 2 x 2 matrix A, return coefficients a1, a0 of
        s^2 + a1 s + a0.
    Since det(sI - A) = s^2 - tr(A) s + det(A),
        a1 = -tr(A), a0 = det(A).
    """
    trace = float(np.trace(A))
    determinant = float(np.linalg.det(A))
    return -trace, determinant


def second_order_feedback_by_matching(A: NDArray[np.float64],
                                      B: NDArray[np.float64],
                                      desired_poles: list[complex]) -> NDArray[np.float64]:
    """
    From-scratch gain computation for a controllable second-order SISO system.
    """
    if A.shape != (2, 2) or B.shape != (2, 1):
        raise ValueError("This scratch implementation is only for 2x2 SISO systems.")

    p1, p2 = desired_poles
    desired_a1 = float(np.real(-(p1 + p2)))
    desired_a0 = float(np.real(p1 * p2))

    def coeffs_for(k1: float, k2: float) -> NDArray[np.float64]:
        K = np.array([[k1, k2]], dtype=float)
        Acl = closed_loop_matrix(A, B, K)
        a1, a0 = characteristic_coefficients_2x2(Acl)
        return np.array([a1, a0], dtype=float)

    c00 = coeffs_for(0.0, 0.0)
    c10 = coeffs_for(1.0, 0.0)
    c01 = coeffs_for(0.0, 1.0)

    M = np.column_stack([c10 - c00, c01 - c00])
    target = np.array([desired_a1, desired_a0], dtype=float)
    k = np.linalg.solve(M, target - c00)
    return k.reshape(1, 2)


def simulate_homogeneous(Acl: NDArray[np.float64],
                         x0: NDArray[np.float64],
                         t_grid: NDArray[np.float64]) -> NDArray[np.float64]:
    """Return x(t) = exp(Acl t) x0 for all t in t_grid."""
    if not SCIPY_AVAILABLE:
        raise RuntimeError("scipy.linalg.expm is required for simulation.")
    states = []
    for t in t_grid:
        states.append(expm(Acl * t) @ x0)
    return np.asarray(states)


def main() -> None:
    A = np.array([[0.0, 1.0],
                  [-2.0, -0.4]])
    B = np.array([[0.0],
                  [1.0]])

    print("Open-loop modes:", np.linalg.eigvals(A))

    desired_poles = [-2.0, -3.0]

    K_scratch = second_order_feedback_by_matching(A, B, desired_poles)
    Acl_scratch = closed_loop_matrix(A, B, K_scratch)

    print("K from coefficient matching:")
    print(K_scratch)
    print("Closed-loop modes:", np.linalg.eigvals(Acl_scratch))

    if SCIPY_AVAILABLE:
        result = place_poles(A, B, desired_poles)
        K_library = result.gain_matrix
        Acl_library = closed_loop_matrix(A, B, K_library)

        print("K from scipy.signal.place_poles:")
        print(K_library)
        print("Closed-loop modes:", np.linalg.eigvals(Acl_library))

        t = np.linspace(0.0, 5.0, 201)
        x0 = np.array([1.0, 0.0])
        X = simulate_homogeneous(Acl_library, x0, t)
        print("Final state:", X[-1])


if __name__ == "__main__":
    main()
      

10. C++ Implementation — From-Scratch 2x2 Relocation

Chapter22_Lesson2.cpp

/*
Chapter22_Lesson2.cpp
Closed-Loop State Matrix and Mode Relocation
*/

#include <array>
#include <cmath>
#include <complex>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <vector>

struct Matrix2 {
    double a11, a12, a21, a22;
};

struct Vector2 {
    double v1, v2;
};

Matrix2 closedLoopMatrix(const Matrix2& A, const Vector2& B, const Vector2& K) {
    return Matrix2{
        A.a11 - B.v1 * K.v1, A.a12 - B.v1 * K.v2,
        A.a21 - B.v2 * K.v1, A.a22 - B.v2 * K.v2
    };
}

double trace(const Matrix2& M) {
    return M.a11 + M.a22;
}

double determinant(const Matrix2& M) {
    return M.a11 * M.a22 - M.a12 * M.a21;
}

std::pair<double, double> characteristicCoefficients(const Matrix2& M) {
    return {-trace(M), determinant(M)};
}

std::pair<std::complex<double>, std::complex<double>> eigenvalues2x2(const Matrix2& M) {
    const double tr = trace(M);
    const double det = determinant(M);
    const double disc = tr * tr - 4.0 * det;

    if (disc >= 0.0) {
        const double root = std::sqrt(disc);
        return { {0.5 * (tr + root), 0.0}, {0.5 * (tr - root), 0.0} };
    }

    const double root = std::sqrt(-disc);
    return { {0.5 * tr, 0.5 * root}, {0.5 * tr, -0.5 * root} };
}

Vector2 solve2x2(double m11, double m12, double m21, double m22,
                 double b1, double b2) {
    const double det = m11 * m22 - m12 * m21;
    if (std::abs(det) < 1e-12) {
        throw std::runtime_error("Singular coefficient-matching equations.");
    }

    return Vector2{
        ( b1 * m22 - m12 * b2) / det,
        ( m11 * b2 - b1 * m21) / det
    };
}

Vector2 secondOrderFeedbackByMatching(const Matrix2& A,
                                      const Vector2& B,
                                      double p1,
                                      double p2) {
    const double desiredA1 = -(p1 + p2);
    const double desiredA0 = p1 * p2;

    auto coeffsFor = [&](double k1, double k2) {
        Matrix2 Acl = closedLoopMatrix(A, B, Vector2{k1, k2});
        return characteristicCoefficients(Acl);
    };

    auto c00 = coeffsFor(0.0, 0.0);
    auto c10 = coeffsFor(1.0, 0.0);
    auto c01 = coeffsFor(0.0, 1.0);

    const double m11 = c10.first  - c00.first;
    const double m21 = c10.second - c00.second;
    const double m12 = c01.first  - c00.first;
    const double m22 = c01.second - c00.second;

    const double rhs1 = desiredA1 - c00.first;
    const double rhs2 = desiredA0 - c00.second;

    return solve2x2(m11, m12, m21, m22, rhs1, rhs2);
}

int main() {
    Matrix2 A{0.0, 1.0, -2.0, -0.4};
    Vector2 B{0.0, 1.0};

    auto openModes = eigenvalues2x2(A);
    std::cout << std::fixed << std::setprecision(6);
    std::cout << "Open-loop modes:\n";
    std::cout << "lambda1 = " << openModes.first << "\n";
    std::cout << "lambda2 = " << openModes.second << "\n\n";

    Vector2 K = secondOrderFeedbackByMatching(A, B, -2.0, -3.0);
    Matrix2 Acl = closedLoopMatrix(A, B, K);

    auto closedModes = eigenvalues2x2(Acl);
    auto coeffs = characteristicCoefficients(Acl);

    std::cout << "K = [" << K.v1 << ", " << K.v2 << "]\n";
    std::cout << "Closed-loop modes:\n";
    std::cout << "lambda1 = " << closedModes.first << "\n";
    std::cout << "lambda2 = " << closedModes.second << "\n";
    std::cout << "Characteristic polynomial: s^2 + "
              << coeffs.first << " s + " << coeffs.second << "\n";

    return 0;
}
      

11. Java Implementation — From-Scratch 2x2 Relocation

Chapter22_Lesson2.java

/*
Chapter22_Lesson2.java
Closed-Loop State Matrix and Mode Relocation
*/

public class Chapter22_Lesson2 {
    static class Matrix2 {
        double a11, a12, a21, a22;

        Matrix2(double a11, double a12, double a21, double a22) {
            this.a11 = a11;
            this.a12 = a12;
            this.a21 = a21;
            this.a22 = a22;
        }
    }

    static class Vector2 {
        double v1, v2;

        Vector2(double v1, double v2) {
            this.v1 = v1;
            this.v2 = v2;
        }
    }

    static class Complex {
        double re, im;

        Complex(double re, double im) {
            this.re = re;
            this.im = im;
        }

        @Override
        public String toString() {
            if (Math.abs(im) < 1e-12) {
                return String.format("%.6f", re);
            }
            return String.format("%.6f%+.6fi", re, im);
        }
    }

    static Matrix2 closedLoopMatrix(Matrix2 A, Vector2 B, Vector2 K) {
        return new Matrix2(
            A.a11 - B.v1 * K.v1, A.a12 - B.v1 * K.v2,
            A.a21 - B.v2 * K.v1, A.a22 - B.v2 * K.v2
        );
    }

    static double trace(Matrix2 M) {
        return M.a11 + M.a22;
    }

    static double determinant(Matrix2 M) {
        return M.a11 * M.a22 - M.a12 * M.a21;
    }

    static double[] characteristicCoefficients(Matrix2 M) {
        return new double[]{-trace(M), determinant(M)};
    }

    static Complex[] eigenvalues2x2(Matrix2 M) {
        double tr = trace(M);
        double det = determinant(M);
        double disc = tr * tr - 4.0 * det;

        if (disc >= 0.0) {
            double root = Math.sqrt(disc);
            return new Complex[]{
                new Complex(0.5 * (tr + root), 0.0),
                new Complex(0.5 * (tr - root), 0.0)
            };
        }

        double root = Math.sqrt(-disc);
        return new Complex[]{
            new Complex(0.5 * tr, 0.5 * root),
            new Complex(0.5 * tr, -0.5 * root)
        };
    }

    static Vector2 solve2x2(double m11, double m12, double m21, double m22,
                            double b1, double b2) {
        double det = m11 * m22 - m12 * m21;
        if (Math.abs(det) < 1e-12) {
            throw new IllegalArgumentException("Singular coefficient-matching equations.");
        }

        return new Vector2(
            ( b1 * m22 - m12 * b2) / det,
            ( m11 * b2 - b1 * m21) / det
        );
    }

    static Vector2 secondOrderFeedbackByMatching(Matrix2 A, Vector2 B,
                                                 double p1, double p2) {
        double desiredA1 = -(p1 + p2);
        double desiredA0 = p1 * p2;

        double[] c00 = characteristicCoefficients(closedLoopMatrix(A, B, new Vector2(0.0, 0.0)));
        double[] c10 = characteristicCoefficients(closedLoopMatrix(A, B, new Vector2(1.0, 0.0)));
        double[] c01 = characteristicCoefficients(closedLoopMatrix(A, B, new Vector2(0.0, 1.0)));

        double m11 = c10[0] - c00[0];
        double m21 = c10[1] - c00[1];
        double m12 = c01[0] - c00[0];
        double m22 = c01[1] - c00[1];

        double rhs1 = desiredA1 - c00[0];
        double rhs2 = desiredA0 - c00[1];

        return solve2x2(m11, m12, m21, m22, rhs1, rhs2);
    }

    public static void main(String[] args) {
        Matrix2 A = new Matrix2(0.0, 1.0, -2.0, -0.4);
        Vector2 B = new Vector2(0.0, 1.0);

        Complex[] openModes = eigenvalues2x2(A);
        System.out.println("Open-loop modes:");
        System.out.println("lambda1 = " + openModes[0]);
        System.out.println("lambda2 = " + openModes[1]);

        Vector2 K = secondOrderFeedbackByMatching(A, B, -2.0, -3.0);
        Matrix2 Acl = closedLoopMatrix(A, B, K);
        Complex[] closedModes = eigenvalues2x2(Acl);

        System.out.printf("%nK = [%.6f, %.6f]%n", K.v1, K.v2);
        System.out.println("Closed-loop modes:");
        System.out.println("lambda1 = " + closedModes[0]);
        System.out.println("lambda2 = " + closedModes[1]);
    }
}
      

12. MATLAB / Simulink Implementation

Chapter22_Lesson2.m

% Chapter22_Lesson2.m
% Closed-Loop State Matrix and Mode Relocation

clear; clc; close all;

A = [0 1;
    -2 -0.4];

B = [0;
     1];

C = [1 0];
D = 0;

disp('Open-loop modes:');
disp(eig(A));

desiredPoles = [-2 -3];

if exist('place', 'file') == 2
    K_place = place(A, B, desiredPoles);
else
    K_place = secondOrderFeedbackByMatching(A, B, desiredPoles);
end

Acl = A - B*K_place;

disp('K:');
disp(K_place);

disp('Acl = A - B*K:');
disp(Acl);

disp('Closed-loop modes:');
disp(eig(Acl));

disp('Closed-loop characteristic polynomial coefficients:');
disp(poly(Acl));

if exist('ss', 'file') == 2
    sys_cl = ss(Acl, B, C, D);
    t = linspace(0, 5, 250);
    x0 = [1; 0];
    initial(sys_cl, x0, t);
    title('Closed-loop initial response: x_dot = (A - B K)x');
end

% Simulink implementation note:
% 1. Put a State-Space block with A = A, B = B, C = eye(2), D = zeros(2,1).
% 2. Feed its state output x into a Gain block K.
% 3. Use a Sum block to implement u = -K*x + r.
% 4. Feed u back into the State-Space block input.

function K = secondOrderFeedbackByMatching(A, B, desiredPoles)
    p1 = desiredPoles(1);
    p2 = desiredPoles(2);

    desiredA1 = -(p1 + p2);
    desiredA0 = p1 * p2;

    coeffsFor = @(k1, k2) charCoeffs2(A - B*[k1 k2]);

    c00 = coeffsFor(0, 0);
    c10 = coeffsFor(1, 0);
    c01 = coeffsFor(0, 1);

    M = [(c10 - c00), (c01 - c00)];
    target = [desiredA1; desiredA0];
    k = M \ (target - c00);
    K = k.';
end

function c = charCoeffs2(M)
    c = [-trace(M); det(M)];
end
      

13. Wolfram Mathematica Implementation

Chapter22_Lesson2.nb

A = { {0, 1}, {-2, -0.4} };
B = { {0}, {1} };

Eigenvalues[A]

desiredPoles = {-2, -3};

charCoeffs2[M_] := {-Tr[M], Det[M]}

coeffsFor[k1_, k2_] := charCoeffs2[A - B.{ {k1, k2} }]

c00 = coeffsFor[0, 0];
c10 = coeffsFor[1, 0];
c01 = coeffsFor[0, 1];

M = Transpose[{c10 - c00, c01 - c00}];

target = {-Total[desiredPoles], Times @@ desiredPoles};

k = LinearSolve[M, target - c00];
K = {k};

Acl = A - B.K;

MatrixForm[Acl]

Eigenvalues[Acl]

CharacteristicPolynomial[Acl, s]

Expand[Det[s IdentityMatrix[2] - Acl] - Times @@ (s - desiredPoles)]
      

14. Problems and Solutions

Problem 1: Consider \( \dot{\mathbf{x} }=\mathbf{A}\mathbf{x}+\mathbf{B}\mathbf{u} \) with \( \mathbf{u}=-\mathbf{K}\mathbf{x}+\mathbf{r} \). Derive the closed-loop state equation and identify the matrix that determines the closed-loop modes.

Solution: Substitute the feedback law into the state equation:

\[ \dot{\mathbf{x} }= \mathbf{A}\mathbf{x}+\mathbf{B}(-\mathbf{K}\mathbf{x}+\mathbf{r}) =(\mathbf{A}-\mathbf{B}\mathbf{K})\mathbf{x}+\mathbf{B}\mathbf{r}. \]

Therefore, the closed-loop state matrix is \( \mathbf{A}_{cl}=\mathbf{A}-\mathbf{B}\mathbf{K} \), and the closed-loop modes are the eigenvalues of \( \mathbf{A}_{cl} \).

Problem 2: For

\[ \mathbf{A}=\begin{bmatrix}0 & 1\\ -2 & -0.4\end{bmatrix}, \qquad \mathbf{B}=\begin{bmatrix}0\\1\end{bmatrix},\qquad \mathbf{K}=\begin{bmatrix}4 & 4.6\end{bmatrix}, \]

compute \( \mathbf{A}_{cl} \) and its characteristic polynomial.

Solution:

\[ \mathbf{A}_{cl}=\mathbf{A}-\mathbf{B}\mathbf{K} = \begin{bmatrix}0 & 1\\ -2 & -0.4\end{bmatrix} - \begin{bmatrix}0\\1\end{bmatrix} \begin{bmatrix}4 & 4.6\end{bmatrix} = \begin{bmatrix}0 & 1\\ -6 & -5\end{bmatrix}. \]

\[ \det(s\mathbf{I}-\mathbf{A}_{cl}) = \det\begin{bmatrix}s & -1\\ 6 & s+5\end{bmatrix} =s(s+5)+6=s^2+5s+6. \]

Hence the closed-loop modes are \( -2 \) and \( -3 \).

Problem 3: Show that if \( \mathbf{q}^{T}\mathbf{A}=\lambda\mathbf{q}^{T} \) and \( \mathbf{q}^{T}\mathbf{B}=\mathbf{0} \), then \( \lambda \) remains a closed-loop eigenvalue for all feedback gains \( \mathbf{K} \).

Solution:

\[ \mathbf{q}^{T}(\mathbf{A}-\mathbf{B}\mathbf{K}) = \mathbf{q}^{T}\mathbf{A}-\mathbf{q}^{T}\mathbf{B}\mathbf{K} = \lambda\mathbf{q}^{T}-\mathbf{0}\mathbf{K} = \lambda\mathbf{q}^{T}. \]

Therefore, \( \mathbf{q}^{T} \) is still a left eigenvector of the closed-loop matrix with eigenvalue \( \lambda \). The mode cannot be relocated by state feedback.

Problem 4: A closed-loop matrix has eigenvalues \( -1 \), \( -4 \), and \( -2\pm 3j \). Is the closed-loop homogeneous system asymptotically stable?

Solution: Yes. Every eigenvalue has negative real part:

\[ \operatorname{Re}(-1)=-1,\qquad \operatorname{Re}(-4)=-4,\qquad \operatorname{Re}(-2\pm 3j)=-2. \]

Therefore \( \operatorname{Re}(\lambda_i)<0 \) for all modes, so the closed-loop origin is asymptotically stable.

Problem 5: For the second-order phase-variable system

\[ \mathbf{A}=\begin{bmatrix}0 & 1\\ -a_0 & -a_1\end{bmatrix}, \qquad \mathbf{B}=\begin{bmatrix}0\\1\end{bmatrix}, \]

derive the gain \( \mathbf{K}=\begin{bmatrix}k_1 & k_2\end{bmatrix} \) that relocates the modes to \( \mu_1 \) and \( \mu_2 \).

Solution: The closed-loop matrix is

\[ \mathbf{A}_{cl}= \begin{bmatrix}0 & 1\\ -(a_0+k_1) & -(a_1+k_2)\end{bmatrix}. \]

Thus

\[ p_{cl}(s)=s^2+(a_1+k_2)s+(a_0+k_1). \]

The desired polynomial is

\[ p_d(s)=(s-\mu_1)(s-\mu_2) =s^2-(\mu_1+\mu_2)s+\mu_1\mu_2. \]

Matching coefficients yields

\[ k_1=\mu_1\mu_2-a_0,\qquad k_2=-(\mu_1+\mu_2)-a_1. \]

15. Summary

State feedback replaces the open-loop state matrix \( \mathbf{A} \) by the closed-loop matrix \( \mathbf{A}_{cl}=\mathbf{A}-\mathbf{B}\mathbf{K} \). The eigenvalues of this matrix are the closed-loop modes, and relocating them changes stability and transient behavior. If the pair \( (\mathbf{A},\mathbf{B}) \) is controllable, full mode relocation is possible; if a mode is uncontrollable, it cannot be moved by any state-feedback gain. The next chapter develops systematic pole-placement procedures for computing \( \mathbf{K} \).

16. References

  1. Kalman, R.E. (1960). Contributions to the theory of optimal control. Boletín de la Sociedad Matemática Mexicana, 5, 102–119.
  2. 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.
  3. Wonham, W.M. (1967). On pole assignment in multi-input controllable linear systems. IEEE Transactions on Automatic Control, 12(6), 660–665.
  4. Heymann, M. (1968). Comments on pole assignment in multi-input controllable linear systems. IEEE Transactions on Automatic Control, 13(6), 748–749.
  5. Rosenbrock, H.H. (1970). State-space and multivariable theory. Proceedings of the Institution of Electrical Engineers, 117(6), 1191–1193.
  6. Davison, E.J. (1968). On pole assignment in linear systems with incomplete state feedback. IEEE Transactions on Automatic Control, 13(3), 348–351.
  7. Kailath, T. (1980). Linear systems. Prentice-Hall theoretical systems series.
  8. Kautsky, J., Nichols, N.K., & Van Dooren, P. (1985). Robust pole assignment in linear state feedback. International Journal of Control, 41(5), 1129–1155.