Chapter 27: Reference Tracking and Disturbance Rejection in State Space
Lesson 3: Internal Model Principle in a Linear State-Space Setting
This lesson develops the internal model principle for linear state-space servo systems. We connect exosystems, regulator equations, integral augmentation, robust zero-error tracking, and disturbance rejection. The emphasis is on why feedforward alone is not robust and why exact asymptotic regulation requires a controller that embeds the dynamics of the reference or disturbance signal.
1. Conceptual Overview
In Lesson 2, feedforward gain design was used to remove steady-state tracking error for a fixed nominal model. The limitation is that a feedforward gain generally cancels error only for the exact plant matrices used in its computation. The internal model principle states a stronger and more structural fact: robust asymptotic tracking and disturbance rejection require the controller to contain a dynamic model of the signal class to be tracked or rejected.
Consider the continuous-time linear plant \( \dot{x}=Ax+Bu+E_d d \), \( y=Cx+Du \), and tracking error \( e=r-y \). A reference or disturbance generated by an autonomous signal generator can be written as
\[ \dot{w}=Sw,\qquad r=F_rw,\qquad d=F_dw. \]
The matrix \( S \) is called the exosystem. Constant references are generated by \( S=0 \). Ramp signals require a Jordan block at zero. Sinusoidal references require imaginary eigenvalues \( \pm j\omega \). The internal model principle says that the controller must contain these modes of \( S \) in an appropriate multiplicity; otherwise, zero steady-state error is fragile or impossible for that signal class.
flowchart TD
A["Choose signal class"] --> B["Build exosystem S"]
B --> C["Check plant feasibility: regulator equations"]
C --> D["Embed S modes in controller"]
D --> E["Stabilize augmented closed loop"]
E --> F["Verify error e(t) tends to zero"]
F --> G["Test robustness to small plant changes"]
2. Exosystems and Signal Classes
The internal model principle is easiest to understand by classifying reference and disturbance signals through finite-dimensional generators. A signal belongs to the modeled class when it can be written as an output of \( \dot{w}=Sw \). For example, a constant reference \( r(t)=r_0 \) is generated by \( S=0 \). A ramp reference \( r(t)=a+bt \) is generated by a nilpotent Jordan block:
\[ S_{\text{ramp} }= \begin{bmatrix} 0 & 1\\ 0 & 0 \end{bmatrix},\qquad w(t)=e^{S_{\text{ramp} }t}w(0). \]
A sinusoid \( r(t)=a\cos(\omega t)+b\sin(\omega t) \) is generated by the oscillator
\[ S_{\text{sin} }= \begin{bmatrix} 0 & -\omega\\ \omega & 0 \end{bmatrix},\qquad \sigma(S_{\text{sin} })=\{j\omega,-j\omega\}. \]
The eigenvalues of \( S \) are the frequencies or polynomial-growth modes that must be represented inside the controller. In a continuous-time stabilization problem, all closed-loop modes not belonging to the exosystem must be placed in the open left half-plane:
\[ \operatorname{Re}(\mu_i)<0,\qquad \mu_i\in\sigma(A_{\text{cl} })\setminus\sigma(S). \]
3. Regulator Equations
Before embedding an internal model, one must check whether exact regulation is algebraically feasible. Suppose the plant is driven by an exosystem through
\[ \dot{x}=Ax+Bu+Ew,\qquad y=Cx+Du,\qquad r=Fw,\qquad \dot{w}=Sw. \]
If zero tracking error is achieved asymptotically, then on the invariant steady-state manifold there must exist matrices \( \Pi \) and \( \Gamma \) such that \( x=\Pi w \) and \( u=\Gamma w \). Substitution gives the regulator equations:
\[ A\Pi+B\Gamma+E=\Pi S,\qquad C\Pi+D\Gamma=F. \]
These equations are not merely computational devices. They express the compatibility between the plant zeros, the input directions, the output map, and the exosystem modes. If they have no solution, exact zero-error regulation for that signal class is impossible with any stabilizing finite-dimensional linear controller.
For a constant reference and no disturbance, take \( S=0 \), \( E=0 \), and \( F=I \). The equations reduce to
\[ A\Pi+B\Gamma=0,\qquad C\Pi+D\Gamma=I. \]
If \( D=0 \) and the plant is square, solvability is closely connected to the absence of a transmission zero at the reference-generator eigenvalue. For a single-output plant tracking a constant reference, a zero at the origin blocks robust step tracking.
4. Integral Action as the Simplest Internal Model
The most common internal model is the integrator. For a constant reference, the exosystem has eigenvalue zero. Embedding that mode in the controller gives the integral state
\[ \dot{\eta}=r-y=r-Cx-Du. \]
For the strictly proper case \( D=0 \), the augmented system becomes
\[ \frac{d}{dt} \begin{bmatrix} x\\ \eta \end{bmatrix} = \begin{bmatrix} A & 0\\ -C & 0 \end{bmatrix} \begin{bmatrix} x\\ \eta \end{bmatrix} + \begin{bmatrix} B\\ 0 \end{bmatrix}u + \begin{bmatrix} 0\\ I \end{bmatrix}r. \]
A state-feedback servo law can then be written as
\[ u=-K_xx+K_i\eta. \]
The closed-loop homogeneous augmented matrix is
\[ A_a-B_aK_a= \begin{bmatrix} A-BK_x & BK_i\\ -C & 0 \end{bmatrix}. \]
If this matrix is Hurwitz and the regulator equations for the constant reference are solvable, then the steady-state error satisfies \( \lim_{t\to\infty} e(t)=0 \). Unlike static feedforward tracking, this conclusion is robust to many small plant perturbations because the integrator continues to accumulate error until the output reaches the reference.
flowchart TD
R["reference r"] --> SUM["error: r minus y"]
Y["output y"] --> SUM
SUM --> INT["internal model integrator"]
INT --> CTRL["state feedback plus integral gain"]
X["state x"] --> CTRL
CTRL --> U["input u"]
U --> PLANT["plant"]
PLANT --> Y
5. Internal Model Multiplicity and Polynomial References
A single integrator rejects constant disturbances and tracks constant references. A double integrator is needed for ramp tracking. More generally, a polynomial of degree \( q-1 \) requires a Jordan block of size \( q \) at the origin:
\[ S_q= \begin{bmatrix} 0 & 1 & 0 & \cdots & 0\\ 0 & 0 & 1 & \cdots & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 0 & 0 & 0 & \cdots & 1\\ 0 & 0 & 0 & \cdots & 0 \end{bmatrix}. \]
For a multi-output plant with \( p \) regulated outputs, the internal model must contain enough copies of the exosystem to influence every regulated error channel. Informally, the controller must contain \( p \) copies of each relevant exosystem mode. This idea is often called the p-copy internal model.
If the minimal polynomial of the exosystem is \( m_S(s)=\prod_i(s-\lambda_i)^{\nu_i} \), then the controller must contain the factors \( (s-\lambda_i)^{\nu_i} \) in the error-to-control path with sufficient output-channel multiplicity. This is the state-space counterpart of the classical final-value theorem rule: include an integrator for steps, two integrators for ramps, and a resonant oscillator for sinusoids.
6. Proof of Zero Steady-State Error for Integral Servo
Consider the strictly proper plant \( \dot{x}=Ax+Bu,\; y=Cx \) with integral state \( \dot{\eta}=r-y \) and control \( u=-K_xx+K_i\eta \). For constant \( r \), define the augmented state \( x_a=[x^T,\eta^T]^T \). The closed-loop dynamics are
\[ \dot{x}_a=A_{\text{cl},a}x_a+B_rr,\qquad A_{\text{cl},a}= \begin{bmatrix} A-BK_x & BK_i\\ -C & 0 \end{bmatrix},\qquad B_r= \begin{bmatrix} 0\\ I \end{bmatrix}. \]
Assume \( A_{\text{cl},a} \) is Hurwitz. Then the closed-loop state converges to a unique equilibrium \( x_a^\star \) satisfying \( 0=A_{\text{cl},a}x_a^\star+B_rr \). The last block row of this equilibrium equation gives
\[ 0=-Cx^\star+r. \]
Therefore \( e^\star=r-y^\star=r-Cx^\star=0 \). Since the augmented matrix is Hurwitz, the transient component \( e^{A_{\text{cl},a}t}(x_a(0)-x_a^\star) \) decays exponentially. Hence
\[ \lim_{t\to\infty}e(t)=0. \]
This proof clarifies why the internal model is powerful. The zero-error property is enforced by an equilibrium constraint in the integrator row, not by a delicate static cancellation of the plant DC gain.
7. Solvability and Stabilizability of the Augmented Pair
Integral augmentation is useful only if the augmented pair is stabilizable. For the step-tracking case with \( D=0 \), the augmented matrices are
\[ A_a= \begin{bmatrix} A & 0\\ -C & 0 \end{bmatrix},\qquad B_a= \begin{bmatrix} B\\ 0 \end{bmatrix}. \]
A necessary rank condition at the internal-model eigenvalue zero is
\[ \operatorname{rank} \begin{bmatrix} A & B\\ C & D \end{bmatrix} =n+p. \]
For a square plant, failure of this rank condition indicates a transmission zero at the origin. More generally, for an exosystem eigenvalue \( \lambda\in\sigma(S) \), the corresponding Rosenbrock matrix must have enough rank:
\[ \operatorname{rank} \begin{bmatrix} A-\lambda I & B\\ C & D \end{bmatrix} =n+p. \]
This condition links the internal model principle to the zero-dynamics material from Chapter 21. If the plant has a transmission zero at the exact frequency or growth mode that the controller is trying to track or reject, the internal-model mode cannot be used to regulate the error without violating internal stability.
8. Robust Regulation Interpretation
The internal model principle is fundamentally a robustness result. A nominal feedforward gain can make the error zero for one plant model:
\[ N=\left(C(A-BK_x)^{-1}B\right)^{-1}. \]
However, if \( A \), \( B \), or \( C \) changes slightly, the computed DC map is no longer exact. Integral action does not require exact knowledge of the DC gain; it only requires closed-loop stability and solvability of the steady-state regulation equations. The integrator keeps changing the control input as long as the average error is nonzero.
In frequency-domain language, the loop gain has infinite gain at the exosystem frequency. In state-space language, the controller contains a copy of \( S \). These are two descriptions of the same structural mechanism.
9. Software Implementations
The following implementations use the same second-order plant \( \dot{x}=Ax+Bu,\; y=Cx \) with \( A=\begin{bmatrix}0&1\\-2&-0.4\end{bmatrix} \), \( B=\begin{bmatrix}0\\1\end{bmatrix} \), and \( C=\begin{bmatrix}1&0\end{bmatrix} \). The goal is robust step tracking with the integral internal model \( \dot{\eta}=r-y \).
Related libraries include scipy.signal and
python-control for Python, Control System Toolbox and
Simulink for MATLAB, Eigen or Armadillo for C++, Apache Commons Math for
Java, and Wolfram Language functions such as NDSolve and
StateSpaceModel for Mathematica.
Chapter27_Lesson3.py
# Chapter27_Lesson3.py
# Internal Model Principle for step tracking in a continuous-time state-space plant.
# Required packages: numpy, scipy
import numpy as np
from scipy.integrate import solve_ivp
from scipy.signal import place_poles
def build_augmented_step_servo():
"""Plant:
x_dot = A x + B u
y = C x
Internal model for a constant reference:
eta_dot = r - y
Control:
u = -Kx x + Ki eta
"""
A = np.array([[0.0, 1.0],
[-2.0, -0.4]])
B = np.array([[0.0],
[1.0]])
C = np.array([[1.0, 0.0]])
# Augmented state xa = [x1, x2, eta]^T, eta_dot = r - Cx.
A_aug = np.block([
[A, np.zeros((2, 1))],
[-C, np.zeros((1, 1))]
])
B_aug = np.vstack([B, [[0.0]]])
desired_poles = np.array([-2.0 + 2.0j, -2.0 - 2.0j, -5.0])
placed = place_poles(A_aug, B_aug, desired_poles)
K_aug = placed.gain_matrix
# Since u = -K_aug * [x; eta], and the integrator state is eta_dot = -Cx + r,
# the third gain is negative for the convention u = -Kx + Ki eta.
Kx = K_aug[:, :2]
Ki = -K_aug[:, 2:3]
return A, B, C, Kx, Ki, A_aug, B_aug
def simulate_step_response(t_final=8.0, reference=1.0):
A, B, C, Kx, Ki, _, _ = build_augmented_step_servo()
def closed_loop_rhs(t, xa):
x = xa[:2].reshape(2, 1)
eta = xa[2]
y = float(C @ x)
u = float(-Kx @ x + Ki * eta)
xdot = A @ x + B * u
etadot = reference - y
return np.array([xdot[0, 0], xdot[1, 0], etadot])
sol = solve_ivp(
closed_loop_rhs,
t_span=(0.0, t_final),
y0=np.array([0.0, 0.0, 0.0]),
max_step=0.01,
rtol=1e-8,
atol=1e-10,
)
x1 = sol.y[0, :]
x2 = sol.y[1, :]
eta = sol.y[2, :]
y = x1
u = -Kx[0, 0] * x1 - Kx[0, 1] * x2 + Ki[0, 0] * eta
e = reference - y
return sol.t, y, u, e, Kx, Ki
def solve_regulator_equations_for_constant_reference():
"""Solve the steady-state regulator equations for S = 0 and y_ref = w.
A*pi + B*gamma = 0
C*pi = 1
This gives the steady-state x = pi*w and u = gamma*w.
"""
A = np.array([[0.0, 1.0],
[-2.0, -0.4]])
B = np.array([[0.0],
[1.0]])
C = np.array([[1.0, 0.0]])
M = np.block([
[A, B],
[C, np.zeros((1, 1))]
])
rhs = np.array([[0.0], [0.0], [1.0]])
sol = np.linalg.solve(M, rhs)
pi = sol[:2, :]
gamma = sol[2:, :]
return pi, gamma
if __name__ == "__main__":
t, y, u, e, Kx, Ki = simulate_step_response()
pi, gamma = solve_regulator_equations_for_constant_reference()
print("Kx =", Kx)
print("Ki =", Ki)
print("Regulator equation Pi =", pi.ravel())
print("Regulator equation Gamma =", gamma.ravel())
print("Final output y(T) =", y[-1])
print("Final tracking error e(T) =", e[-1])
print("Peak absolute control =", np.max(np.abs(u)))
Chapter27_Lesson3.cpp
// Chapter27_Lesson3.cpp
// From-scratch RK4 simulation of a state-feedback servo with one integrator.
// Compile: g++ -std=c++17 Chapter27_Lesson3.cpp -O2 -o Chapter27_Lesson3
#include <cmath>
#include <iomanip>
#include <iostream>
#include <vector>
struct State {
double x1;
double x2;
double eta;
};
State add_scaled(const State& a, const State& b, double h) {
return {a.x1 + h * b.x1, a.x2 + h * b.x2, a.eta + h * b.eta};
}
State rhs(const State& s, double reference) {
// Plant: x1_dot = x2
// x2_dot = -2*x1 - 0.4*x2 + u
// Output: y = x1
// Internal model: eta_dot = reference - y
// Closed-loop gain for desired poles -2 +/- 2i and -5:
// u = -26*x1 - 8.6*x2 + 40*eta
double y = s.x1;
double u = -26.0 * s.x1 - 8.6 * s.x2 + 40.0 * s.eta;
State ds;
ds.x1 = s.x2;
ds.x2 = -2.0 * s.x1 - 0.4 * s.x2 + u;
ds.eta = reference - y;
return ds;
}
State rk4_step(const State& s, double h, double reference) {
State k1 = rhs(s, reference);
State k2 = rhs(add_scaled(s, k1, 0.5 * h), reference);
State k3 = rhs(add_scaled(s, k2, 0.5 * h), reference);
State k4 = rhs(add_scaled(s, k3, h), reference);
State out;
out.x1 = s.x1 + h * (k1.x1 + 2.0 * k2.x1 + 2.0 * k3.x1 + k4.x1) / 6.0;
out.x2 = s.x2 + h * (k1.x2 + 2.0 * k2.x2 + 2.0 * k3.x2 + k4.x2) / 6.0;
out.eta = s.eta + h * (k1.eta + 2.0 * k2.eta + 2.0 * k3.eta + k4.eta) / 6.0;
return out;
}
int main() {
const double reference = 1.0;
const double h = 0.001;
const double tf = 8.0;
const int steps = static_cast<int>(tf / h);
State s{0.0, 0.0, 0.0};
double peak_abs_u = 0.0;
for (int k = 0; k < steps; ++k) {
double u = -26.0 * s.x1 - 8.6 * s.x2 + 40.0 * s.eta;
peak_abs_u = std::max(peak_abs_u, std::abs(u));
s = rk4_step(s, h, reference);
}
double y = s.x1;
double error = reference - y;
std::cout << std::fixed << std::setprecision(8);
std::cout << "Final output y(T) = " << y << "\n";
std::cout << "Final tracking error e(T) = " << error << "\n";
std::cout << "Final integrator state eta(T) = " << s.eta << "\n";
std::cout << "Peak absolute control = " << peak_abs_u << "\n";
return 0;
}
Chapter27_Lesson3.java
// Chapter27_Lesson3.java
// From-scratch RK4 simulation of the internal-model servo.
// Compile: javac Chapter27_Lesson3.java
// Run: java Chapter27_Lesson3
public class Chapter27_Lesson3 {
static class State {
double x1;
double x2;
double eta;
State(double x1, double x2, double eta) {
this.x1 = x1;
this.x2 = x2;
this.eta = eta;
}
}
static State addScaled(State a, State b, double h) {
return new State(a.x1 + h * b.x1, a.x2 + h * b.x2, a.eta + h * b.eta);
}
static State rhs(State s, double reference) {
double y = s.x1;
double u = -26.0 * s.x1 - 8.6 * s.x2 + 40.0 * s.eta;
double dx1 = s.x2;
double dx2 = -2.0 * s.x1 - 0.4 * s.x2 + u;
double deta = reference - y;
return new State(dx1, dx2, deta);
}
static State rk4Step(State s, double h, double reference) {
State k1 = rhs(s, reference);
State k2 = rhs(addScaled(s, k1, 0.5 * h), reference);
State k3 = rhs(addScaled(s, k2, 0.5 * h), reference);
State k4 = rhs(addScaled(s, k3, h), reference);
double x1 = s.x1 + h * (k1.x1 + 2.0 * k2.x1 + 2.0 * k3.x1 + k4.x1) / 6.0;
double x2 = s.x2 + h * (k1.x2 + 2.0 * k2.x2 + 2.0 * k3.x2 + k4.x2) / 6.0;
double eta = s.eta + h * (k1.eta + 2.0 * k2.eta + 2.0 * k3.eta + k4.eta) / 6.0;
return new State(x1, x2, eta);
}
public static void main(String[] args) {
double reference = 1.0;
double h = 0.001;
double tf = 8.0;
int steps = (int) Math.round(tf / h);
State s = new State(0.0, 0.0, 0.0);
double peakAbsU = 0.0;
for (int k = 0; k < steps; k++) {
double u = -26.0 * s.x1 - 8.6 * s.x2 + 40.0 * s.eta;
peakAbsU = Math.max(peakAbsU, Math.abs(u));
s = rk4Step(s, h, reference);
}
double y = s.x1;
double error = reference - y;
System.out.printf("Final output y(T) = %.8f%n", y);
System.out.printf("Final tracking error e(T) = %.8e%n", error);
System.out.printf("Final integrator state eta(T) = %.8f%n", s.eta);
System.out.printf("Peak absolute control = %.8f%n", peakAbsU);
}
}
Chapter27_Lesson3.m
% Chapter27_Lesson3.m
% Internal Model Principle in a linear state-space setting.
% Requires Control System Toolbox for place().
% Optional: creates a simple Simulink model if Simulink is available.
clear; clc; close all;
A = [0 1; -2 -0.4];
B = [0; 1];
C = [1 0];
D = 0;
% Step-reference internal model: eta_dot = r - y.
Aaug = [A zeros(2,1); -C 0];
Baug = [B; 0];
desired_poles = [-2+2i, -2-2i, -5];
Kaug = place(Aaug, Baug, desired_poles);
Kx = Kaug(1:2);
Ki = -Kaug(3);
fprintf('Kx = [%g %g]\n', Kx(1), Kx(2));
fprintf('Ki = %g\n', Ki);
r = 1.0;
f = @(t,xa) [
xa(2);
-2*xa(1) - 0.4*xa(2) + (-Kx*[xa(1); xa(2)] + Ki*xa(3));
r - C*[xa(1); xa(2)]
];
[t, xa] = ode45(f, [0 8], [0; 0; 0]);
y = xa(:,1);
u = -Kx(1)*xa(:,1) - Kx(2)*xa(:,2) + Ki*xa(:,3);
e = r - y;
figure;
plot(t, y, 'LineWidth', 1.5); grid on;
xlabel('Time (s)');
ylabel('Output y(t)');
title('Step Tracking with an Internal Model');
figure;
plot(t, e, 'LineWidth', 1.5); grid on;
xlabel('Time (s)');
ylabel('Tracking error e(t)');
title('Error Convergence');
fprintf('Final y(T) = %.8f\n', y(end));
fprintf('Final e(T) = %.8e\n', e(end));
fprintf('Peak |u| = %.8f\n', max(abs(u)));
% Regulator equations for constant reference:
% A*Pi + B*Gamma = 0, C*Pi = 1.
M = [A B; C 0];
rhs = [0; 0; 1];
sol = M \ rhs;
Pi = sol(1:2);
Gamma = sol(3);
fprintf('Pi = [%g %g]^T\n', Pi(1), Pi(2));
fprintf('Gamma = %g\n', Gamma);
% Optional Simulink skeleton: integrator state eta and State-Space plant block.
if license('test','SIMULINK')
model = 'Chapter27_Lesson3_Simulink';
if bdIsLoaded(model)
close_system(model, 0);
end
new_system(model);
open_system(model);
add_block('simulink/Sources/Step', [model '/Reference'], ...
'Position', [40 80 80 110], 'Time', '0', 'Before', '0', 'After', '1');
add_block('simulink/Continuous/State-Space', [model '/Plant'], ...
'Position', [320 70 430 130], ...
'A', mat2str(A), 'B', mat2str(B), 'C', mat2str(C), 'D', mat2str(D));
add_block('simulink/Math Operations/Sum', [model '/Error r-y'], ...
'Position', [130 75 160 115], 'Inputs', '+-');
add_block('simulink/Continuous/Integrator', [model '/Internal Model Integrator'], ...
'Position', [190 75 230 115]);
add_block('simulink/Sinks/Scope', [model '/Output Scope'], ...
'Position', [500 75 540 115]);
% Full feedback interconnection usually needs gain and sum blocks for
% u = -Kx + Ki*eta. This skeleton shows the internal-model signal path.
add_line(model, 'Reference/1', 'Error r-y/1');
add_line(model, 'Error r-y/1', 'Internal Model Integrator/1');
add_line(model, 'Plant/1', 'Output Scope/1');
save_system(model);
fprintf('Created Simulink skeleton: %s.slx\n', model);
end
Chapter27_Lesson3.nb
Notebook[{
Cell["Chapter27_Lesson3.nb", "Title"],
Cell["Internal Model Principle for step tracking in a continuous-time state-space plant.", "Text"],
Cell[BoxData[
RowBox[{
RowBox[{"A", "=", RowBox[{"{ {", RowBox[{
RowBox[{"0", ",", "1"}], ",", RowBox[{
RowBox[{"-", "2"}], ",", RowBox[{"-", "0.4"}]}]}], "} }"}]}], ";"}]], "Input"],
Cell[BoxData[
RowBox[{
RowBox[{"B", "=", RowBox[{"{ {", "0", "}", ",", "{", "1", "} }"}]}], ";"}]], "Input"],
Cell[BoxData[
RowBox[{
RowBox[{"Cmat", "=", RowBox[{"{ {", RowBox[{"1", ",", "0"}], "} }"}]}], ";"}]], "Input"],
Cell[BoxData[
RowBox[{
RowBox[{"Kx", "=", RowBox[{"{", RowBox[{"26", ",", "8.6"}], "}"}]}], ";",
RowBox[{"Ki", "=", "40"}], ";",
RowBox[{"r", "=", "1"}], ";"}]], "Input"],
Cell[BoxData[
RowBox[{
RowBox[{"sol", "=",
RowBox[{"NDSolve", "[",
RowBox[{
RowBox[{"{",
RowBox[{
RowBox[{
RowBox[{
RowBox[{"x1", "'"}], "[", "t", "]"}], "==", RowBox[{"x2", "[", "t", "]"}]}], ",",
RowBox[{
RowBox[{
RowBox[{"x2", "'"}], "[", "t", "]"}], "==",
RowBox[{
RowBox[{
RowBox[{"-", "2"}], " ", RowBox[{"x1", "[", "t", "]"}]}], "-",
RowBox[{"0.4", " ", RowBox[{"x2", "[", "t", "]"}]}], "-",
RowBox[{"26", " ", RowBox[{"x1", "[", "t", "]"}]}], "-",
RowBox[{"8.6", " ", RowBox[{"x2", "[", "t", "]"}]}], "+",
RowBox[{"40", " ", RowBox[{"eta", "[", "t", "]"}]}]}]}], ",",
RowBox[{
RowBox[{
RowBox[{"eta", "'"}], "[", "t", "]"}], "==",
RowBox[{"r", "-", RowBox[{"x1", "[", "t", "]"}]}]}], ",",
RowBox[{
RowBox[{"x1", "[", "0", "]"}], "==", "0"}], ",",
RowBox[{
RowBox[{"x2", "[", "0", "]"}], "==", "0"}], ",",
RowBox[{
RowBox[{"eta", "[", "0", "]"}], "==", "0"}]}], "}"}], ",",
RowBox[{"{", RowBox[{"x1", ",", "x2", ",", "eta"}], "}"}], ",",
RowBox[{"{", RowBox[{"t", ",", "0", ",", "8"}], "}"}]}], "]"}]}], ";"}]], "Input"],
Cell[BoxData[
RowBox[{"Plot", "[",
RowBox[{
RowBox[{"Evaluate", "[", RowBox[{
RowBox[{"x1", "[", "t", "]"}], "/.", "sol"}], "]"}], ",",
RowBox[{"{", RowBox[{"t", ",", "0", ",", "8"}], "}"}], ",",
RowBox[{"GridLines", "->", "Automatic"}], ",",
RowBox[{"AxesLabel", "->", RowBox[{"{", RowBox[{"\"t\"", ",", "\"y(t)\""}], "}"}]}], ",",
RowBox[{"PlotLabel", "->", "\"Step Tracking with Internal Model\""}]}], "]"}]], "Input"],
Cell[BoxData[
RowBox[{"N", "[",
RowBox[{"1", "-", RowBox[{"Evaluate", "[", RowBox[{
RowBox[{"x1", "[", "8", "]"}], "/.", "sol"}], "]"}]}], "]"}]], "Input"]
}]
10. Design Procedure for a Linear Internal-Model Servo
A practical design workflow is:
- Specify the regulated error \( e=r-y \) or \( e=F w-(Cx+Du) \).
- Identify the signal generator \( \dot{w}=Sw \) for the reference or disturbance class.
- Check regulator equation solvability: \( A\Pi+B\Gamma+E=\Pi S \) and \( C\Pi+D\Gamma=F \).
- Construct the internal-model state, such as \( \dot{\eta}=r-y \) for step tracking.
- Form the augmented pair \( (A_a,B_a) \) and verify stabilizability.
- Choose feedback gains using pole placement, LQR, or another stabilizing design method.
- Simulate nominal and perturbed plants to verify zero-error regulation and acceptable control effort.
Pole placement is pedagogically transparent because it shows whether the augmented system has enough control authority. In later advanced courses, the same internal-model augmentation can be combined with LQR, observers, robust control, or model predictive control.
11. Problems and Solutions
Problem 1 (Regulator Equations for Step Tracking): Consider \( \dot{x}=Ax+Bu,\; y=Cx \) with \( A=\begin{bmatrix}0&1\\-2&-0.4\end{bmatrix} \), \( B=\begin{bmatrix}0\\1\end{bmatrix} \), and \( C=\begin{bmatrix}1&0\end{bmatrix} \). Solve the regulator equations for unit constant reference.
Solution: For a constant reference, use \( S=0 \), \( E=0 \), and \( F=1 \). We need
\[ A\Pi+B\Gamma=0,\qquad C\Pi=1. \]
Let \( \Pi=[\pi_1,\pi_2]^T \). Since \( C\Pi=\pi_1=1 \), we have \( \pi_1=1 \). The first row of \( A\Pi+B\Gamma=0 \) gives \( \pi_2=0 \). The second row gives \( -2\pi_1-0.4\pi_2+\Gamma=0 \), hence \( \Gamma=2 \). Therefore
\[ \Pi=\begin{bmatrix}1\\0\end{bmatrix},\qquad \Gamma=2. \]
Problem 2 (Pole Placement with Integral Action): For the same plant, use the servo law \( u=-k_1x_1-k_2x_2+k_i\eta \) and \( \dot{\eta}=r-x_1 \). Find gains that place the augmented poles at \( -2\pm2j \) and \( -5 \).
Solution: The closed-loop augmented matrix is
\[ A_{\text{cl},a}= \begin{bmatrix} 0 & 1 & 0\\ -2-k_1 & -0.4-k_2 & k_i\\ -1 & 0 & 0 \end{bmatrix}. \]
Its characteristic polynomial is
\[ p(s)=s^3+(0.4+k_2)s^2+(2+k_1)s+k_i. \]
The desired polynomial is
\[ (s+5)\left((s+2)^2+2^2\right)=s^3+9s^2+28s+40. \]
Matching coefficients gives \( k_2=8.6 \), \( k_1=26 \), and \( k_i=40 \).
Problem 3 (Why Feedforward Alone Is Not Robust): Explain why a static reference gain computed from a nominal DC gain does not generally provide robust zero steady-state error.
Solution: A static feedforward gain uses an algebraic inverse of the nominal closed-loop DC map. If the actual plant has slightly different \( A \), \( B \), or \( C \), the actual DC map differs from the nominal one, so the feedforward gain is no longer the exact inverse. Integral action instead imposes the equilibrium equation \( 0=r-y^\star \) through the integrator row, provided the augmented closed loop remains stable.
Problem 4 (Ramp Tracking): What internal model is required to track a ramp reference \( r(t)=a+bt \)?
Solution: A ramp requires a size-two Jordan block at the origin:
\[ S= \begin{bmatrix} 0 & 1\\ 0 & 0 \end{bmatrix}. \]
Equivalently, the controller must contain two integrator levels in the error-to-control path. A single integrator is sufficient for constant tracking but not for exact robust tracking of arbitrary ramps.
Problem 5 (Sinusoidal Disturbance Rejection): A disturbance is known to be sinusoidal with frequency \( \omega \). What mode must appear in the controller?
Solution: The controller must contain the oscillator
\[ S= \begin{bmatrix} 0 & -\omega\\ \omega & 0 \end{bmatrix}. \]
This embeds the modes \( j\omega \) and \( -j\omega \). If the closed-loop system is stable and the regulator equations are solvable, the regulated output rejects that sinusoidal disturbance asymptotically.
12. Summary
The internal model principle explains the structural reason behind integral action and its generalizations. A controller that robustly tracks or rejects a signal generated by \( \dot{w}=Sw \) must contain the relevant modes of \( S \). The regulator equations describe feasibility, while augmented-system stabilizability determines whether feedback can stabilize the internal model together with the plant. For step tracking, the result reduces to the familiar but powerful design: add an integrator of the error and stabilize the augmented state-space system.
13. References
- Francis, B.A., & Wonham, W.M. (1975). The internal model principle for linear multivariable regulators. Applied Mathematics and Optimization, 2, 170–194.
- Davison, E.J. (1976). The robust control of a servomechanism problem for linear time-invariant multivariable systems. IEEE Transactions on Automatic Control, 21(1), 25–34.
- Francis, B.A. (1977). The linear multivariable regulator problem. SIAM Journal on Control and Optimization, 15(3), 486–505.
- Wonham, W.M. (1974). Linear multivariable control: a geometric approach. Lecture Notes in Economics and Mathematical Systems, 101, Springer.
- Hautus, M.L.J. (1983). Strong detectability and observers. Linear Algebra and Its Applications, 50, 353–368.
- Byrnes, C.I., & Isidori, A. (2003). Limit sets, zero dynamics, and internal models in the problem of nonlinear output regulation. IEEE Transactions on Automatic Control, 48(10), 1712–1723.
- Huang, J., & Rugh, W.J. (1990). On a nonlinear multivariable servomechanism problem. Automatica, 26(6), 963–972.
- Isidori, A., & Byrnes, C.I. (1990). Output regulation of nonlinear systems. IEEE Transactions on Automatic Control, 35(2), 131–140.