Chapter 1: Introduction to Adaptive Control

Lesson 5: Example Applications: Aerospace, Robotics, Process, Automotive

This lesson connects the conceptual ideas from the first four lessons to representative engineering application domains. The goal is not yet to design a complete flight controller, robot manipulator controller, process controller, or automotive controller. Instead, we build a common mathematical template showing why adaptive control is useful when physical parameters, operating conditions, or actuator effectiveness change during operation.

1. Motivation and Learning Objectives

Adaptive control is valuable when a fixed controller cannot maintain acceptable performance over a wide operating range, but the uncertainty has enough structure that online adjustment can improve tracking, regulation, or disturbance rejection. In aerospace, uncertainty may come from changing aerodynamic derivatives. In robotics, it may come from payload and inertia variation. In process control, it may come from operating-point-dependent gains and time constants. In automotive systems, it may come from mass, road grade, tire-road interaction, and drivetrain variation.

In this introductory lesson, we use the scalar plant \( y(t) \) as a generic measured output:

\[ \dot{y}(t) = -a y(t) + b u(t) + d(t), \qquad a > 0,\; b > 0 \]

where \( a \) is an unknown damping or loss rate, \( b \) is an unknown control effectiveness, and \( d(t) \) is a bounded disturbance. This simple model is not a complete model of any of the four application areas. Rather, it is a teaching model that captures the repeated pattern: uncertain plant parameters plus a desired reference behavior.

By the end of this lesson, students should be able to:

  • map aerospace, robotic, process, and automotive examples into a common adaptive-control viewpoint;
  • distinguish parameter adaptation from ordinary fixed-gain retuning;
  • derive a basic tracking-error model for a first-order adaptive benchmark;
  • verify boundedness using a Lyapunov-style argument;
  • implement the same introductory adaptive law in Python, C++, Java, MATLAB/Simulink, and Wolfram Mathematica.

2. A Common Application Taxonomy

The four application areas can be organized around three questions: what changes, how fast it changes, and which signals are available for feedback. This determines whether adaptation is appropriate or whether a fixed, robust, optimal, or gain-scheduled controller is more suitable.

flowchart TD
  A["Engineering system"] --> B["What changes?"]
  B --> C1["Plant gain or \ncontrol effectiveness"]
  B --> C2["Damping, mass, inertia, \ntime constant"]
  B --> C3["External load \nor disturbance"]
  C1 --> D["Can uncertainty \nbe parameterized?"]
  C2 --> D
  C3 --> D
  D -->|yes| E["Adaptive controller \nupdates theta_hat online"]
  D -->|no| F["Prefer robust, scheduled, \nor redesigned controller"]
  E --> G1["Aerospace: changing \naerodynamic \neffectiveness"]
  E --> G2["Robotics: payload \nand inertia variation"]
  E --> G3["Process: operating \npoint drift"]
  E --> G4["Automotive: \nmass, drag, \nroad grade variation"]
        

A useful first abstraction is the following linearly parameterized model:

\[ \dot{y}(t) = \boldsymbol{\theta}^{*\top}\boldsymbol{\phi}(t) + d(t) \]

where \( \boldsymbol{\theta}^* \) is an unknown constant or slowly varying parameter vector and \( \boldsymbol{\phi}(t) \) is a measurable regressor vector constructed from available signals. Later chapters will study the exact meaning of linear parameterization, regressors, matching conditions, and persistent excitation. For now, the important idea is that adaptation is useful when the unknown physical quantities enter the control-oriented model through identifiable parameter-like coefficients.

3. Unified First-Order Adaptive Tracking Template

Suppose the desired closed-loop behavior is specified by the reference model

\[ \dot{y}_m(t) = -a_m y_m(t) + b_m r(t), \qquad a_m > 0,\; b_m > 0 \]

where \( r(t) \) is the command input and \( y_m(t) \) is the ideal output response. We choose the adaptive controller

\[ u(t)=\hat{\theta}_r(t)r(t)+\hat{\theta}_y(t)y(t) \]

where \( \hat{\theta}_r(t) \) and \( \hat{\theta}_y(t) \) are adjusted online. If the unknown plant parameters were known, the ideal parameters would satisfy

\[ -a+b\theta_y^*=-a_m,\qquad b\theta_r^*=b_m \]

Hence,

\[ \theta_y^*=\frac{a-a_m}{b},\qquad \theta_r^*=\frac{b_m}{b} \]

Define the tracking error and parameter error as

\[ e(t)=y(t)-y_m(t),\qquad \tilde{\boldsymbol{\theta} }(t)= \hat{\boldsymbol{\theta} }(t)-\boldsymbol{\theta}^*,\qquad \boldsymbol{\phi}(t)= \begin{bmatrix} r(t) \\ y(t) \end{bmatrix} \]

where \( \hat{\boldsymbol{\theta} }=[\hat{\theta}_r,\hat{\theta}_y]^\top \) and \( \boldsymbol{\theta}^*=[\theta_r^*,\theta_y^*]^\top \) . Substitution gives the error model

\[ \dot{e}(t)=-a_m e(t)+b\tilde{\boldsymbol{\theta} }^\top(t) \boldsymbol{\phi}(t)+d(t) \]

For the nominal case \( d(t)=0 \), one simple adaptive law is

\[ \dot{\hat{\boldsymbol{\theta} } }(t) =-\gamma e(t)\boldsymbol{\phi}(t),\qquad \gamma > 0 \]

This law is intentionally simple. It will be refined in later chapters through normalization, projection, robust modifications, and discrete implementation.

4. Application Mapping: Aerospace, Robotics, Process, Automotive

The same mathematical structure can represent different physical meanings depending on the application domain.

Application Output \( y(t) \) Control \( u(t) \) Uncertain parameter meaning Why adaptation helps
Aerospace Pitch-rate, roll-rate, altitude-rate, or simplified attitude variable Elevator, aileron, throttle, or virtual control command Aerodynamic damping and control effectiveness Flight condition, mass distribution, damage, or actuator effectiveness changes
Robotics Joint velocity, joint position error, or task-space coordinate Motor torque or velocity command Inertia, viscous friction, payload-dependent coefficients Payloads and contact conditions modify robot dynamics
Process Temperature, level, pressure, concentration, or flow variable Valve position, heater power, pump speed Time constant, process gain, heat-transfer coefficient Operating point, fouling, composition, and environmental conditions drift slowly
Automotive Vehicle speed, wheel slip, yaw rate, suspension displacement Throttle, brake, steering, damping command Mass, drag, rolling resistance, road grade, tire-road coefficient Load, road, tire, and environment vary significantly during operation

A domain-specific model is usually higher order and nonlinear. However, the first-order benchmark is useful because it teaches the control design pattern:

\[ \text{physical uncertainty} \quad \Longrightarrow \quad \text{unknown parameters} \quad \Longrightarrow \quad \text{online parameter adjustment} \]

5. Aerospace Example: Changing Control Effectiveness

A simplified pitch-rate channel can be approximated near an operating condition by

\[ \dot{q}(t) = -a_q q(t) + b_\delta \delta_e(t) \]

where \( q(t) \) is pitch rate, \( \delta_e(t) \) is elevator deflection, \( a_q \) is aerodynamic damping, and \( b_\delta \) is elevator control effectiveness. In a fixed controller, one might choose

\[ \delta_e(t)=k_r r_q(t)+k_q q(t) \]

but if \( b_\delta \) changes due to altitude, speed, mass distribution, or actuator degradation, the same gain pair may no longer produce the desired response. Adaptive control replaces fixed gains by adjustable gains:

\[ \delta_e(t)=\hat{k}_r(t)r_q(t)+\hat{k}_q(t)q(t) \]

In this introductory model, the matching equations are

\[ -a_q+b_\delta k_q^*=-a_m,\qquad b_\delta k_r^*=b_m \]

The controller does not need to explicitly know \( a_q \) and \( b_\delta \) if the adaptive law can move the estimates toward values that reduce tracking error. In real aircraft, safety filters, actuator limits, envelope protection, gain scheduling, and verification constraints are essential. Those issues will be discussed later in the course.

6. Robotics Example: Payload and Inertia Variation

A single robot joint with motor torque \( \tau(t) \) can be approximated by

\[ J\ddot{q}(t)+B\dot{q}(t)+g_q(q)=\tau(t) \]

where \( J \) is inertia, \( B \) is viscous friction, and \( g_q(q) \) is a gravity-related term. If the robot picks up an unknown payload, \( J \) and the gravity term change. A velocity-loop approximation near a local operating region can be written as

\[ \dot{\omega}(t)=-a_\omega \omega(t)+b_\tau \tau(t)+\eta(t) \]

where \( \omega=\dot{q} \) and \( \eta(t) \) collects gravity and coupling effects. The adaptive law can adjust the effective feedback and feedforward gains when the payload changes.

For more complete robot manipulators, the standard rigid-body dynamics are

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

A key reason adaptive robot control is mathematically attractive is that many rigid-body robot dynamics can be written in a linearly parameterized form:

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

This is a preview only. The detailed manipulator design will appear in later chapters after Lyapunov tools, parameter vectors, and adaptive laws have been formally developed.

7. Process Example: Slowly Varying Gain and Time Constant

Many process systems are modeled locally by a first-order lag:

\[ \tau_p \dot{y}(t)+y(t)=K_p u(t) \]

Equivalently,

\[ \dot{y}(t)=-\frac{1}{\tau_p}y(t)+\frac{K_p}{\tau_p}u(t) \]

so the common benchmark has

\[ a=\frac{1}{\tau_p},\qquad b=\frac{K_p}{\tau_p} \]

In a heat exchanger, reactor, tank, or pressure loop, the process gain \( K_p \) and time constant \( \tau_p \) may change due to flow rate, fouling, composition, ambient conditions, or operating point. Adaptive control is especially natural when these variations are slow compared with the dominant closed-loop dynamics.

If the reference model is

\[ \dot{y}_m(t)=-a_m y_m(t)+b_m r(t) \]

then the adaptive controller attempts to make the process output follow this desired first-order response despite changes in \( \tau_p \) and \( K_p \).

8. Automotive Example: Speed Control with Mass and Drag Variation

A simplified longitudinal vehicle-speed model is

\[ m\dot{v}(t)=F_u(t)-c_r v(t)-c_d v^2(t)-mg\sin(\alpha(t)) \]

where \( m \) is vehicle mass, \( F_u(t) \) is the commanded traction or braking force, \( c_r \) is a rolling-loss coefficient, \( c_d \) is an aerodynamic drag coefficient, and \( \alpha(t) \) is road grade. Around a nominal speed \( v_0 \), linearization gives an approximate model

\[ \dot{\tilde{v} }(t) = -\frac{c_r+2c_d v_0}{m}\tilde{v}(t) + \frac{1}{m}\tilde{F}_u(t) + d_g(t) \]

where \( \tilde{v}=v-v_0 \), \( \tilde{F}_u \) is the incremental force command, and \( d_g(t) \) contains grade and modeling terms. The adaptive benchmark identifies

\[ a=\frac{c_r+2c_d v_0}{m},\qquad b=\frac{1}{m} \]

When passengers, cargo, road slope, wind, and tire conditions change, a fixed speed controller may become sluggish or aggressive. The adaptive version updates the effective gains using tracking error rather than requiring a perfect estimate of the vehicle mass or drag.

9. Adaptive Implementation Workflow

The following workflow is common across the four domains. This is not a certification or safety workflow; it is the educational design workflow used in this introductory lesson.

flowchart TD
  S["Select application channel"] --> M["Build simplified model: ydot = -a y + b u + d"]
  M --> R["Choose reference model: ymdot = -am ym + bm r"]
  R --> C["Choose adaptive controller: u = theta_r_hat r + theta_y_hat y"]
  C --> E["Compute tracking error: e = y - ym"]
  E --> A["Update parameters: theta_hat_dot = -gamma e phi"]
  A --> L["Check Lyapunov boundedness"]
  L --> SIM["Simulate across aerospace, robotics, process, automotive cases"]
  SIM --> P["Inspect error, control effort, and parameter evolution"]
        

10. Lyapunov Boundedness Proof for the Nominal Benchmark

We now prove the central boundedness result for the nominal case \( d(t)=0 \). This is not yet a full practical adaptive controller theorem; it is the first mathematical stability argument students should understand.

Assumptions:

  • \( a_m > 0 \) and \( \gamma > 0 \).
  • The plant input gain sign is known and \( b > 0 \).
  • The command \( r(t) \) is bounded.
  • There exist constant ideal parameters satisfying the matching equations.

Use the Lyapunov candidate

\[ V(e,\tilde{\boldsymbol{\theta} }) = \frac{1}{2}e^2+ \frac{b}{2\gamma} \tilde{\boldsymbol{\theta} }^\top \tilde{\boldsymbol{\theta} } \]

Because \( b > 0 \) and \( \gamma > 0 \), this function is positive definite in \( e \) and \( \tilde{\boldsymbol{\theta} } \). Differentiating:

\[ \dot{V} = e\dot{e} + \frac{b}{\gamma} \tilde{\boldsymbol{\theta} }^\top \dot{\tilde{\boldsymbol{\theta} } } \]

Since \( \boldsymbol{\theta}^* \) is constant, \( \dot{\tilde{\boldsymbol{\theta} } }= \dot{\hat{\boldsymbol{\theta} } } \) . Substitute the nominal error model and adaptive law:

\[ \begin{aligned} \dot{V} &= e\left(-a_m e+b\tilde{\boldsymbol{\theta} }^\top\boldsymbol{\phi}\right) + \frac{b}{\gamma} \tilde{\boldsymbol{\theta} }^\top \left(-\gamma e\boldsymbol{\phi}\right) \\ &= -a_m e^2 +be\tilde{\boldsymbol{\theta} }^\top\boldsymbol{\phi} -be\tilde{\boldsymbol{\theta} }^\top\boldsymbol{\phi} \\ &= -a_m e^2 \leq 0 \end{aligned} \]

Therefore \( V(t)\leq V(0) \) for all \( t\geq 0 \). Hence \( e(t) \) and \( \tilde{\boldsymbol{\theta} }(t) \) are bounded. Also,

\[ \int_0^T e^2(t)\,dt \leq \frac{V(0)-V(T)}{a_m} \leq \frac{V(0)}{a_m} \]

Thus \( e(t) \) is square-integrable. Under the usual bounded-signal regularity conditions, this leads to tracking-error convergence. The formal convergence theorem will be developed later when Barbalat-type arguments are introduced.

Important interpretation: This proof guarantees bounded tracking error and bounded parameter estimates for the nominal model. It does not say that the estimated parameters must converge to the true physical parameters. Parameter convergence requires additional excitation conditions, which are studied later in the course.

11. Python Implementation

File: Chapter1_Lesson5.py

This Python script uses only the standard library. It simulates the adaptive benchmark for four application-inspired scenarios and writes CSV files for later plotting or analysis.

"""
Chapter1_Lesson5.py

Adaptive Control course - Chapter 1, Lesson 5
Example Applications: Aerospace, Robotics, Process, Automotive

This file simulates the same scalar direct adaptive tracking law for four
application-inspired plants.  The model is intentionally first order because
Chapter 1 is introductory; later chapters replace this benchmark with full
MRAC, STR, adaptive robot, and discrete-time designs.

Plant:
    y_dot = -a*y + b*u + d(t)

Reference model:
    ym_dot = -am*ym + bm*r(t)

Adaptive control:
    u = theta_r_hat*r + theta_y_hat*y
    theta_hat_dot = -gamma*e*phi,  phi = [r, y]^T, e = y - ym

Assumption used here:
    b > 0 and the sign of b is known.
"""

from dataclasses import dataclass
from typing import Callable, Dict, List, Tuple
import math
import csv


@dataclass
class Scenario:
    name: str
    a: float
    b: float
    am: float
    bm: float
    gamma: float
    disturbance_amp: float
    reference_amp: float
    reference_freq: float


def reference_signal(t: float, amp: float, freq: float) -> float:
    """Smooth bounded command used for all examples."""
    return amp * (0.7 * math.sin(freq * t) + 0.3 * math.sin(0.35 * freq * t))


def simulate(s: Scenario, tf: float = 30.0, dt: float = 0.002) -> List[Tuple[float, float, float, float, float, float, float]]:
    """Forward-Euler simulation of the adaptive closed loop."""
    y = 0.0
    ym = 0.0
    theta_r = 0.0
    theta_y = 0.0
    rows = []

    n_steps = int(tf / dt)
    for k in range(n_steps + 1):
        t = k * dt
        r = reference_signal(t, s.reference_amp, s.reference_freq)
        e = y - ym

        # Adaptive controller
        u = theta_r * r + theta_y * y

        # A small disturbance makes the example more application-like.
        # For the Lyapunov proof in the lesson, set disturbance_amp = 0.
        d = s.disturbance_amp * math.sin(0.9 * t)

        y_dot = -s.a * y + s.b * u + d
        ym_dot = -s.am * ym + s.bm * r

        theta_r_dot = -s.gamma * e * r
        theta_y_dot = -s.gamma * e * y

        y += dt * y_dot
        ym += dt * ym_dot
        theta_r += dt * theta_r_dot
        theta_y += dt * theta_y_dot

        if k % 100 == 0:
            rows.append((t, y, ym, e, u, theta_r, theta_y))
    return rows


def main() -> None:
    scenarios: Dict[str, Scenario] = {
        "aerospace_pitch_channel": Scenario("aerospace_pitch_channel", a=0.80, b=1.10, am=1.60, bm=1.60, gamma=2.0, disturbance_amp=0.02, reference_amp=0.15, reference_freq=0.8),
        "robot_joint_velocity": Scenario("robot_joint_velocity", a=1.40, b=0.85, am=2.00, bm=2.00, gamma=2.5, disturbance_amp=0.03, reference_amp=0.60, reference_freq=1.2),
        "process_temperature_loop": Scenario("process_temperature_loop", a=0.18, b=0.32, am=0.45, bm=0.45, gamma=0.6, disturbance_amp=0.01, reference_amp=1.00, reference_freq=0.18),
        "automotive_speed_loop": Scenario("automotive_speed_loop", a=0.55, b=0.70, am=1.10, bm=1.10, gamma=1.5, disturbance_amp=0.03, reference_amp=4.00, reference_freq=0.25),
    }

    for scenario in scenarios.values():
        rows = simulate(scenario)
        filename = f"Chapter1_Lesson5_{scenario.name}.csv"
        with open(filename, "w", newline="", encoding="utf-8") as f:
            writer = csv.writer(f)
            writer.writerow(["t", "y", "ym", "e", "u", "theta_r_hat", "theta_y_hat"])
            writer.writerows(rows)

        final = rows[-1]
        print(
            f"{scenario.name:28s} | final e={final[3]: .5f} | "
            f"theta_r_hat={final[5]: .5f} | theta_y_hat={final[6]: .5f}"
        )


if __name__ == "__main__":
    main()

12. C++ Implementation

File: Chapter1_Lesson5.cpp

This C++17 version uses only the standard library and writes one CSV file per application-inspired scenario.

/*
Chapter1_Lesson5.cpp

Adaptive Control course - Chapter 1, Lesson 5
Example Applications: Aerospace, Robotics, Process, Automotive

Compile:
    g++ -std=c++17 -O2 Chapter1_Lesson5.cpp -o Chapter1_Lesson5

Run:
    ./Chapter1_Lesson5

No external library is required.  The program writes one CSV file per scenario.
*/

#include <cmath>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

struct Scenario {
    std::string name;
    double a;
    double b;
    double am;
    double bm;
    double gamma;
    double disturbance_amp;
    double reference_amp;
    double reference_freq;
};

double referenceSignal(double t, double amp, double freq) {
    return amp * (0.7 * std::sin(freq * t) + 0.3 * std::sin(0.35 * freq * t));
}

void simulate(const Scenario& s, double tf = 30.0, double dt = 0.002) {
    double y = 0.0;
    double ym = 0.0;
    double theta_r = 0.0;
    double theta_y = 0.0;

    std::ofstream file("Chapter1_Lesson5_" + s.name + ".csv");
    file << "t,y,ym,e,u,theta_r_hat,theta_y_hat\n";

    int n_steps = static_cast<int>(tf / dt);
    for (int k = 0; k <= n_steps; ++k) {
        double t = k * dt;
        double r = referenceSignal(t, s.reference_amp, s.reference_freq);
        double e = y - ym;
        double u = theta_r * r + theta_y * y;
        double d = s.disturbance_amp * std::sin(0.9 * t);

        double y_dot = -s.a * y + s.b * u + d;
        double ym_dot = -s.am * ym + s.bm * r;
        double theta_r_dot = -s.gamma * e * r;
        double theta_y_dot = -s.gamma * e * y;

        y += dt * y_dot;
        ym += dt * ym_dot;
        theta_r += dt * theta_r_dot;
        theta_y += dt * theta_y_dot;

        if (k % 100 == 0) {
            file << std::setprecision(10)
                 << t << "," << y << "," << ym << "," << e << ","
                 << u << "," << theta_r << "," << theta_y << "\n";
        }
    }

    std::cout << std::setw(28) << std::left << s.name
              << " | final e=" << std::setw(12) << (y - ym)
              << " | theta_r_hat=" << std::setw(12) << theta_r
              << " | theta_y_hat=" << theta_y << "\n";
}

int main() {
    std::vector<Scenario> scenarios = {
        {"aerospace_pitch_channel", 0.80, 1.10, 1.60, 1.60, 2.0, 0.02, 0.15, 0.8},
        {"robot_joint_velocity", 1.40, 0.85, 2.00, 2.00, 2.5, 0.03, 0.60, 1.2},
        {"process_temperature_loop", 0.18, 0.32, 0.45, 0.45, 0.6, 0.01, 1.00, 0.18},
        {"automotive_speed_loop", 0.55, 0.70, 1.10, 1.10, 1.5, 0.03, 4.00, 0.25}
    };

    for (const auto& s : scenarios) {
        simulate(s);
    }

    return 0;
}

13. Java Implementation

File: Chapter1_Lesson5.java

This Java implementation is self-contained and uses no external adaptive-control package.

/*
Chapter1_Lesson5.java

Adaptive Control course - Chapter 1, Lesson 5
Example Applications: Aerospace, Robotics, Process, Automotive

Compile:
    javac Chapter1_Lesson5.java

Run:
    java Chapter1_Lesson5

No external Java library is required.
*/

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;

public class Chapter1_Lesson5 {
    static class Scenario {
        String name;
        double a, b, am, bm, gamma, disturbanceAmp, referenceAmp, referenceFreq;

        Scenario(String name, double a, double b, double am, double bm,
                 double gamma, double disturbanceAmp, double referenceAmp, double referenceFreq) {
            this.name = name;
            this.a = a;
            this.b = b;
            this.am = am;
            this.bm = bm;
            this.gamma = gamma;
            this.disturbanceAmp = disturbanceAmp;
            this.referenceAmp = referenceAmp;
            this.referenceFreq = referenceFreq;
        }
    }

    static double referenceSignal(double t, double amp, double freq) {
        return amp * (0.7 * Math.sin(freq * t) + 0.3 * Math.sin(0.35 * freq * t));
    }

    static void simulate(Scenario s, double tf, double dt) throws IOException {
        double y = 0.0;
        double ym = 0.0;
        double thetaR = 0.0;
        double thetaY = 0.0;

        try (PrintWriter out = new PrintWriter(new FileWriter("Chapter1_Lesson5_" + s.name + ".csv"))) {
            out.println("t,y,ym,e,u,theta_r_hat,theta_y_hat");

            int nSteps = (int) (tf / dt);
            for (int k = 0; k <= nSteps; k++) {
                double t = k * dt;
                double r = referenceSignal(t, s.referenceAmp, s.referenceFreq);
                double e = y - ym;
                double u = thetaR * r + thetaY * y;
                double d = s.disturbanceAmp * Math.sin(0.9 * t);

                double yDot = -s.a * y + s.b * u + d;
                double ymDot = -s.am * ym + s.bm * r;
                double thetaRDot = -s.gamma * e * r;
                double thetaYDot = -s.gamma * e * y;

                y += dt * yDot;
                ym += dt * ymDot;
                thetaR += dt * thetaRDot;
                thetaY += dt * thetaYDot;

                if (k % 100 == 0) {
                    out.printf(Locale.US, "%.8f,%.8f,%.8f,%.8f,%.8f,%.8f,%.8f%n",
                            t, y, ym, e, u, thetaR, thetaY);
                }
            }
        }

        System.out.printf(Locale.US,
                "%-28s | final e=% .5f | theta_r_hat=% .5f | theta_y_hat=% .5f%n",
                s.name, y - ym, thetaR, thetaY);
    }

    public static void main(String[] args) throws IOException {
        Scenario[] scenarios = new Scenario[] {
                new Scenario("aerospace_pitch_channel", 0.80, 1.10, 1.60, 1.60, 2.0, 0.02, 0.15, 0.8),
                new Scenario("robot_joint_velocity", 1.40, 0.85, 2.00, 2.00, 2.5, 0.03, 0.60, 1.2),
                new Scenario("process_temperature_loop", 0.18, 0.32, 0.45, 0.45, 0.6, 0.01, 1.00, 0.18),
                new Scenario("automotive_speed_loop", 0.55, 0.70, 1.10, 1.10, 1.5, 0.03, 4.00, 0.25)
        };

        for (Scenario s : scenarios) {
            simulate(s, 30.0, 0.002);
        }
    }
}

14. MATLAB and Simulink Implementation

File: Chapter1_Lesson5.m

This MATLAB script simulates the same adaptive law and optionally creates a minimal Simulink skeleton if Simulink is available.

% Chapter1_Lesson5.m
%
% Adaptive Control course - Chapter 1, Lesson 5
% Example Applications: Aerospace, Robotics, Process, Automotive
%
% This script simulates a first-order adaptive tracking law and also shows
% how the same equations can be placed into a simple Simulink model skeleton.
%
% Required for numerical simulation: base MATLAB.
% Optional for model generation: Simulink.

clear; clc;

scenarios = {
    struct('name','aerospace_pitch_channel','a',0.80,'b',1.10,'am',1.60,'bm',1.60,'gamma',2.0,'disturbanceAmp',0.02,'referenceAmp',0.15,'referenceFreq',0.8)
    struct('name','robot_joint_velocity','a',1.40,'b',0.85,'am',2.00,'bm',2.00,'gamma',2.5,'disturbanceAmp',0.03,'referenceAmp',0.60,'referenceFreq',1.2)
    struct('name','process_temperature_loop','a',0.18,'b',0.32,'am',0.45,'bm',0.45,'gamma',0.6,'disturbanceAmp',0.01,'referenceAmp',1.00,'referenceFreq',0.18)
    struct('name','automotive_speed_loop','a',0.55,'b',0.70,'am',1.10,'bm',1.10,'gamma',1.5,'disturbanceAmp',0.03,'referenceAmp',4.00,'referenceFreq',0.25)
};

for i = 1:numel(scenarios)
    s = scenarios{i};
    result = simulateScenario(s, 30.0, 0.002);
    writetable(result, ['Chapter1_Lesson5_' s.name '.csv']);
    fprintf('%-28s | final e=% .5f | theta_r_hat=% .5f | theta_y_hat=% .5f\n', ...
        s.name, result.e(end), result.theta_r_hat(end), result.theta_y_hat(end));
end

% Optional: create a minimal Simulink model skeleton if Simulink exists.
if license('test','Simulink')
    createSimulinkSkeleton();
end

function result = simulateScenario(s, tf, dt)
    y = 0.0; ym = 0.0; thetaR = 0.0; thetaY = 0.0;
    nSteps = floor(tf / dt);

    logEvery = 100;
    m = floor(nSteps / logEvery) + 1;
    T = zeros(m,1); Y = zeros(m,1); YM = zeros(m,1); E = zeros(m,1);
    U = zeros(m,1); THR = zeros(m,1); THY = zeros(m,1);

    idx = 1;
    for k = 0:nSteps
        t = k * dt;
        r = referenceSignal(t, s.referenceAmp, s.referenceFreq);
        e = y - ym;
        u = thetaR * r + thetaY * y;
        d = s.disturbanceAmp * sin(0.9 * t);

        yDot = -s.a * y + s.b * u + d;
        ymDot = -s.am * ym + s.bm * r;
        thetaRDot = -s.gamma * e * r;
        thetaYDot = -s.gamma * e * y;

        y = y + dt * yDot;
        ym = ym + dt * ymDot;
        thetaR = thetaR + dt * thetaRDot;
        thetaY = thetaY + dt * thetaYDot;

        if mod(k, logEvery) == 0
            T(idx) = t; Y(idx) = y; YM(idx) = ym; E(idx) = e;
            U(idx) = u; THR(idx) = thetaR; THY(idx) = thetaY;
            idx = idx + 1;
        end
    end

    result = table(T,Y,YM,E,U,THR,THY, ...
        'VariableNames', {'t','y','ym','e','u','theta_r_hat','theta_y_hat'});
end

function r = referenceSignal(t, amp, freq)
    r = amp * (0.7 * sin(freq * t) + 0.3 * sin(0.35 * freq * t));
end

function createSimulinkSkeleton()
    model = 'Chapter1_Lesson5_SimulinkSkeleton';
    if bdIsLoaded(model)
        close_system(model, 0);
    end
    new_system(model);
    open_system(model);

    add_block('simulink/Sources/Sine Wave', [model '/Reference r'], ...
        'Position', [40 80 100 120]);
    add_block('simulink/Continuous/Integrator', [model '/Plant integrator y'], ...
        'Position', [330 80 360 120]);
    add_block('simulink/Continuous/Integrator', [model '/Reference model integrator ym'], ...
        'Position', [330 180 360 220]);
    add_block('simulink/Math Operations/Sum', [model '/Error e = y - ym'], ...
        'Inputs', '+-', 'Position', [430 120 460 160]);
    add_block('simulink/Sinks/Scope', [model '/Scope'], ...
        'Position', [540 100 590 160]);

    add_line(model, 'Plant integrator y/1', 'Error e = y - ym/1');
    add_line(model, 'Reference model integrator ym/1', 'Error e = y - ym/2');
    add_line(model, 'Error e = y - ym/1', 'Scope/1');

    save_system(model);
    fprintf('Created optional Simulink skeleton: %s.slx\n', model);
end

15. Wolfram Mathematica Implementation

File: Chapter1_Lesson5.nb

The following notebook expression implements the same application benchmark in Wolfram Language.

Notebook[{
Cell["Chapter1_Lesson5.nb", "Title"],
Cell["Adaptive Control course - Chapter 1, Lesson 5. Example Applications: Aerospace, Robotics, Process, Automotive.", "Text"],
Cell["This notebook simulates the introductory first-order adaptive tracking benchmark used in the lesson.", "Text"],
Cell[BoxData["
ClearAll[referenceSignal, simulateScenario];

referenceSignal[t_, amp_, freq_] := amp (0.7 Sin[freq t] + 0.3 Sin[0.35 freq t]);

simulateScenario[scenario_Association, tf_:30, dt_:0.002] := Module[
  {a, b, am, bm, gamma, damp, ramp, rfreq, y = 0., ym = 0., 
   thetaR = 0., thetaY = 0., rows = {}, nSteps, t, r, e, u, d, 
   yDot, ymDot, thetaRDot, thetaYDot},

  {a, b, am, bm, gamma, damp, ramp, rfreq} =
    scenario /@ {\"a\", \"b\", \"am\", \"bm\", \"gamma\", \"disturbanceAmp\", \"referenceAmp\", \"referenceFreq\"};

  nSteps = Floor[tf/dt];

  Do[
    t = k dt;
    r = referenceSignal[t, ramp, rfreq];
    e = y - ym;
    u = thetaR r + thetaY y;
    d = damp Sin[0.9 t];

    yDot = -a y + b u + d;
    ymDot = -am ym + bm r;
    thetaRDot = -gamma e r;
    thetaYDot = -gamma e y;

    y = y + dt yDot;
    ym = ym + dt ymDot;
    thetaR = thetaR + dt thetaRDot;
    thetaY = thetaY + dt thetaYDot;

    If[Mod[k, 100] == 0, AppendTo[rows, {t, y, ym, e, u, thetaR, thetaY}]],
    {k, 0, nSteps}
  ];

  <|\"name\" -> scenario[\"name\"], \"data\" -> rows, 
    \"finalError\" -> Last[rows][[4]], 
    \"thetaRHat\" -> Last[rows][[6]], 
    \"thetaYHat\" -> Last[rows][[7]]|>
];

scenarios = {
  <|\"name\" -> \"aerospace_pitch_channel\", \"a\" -> 0.80, \"b\" -> 1.10, \"am\" -> 1.60, \"bm\" -> 1.60, \"gamma\" -> 2.0, \"disturbanceAmp\" -> 0.02, \"referenceAmp\" -> 0.15, \"referenceFreq\" -> 0.8|>,
  <|\"name\" -> \"robot_joint_velocity\", \"a\" -> 1.40, \"b\" -> 0.85, \"am\" -> 2.00, \"bm\" -> 2.00, \"gamma\" -> 2.5, \"disturbanceAmp\" -> 0.03, \"referenceAmp\" -> 0.60, \"referenceFreq\" -> 1.2|>,
  <|\"name\" -> \"process_temperature_loop\", \"a\" -> 0.18, \"b\" -> 0.32, \"am\" -> 0.45, \"bm\" -> 0.45, \"gamma\" -> 0.6, \"disturbanceAmp\" -> 0.01, \"referenceAmp\" -> 1.00, \"referenceFreq\" -> 0.18|>,
  <|\"name\" -> \"automotive_speed_loop\", \"a\" -> 0.55, \"b\" -> 0.70, \"am\" -> 1.10, \"bm\" -> 1.10, \"gamma\" -> 1.5, \"disturbanceAmp\" -> 0.03, \"referenceAmp\" -> 4.00, \"referenceFreq\" -> 0.25|>
};

results = simulateScenario /@ scenarios;

Grid[
  Prepend[
    ({ #[\"name\"], #[\"finalError\"], #[\"thetaRHat\"], #[\"thetaYHat\"]} & /@ results),
    {\"scenario\", \"final error\", \"theta_r_hat\", \"theta_y_hat\"}
  ],
  Frame -> All
]
"], "Input"],
Cell[BoxData["
ListLinePlot[
  Table[
    With[{data = results[[i]][\"data\"]},
      {data[[All,1]], data[[All,4]]}\\[Transpose]
    ],
    {i, Length[results]}
  ],
  PlotLegends -> (#[\"name\"] & /@ results),
  AxesLabel -> {\"time\", \"tracking error\"},
  PlotRange -> All,
  ImageSize -> Large
]
"], "Input"]
}]

16. Problems and Solutions

Problem 1: Ideal Parameters for the First-Order Benchmark. Consider the plant \( \dot{y}=-ay+bu \) with \( a > 0 \), \( b > 0 \), and the reference model \( \dot{y}_m=-a_m y_m+b_m r \). For the controller \( u=\theta_r r+\theta_y y \), derive the ideal parameters.

Solution: Substituting the controller into the plant:

\[ \dot{y}=(-a+b\theta_y)y+b\theta_r r \]

Matching this with the reference model requires

\[ -a+b\theta_y^*=-a_m,\qquad b\theta_r^*=b_m \]

Therefore,

\[ \theta_y^*=\frac{a-a_m}{b},\qquad \theta_r^*=\frac{b_m}{b} \]

Problem 2: Tracking-Error Dynamics. Using the same plant and reference model, define \( e=y-y_m \) and \( \tilde{\boldsymbol{\theta} }= \hat{\boldsymbol{\theta} }-\boldsymbol{\theta}^* \) . Show that the tracking error satisfies

\[ \dot{e}=-a_m e+b\tilde{\boldsymbol{\theta} }^\top\boldsymbol{\phi} \]

where \( \boldsymbol{\phi}=[r,y]^\top \).

Solution: The adaptive controller is \( u=\hat{\theta}_r r+\hat{\theta}_y y \) . Substitution gives

\[ \dot{y} = -ay+b\hat{\theta}_r r+b\hat{\theta}_y y \]

Add and subtract the ideal matched terms:

\[ \dot{y} = -a_m y+b_m r+ b(\hat{\theta}_r-\theta_r^*)r+ b(\hat{\theta}_y-\theta_y^*)y \]

Since \( \dot{y}_m=-a_m y_m+b_m r \),

\[ \dot{e}=\dot{y}-\dot{y}_m = -a_m(y-y_m)+ b\tilde{\theta}_r r+ b\tilde{\theta}_y y = -a_m e+b\tilde{\boldsymbol{\theta} }^\top\boldsymbol{\phi} \]

Problem 3: Lyapunov Cancellation. For the nominal case, use \( V=\frac{1}{2}e^2+ \frac{b}{2\gamma}\tilde{\boldsymbol{\theta} }^\top \tilde{\boldsymbol{\theta} } \) . Find an adaptive law that cancels the cross term in \( \dot{V} \).

Solution: Differentiation gives

\[ \dot{V} = e(-a_m e+b\tilde{\boldsymbol{\theta} }^\top\boldsymbol{\phi}) + \frac{b}{\gamma} \tilde{\boldsymbol{\theta} }^\top \dot{\hat{\boldsymbol{\theta} } } \]

The cross term is \( be\tilde{\boldsymbol{\theta} }^\top\boldsymbol{\phi} \) . Choose

\[ \dot{\hat{\boldsymbol{\theta} } } = -\gamma e\boldsymbol{\phi} \]

Then

\[ \frac{b}{\gamma} \tilde{\boldsymbol{\theta} }^\top \dot{\hat{\boldsymbol{\theta} } } = -be\tilde{\boldsymbol{\theta} }^\top\boldsymbol{\phi} \]

and therefore

\[ \dot{V}=-a_m e^2\leq 0 \]

Problem 4: Process-Control Interpretation. A process is described by \( \tau_p \dot{y}+y=K_p u \). Express it in the benchmark form \( \dot{y}=-ay+bu \) and explain which physical changes affect \( a \) and \( b \).

Solution: Divide by \( \tau_p \):

\[ \dot{y}=-\frac{1}{\tau_p}y+\frac{K_p}{\tau_p}u \]

Hence,

\[ a=\frac{1}{\tau_p},\qquad b=\frac{K_p}{\tau_p} \]

If fouling, flow rate, ambient temperature, or operating point changes the process time constant or gain, both \( a \) and \( b \) may change. Adaptive control can compensate by adjusting the controller gains online.

Problem 5: Automotive Linearization. Starting from \( m\dot{v}=F_u-c_r v-c_d v^2-mg\sin(\alpha) \) , linearize the drag term about a nominal speed \( v_0 \) and identify the approximate benchmark parameters.

Solution: Let \( v=v_0+\tilde{v} \). The nonlinear drag term satisfies

\[ c_d v^2 = c_d(v_0+\tilde{v})^2 = c_d v_0^2+2c_d v_0\tilde{v}+c_d\tilde{v}^2 \]

For small \( \tilde{v} \), neglect \( c_d\tilde{v}^2 \). After subtracting the equilibrium force balance, the incremental model is approximately

\[ \dot{\tilde{v} } = -\frac{c_r+2c_d v_0}{m}\tilde{v} + \frac{1}{m}\tilde{F}_u + d_g(t) \]

Therefore,

\[ a=\frac{c_r+2c_d v_0}{m},\qquad b=\frac{1}{m} \]

Vehicle mass variation changes both the damping ratio and control effectiveness in the incremental model, making the case suitable for an adaptive-control interpretation.

17. Summary

This lesson showed how adaptive control appears in aerospace, robotics, process, and automotive systems. Although real engineering systems are usually nonlinear, multivariable, constrained, and safety-critical, many adaptive-control ideas begin with the same pattern: uncertain plant coefficients, a desired reference response, an error equation, and an online parameter-update law. The scalar first-order benchmark introduced here provides a bridge from the conceptual comparison of the previous lesson to the formal mathematical foundations that begin in Chapter 2 and Chapter 3.

18. References

  1. Åström, K.J., & Wittenmark, B. (1973). On self-tuning regulators. Automatica, 9(2), 185–199.
  2. Narendra, K.S., & Valavani, L.S. (1978). Stable adaptive controller design—Direct control. IEEE Transactions on Automatic Control, 23(4), 570–583.
  3. 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.
  4. Goodwin, G.C., Ramadge, P.J., & Caines, P.E. (1980). Discrete-time multivariable adaptive control. IEEE Transactions on Automatic Control, 25(3), 449–456.
  5. Ioannou, P.A., & Kokotović, P.V. (1984). Robust redesign of adaptive control. IEEE Transactions on Automatic Control, 29(3), 202–211.
  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. Morse, A.S. (1996). Supervisory control of families of linear set-point controllers—Part I: Exact matching. IEEE Transactions on Automatic Control, 41(10), 1413–1431.
  8. Kreisselmeier, G. (1977). Adaptive observers with exponential rate of convergence. IEEE Transactions on Automatic Control, 22(1), 2–8.
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.