Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

2.6 Controllability and Control Authority

Can the input move every relevant state?

For x˙=Ax+Bu\dot{x}=Ax+Bu, the controllability matrix is

C=[BABA2BAn1B].\mathcal{C}=\begin{bmatrix}B&AB&A^2B&\cdots&A^{n-1}B\end{bmatrix}.

The system is controllable if rank(C)=n\operatorname{rank}(\mathcal{C})=n. Rank is a yes-or-no structural test. CCD also needs a quantitative question: how much effort is required to move each state or mode?

The finite-horizon controllability Gramian

Wc(T)=0TeAtBBTeATtdtW_c(T)=\int_0^T e^{At}BB^Te^{A^Tt}\,dt

describes reachable directions. Small eigenvalues indicate directions that require large energy. A design can be mathematically controllable but practically uncontrollable because force, stroke, rate, power, or bandwidth is insufficient.

Actuator placement on a flexible beam

A point actuator couples strongly to modes whose shape is large at the actuator location and weakly to modes near a node. Moving the actuator changes the modal input matrix B(p)B(p). Placement should therefore consider the modes that constrain performance, not only geometric convenience.

Size, authority, and diminishing returns

Control authority improves with actuator size but mass, cost, and energy also grow.

A larger actuator may improve the smallest Gramian eigenvalue and reduce saturation, but it adds mass, volume, heat, cost, and energy demand. Beyond a point, performance becomes limited by sensing, delay, structural flexibility, or another constraint. CCD seeks the knee of this system-level trade, not maximum authority in isolation.

A placement calculation

import numpy as np
from scipy.linalg import solve_continuous_lyapunov

def gramian_metrics(A, B):
    # For stable A, A W + W A^T + B B^T = 0.
    W = solve_continuous_lyapunov(A, -(B @ B.T))
    eigs = np.linalg.eigvalsh(W)
    return eigs.min(), np.trace(W)

A = np.array([[0, 1, 0, 0], [-4, -0.3, 1, 0],
              [0, 0, 0, 1], [1, 0, -25, -0.8]], dtype=float)
for label, B in {
    "near mode-1 antinode": np.array([[0], [1.0], [0], [0.15]]),
    "balanced location":   np.array([[0], [0.65], [0], [0.65]]),
}.items():
    print(label, gramian_metrics(A, B))

Activity 2.6: choose an actuator location