Chapter 2: Uncertainty and Parametric Modeling for Adaptation

Lesson 3: Regressor Vectors and Parameter Vectors in Control-Oriented Models

This lesson develops the precise meaning of regressor vectors and parameter vectors in control-oriented models. Building on the previous lesson on linearly parameterized structures, we learn how uncertain physical constants are separated from measurable signals, how dimensions must be checked, how prediction errors are formed, and why the regressor is the mathematical object through which adaptation can act.

1. Conceptual Overview

In adaptive control, a regressor vector collects known functions of measurable or commanded variables, while a parameter vector collects unknown constants. The central separation is \( \text{known signals} \) versus \( \text{unknown constants} \). A scalar control-oriented model is often written as

\[ z(t)=\boldsymbol{\phi}^{T}(t)\boldsymbol{\theta} = \sum_{i=1}^{p}\phi_i(t)\theta_i, \qquad \boldsymbol{\phi}(t)\in\mathbb{R}^{p}, \quad \boldsymbol{\theta}\in\mathbb{R}^{p} \]

Here \( z(t) \) may represent an acceleration, filtered output, filtered input-output expression, or another signal needed by a controller. The regressor \( \boldsymbol{\phi}(t) \) is known at time \( t \); the parameter vector \( \boldsymbol{\theta} \) is unknown but assumed constant or slowly varying.

flowchart TD
  A["Measured states and known inputs"] --> B["Build known basis signals"]
  B --> C["Regressor vector phi(t)"]
  D["Unknown physical constants"] --> E["Parameter vector theta"]
  C --> F["Linear combination phiT theta"]
  E --> F
  F --> G["Prediction, compensation, or control model"]
  G --> H["Prediction error or tracking error"]
  H --> I["Later adaptive law updates theta_hat"]
        

The adaptive controller never adapts the regressor itself in the basic parametric setting. Instead, it adapts an estimate \( \hat{\boldsymbol{\theta}}(t) \) of the unknown parameter vector. This distinction is essential: the regressor is data, the parameter vector is uncertainty.

2. Dimensions and Notational Discipline

A common source of mistakes in adaptive modeling is dimension mismatch. If the model output is scalar, then \( \boldsymbol{\phi}^{T}\boldsymbol{\theta} \) must be scalar. Therefore,

\[ \boldsymbol{\phi}(t)= \begin{bmatrix} \phi_1(t)\\ \phi_2(t)\\ \vdots\\ \phi_p(t) \end{bmatrix}, \qquad \boldsymbol{\theta}= \begin{bmatrix} \theta_1\\ \theta_2\\ \vdots\\ \theta_p \end{bmatrix}, \qquad \boldsymbol{\phi}^{T}\boldsymbol{\theta}\in\mathbb{R} \]

For a vector model with \( \mathbf{z}(t)\in\mathbb{R}^{n} \), one may use a matrix regressor:

\[ \mathbf{z}(t)=\mathbf{Y}(t)\boldsymbol{\theta}, \qquad \mathbf{Y}(t)\in\mathbb{R}^{n\times p}, \qquad \boldsymbol{\theta}\in\mathbb{R}^{p} \]

In control-oriented notation, \( \mathbf{Y}(t) \) is also called a regressor. The symbol \( \boldsymbol{\phi}(t) \) is more common for scalar regressions, while \( \mathbf{Y}(t) \) is common in mechanical systems and robot control.

\[ \text{scalar regression: } z=\boldsymbol{\phi}^{T}\boldsymbol{\theta}, \qquad \text{vector regression: } \mathbf{z}=\mathbf{Y}\boldsymbol{\theta} \]

The parameter estimate must have the same dimension as the true parameter vector: \( \hat{\boldsymbol{\theta}}(t)\in\mathbb{R}^{p} \). The parameter error is

\[ \tilde{\boldsymbol{\theta}}(t) = \hat{\boldsymbol{\theta}}(t)-\boldsymbol{\theta} \]

This definition will be used throughout the course. Some books define the opposite sign, but the algebra must then be adjusted consistently.

3. Worked Model 1 — Mass-Spring-Damper Plant

Consider the second-order plant

\[ m\ddot{y}+c\dot{y}+ky=bu \]

where \( m \), \( c \), \( k \), and \( b \) are constant but not perfectly known. Solving for acceleration gives

\[ \ddot{y} = -\frac{k}{m}y-\frac{c}{m}\dot{y}+\frac{b}{m}u \]

This is linear in the normalized unknown parameters. Define

\[ \boldsymbol{\phi}(y,\dot{y},u) = \begin{bmatrix} -y\\ -\dot{y}\\ u \end{bmatrix}, \qquad \boldsymbol{\theta} = \begin{bmatrix} k/m\\ c/m\\ b/m \end{bmatrix} \]

Then the control-oriented acceleration model is

\[ \ddot{y}=\boldsymbol{\phi}^{T}(y,\dot{y},u)\boldsymbol{\theta} \]

Notice that the physical constants \( m,c,k,b \) do not appear separately in the parameter vector. The adaptive estimator can identify only the normalized ratios \( k/m \), \( c/m \), and \( b/m \) from this acceleration equation. This is not a weakness; it is exactly what is needed for acceleration prediction and model compensation.

\[ \hat{\ddot{y}} = \boldsymbol{\phi}^{T}\hat{\boldsymbol{\theta}}, \qquad \varepsilon = \hat{\ddot{y}}-\ddot{y} = \boldsymbol{\phi}^{T} \left(\hat{\boldsymbol{\theta}}-\boldsymbol{\theta}\right) = \boldsymbol{\phi}^{T}\tilde{\boldsymbol{\theta}} \]

4. Physical Parameters vs Control-Oriented Parameters

Adaptive control does not always estimate physical constants directly. Often it estimates parameter combinations that appear linearly in the model. For the mass-spring-damper plant, the physical parameter vector and the control-oriented vector are

\[ \boldsymbol{\rho} = \begin{bmatrix} m\\c\\k\\b \end{bmatrix}, \qquad \boldsymbol{\theta} = \begin{bmatrix} k/m\\c/m\\b/m \end{bmatrix} \]

The vector \( \boldsymbol{\rho} \) has four entries, while \( \boldsymbol{\theta} \) has three entries. From the normalized acceleration equation alone, one cannot uniquely recover all four physical constants. For example, multiplying \( m,c,k,b \) by the same positive scalar gives the same normalized vector.

\[ \frac{\alpha k}{\alpha m}=\frac{k}{m}, \qquad \frac{\alpha c}{\alpha m}=\frac{c}{m}, \qquad \frac{\alpha b}{\alpha m}=\frac{b}{m}, \qquad \alpha>0 \]

Therefore, a control-oriented parameter vector should be chosen for the purpose of control, not merely for physical interpretation. If a controller needs \( k/m \), estimating \( k \) and \( m \) separately may be unnecessary.

5. Prediction Error and Instantaneous Gradient Update

Suppose a measured or computed scalar signal \( z(t) \) satisfies \( z=\boldsymbol{\phi}^{T}\boldsymbol{\theta} \). The prediction using an estimated parameter vector is

\[ \hat{z} = \boldsymbol{\phi}^{T}\hat{\boldsymbol{\theta}}, \qquad \varepsilon = \hat{z}-z = \boldsymbol{\phi}^{T}\tilde{\boldsymbol{\theta}} \]

A simple instantaneous squared prediction loss is

\[ J(\hat{\boldsymbol{\theta}}) = \frac{1}{2}\varepsilon^{2} = \frac{1}{2} \left( \boldsymbol{\phi}^{T}\hat{\boldsymbol{\theta}}-z \right)^{2} \]

Its gradient with respect to the estimate is

\[ \nabla_{\hat{\boldsymbol{\theta}}}J = \boldsymbol{\phi}\varepsilon \]

Therefore, an elementary continuous-time gradient estimator is

\[ \dot{\hat{\boldsymbol{\theta}}} = -\boldsymbol{\Gamma}\boldsymbol{\phi}\varepsilon, \qquad \boldsymbol{\Gamma} = \boldsymbol{\Gamma}^{T}>0 \]

This is not yet a full adaptive controller; it is only a parameter estimator for a regression equation. Later lessons will combine similar update laws with closed-loop tracking-error dynamics.

6. Proofs

Proof 1 — Prediction error is linear in parameter error. If \( z=\boldsymbol{\phi}^{T}\boldsymbol{\theta} \) and \( \hat{z}=\boldsymbol{\phi}^{T}\hat{\boldsymbol{\theta}} \), then

\[ \varepsilon = \hat{z}-z = \boldsymbol{\phi}^{T}\hat{\boldsymbol{\theta}} - \boldsymbol{\phi}^{T}\boldsymbol{\theta} = \boldsymbol{\phi}^{T} \left( \hat{\boldsymbol{\theta}}-\boldsymbol{\theta} \right) = \boldsymbol{\phi}^{T}\tilde{\boldsymbol{\theta}} \]

Thus the prediction error is scalar but depends on the projection of the parameter error onto the current regressor direction.

Proof 2 — Instantaneous gradient direction. For \( J=\frac{1}{2}\varepsilon^{2} \) and \( \varepsilon=\boldsymbol{\phi}^{T}\hat{\boldsymbol{\theta}}-z \), use the chain rule:

\[ \frac{\partial J}{\partial\hat{\boldsymbol{\theta}}} = \frac{\partial J}{\partial\varepsilon} \frac{\partial\varepsilon}{\partial\hat{\boldsymbol{\theta}}} = \varepsilon\boldsymbol{\phi} \]

Therefore the steepest descent direction, scaled by a symmetric positive definite gain matrix \( \boldsymbol{\Gamma} \), is

\[ \dot{\hat{\boldsymbol{\theta}}} = -\boldsymbol{\Gamma} \frac{\partial J}{\partial\hat{\boldsymbol{\theta}}} = -\boldsymbol{\Gamma}\boldsymbol{\phi}\varepsilon \]

Proof 3 — Least-squares normal equation. For sampled data \( z_i=\boldsymbol{\phi}_i^{T}\boldsymbol{\theta}+\eta_i \), stack the data as

\[ \mathbf{z} = \mathbf{\Phi}\boldsymbol{\theta}+\boldsymbol{\eta}, \qquad \mathbf{\Phi} = \begin{bmatrix} \boldsymbol{\phi}_1^{T}\\ \boldsymbol{\phi}_2^{T}\\ \vdots\\ \boldsymbol{\phi}_N^{T} \end{bmatrix} \]

The least-squares criterion is

\[ J_N(\hat{\boldsymbol{\theta}}) = \frac{1}{2} \left\| \mathbf{z}-\mathbf{\Phi}\hat{\boldsymbol{\theta}} \right\|^{2} \]

Differentiating and setting the gradient to zero gives

\[ -\mathbf{\Phi}^{T} \left( \mathbf{z}-\mathbf{\Phi}\hat{\boldsymbol{\theta}} \right) = \mathbf{0} \]

Hence, if \( \mathbf{\Phi}^{T}\mathbf{\Phi} \) is nonsingular,

\[ \hat{\boldsymbol{\theta}}_{LS} = \left( \mathbf{\Phi}^{T}\mathbf{\Phi} \right)^{-1} \mathbf{\Phi}^{T}\mathbf{z} \]

The matrix \( \mathbf{\Phi}^{T}\mathbf{\Phi} \) is the finite-data information matrix. If it is singular, some parameter directions cannot be distinguished from the collected data.

7. Control-Oriented Modeling Workflow

A practical workflow for constructing a useful regressor is shown below. The goal is not to write the most physically detailed model, but to isolate the uncertainty in a form that can later enter an adaptive law.

flowchart TD
  A["Start from differential equation"] --> B["Move known measured terms to one side"]
  B --> C["Choose model signal z(t)"]
  C --> D["Collect known basis functions"]
  D --> E["Define phi(t) or Y(t)"]
  E --> F["Define theta as unknown constant coefficients"]
  F --> G["Check dimensions and units"]
  G --> H["Build prediction z_hat = phiT theta_hat"]
  H --> I["Use prediction error for estimation"]
        

The unit check is not cosmetic. If \( z=\ddot{y} \), each product \( \phi_i\theta_i \) must have acceleration units. This prevents accidental mixing of physical parameters and normalized parameters.

8. Vector Regressor Example for a Two-State Model

Consider a two-state system with uncertain coefficients:

\[ \dot{x}_1=x_2, \qquad \dot{x}_2= \theta_1 x_1+\theta_2 x_2+\theta_3 u \]

The second equation can be written as

\[ \dot{x}_2= \begin{bmatrix} x_1 & x_2 & u \end{bmatrix} \begin{bmatrix} \theta_1\\ \theta_2\\ \theta_3 \end{bmatrix} = \boldsymbol{\phi}^{T}(x,u)\boldsymbol{\theta} \]

The full state equation is

\[ \dot{\mathbf{x}} = \begin{bmatrix} x_2\\ \boldsymbol{\phi}^{T}(x,u)\boldsymbol{\theta} \end{bmatrix} \]

This is a control-oriented state-space model with uncertainty appearing in the acceleration channel. In future MRAC lessons, similar structures will be embedded into tracking-error dynamics.

9. Matrix Regressor Example for Mechanical Systems

Many mechanical systems have equations of motion of the form

\[ \mathbf{M}(q,\boldsymbol{\theta})\ddot{q} + \mathbf{C}(q,\dot{q},\boldsymbol{\theta})\dot{q} + \mathbf{g}(q,\boldsymbol{\theta}) = \boldsymbol{\tau} \]

A crucial structural property is that the dynamics can often be written linearly in a vector of inertial and gravitational parameters:

\[ \mathbf{M}(q,\boldsymbol{\theta})\mathbf{v} + \mathbf{C}(q,\dot{q},\boldsymbol{\theta})\mathbf{w} + \mathbf{g}(q,\boldsymbol{\theta}) = \mathbf{Y}(q,\dot{q},\mathbf{v},\mathbf{w}) \boldsymbol{\theta} \]

Here \( \mathbf{Y} \) is a matrix regressor, and \( \boldsymbol{\theta} \) contains constant mechanical parameters. This property is one reason adaptive control became highly influential in robot manipulators. We only need the notation here; the full robot-control derivation appears later in the applications chapters.

10. Identifiability and Rank

Parameter estimation depends on the information content of the regressor. For finite sampled data,

\[ \mathbf{z} = \mathbf{\Phi}\boldsymbol{\theta}, \qquad \mathbf{\Phi}\in\mathbb{R}^{N\times p} \]

exact recovery of \( \boldsymbol{\theta} \) from noiseless data requires

\[ \operatorname{rank}(\mathbf{\Phi})=p \]

Equivalently, \( \mathbf{\Phi}^{T}\mathbf{\Phi} \) must be positive definite:

\[ \mathbf{v}^{T}\mathbf{\Phi}^{T}\mathbf{\Phi}\mathbf{v} = \left\| \mathbf{\Phi}\mathbf{v} \right\|^{2} >0 \qquad \text{for every } \mathbf{v}\neq\mathbf{0} \]

In adaptive control, the analogous time-domain concept is persistent excitation, but that topic is postponed to Chapter 10. For now, remember the finite-data message: if the input and state trajectories do not move the regressor in enough independent directions, some parameters cannot be learned.

11. Python Implementation

The following Python program simulates the mass-spring-damper plant and estimates the normalized parameter vector using a gradient prediction-error update.

Chapter2_Lesson3.py

# Chapter2_Lesson3.py
"""
Regressor vectors and parameter vectors for a control-oriented
mass-spring-damper model:

    m*y_ddot + c*y_dot + k*y = b*u

Normalized acceleration model:

    y_ddot = theta^T phi(y, y_dot, u)

where

    phi   = [-y, -y_dot, u]^T
    theta = [k/m, c/m, b/m]^T

The script simulates the plant and estimates theta from measured
acceleration using a gradient prediction-error update.
"""

from __future__ import annotations

import numpy as np


def regressor(y: float, y_dot: float, u: float) -> np.ndarray:
    """Return phi(y, y_dot, u) = [-y, -y_dot, u]^T."""
    return np.array([-y, -y_dot, u], dtype=float)


def control_input(t: float) -> float:
    """A multi-sine input that gives richer regressor motion than a step."""
    return 1.2 * np.sin(1.1 * t) + 0.7 * np.sin(2.3 * t)


def simulate_and_estimate(
    t_final: float = 25.0,
    dt: float = 0.002,
    m: float = 2.0,
    c: float = 0.8,
    k: float = 5.0,
    b: float = 1.5,
    gamma_diag: tuple[float, float, float] = (8.0, 8.0, 4.0),
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
    """
    Simulate the physical plant and estimate normalized parameters.

    Prediction:
        y_ddot_hat = phi^T theta_hat

    Prediction error:
        epsilon = y_ddot_hat - y_ddot

    Gradient update:
        theta_hat_dot = - Gamma phi epsilon
    """
    n_steps = int(t_final / dt) + 1
    t = np.linspace(0.0, t_final, n_steps)

    x = np.zeros((n_steps, 2))          # x[:,0]=y, x[:,1]=y_dot
    theta_hat = np.zeros((n_steps, 3))  # estimates of [k/m, c/m, b/m]
    eps_hist = np.zeros(n_steps)

    theta_true = np.array([k / m, c / m, b / m], dtype=float)
    gamma = np.diag(gamma_diag)

    # Initial condition chosen away from zero so that phi initially contains state information.
    x[0, :] = np.array([0.4, -0.2])
    theta_hat[0, :] = np.array([0.4, 0.1, 0.2])

    for i in range(n_steps - 1):
        y, y_dot = x[i, :]
        u = control_input(t[i])
        phi = regressor(y, y_dot, u)

        # True acceleration from physical model.
        y_ddot = float(phi @ theta_true)

        # Prediction from current parameter estimate.
        y_ddot_hat = float(phi @ theta_hat[i, :])
        epsilon = y_ddot_hat - y_ddot
        eps_hist[i] = epsilon

        theta_dot_hat = -gamma @ phi * epsilon

        # Euler integration for the estimator and plant.
        theta_hat[i + 1, :] = theta_hat[i, :] + dt * theta_dot_hat
        x[i + 1, 0] = y + dt * y_dot
        x[i + 1, 1] = y_dot + dt * y_ddot

    eps_hist[-1] = eps_hist[-2]
    return t, theta_hat, eps_hist


if __name__ == "__main__":
    t, theta_hat, eps = simulate_and_estimate()
    print("Final theta_hat = [k/m, c/m, b/m]:", theta_hat[-1])
    print("Final absolute prediction error:", abs(eps[-1]))
    print("Mean absolute prediction error over last 20%:",
          np.mean(np.abs(eps[int(0.8 * len(eps)):])))

12. C++ Implementation

The C++ version uses only the standard library. It is suitable for embedded-control style code where dynamic allocation should be avoided.

Chapter2_Lesson3.cpp

// Chapter2_Lesson3.cpp
// Compile: g++ -std=c++17 Chapter2_Lesson3.cpp -O2 -o Chapter2_Lesson3
//
// Regressor-vector demonstration for
//     m*y_ddot + c*y_dot + k*y = b*u
//
// Normalized form:
//     y_ddot = theta^T phi,  phi = [-y, -y_dot, u]^T,
//     theta = [k/m, c/m, b/m]^T.

#include <array>
#include <cmath>
#include <iomanip>
#include <iostream>

using Vec3 = std::array<double, 3>;

Vec3 regressor(double y, double y_dot, double u) {
    return Vec3{-y, -y_dot, u};
}

double dot(const Vec3& a, const Vec3& b) {
    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}

double control_input(double t) {
    return 1.2 * std::sin(1.1 * t) + 0.7 * std::sin(2.3 * t);
}

int main() {
    const double dt = 0.002;
    const double t_final = 25.0;
    const int n_steps = static_cast<int>(t_final / dt) + 1;

    const double m = 2.0;
    const double c = 0.8;
    const double k = 5.0;
    const double b = 1.5;

    Vec3 theta_true{k / m, c / m, b / m};
    Vec3 theta_hat{0.4, 0.1, 0.2};
    Vec3 gamma{8.0, 8.0, 4.0};

    double y = 0.4;
    double y_dot = -0.2;
    double mean_abs_eps_tail = 0.0;
    int tail_count = 0;

    for (int i = 0; i < n_steps; ++i) {
        double t = i * dt;
        double u = control_input(t);
        Vec3 phi = regressor(y, y_dot, u);

        double y_ddot = dot(phi, theta_true);
        double y_ddot_hat = dot(phi, theta_hat);
        double epsilon = y_ddot_hat - y_ddot;

        if (i > static_cast<int>(0.8 * n_steps)) {
            mean_abs_eps_tail += std::abs(epsilon);
            tail_count++;
        }

        for (int j = 0; j < 3; ++j) {
            double theta_dot_hat_j = -gamma[j] * phi[j] * epsilon;
            theta_hat[j] += dt * theta_dot_hat_j;
        }

        y += dt * y_dot;
        y_dot += dt * y_ddot;
    }

    mean_abs_eps_tail /= static_cast<double>(tail_count);

    std::cout << std::fixed << std::setprecision(6);
    std::cout << "Final theta_hat = ["
              << theta_hat[0] << ", "
              << theta_hat[1] << ", "
              << theta_hat[2] << "]\n";
    std::cout << "True theta = ["
              << theta_true[0] << ", "
              << theta_true[1] << ", "
              << theta_true[2] << "]\n";
    std::cout << "Mean absolute prediction error over last 20% = "
              << mean_abs_eps_tail << "\n";

    return 0;
}

13. Java Implementation

The Java implementation mirrors the C++ logic and is useful for students who want to implement adaptive-model components in object-oriented simulation tools.

Chapter2_Lesson3.java

// Chapter2_Lesson3.java
// Compile: javac Chapter2_Lesson3.java
// Run:     java Chapter2_Lesson3
//
// Regressor-vector demonstration for
//     m*y_ddot + c*y_dot + k*y = b*u
//
// Normalized form:
//     y_ddot = theta^T phi,  phi = [-y, -y_dot, u]^T,
//     theta = [k/m, c/m, b/m]^T.

public class Chapter2_Lesson3 {
    static double[] regressor(double y, double yDot, double u) {
        return new double[] {-y, -yDot, u};
    }

    static double dot(double[] a, double[] b) {
        return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
    }

    static double controlInput(double t) {
        return 1.2 * Math.sin(1.1 * t) + 0.7 * Math.sin(2.3 * t);
    }

    public static void main(String[] args) {
        double dt = 0.002;
        double tFinal = 25.0;
        int nSteps = (int) (tFinal / dt) + 1;

        double m = 2.0;
        double c = 0.8;
        double k = 5.0;
        double b = 1.5;

        double[] thetaTrue = {k / m, c / m, b / m};
        double[] thetaHat = {0.4, 0.1, 0.2};
        double[] gamma = {8.0, 8.0, 4.0};

        double y = 0.4;
        double yDot = -0.2;
        double meanAbsEpsTail = 0.0;
        int tailCount = 0;

        for (int i = 0; i < nSteps; i++) {
            double t = i * dt;
            double u = controlInput(t);
            double[] phi = regressor(y, yDot, u);

            double yDDot = dot(phi, thetaTrue);
            double yDDotHat = dot(phi, thetaHat);
            double epsilon = yDDotHat - yDDot;

            if (i > (int) (0.8 * nSteps)) {
                meanAbsEpsTail += Math.abs(epsilon);
                tailCount++;
            }

            for (int j = 0; j < 3; j++) {
                double thetaDotHatJ = -gamma[j] * phi[j] * epsilon;
                thetaHat[j] += dt * thetaDotHatJ;
            }

            y += dt * yDot;
            yDot += dt * yDDot;
        }

        meanAbsEpsTail /= (double) tailCount;

        System.out.printf("Final thetaHat = [%.6f, %.6f, %.6f]%n",
                thetaHat[0], thetaHat[1], thetaHat[2]);
        System.out.printf("True theta     = [%.6f, %.6f, %.6f]%n",
                thetaTrue[0], thetaTrue[1], thetaTrue[2]);
        System.out.printf("Mean absolute prediction error over last 20%% = %.6f%n",
                meanAbsEpsTail);
    }
}

14. MATLAB/Simulink Implementation

The MATLAB script simulates the plant, estimates the parameter vector, plots the estimates, and writes a small MATLAB Function block source that can be inserted into a Simulink model.

Chapter2_Lesson3.m

% Chapter2_Lesson3.m
% MATLAB/Simulink-oriented demonstration of regressor and parameter vectors.
%
% Plant:
%     m*y_ddot + c*y_dot + k*y = b*u
%
% Normalized acceleration model:
%     y_ddot = theta.' * phi
%     phi   = [-y; -y_dot; u]
%     theta = [k/m; c/m; b/m]
%
% The script simulates the plant and estimates theta using a gradient
% prediction-error update. It also creates a small Simulink-ready function file
% named Chapter2_Lesson3_RegressorBlock.m.

clear; clc;

dt = 0.002;
tFinal = 25.0;
t = 0:dt:tFinal;
nSteps = numel(t);

m = 2.0;
c = 0.8;
k = 5.0;
b = 1.5;

thetaTrue = [k/m; c/m; b/m];
thetaHat = zeros(3, nSteps);
thetaHat(:, 1) = [0.4; 0.1; 0.2];
Gamma = diag([8.0, 8.0, 4.0]);

x = zeros(2, nSteps);
x(:, 1) = [0.4; -0.2];
epsHist = zeros(1, nSteps);

for i = 1:nSteps-1
    y = x(1, i);
    yDot = x(2, i);
    u = 1.2*sin(1.1*t(i)) + 0.7*sin(2.3*t(i));

    phi = [-y; -yDot; u];

    yDDot = thetaTrue.' * phi;
    yDDotHat = thetaHat(:, i).' * phi;
    epsilon = yDDotHat - yDDot;
    epsHist(i) = epsilon;

    thetaDotHat = -Gamma * phi * epsilon;

    thetaHat(:, i+1) = thetaHat(:, i) + dt * thetaDotHat;
    x(1, i+1) = y + dt * yDot;
    x(2, i+1) = yDot + dt * yDDot;
end

tail = floor(0.8*nSteps):nSteps;
fprintf('Final thetaHat = [%.6f %.6f %.6f]\n', thetaHat(1,end), thetaHat(2,end), thetaHat(3,end));
fprintf('True theta     = [%.6f %.6f %.6f]\n', thetaTrue(1), thetaTrue(2), thetaTrue(3));
fprintf('Mean absolute prediction error over last 20%% = %.6f\n', mean(abs(epsHist(tail))));

figure;
plot(t, thetaHat(1,:), t, thetaHat(2,:), t, thetaHat(3,:));
grid on;
xlabel('Time (s)');
ylabel('Estimated normalized parameters');
legend('k/m estimate','c/m estimate','b/m estimate');

% Create a Simulink-ready MATLAB Function block source.
blockCode = [
"function [phi, yDDotHat] = Chapter2_Lesson3_RegressorBlock(y, yDot, u, thetaHat)" newline ...
"%#codegen" newline ...
"% Simulink MATLAB Function block for control-oriented regression." newline ...
"phi = [-y; -yDot; u];" newline ...
"yDDotHat = thetaHat(:).' * phi;" newline ...
"end" newline ...
];

fid = fopen('Chapter2_Lesson3_RegressorBlock.m', 'w');
fprintf(fid, '%s', blockCode);
fclose(fid);

disp('Created Chapter2_Lesson3_RegressorBlock.m for use inside a Simulink MATLAB Function block.');

15. Wolfram Mathematica Implementation

The Mathematica code gives both a numerical estimator and a symbolic verification that the acceleration equation equals \( \boldsymbol{\theta}^{T}\boldsymbol{\phi} \).

Chapter2_Lesson3.nb

(* Chapter2_Lesson3.nb *)
(* Wolfram Mathematica code for regressor and parameter vectors. *)

ClearAll["Global`*"];

(* Plant: m y'' + c y' + k y == b u
   Normalized model:
      y'' == theta.phi
      phi == {-y, -yDot, u}
      theta == {k/m, c/m, b/m}
*)

regressor[y_, yDot_, u_] := {-y, -yDot, u};

controlInput[t_] := 1.2 Sin[1.1 t] + 0.7 Sin[2.3 t];

params = <|"m" -> 2.0, "c" -> 0.8, "k" -> 5.0, "b" -> 1.5|>;
thetaTrue = {params["k"]/params["m"], params["c"]/params["m"], params["b"]/params["m"]};

dt = 0.002;
tFinal = 25.0;
nSteps = Round[tFinal/dt] + 1;

gamma = DiagonalMatrix[{8.0, 8.0, 4.0}];
x = ConstantArray[{0.0, 0.0}, nSteps];
thetaHat = ConstantArray[{0.0, 0.0, 0.0}, nSteps];
epsHist = ConstantArray[0.0, nSteps];

x[[1]] = {0.4, -0.2};
thetaHat[[1]] = {0.4, 0.1, 0.2};

Do[
  t = (i - 1) dt;
  y = x[[i, 1]];
  yDot = x[[i, 2]];
  u = controlInput[t];
  phi = regressor[y, yDot, u];

  yDDot = thetaTrue.phi;
  yDDotHat = thetaHat[[i]].phi;
  epsilon = yDDotHat - yDDot;
  epsHist[[i]] = epsilon;

  thetaDotHat = -gamma.phi*epsilon;

  thetaHat[[i + 1]] = thetaHat[[i]] + dt thetaDotHat;
  x[[i + 1]] = {y + dt yDot, yDot + dt yDDot};
  ,
  {i, 1, nSteps - 1}
];

Print["True theta = ", thetaTrue];
Print["Final thetaHat = ", thetaHat[[-1]]];

ListLinePlot[
  Transpose[thetaHat],
  PlotLegends -> {"k/m estimate", "c/m estimate", "b/m estimate"},
  AxesLabel -> {"sample", "parameter estimate"},
  GridLines -> Automatic
]

(* Symbolic regressor extraction from a physical equation. *)
eq = m ydd + c yd + k y == b u;
sol = Solve[eq, ydd][[1, 1, 2]];
theta = {k/m, c/m, b/m};
phi = {-y, -yd, u};
FullSimplify[sol == theta.phi]

16. Problems and Solutions

Problem 1: For the plant \( m\ddot{y}+c\dot{y}+ky=bu \), derive a scalar regression for \( \ddot{y} \) and identify \( \boldsymbol{\phi} \) and \( \boldsymbol{\theta} \).

Solution: Divide the equation by \( m \):

\[ \ddot{y} = -\frac{k}{m}y-\frac{c}{m}\dot{y}+\frac{b}{m}u \]

Therefore,

\[ \boldsymbol{\phi} = \begin{bmatrix} -y\\-\dot{y}\\u \end{bmatrix}, \qquad \boldsymbol{\theta} = \begin{bmatrix} k/m\\c/m\\b/m \end{bmatrix}, \qquad \ddot{y}=\boldsymbol{\phi}^{T}\boldsymbol{\theta} \]

Problem 2: Suppose \( z=\boldsymbol{\phi}^{T}\boldsymbol{\theta} \) and \( \hat{z}=\boldsymbol{\phi}^{T}\hat{\boldsymbol{\theta}} \). Show that \( \varepsilon=\hat{z}-z \) is linear in the parameter error.

Solution:

\[ \varepsilon = \boldsymbol{\phi}^{T}\hat{\boldsymbol{\theta}} - \boldsymbol{\phi}^{T}\boldsymbol{\theta} = \boldsymbol{\phi}^{T} \left( \hat{\boldsymbol{\theta}}-\boldsymbol{\theta} \right) = \boldsymbol{\phi}^{T}\tilde{\boldsymbol{\theta}} \]

Thus the measured scalar error gives information only about the projection of \( \tilde{\boldsymbol{\theta}} \) along \( \boldsymbol{\phi} \).

Problem 3: Given sampled regressors \( \boldsymbol{\phi}_1=[1,0]^{T} \), \( \boldsymbol{\phi}_2=[2,0]^{T} \), and \( \boldsymbol{\phi}_3=[3,0]^{T} \), can both entries of \( \boldsymbol{\theta}\in\mathbb{R}^{2} \) be identified?

Solution: The data matrix is

\[ \mathbf{\Phi} = \begin{bmatrix} 1 & 0\\ 2 & 0\\ 3 & 0 \end{bmatrix} \]

Its second column is zero, so \( \operatorname{rank}(\mathbf{\Phi})=1<2 \). The second parameter never appears in the data. Therefore, both entries cannot be identified from these regressors.

Problem 4: For \( z=\theta_1 x+\theta_2 x^2+\theta_3 u \), write the regression in vector form.

Solution:

\[ \boldsymbol{\phi}(x,u) = \begin{bmatrix} x\\x^2\\u \end{bmatrix}, \qquad \boldsymbol{\theta} = \begin{bmatrix} \theta_1\\\theta_2\\\theta_3 \end{bmatrix}, \qquad z=\boldsymbol{\phi}^{T}\boldsymbol{\theta} \]

This is nonlinear in the signal \( x \) but linear in the unknown parameter vector. That distinction is central in adaptive control.

Problem 5: Derive the gradient update for minimizing \( J=\frac{1}{2}(\boldsymbol{\phi}^{T}\hat{\boldsymbol{\theta}}-z)^2 \).

Solution: Let \( \varepsilon=\boldsymbol{\phi}^{T}\hat{\boldsymbol{\theta}}-z \). Then

\[ \nabla_{\hat{\boldsymbol{\theta}}}J = \boldsymbol{\phi}\varepsilon \]

Hence the negative-gradient update with adaptation gain \( \boldsymbol{\Gamma}=\boldsymbol{\Gamma}^{T}>0 \) is

\[ \dot{\hat{\boldsymbol{\theta}}} = -\boldsymbol{\Gamma}\boldsymbol{\phi}\varepsilon \]

17. Summary

A regressor vector contains known signal-dependent basis functions, while a parameter vector contains unknown constants or constant combinations. The expression \( z=\boldsymbol{\phi}^{T}\boldsymbol{\theta} \) is the basic scalar regression form, and \( \mathbf{z}=\mathbf{Y}\boldsymbol{\theta} \) is the corresponding vector form. The prediction error is \( \varepsilon=\boldsymbol{\phi}^{T}\tilde{\boldsymbol{\theta}} \), and this identity explains why regressor richness is necessary for parameter learning. In later chapters, these same objects will appear inside Lyapunov functions and adaptive controller update laws.

18. References

  1. Monopoli, R.V. (1974). Model reference adaptive control with an augmented error signal. IEEE Transactions on Automatic Control, AC-19(5), 474–484.
  2. 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.
  3. Goodwin, G.C., Ramadge, P.J., & Caines, P.E. (1980). Discrete-time multivariable adaptive control. IEEE Transactions on Automatic Control, 25(3), 449–456.
  4. Ioannou, P.A., & Kokotović, P.V. (1984). Robust redesign of adaptive control. IEEE Transactions on Automatic Control, AC-29(3), 202–211.
  5. Craig, J.J., Hsu, P., & Sastry, S.S. (1987). Adaptive control of mechanical manipulators. The International Journal of Robotics Research, 6(2), 16–28.
  6. Slotine, J.J.E., & Li, W. (1987). On the adaptive control of robot manipulators. The International Journal of Robotics Research, 6(3), 49–59.
  7. Middleton, R.H., & Goodwin, G.C. (1988). Adaptive computed torque control for rigid link manipulators. Systems & Control Letters, 10(1), 9–16.
  8. Ortega, R., & Spong, M.W. (1989). Adaptive motion control of rigid robots: A tutorial. Automatica, 25(6), 877–888.
  9. Morse, A.S. (1980). Global stability of parameter-adaptive control systems. IEEE Transactions on Automatic Control, AC-25(3), 433–439.
  10. Narendra, K.S., & Annaswamy, A.M. (1987). A new adaptive law for robust adaptation without persistent excitation. IEEE Transactions on Automatic Control, 32(2), 134–145.
Support CaaT Academy

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.