8. Stability
Stability is the most fundamental property of a dynamic system. This chapter introduces the tools — norms, eigenvalues, and Lyapunov’s direct method — needed to analyze it rigorously.
Lecture videos
Section titled “Lecture videos”Slides
Section titled “Slides”PowerPoint handouts: Stability via Eigenvalues (dark) · Stability via Eigenvalues (light) · Lyapunov Stability (dark) · Lyapunov Stability (light)
Interactive example
Section titled “Interactive example”Continuous-time Lyapunov equation
Section titled “Continuous-time Lyapunov equation”For A = [[-1,1],[-1,0]] and Q = I, this solves the Lyapunov equation A^T P + P A = -Q for P, then checks its eigenvalues. Both matching the hand-solved P = [[1, -0.5], [-0.5, 1.5]] from the text: all eigenvalues of P are positive, so P is positive definite and the origin is asymptotically stable.
import control as ctimport numpy as np
A = np.array([[-1, 1], [-1, 0]])Q = np.identity(2)# ct.lyap solves A P + P A^T + Q = 0 by default, so we pass A.T to solve the# Lyapunov equation A^T P + P A + Q = 0 used in the textP = ct.lyap(A.transpose(), Q)print("P =")print(P)
w = np.linalg.eigvals(P)print(f"\neigenvalues of P: {w}")print("All eigenvalues positive -> P is positive definite -> asymptotically stable")Continuous-time Lyapunov equation (mcimp/codes/lyapunov/ctlyapunov_sol.py)
Click "Run" to execute.
The Lyapunov equation as a linear operator
Section titled “The Lyapunov equation as a linear operator”A^T P + P A = -Q is linear in the unknown P, so it can be written as L_A(P) = -Q for a linear operator L_A built from A via the Kronecker product: L_A = I ⊗ A^T + A^T ⊗ I. This computes L_A’s eigenvalues directly and confirms the claim from the text: each eigenvalue of L_A is a pairwise sum lambda_i + lambda_j of A’s own eigenvalues — which is also exactly the condition (lambda_i + lambda_j != 0) that guarantees the Lyapunov equation has a unique solution.
import numpy as np
A = [[-1, 1], [-1, 0]]I2 = np.eye(2)AT = np.transpose(A)
# The Lyapunov equation A^T P + P A = -Q is linear in P; L_A is the matrix# representation of that linear operator via the Kronecker product,# L_A = I (x) A^T + A^T (x) IL_A = np.kron(I2, AT) + np.kron(AT, I2)
eigLA = np.linalg.eigvals(L_A)eigA = np.linalg.eigvals(A)print("Eigenvalues of L_A:", eigLA)print("Eigenvalues of A: ", eigA)print("\nEach eigenvalue of L_A is a pairwise sum lambda_i + lambda_j of A's eigenvalues.")The Lyapunov equation as a linear operator (mcimp/codes/lyapunov/lyapunov_operator.py)
Click "Run" to execute.
Discrete-time Lyapunov equation
Section titled “Discrete-time Lyapunov equation”The discrete-time analogue solves A^T P A - P = -Q instead. For the third-order A in the text’s example, this confirms all three eigenvalues of the resulting P are positive — so P is positive definite and the discrete-time system’s origin is asymptotically stable, the discrete-time counterpart of the continuous-time result above.
import control as ctimport numpy as npfrom numpy.linalg import eig
A = np.array([[0, 1, 0], [0, 0, 1], [0.275, -0.225, -0.1]])Q = np.identity(3)# ct.dlyap solves A P A^T - P + Q = 0 by default, so we pass A.T to match# the discrete-time Lyapunov equation A^T P A - P = -Q used in the textP = ct.dlyap(A.transpose(), Q)w, v = eig(P)print("eigenvalues of P:", w)print("All positive -> P is positive definite -> the origin is asymptotically stable")Discrete-time Lyapunov equation (mcimp/codes/lyapunov/dtlyapunov_sol.py)
Click "Run" to execute.