Chapter 2: Uncertainty and Parametric Modeling for Adaptation
Lesson 1: Parametric vs Unmodeled Dynamics vs Disturbances
This lesson introduces the three uncertainty classes that dominate adaptive control analysis: unknown parameters inside a known model structure, dynamics omitted from the nominal model, and external disturbances. The distinction is not semantic: adaptive laws can estimate parameters only when uncertainty enters through a suitable parameterization. Unmodeled dynamics and disturbances usually appear as residual terms that must be bounded, filtered, or robustified in later lessons.
1. Why This Distinction Matters
Adaptive control is useful when a plant has a known mathematical structure but unknown numerical coefficients. For example, in a mass-spring-damper system, the mass, damping, or stiffness may be uncertain while the governing differential equation remains known. This is parametric uncertainty.
However, real plants also contain neglected flexible modes, actuator bandwidth limits, time delays, sensor filters, friction nonlinearities, and high-frequency effects. These are usually called unmodeled dynamics. Finally, wind loads, load torques, road forces, process inflow variations, and measurement contamination are disturbances.
A compact continuous-time description is
\[ \dot{\mathbf{x}} = \mathbf{f}_0(\mathbf{x},u) + \mathbf{Y}(\mathbf{x},u)\boldsymbol{\theta} + \boldsymbol{\eta}(\mathbf{x},u,t) + \mathbf{B}_d d(t), \]
where \( \mathbf{Y}(\mathbf{x},u)\boldsymbol{\theta} \) is the parametric part, \( \boldsymbol{\eta}(\mathbf{x},u,t) \) denotes unmodeled dynamics, and \( d(t) \) is an external disturbance. In early adaptive-control theory, most clean convergence results require \( \boldsymbol{\eta}=0 \) and \( d=0 \). Later robust adaptive control relaxes these assumptions.
flowchart TD
A["Real plant"] --> B["Known nominal structure"]
A --> C["Unknown effects"]
C --> D["Parametric uncertainty: \nunknown constants in \nknown equations"]
C --> E["Unmodeled dynamics: \nmissing states, \nmodes, delays, filters"]
C --> F["Disturbances: external inputs \nor measurement contamination"]
D --> G["Can be estimated if model \nis linearly parameterized"]
E --> H["Usually appears as \nresidual modeling error"]
F --> I["Usually handled by rejection, \nfiltering, or robustness"]
G --> J["Adaptive control design"]
H --> K["Robust adaptive modifications"]
I --> K
2. Parametric Uncertainty
Parametric uncertainty means that the differential equation has the correct form, but some coefficients are unknown. A standard scalar second-order plant is
\[ m\ddot{x}+c\dot{x}+kx=u. \]
If \( m,c,k \) are unknown but the equation is correct, the uncertainty is parametric. Dividing by \( m \) gives
\[ \ddot{x}=\theta_1 x+\theta_2\dot{x}+\theta_3 u, \quad \theta_1=-\frac{k}{m},\quad \theta_2=-\frac{c}{m},\quad \theta_3=\frac{1}{m}. \]
Define the regressor vector and parameter vector as
\[ \boldsymbol{\phi}(t)= \begin{bmatrix} x(t)\\ \dot{x}(t)\\ u(t) \end{bmatrix}, \qquad \boldsymbol{\theta}= \begin{bmatrix} \theta_1\\ \theta_2\\ \theta_3 \end{bmatrix}. \]
Then the model is linearly parameterized:
\[ \ddot{x}(t)=\boldsymbol{\phi}^{T}(t)\boldsymbol{\theta}. \]
The phrase linearly parameterized does not mean the plant is linear in the state. It means the unknown parameters enter linearly. This distinction is fundamental because many adaptive laws estimate \( \boldsymbol{\theta} \) using regressors such as \( \boldsymbol{\phi}(t) \).
3. Unmodeled Dynamics
Unmodeled dynamics are dynamic effects that are not included in the nominal model. They usually introduce additional states, poles, zeros, delays, filters, or nonlinear memory effects. For example, suppose the nominal model is
\[ \ddot{x}=\theta_1 x+\theta_2\dot{x}+b u. \]
The real plant may contain a neglected fast state \( z(t) \):
\[ \begin{aligned} \dot{x}_1 &= x_2,\\ \dot{x}_2 &= \theta_1 x_1+\theta_2 x_2+b u+\varepsilon z,\\ \dot{z} &= -\lambda z+\rho x_2, \end{aligned} \qquad \lambda \ge 0. \]
If the controller or estimator ignores \( z \), the term \( \varepsilon z \) cannot be represented as a constant parameter multiplying the nominal regressor \( [x_1,x_2,u]^T \) over all frequencies. At low frequency, the fast mode may look approximately like a change in damping, but at higher frequency it behaves as a real additional dynamic state.
In transfer-function language, parametric uncertainty changes the coefficients of a chosen model order:
\[ G_p(s)=\frac{b_0}{s^2+a_1s+a_0}. \]
Unmodeled dynamics change the model order or introduce additional factors:
\[ G_{\mathrm{real}}(s) = \frac{b_0}{s^2+a_1s+a_0} \left(\frac{\omega_f}{s+\omega_f}\right) e^{-s\tau}. \]
The filter factor and delay cannot be fully captured by simply changing \( a_0,a_1,b_0 \). This is why unmodeled dynamics are central to robustness analysis in adaptive systems.
4. Disturbances
A disturbance is an exogenous signal that affects the plant but is not a fixed unknown coefficient. In state-space form:
\[ \dot{\mathbf{x}} = \mathbf{A}\mathbf{x} + \mathbf{B}u + \mathbf{B}_d d(t). \]
If \( d(t) \) is unknown and time-varying, it cannot be treated as a constant parameter. Typical assumptions are boundedness, energy boundedness, or known frequency structure:
\[ |d(t)|\le \bar{d}, \qquad \int_0^T d^2(t)\,dt \le D_T, \qquad d(t)=D\sin(\omega t+\varphi). \]
Disturbances may enter at different locations:
\[ \begin{aligned} \dot{\mathbf{x}} &= \mathbf{A}\mathbf{x}+\mathbf{B}(u+d_u),\\ \dot{\mathbf{x}} &= \mathbf{A}\mathbf{x}+\mathbf{B}u+\mathbf{B}_d d_x,\\ y &= \mathbf{C}\mathbf{x}+d_y. \end{aligned} \]
Input disturbances, state disturbances, and measurement disturbances affect adaptive systems differently. Measurement noise is especially important because many adaptive laws use measured signals directly in regressors.
5. Regression View: What Adaptation Can and Cannot Estimate
The cleanest way to distinguish the uncertainty types is to write the measurable model equation as
\[ y(t)=\boldsymbol{\phi}^{T}(t)\boldsymbol{\theta}+v(t), \]
where \( y(t) \) is a measured or filtered signal, \( \boldsymbol{\phi}(t) \) is a known regressor, \( \boldsymbol{\theta} \) is an unknown constant parameter vector, and
\[ v(t)=v_{\mathrm{unmodeled}}(t)+v_{\mathrm{disturbance}}(t) \]
is the residual that cannot be represented exactly by \( \boldsymbol{\phi}^{T}(t)\boldsymbol{\theta} \). In sampled form:
\[ \mathbf{y}=\boldsymbol{\Phi}\boldsymbol{\theta}+\mathbf{v}. \]
The least-squares estimate is
\[ \hat{\boldsymbol{\theta}} = \left(\boldsymbol{\Phi}^{T}\boldsymbol{\Phi}\right)^{-1} \boldsymbol{\Phi}^{T}\mathbf{y}. \]
Substituting the true equation gives the exact decomposition:
\[ \hat{\boldsymbol{\theta}} = \boldsymbol{\theta} + \left(\boldsymbol{\Phi}^{T}\boldsymbol{\Phi}\right)^{-1} \boldsymbol{\Phi}^{T}\mathbf{v}. \]
Therefore, unmodeled dynamics and disturbances can bias parameter estimates when they are correlated with the regressor. This explains why adaptive control is not merely online curve fitting: stability and robustness must be analyzed with the residual terms included.
flowchart TD
A["Measured relation y"] --> B["Choose regressor phi"]
B --> C["Can uncertainty be \nwritten as theta*T phi?"]
C -->|yes| D["Parametric uncertainty"]
C -->|no| E["Residual term v"]
E --> F["Unmodeled dynamics \nif generated by missing \nstates or filters"]
E --> G["Disturbance if generated \nby external signal"]
D --> H["Candidate for \nparameter adaptation"]
F --> I["Needs robustness \nor model extension"]
G --> I
6. A Basic Identification Lemma
The next chapters will derive adaptive laws using Lyapunov arguments. Before that, we need one elementary fact: parameter estimation is exact only when the residual is absent or orthogonal to the regressor.
Lemma: Suppose the sampled model satisfies \( \mathbf{y}=\boldsymbol{\Phi}\boldsymbol{\theta}+\mathbf{v} \), where \( \boldsymbol{\Phi}^{T}\boldsymbol{\Phi} \) is nonsingular. The least-squares parameter error is
\[ \tilde{\boldsymbol{\theta}} = \hat{\boldsymbol{\theta}}-\boldsymbol{\theta} = \left(\boldsymbol{\Phi}^{T}\boldsymbol{\Phi}\right)^{-1} \boldsymbol{\Phi}^{T}\mathbf{v}. \]
Hence exact recovery occurs if \( \boldsymbol{\Phi}^{T}\mathbf{v}=0 \).
Proof: Since \( \hat{\boldsymbol{\theta}} = \left(\boldsymbol{\Phi}^{T}\boldsymbol{\Phi}\right)^{-1} \boldsymbol{\Phi}^{T}\mathbf{y} \), substitute \( \mathbf{y}=\boldsymbol{\Phi}\boldsymbol{\theta}+\mathbf{v} \):
\[ \begin{aligned} \hat{\boldsymbol{\theta}} &= \left(\boldsymbol{\Phi}^{T}\boldsymbol{\Phi}\right)^{-1} \boldsymbol{\Phi}^{T} \left(\boldsymbol{\Phi}\boldsymbol{\theta}+\mathbf{v}\right)\\ &= \boldsymbol{\theta} + \left(\boldsymbol{\Phi}^{T}\boldsymbol{\Phi}\right)^{-1} \boldsymbol{\Phi}^{T}\mathbf{v}. \end{aligned} \]
Subtracting \( \boldsymbol{\theta} \) gives the result. Furthermore,
\[ \left\|\tilde{\boldsymbol{\theta}}\right\| \le \left\| \left(\boldsymbol{\Phi}^{T}\boldsymbol{\Phi}\right)^{-1} \right\| \left\|\boldsymbol{\Phi}^{T}\mathbf{v}\right\|. \]
Thus a small residual does not automatically imply a small parameter error if the data matrix is ill-conditioned. This fact will reappear in the lessons on persistent excitation and parameter convergence.
7. Modeling Examples
7.1 Mechanical System
Consider a rigid-body translational system:
\[ m\ddot{x}+c\dot{x}+kx=u+d(t). \]
Unknown \( m,c,k \) are parametric uncertainties. A neglected flexible appendage is unmodeled dynamics. An unknown force \( d(t) \) is a disturbance.
7.2 Electrical System
For an RLC circuit,
\[ L\ddot{q}+R\dot{q}+\frac{1}{C}q=v_{\mathrm{in}}. \]
Unknown \( R,L,C \) are parametric. A neglected parasitic capacitance or op-amp bandwidth is unmodeled dynamics. Supply ripple is a disturbance.
7.3 Control-Oriented State Model
A nominal linear plant with parametric uncertainty may be written as
\[ \dot{\mathbf{x}} = \left(\mathbf{A}_0+\sum_{i=1}^{p}\theta_i\mathbf{A}_i\right)\mathbf{x} + \left(\mathbf{B}_0+\sum_{i=1}^{p}\theta_i\mathbf{B}_i\right)u. \]
This is still parameterized by a finite vector \( \boldsymbol{\theta}\in\mathbb{R}^{p} \). By contrast, an omitted actuator transfer function such as
\[ U_{\mathrm{act}}(s)=\frac{\omega_a}{s+\omega_a}U_{\mathrm{cmd}}(s) \]
adds a missing dynamic state. That is unmodeled dynamics unless the actuator state is included in the model.
8. Computational Implementations
The following programs simulate the same conceptual plant:
\[ \begin{aligned} \dot{x}_1 &= x_2,\\ \dot{x}_2 &= \theta_1x_1+\theta_2x_2+bu+\varepsilon z+d(t),\\ \dot{z} &= -\lambda z+\rho x_2. \end{aligned} \]
The nominal regression ignores \( z \) and \( d(t) \), so the least-squares residual separates the estimable parametric part from the nonparametric residual. Useful libraries include NumPy, SciPy, Matplotlib, Eigen, Apache Commons Math, MATLAB Control System Toolbox, Simulink, and Wolfram NDSolve.
Chapter2_Lesson1.py
# Chapter2_Lesson1.py
# Parametric uncertainty vs unmodeled dynamics vs external disturbances
# Simulates a second-order plant with unknown mass/damping/stiffness effects,
# an unmodeled fast mode, and a sinusoidal disturbance, then estimates the
# parametric part using least squares.
import numpy as np
import matplotlib.pyplot as plt
def rk4_step(f, t, x, h):
k1 = f(t, x)
k2 = f(t + 0.5 * h, x + 0.5 * h * k1)
k3 = f(t + 0.5 * h, x + 0.5 * h * k2)
k4 = f(t + h, x + h * k3)
return x + (h / 6.0) * (k1 + 2.0 * k2 + 2.0 * k3 + k4)
def main():
# True plant: x1dot = x2
# x2dot = theta1*x1 + theta2*x2 + b*u + eps*z + d(t)
# zdot = -lambda*z + rho*x2
theta_true = np.array([-2.0, -0.7]) # parametric part: stiffness and damping terms
b = 1.0
eps = 0.35 # strength of unmodeled mode
lam = 18.0 # fast unmodeled mode
rho = 6.0
dist_amp = 0.25
dist_freq = 1.7
dt = 0.002
tf = 12.0
t = np.arange(0.0, tf + dt, dt)
x = np.zeros((len(t), 3))
x[0, :] = [0.4, 0.0, 0.0]
def u_of_t(time):
# Rich input helps separate parametric terms from residuals.
return 0.8 * np.sin(0.8 * time) + 0.4 * np.sin(2.2 * time)
def d_of_t(time):
return dist_amp * np.sin(dist_freq * time)
def f(time, state):
x1, x2, z = state
u = u_of_t(time)
return np.array([
x2,
theta_true[0] * x1 + theta_true[1] * x2 + b * u + eps * z + d_of_t(time),
-lam * z + rho * x2
])
for k in range(len(t) - 1):
x[k + 1, :] = rk4_step(f, t[k], x[k, :], dt)
u = np.array([u_of_t(time) for time in t])
d = np.array([d_of_t(time) for time in t])
# Numerical acceleration from simulated velocity.
x2dot_est = np.gradient(x[:, 1], dt)
# Regression: y = theta1*x1 + theta2*x2 + residual,
# where residual = eps*z + d(t) plus numerical differentiation error.
y = x2dot_est - b * u
Phi = np.column_stack([x[:, 0], x[:, 1]])
theta_hat, _, _, _ = np.linalg.lstsq(Phi, y, rcond=None)
y_param = Phi @ theta_hat
residual = y - y_param
print("True theta: ", theta_true)
print("Estimated theta:", theta_hat)
print("Residual RMS: ", np.sqrt(np.mean(residual**2)))
print("Disturbance RMS:", np.sqrt(np.mean(d**2)))
print("Unmodeled RMS: ", np.sqrt(np.mean((eps * x[:, 2])**2)))
plt.figure()
plt.plot(t, x[:, 0], label="x1 position")
plt.plot(t, x[:, 1], label="x2 velocity")
plt.xlabel("time [s]")
plt.ylabel("state")
plt.title("Main modeled state")
plt.grid(True)
plt.legend()
plt.figure()
plt.plot(t, residual, label="unexplained residual")
plt.plot(t, eps * x[:, 2], "--", label="unmodeled fast mode contribution")
plt.plot(t, d, ":", label="external disturbance")
plt.xlabel("time [s]")
plt.ylabel("acceleration contribution")
plt.title("Residual = unmodeled dynamics + disturbance + numerical error")
plt.grid(True)
plt.legend()
plt.show()
if __name__ == "__main__":
main()
Chapter2_Lesson1.cpp
// Chapter2_Lesson1.cpp
// Compile: g++ -std=c++17 Chapter2_Lesson1.cpp -O2 -o Chapter2_Lesson1
// Simulates parametric uncertainty, unmodeled dynamics, and disturbances.
// No external libraries are required.
#include <array>
#include <cmath>
#include <iostream>
#include <vector>
struct State {
double x1;
double x2;
double z;
};
State add(const State& a, const State& b, double scale) {
return {a.x1 + scale * b.x1, a.x2 + scale * b.x2, a.z + scale * b.z};
}
State f(double t, const State& x) {
const double theta1 = -2.0;
const double theta2 = -0.7;
const double b = 1.0;
const double eps = 0.35;
const double lambda = 18.0;
const double rho = 6.0;
double u = 0.8 * std::sin(0.8 * t) + 0.4 * std::sin(2.2 * t);
double d = 0.25 * std::sin(1.7 * t);
return {
x.x2,
theta1 * x.x1 + theta2 * x.x2 + b * u + eps * x.z + d,
-lambda * x.z + rho * x.x2
};
}
State rk4(double t, const State& x, double h) {
State k1 = f(t, x);
State k2 = f(t + 0.5 * h, add(x, k1, 0.5 * h));
State k3 = f(t + 0.5 * h, add(x, k2, 0.5 * h));
State k4 = f(t + h, add(x, k3, h));
return {
x.x1 + h * (k1.x1 + 2.0 * k2.x1 + 2.0 * k3.x1 + k4.x1) / 6.0,
x.x2 + h * (k1.x2 + 2.0 * k2.x2 + 2.0 * k3.x2 + k4.x2) / 6.0,
x.z + h * (k1.z + 2.0 * k2.z + 2.0 * k3.z + k4.z ) / 6.0
};
}
int main() {
const double dt = 0.002;
const double tf = 12.0;
const int n = static_cast<int>(tf / dt) + 1;
std::vector<double> time(n), u(n), y(n), residual(n);
std::vector<State> x(n);
x[0] = {0.4, 0.0, 0.0};
for (int k = 0; k < n; ++k) {
time[k] = k * dt;
u[k] = 0.8 * std::sin(0.8 * time[k]) + 0.4 * std::sin(2.2 * time[k]);
}
for (int k = 0; k < n - 1; ++k) {
x[k + 1] = rk4(time[k], x[k], dt);
}
// Estimate acceleration by centered differences.
for (int k = 1; k < n - 1; ++k) {
double x2dot = (x[k + 1].x2 - x[k - 1].x2) / (2.0 * dt);
y[k] = x2dot - u[k];
}
y[0] = y[1];
y[n - 1] = y[n - 2];
// Least squares for theta = [theta1 theta2]^T:
// minimize sum (y - theta1*x1 - theta2*x2)^2.
double s11 = 0.0, s12 = 0.0, s22 = 0.0, q1 = 0.0, q2 = 0.0;
for (int k = 0; k < n; ++k) {
s11 += x[k].x1 * x[k].x1;
s12 += x[k].x1 * x[k].x2;
s22 += x[k].x2 * x[k].x2;
q1 += x[k].x1 * y[k];
q2 += x[k].x2 * y[k];
}
double det = s11 * s22 - s12 * s12;
double theta1_hat = (s22 * q1 - s12 * q2) / det;
double theta2_hat = (-s12 * q1 + s11 * q2) / det;
double rms = 0.0;
for (int k = 0; k < n; ++k) {
residual[k] = y[k] - theta1_hat * x[k].x1 - theta2_hat * x[k].x2;
rms += residual[k] * residual[k];
}
rms = std::sqrt(rms / n);
std::cout << "Estimated theta1 = " << theta1_hat << "\n";
std::cout << "Estimated theta2 = " << theta2_hat << "\n";
std::cout << "Residual RMS = " << rms << "\n";
std::cout << "Interpretation: the residual contains unmodeled fast dynamics and disturbance.\n";
return 0;
}
Chapter2_Lesson1.java
// Chapter2_Lesson1.java
// Compile: javac Chapter2_Lesson1.java
// Run: java Chapter2_Lesson1
// Demonstrates least-squares separation of parametric uncertainty from residual effects.
public class Chapter2_Lesson1 {
static class State {
double x1, x2, z;
State(double x1, double x2, double z) {
this.x1 = x1;
this.x2 = x2;
this.z = z;
}
}
static State add(State a, State b, double scale) {
return new State(a.x1 + scale * b.x1, a.x2 + scale * b.x2, a.z + scale * b.z);
}
static State dynamics(double t, State x) {
double theta1 = -2.0;
double theta2 = -0.7;
double b = 1.0;
double eps = 0.35;
double lambda = 18.0;
double rho = 6.0;
double u = 0.8 * Math.sin(0.8 * t) + 0.4 * Math.sin(2.2 * t);
double d = 0.25 * Math.sin(1.7 * t);
return new State(
x.x2,
theta1 * x.x1 + theta2 * x.x2 + b * u + eps * x.z + d,
-lambda * x.z + rho * x.x2
);
}
static State rk4(double t, State x, double h) {
State k1 = dynamics(t, x);
State k2 = dynamics(t + 0.5 * h, add(x, k1, 0.5 * h));
State k3 = dynamics(t + 0.5 * h, add(x, k2, 0.5 * h));
State k4 = dynamics(t + h, add(x, k3, h));
return new State(
x.x1 + h * (k1.x1 + 2.0 * k2.x1 + 2.0 * k3.x1 + k4.x1) / 6.0,
x.x2 + h * (k1.x2 + 2.0 * k2.x2 + 2.0 * k3.x2 + k4.x2) / 6.0,
x.z + h * (k1.z + 2.0 * k2.z + 2.0 * k3.z + k4.z ) / 6.0
);
}
public static void main(String[] args) {
double dt = 0.002;
double tf = 12.0;
int n = (int)(tf / dt) + 1;
double[] time = new double[n];
double[] u = new double[n];
double[] y = new double[n];
double[] residual = new double[n];
State[] x = new State[n];
x[0] = new State(0.4, 0.0, 0.0);
for (int k = 0; k < n; k++) {
time[k] = k * dt;
u[k] = 0.8 * Math.sin(0.8 * time[k]) + 0.4 * Math.sin(2.2 * time[k]);
}
for (int k = 0; k < n - 1; k++) {
x[k + 1] = rk4(time[k], x[k], dt);
}
for (int k = 1; k < n - 1; k++) {
double x2dot = (x[k + 1].x2 - x[k - 1].x2) / (2.0 * dt);
y[k] = x2dot - u[k];
}
y[0] = y[1];
y[n - 1] = y[n - 2];
double s11 = 0.0, s12 = 0.0, s22 = 0.0, q1 = 0.0, q2 = 0.0;
for (int k = 0; k < n; k++) {
s11 += x[k].x1 * x[k].x1;
s12 += x[k].x1 * x[k].x2;
s22 += x[k].x2 * x[k].x2;
q1 += x[k].x1 * y[k];
q2 += x[k].x2 * y[k];
}
double det = s11 * s22 - s12 * s12;
double theta1Hat = (s22 * q1 - s12 * q2) / det;
double theta2Hat = (-s12 * q1 + s11 * q2) / det;
double rms = 0.0;
for (int k = 0; k < n; k++) {
residual[k] = y[k] - theta1Hat * x[k].x1 - theta2Hat * x[k].x2;
rms += residual[k] * residual[k];
}
rms = Math.sqrt(rms / n);
System.out.println("Estimated theta1 = " + theta1Hat);
System.out.println("Estimated theta2 = " + theta2Hat);
System.out.println("Residual RMS = " + rms);
System.out.println("Residuals are not parameters; they contain unmodeled dynamics and disturbances.");
}
}
Chapter2_Lesson1.m
% Chapter2_Lesson1.m
% MATLAB/Simulink-oriented script:
% Parametric uncertainty vs unmodeled dynamics vs disturbances.
% The same state equations can be implemented in Simulink using three Integrator
% blocks for x1, x2, and z, plus Sum/Gain blocks for each right-hand side.
clear; clc; close all;
theta_true = [-2.0; -0.7]; % parametric part
b = 1.0;
eps_u = 0.35; % unmodeled-mode strength
lambda = 18.0; % fast unmodeled pole
rho = 6.0;
dist_amp = 0.25;
dist_freq = 1.7;
dt = 0.002;
tf = 12.0;
tspan = 0:dt:tf;
x0 = [0.4; 0.0; 0.0];
u_fun = @(t) 0.8*sin(0.8*t) + 0.4*sin(2.2*t);
d_fun = @(t) dist_amp*sin(dist_freq*t);
dyn = @(t,x) [ ...
x(2); ...
theta_true(1)*x(1) + theta_true(2)*x(2) + b*u_fun(t) + eps_u*x(3) + d_fun(t); ...
-lambda*x(3) + rho*x(2) ...
];
% ode45 is convenient for analysis; fixed-step RK/ODE blocks are typical in Simulink.
[t, x] = ode45(dyn, tspan, x0);
u = arrayfun(u_fun, t);
d = arrayfun(d_fun, t);
x2dot_est = gradient(x(:,2), dt);
y = x2dot_est - b*u;
Phi = [x(:,1), x(:,2)];
theta_hat = Phi \ y;
residual = y - Phi*theta_hat;
fprintf('True theta: [% .4f, % .4f]\n', theta_true(1), theta_true(2));
fprintf('Estimated theta: [% .4f, % .4f]\n', theta_hat(1), theta_hat(2));
fprintf('Residual RMS: % .4f\n', rms(residual));
figure;
plot(t, x(:,1), 'LineWidth', 1.2); hold on;
plot(t, x(:,2), 'LineWidth', 1.2);
grid on; xlabel('time [s]'); ylabel('state');
title('Main modeled state');
legend('x1 position', 'x2 velocity');
figure;
plot(t, residual, 'LineWidth', 1.2); hold on;
plot(t, eps_u*x(:,3), '--', 'LineWidth', 1.2);
plot(t, d, ':', 'LineWidth', 1.2);
grid on; xlabel('time [s]'); ylabel('acceleration contribution');
title('Residual components');
legend('unexplained residual', 'unmodeled fast mode', 'external disturbance');
% Simulink implementation notes:
% 1. Create blocks for x1dot = x2, x2dot = theta1*x1 + theta2*x2 + b*u + eps*z + d.
% 2. Add zdot = -lambda*z + rho*x2 only in the true plant, not in the nominal model.
% 3. Log y = x2dot - b*u and Phi = [x1 x2].
% 4. Estimate theta using Least Squares or Recursive Least Squares blocks.
Chapter2_Lesson1.nb
(* Chapter2_Lesson1.nb *)
(* Wolfram Mathematica code: parametric uncertainty vs unmodeled dynamics vs disturbances *)
ClearAll["Global`*"];
thetaTrue = {-2.0, -0.7};
b = 1.0;
eps = 0.35;
lambda = 18.0;
rho = 6.0;
distAmp = 0.25;
distFreq = 1.7;
u[t_] := 0.8 Sin[0.8 t] + 0.4 Sin[2.2 t];
d[t_] := distAmp Sin[distFreq t];
sol = NDSolveValue[
{
x1'[t] == x2[t],
x2'[t] == thetaTrue[[1]] x1[t] + thetaTrue[[2]] x2[t] + b u[t] + eps z[t] + d[t],
z'[t] == -lambda z[t] + rho x2[t],
x1[0] == 0.4,
x2[0] == 0.0,
z[0] == 0.0
},
{x1, x2, z},
{t, 0, 12}
];
dt = 0.01;
ts = Range[0, 12, dt];
xdata = sol /@ ts;
x1data = xdata[[All, 1]];
x2data = xdata[[All, 2]];
zdata = xdata[[All, 3]];
udata = u /@ ts;
x2dot = Differences[x2data]/dt;
tsShort = Most[ts];
y = x2dot - Most[udata];
phi = Transpose[{Most[x1data], Most[x2data]}];
thetaHat = LinearSolve[Transpose[phi].phi, Transpose[phi].y];
residual = y - phi.thetaHat;
Print["True theta = ", thetaTrue];
Print["Estimated theta = ", thetaHat];
Print["Residual RMS = ", Sqrt[Mean[residual^2]]];
ListLinePlot[
{
Transpose[{ts, x1data}],
Transpose[{ts, x2data}]
},
PlotLegends -> {"x1 position", "x2 velocity"},
AxesLabel -> {"time [s]", "state"},
PlotLabel -> "Main modeled state"
]
ListLinePlot[
{
Transpose[{tsShort, residual}],
Transpose[{tsShort, eps Most[zdata]}],
Transpose[{tsShort, d /@ tsShort}]
},
PlotLegends -> {"unexplained residual", "unmodeled fast mode", "external disturbance"},
AxesLabel -> {"time [s]", "acceleration contribution"},
PlotLabel -> "Residual components"
]
9. Problems and Solutions
Problem 1: Classify each uncertainty in the plant below as parametric uncertainty, unmodeled dynamics, or disturbance:
\[ m\ddot{x}+c\dot{x}+kx+\alpha x^3=u+d(t). \]
Assume the nominal model is \( m\ddot{x}+c\dot{x}+kx=u \).
Solution: Unknown \( m,c,k \) are parametric uncertainties if the second-order rigid-body structure is accepted. The cubic term \( \alpha x^3 \) is not necessarily unmodeled dynamics because it has no additional state; it is an unmodeled nonlinearity unless the model is extended to include \( x^3 \) as a regressor. If \( \alpha \) is unknown and \( x^3 \) is included in the regressor, it becomes parametric uncertainty. The term \( d(t) \) is an external disturbance.
Problem 2: Suppose sampled data satisfy \( \mathbf{y}=\boldsymbol{\Phi}\boldsymbol{\theta}+\mathbf{v} \). Derive the least-squares parameter bias caused by \( \mathbf{v} \).
Solution: The least-squares estimate is
\[ \hat{\boldsymbol{\theta}} = \left(\boldsymbol{\Phi}^{T}\boldsymbol{\Phi}\right)^{-1} \boldsymbol{\Phi}^{T}\mathbf{y}. \]
Substituting the data equation gives
\[ \hat{\boldsymbol{\theta}}-\boldsymbol{\theta} = \left(\boldsymbol{\Phi}^{T}\boldsymbol{\Phi}\right)^{-1} \boldsymbol{\Phi}^{T}\mathbf{v}. \]
Thus the estimate is unbiased only when the residual is orthogonal to the regressor, namely \( \boldsymbol{\Phi}^{T}\mathbf{v}=0 \).
Problem 3: A true plant contains a neglected actuator lag:
\[ \dot{x}=ax+bu_a, \qquad \dot{u}_a=-\omega_a u_a+\omega_a u. \]
The nominal model uses \( \dot{x}=ax+bu \). Is the actuator lag parametric uncertainty?
Solution: No. The actuator lag introduces an additional state \( u_a \). Even if \( \omega_a \) is unknown, the nominal model has the wrong dynamic order. If the actuator equation is added to the model, then uncertainty in \( \omega_a \) may become parametric. Without this extension, it is unmodeled dynamics.
Problem 4: Consider the model \( y(t)=\phi^T(t)\theta+d(t) \), where \( d(t) \) is a sinusoidal disturbance. Why can an adaptive estimator mistakenly interpret this disturbance as a parameter change?
Solution: If \( d(t) \) has frequency content correlated with \( \phi(t) \), then \( \Phi^T d \) is not zero over a finite data window. The least-squares or adaptive estimator then changes \( \hat{\theta} \) to reduce tracking or prediction error, even though the true parameter did not change. This is one source of parameter drift in adaptive systems with disturbances.
Problem 5: For the fast unmodeled mode
\[ \dot{z}=-\lambda z+\rho x_2, \]
explain why the term \( \varepsilon z \) may resemble a parametric damping change at low frequency but not at high frequency.
Solution: In the frequency domain,
\[ Z(s)=\frac{\rho}{s+\lambda}X_2(s). \]
If the signal frequency is much smaller than \( \lambda \), then
\[ \frac{\rho}{s+\lambda}\approx \frac{\rho}{\lambda}. \]
Therefore \( \varepsilon z \approx \varepsilon\rho x_2/\lambda \), which looks like an additional damping term. At higher frequency, the phase lag and dynamic roll-off of \( 1/(s+\lambda) \) become important, so the effect can no longer be represented by a constant damping parameter.
10. Summary
Parametric uncertainty is uncertainty in constants inside a known model structure. Unmodeled dynamics are missing states, filters, delays, or higher-order effects. Disturbances are external signals that enter the plant, input, state, or measurement channel. Adaptive control can estimate parameters only when uncertainty is represented by suitable regressors. Residual effects caused by unmodeled dynamics and disturbances must be treated carefully because they can bias parameter estimates and destabilize naive adaptive laws.
11. References
- Narendra, K.S., & Valavani, L.S. (1978). Stable adaptive controller design: direct control. IEEE Transactions on Automatic Control, 23(4), 570–583.
- Narendra, K.S., Lin, Y.H., & Valavani, L.S. (1980). Stable adaptive controller design, part II: proof of stability. IEEE Transactions on Automatic Control, 25(3), 440–448.
- Kreisselmeier, G., & Narendra, K.S. (1982). Stable model reference adaptive control in the presence of bounded disturbances. IEEE Transactions on Automatic Control, 27(6), 1169–1175.
- Rohrs, C.E., Valavani, L., Athans, M., & Stein, G. (1985). Robustness of continuous-time adaptive control algorithms in the presence of unmodeled dynamics. IEEE Transactions on Automatic Control, 30(9), 881–889.
- Ioannou, P.A., & Kokotovic, P.V. (1984). Instability analysis and improvement of robustness of adaptive control. Automatica, 20(5), 583–594.
- Morse, A.S. (1980). Global stability of parameter-adaptive control systems. IEEE Transactions on Automatic Control, 25(3), 433–439.
- Goodwin, G.C., Ramadge, P.J., & Caines, P.E. (1980). Discrete-time multivariable adaptive control. IEEE Transactions on Automatic Control, 25(3), 449–456.
- Praly, L. (1984). Robustness of model reference adaptive control. Systems & Control Letters, 4(2), 61–65.
Help keep these engineering tutorials free and growing
If these lessons, examples, and project pages help you, a small donation supports the continued creation and improvement of free control, robotics, software, and engineering education resources.
Created and maintained by Abolfazl Mohammadijoo.