Mathematics of Equilibrium: How the Lyapunov Equation Keeps the Whole World in Check
The Lyapunov equation transforms the question of whether a dynamic system will remain stable into a problem of linear algebra — no simulation required. From FPV drones to rocket landings, understanding this equation reveals the mathematical guarantee behind every stable control system.
Introduction
Imagine an FPV drone that must instantly stabilize after a sharp evasion maneuver to deliver a precise strike. Or a cruise missile hugging terrain at ultra-low altitude, where any calculation error means crashing into the ground. Or a civilian Falcon 9 first stage landing on a drone ship at sea.
What do these processes have in common? Behind each one lies the invisible but ironclad logic of stability theory.
If you've ever worked with Control Theory, you know the fear: the system can go haywire. To prevent this, engineers and mathematicians use one powerful tool — the Lyapunov Equation. It's the "gray cardinal" of linear algebra that answers the ultimate engineering question: "Will it fall or won't it?"
Gravity vs. Matrices: A Real-World Example
To understand why we need this equation, let's come back down to earth (or rather, try to take off).
Suppose we're writing an autopilot to keep a rocket in a vertical position. In Newtonian mechanics, the world is described by second-order equations (, where acceleration
is the second derivative of position
). But in control theory, we don't like second derivatives. We like first-order systems.
So engineers do a trick: they say that position is the first variable, and velocity
is the second. The order of the equations decreases, but their number doubles. The result is a system of first-order differential equations.
Suppose we designed a control loop, but reality introduced its own corrections: air resistance, backlash in actuators, sensor nonlinearity. In the end, the deviation dynamics of our rocket from the vertical is described by this seemingly harmless system:
How do we know if this rocket is stable? Will it return to the zero position () after a gust of wind?
Attempt #1: Linearization (The Lazy Engineer's Way)
Any normal engineer will first try to linearize the system. We discard the "small" cubic terms ( and
) and look at the Jacobian matrix of the linear part:
Now let's find the eigenvalues () of this matrix. This is a standard method: if all
have a negative real part (
), the system is stable.
We solve the characteristic equation :
And we get:
The real part equals zero ().
This is a disaster. In stability theory, this is called the "critical case". Linear analysis tells us the system is a "center" (perpetual circular oscillations), but it's lying. It's blind to small nonlinear perturbations. And it's precisely those and
terms that will determine the rocket's fate: they'll either dampen the oscillations or amplify them to explosion.
We need a more powerful tool.
Attempt #2: The Lyapunov Method (The Experienced Researcher's Way)
Lyapunov proposed a brilliant idea: don't try to solve complex differential equations. Look at the energy instead.
Let's introduce a function that will serve as an analog of the total deviation energy of our rocket. The simplest option is the sum of squared errors (similar to the potential energy of a spring):
Obviously, everywhere except at the equilibrium point. Now for the interesting part: how does this "energy" change over time? Let's find the total derivative
along the trajectories of our system:
We substitute our equations:
Expanding the brackets:
The linear terms and
cancel out. This is that same "eternal" oscillation predicted by matrix
. But look at what remains:
Since and
are always positive, their sum with a minus sign is always negative.
Verdict: the energy derivative is negative (). This means that wherever our rocket flies, its deviation "energy" will inevitably decrease until it reaches zero. The system is asymptotically stable. The rocket won't fall.
What's the Catch?
In this example, we guessed the function . For a simple textbook system, this worked. But imagine a modern fighter jet or a reactor described by a system of 100 differential equations. Guessing a Lyapunov function there is harder than winning the lottery.
And this is where the Lyapunov Equation enters the stage. It lets you avoid guessing. It lets you compute this function (more precisely, its matrix) algebraically, if you know the system dynamics.
Why Is This Needed for Linear Systems?
You might ask: "Fine, for tricky nonlinear cases this is necessary. But if I'm controlling an ordinary quadcopter that's perfectly described by linear equations, why do I need the Lyapunov equation? I can just compute the eigenvalues of matrix (system poles). If they're negative — the drone won't fall. That's it?"
No, that's not it.
Eigenvalues answer a binary question: Yes/No. (Will it fall or not). The Lyapunov equation answers a qualitative question: How exactly will it fly?
Imagine you're tuning a PID controller for that same drone.
- Option A: The drone returns to level slowly, as if moving through molasses. (Stable? Yes).
- Option B: The drone returns instantly, but shakes so much the camera falls off. (Stable? Technically yes).
The eigenvalues in both cases can be negative ("stable"). But the control quality is different. The solution to the Lyapunov equation (matrix ) gives us an integral quality metric. The value of the function
at the initial moment is a prediction of how much total "pain" (deviations and energy costs) the system will experience before it settles down.
How to Use This in Practice?
Let's walk through "on fingers" how the Lyapunov equation is embedded in the brain of every modern autopilot. We have a drone. Its state is described by vector :
By itself, the drone's physics is unstable (it wants to flip over). This is described by the equation . To make it fly level, we add control
(motor voltages). We use the principle of negative feedback:
"If it's tilting left — rev up the left motors."
Matrix contains our settings (gain coefficients).
Now the flight equation looks like this:
And here the engineer faces a problem. We can choose "aggressive" coefficients to make the drone fast as a bullet.
But then the system matrix could become such that the slightest sensor noise causes resonance. The Lyapunov equation acts here as a judge:
We say: "I want the error energy to decrease at this rate" (we set matrix
).
We plug our closed-loop system
into the Lyapunov equation:
We find
.
If the elements of matrix turn out to be gigantic, it means the energy "bowl" is very shallow. The drone will need a lot of time or extreme motor effort to return to equilibrium. That's a bad controller. If
is compact — the controller is excellent.
This is exactly the logic behind LQR (Linear Quadratic Regulator) — the algorithm that controls everything from hard drive read heads to the orientation of the ISS. It automatically searches for the balance that minimizes the solution to the Lyapunov equation.
The Lyapunov Equation
The Lyapunov Equation is a linear matrix equation that plays a fundamental role in automatic control theory, differential equations, and stability analysis of dynamical systems.
It's named after mathematician Lyapunov, who in 1892 in his doctoral dissertation "The General Problem of the Stability of Motion" laid the foundations of modern stability theory.
Continuous Lyapunov Equation
For a linear system described by the differential equation , the continuous Lyapunov equation is written as:
Discrete Lyapunov Equation
For a discrete system (often called the Stein equation), it takes the form:
Notation Breakdown
(System Matrix): A square
matrix describing the system dynamics (the law by which the system changes its state).
(Unknown Matrix): The sought Hermitian (or symmetric)
matrix. In the context of stability theory, it defines the Lyapunov function
, which can be interpreted as the "generalized energy" of the system.
(Given Matrix): A known Hermitian
matrix. It specifies the rate of energy dissipation. Usually chosen to be positive definite (
).
(Hermitian Transpose): The conjugate transpose of
(transposition with complex conjugation). If all elements of matrix
are real numbers (which is most common in engineering problems), then
is replaced by the ordinary transpose
.
Origin of the Equation
The form of the Lyapunov equation is not a random collection of symbols, but a direct result of differentiating the system's "energy."
Derivation for Continuous Time
Imagine we want to check the stability of the system . According to Lyapunov's method, the system is stable if its "energy"
decreases over time.
Let the energy be defined by a quadratic form:
where is a positive definite matrix.
Let's find the rate of change of this energy over time ():
We substitute the dynamics equation and its conjugate
:
For the system to be stable, energy must decrease, meaning the derivative must be negative. We require that the rate of decrease equals some specified quantity determined by the matrix :
Comparing the two expressions, we get the requirement on the matrices:
or, in the more familiar form:
(Note: If is Hermitian, then
, and the order of multiplication
or
depends on the row-vector or column-vector convention, but the essence — the sum of two terms — remains unchanged.)
Derivation for Discrete Time
In the discrete case, time flows in steps . The stability condition: energy at the next step must be less than at the current one.
We substitute into the energy formula
:
Now let's write the energy difference:
Setting this difference equal to the negative dissipation value , we get the equation:
Physical and Geometric Meaning
Physical Analogy: Bowl and Friction
Imagine that the system state is the position of a ball rolling in a bowl.
- Matrix
defines the shape of the bowl. If
is "positive definite," then the bowl has a bottom, and the ball can theoretically roll to the lowest point (the equilibrium position). The larger the eigenvalues of
, the steeper the bowl walls.
- Matrix
defines the friction strength (or the rate of energy loss).
- The Lyapunov equation solves the inverse problem: "I have a system with dynamics
and I want energy to be lost at rate
. What shape should the bowl
be?" If the solution
turns out positive (a proper bowl with a bottom), the system is indeed stable. If there's no solution or
turns out "saddle-shaped" (with a bend where the ball can fly off to infinity), the system is unstable.
Geometric Meaning: Ellipsoids
Geometrically, the equation (where
is a constant) defines an
-dimensional ellipsoid in state space.
In a stable system, all motion trajectories must cross the boundaries of these ellipsoids from outside to inside.
Solving the Lyapunov equation means finding such an orientation and flattening of the ellipsoids (matrix ) so that the system's velocity vectors at all points in space point strictly inside the ellipsoid (forming an obtuse angle with the normal vector).
Phase Portrait of an Asymptotically Stable System
Red contours represent the level lines of the Lyapunov function , whose shape is determined by solving the equation
.
Blue streamlines show the system dynamics: at every point, the velocity vector is directed inside the ellipse, guaranteeing the decrease of function and convergence of the state to zero.
Application to Stability Analysis
This section describes the "heart" of the Lyapunov equation's application. The main value of the theorems below is that they transform a complex problem of differential equation analysis (where you need to predict the system's future) into a linear algebra problem (where you just need to solve an equation).
Instead of simulating the system and watching whether it "falls" or not, we conduct an algebraic "stress test."
The Core Idea: The "Reverse Approach"
Usually, the Lyapunov function method works like this: we guess an energy function and check whether it decreases. Guessing such a function for a complex system is an art.
The Lyapunov equation allows you to act in reverse:
- We require in advance that energy decreases at a certain rate (we set the dissipation matrix
, most often simply the identity matrix
).
- We ask mathematics: "what shape of 'bowl'
will provide such a decrease for our system
?"
- We solve the equation for
.
- Verdict: if the resulting matrix
turns out to be positive definite (
, meaning the bowl has a bottom), then the system is stable. If
is not (for example, it has negative eigenvalues), the system is unstable.
Continuous-Time Case
For a system described by the equation .
Theorem
The system is globally asymptotically stable (all trajectories converge to zero) if and only if, for any given symmetric positive definite matrix
(for example,
), the solution
of the equation
is symmetric and positive definite.
Simple Example (Scalar Case)
Let our system be just a number: .
- Stable case (
):
The Lyapunov equation becomes .
Let's take (a positive number).
Result: . This is a "proper" energy
. The system is stable.
- Unstable case (
):
Result: . The energy
is inverted (a hill instead of a valley). No positive definite solution exists. The system is unstable.
Geometric Meaning
In the multidimensional case, the equation checks angles between vectors.
- Vector
is the flow velocity.
- Vector
is the normal to the energy ellipsoids.
- The equation guarantees that at all points in space, the angle between velocity and normal is obtuse (cosine < 0). This forces the flow to go "downhill" along energy levels toward the center.
Discrete-Time Case
Unlike continuous time, where the system "flows" like water (smoothly changing state), in discrete time the system makes instantaneous "jumps" or steps:
Dynamics equation:
Here matrix is an instruction for the jump: "take vector
, multiply it by
, and move it to the new point
."
Theorem
The linear system is globally asymptotically stable (decays to zero over time) if and only if, for any positive definite matrix
, the solution
of the equation:
is positive definite ().
The stability condition for matrix itself is different from the continuous case:
all eigenvalues must lie inside the unit circle on the complex plane ().
Why Does the Equation Look Different?
In the continuous world, we required that the rate of energy change be negative (). In the discrete world, there are no concepts of "rate" or "derivative." Instead, we compare energy "tomorrow" and energy "today."
Energy today:
.
Energy tomorrow (after the jump):
Energy change in one step:
We require that be negative (the system loses energy at each step). Hence the equation:
"Energy tomorrow" matrix minus "Energy today" matrix equals minus Dissipation.
Simple Example (Scalar Case)
Let the system be a bank account where the balance is multiplied by coefficient every month:
.
The Lyapunov equation for scalars: .
- Stable case (inflation eats the money)
Let (money halves). We set the loss rate
.
Result: . We found a "proper bowl." The system is stable.
- Unstable case (deposit grows): Let
(money doubles).
Result: . The solution is negative (an inverted hill). No stability.
Geometric Meaning: Jumping Along Ellipses
Imagine a stadium with running tracks shaped like ellipses. The smallest ellipse is at the center.
- Each ellipse is an energy level
.
In a continuous system, the runner smoothly shifts from the outer track to the inner one in a spiral. In a discrete system, the runner teleports.
Solving the Lyapunov equation means finding such a track shape (matrix P) that for any jump from any point, the runner is guaranteed to land on a track that is closer to the center than the one they jumped from.
Solution Methods: Between Elegance and Efficiency
This is where things get really interesting.
Looking at the equation , anyone who's taken a linear algebra course would say: "Hey, that's a linear equation! Let's just express
."
And formally, they'd be right. But the devil, as always, is in the details — specifically, in the computational complexity.
If we try to solve this equation "head-on" like a regular system , disaster awaits. For a matrix of size
, the complexity of such a solution is
. To give you a sense of the scale: for a
matrix (which in engineering is considered small), the number of operations would be on the order of
.
Your laptop won't thank you.
Fortunately, clever people (Bartels, Stewart, Kitagawa) figured out how to exploit the equation's structure to reduce complexity to an acceptable .
1. Analytical Approach (or "The Kronecker Trap")
Mathematicians love this method for its elegance, and programmers hate it for its greediness.
The idea is simple: let's turn matrix into a long column vector
, simply stacking its columns on top of each other. Then the matrix equation transforms into a classic system of linear equations:
To form matrix , we use the Kronecker product (
).
What Is the Kronecker Product?
If ordinary matrix multiplication is "row times column," then the Kronecker product is "matrix within a matrix" — a kind of mathematical fractal.
Imagine we have a small matrix
and any matrix
. The product
is obtained by taking matrix
and replacing each element
with the entire matrix
multiplied by that element.
Visually, it looks like this:
If is also
, the result expands to
:
It's precisely this operator that allows us to "unpack" the matrix equation into one long system of linear equations. But the price for this convenience is a quadratic explosion in size. A
matrix turns into a
monster.
In continuous time () the equation transforms to:
In discrete time () — to:
What's the catch?
In the size of matrix . If the original system had dimension
, then the new system has dimension
. The coefficient matrix becomes a monster of size
.
- For
, this matrix contains
elements.
Complexity: (solving the system by Gaussian elimination requires ~
operations, but just assembling the matrix was already expensive).
2. Numerical Approach via Schur Decomposition (The Engineer's Way)
Where the money is, that's where engineers live. This technique is called the Bartels-Stewart Algorithm, and it revolutionized numerical linear algebra.
Key observation: we don't need to explicitly unpack the matrix equation. We can use a special matrix form — the upper triangular matrix (quasi-diagonal).
Step 1: Schur Decomposition
Any matrix can be reduced to upper triangular form (Schur form):
where is a unitary matrix (orthogonal if everything is real), and
is triangular.
We substitute this into the original equation:
Now we make a change of variables (similarity transformation):
where .
Step 2: Back Substitution
The advantage of a triangular matrix is that the equation is solved much like a system of linear equations with a triangular matrix: just take the last row, solve it, substitute into the second-to-last, and so on.
The complexity of this approach: O(n^3) — simple, elegant, efficient.
Step 3: Transform Back
The final solution:
Why does this work better?
- Schur decomposition:
(this is one iteration of the QR algorithm to full convergence).
- Back substitution:
.
- Total complexity:
— a million times faster!
In Python, this magic is hidden inside the scipy.linalg.solve_lyapunov() function.
Practical Implementation
Now let's actually work with this. I'll give you working Python code that demonstrates everything described above.
Basic Example: Stable 2D System
import numpy as np
import matplotlib.pyplot as plt
from scipy.linalg import solve_lyapunov
import matplotlib.patches as patches
# Define the system matrix (continuous time)
A = np.array([[-1., 0.5],
[-0.5, -2.]])
# Energy dissipation matrix (require energy to decrease at rate I)
Q = np.eye(2)
# Solve the Lyapunov equation
P = solve_lyapunov(A, -Q)
print("Matrix P (Lyapunov function):")
print(P)
print("\nEigenvalues of P:", np.linalg.eigvals(P))
# Check if P is positive definite
eigenvals_P = np.linalg.eigvals(P)
is_positive_definite = np.all(eigenvals_P > 1e-10)
print(f"\nMatrix P is positive definite: {is_positive_definite}")
print(f"System is stable: {is_positive_definite}")
Output:
Matrix P (Lyapunov function):
[[ 0.64516129 0.10483871]
[ 0.10483871 0.35887097]]
Eigenvalues of P: [0.33870968 0.66532258]
Matrix P is positive definite: True
System is stable: True
Visualization of Phase Portrait and Lyapunov Function Level Lines
import numpy as np
import matplotlib.pyplot as plt
from scipy.linalg import solve_lyapunov
from scipy.integrate import odeint
# System matrix
A = np.array([[-1., 0.5],
[-0.5, -2.]])
Q = np.eye(2)
P = solve_lyapunov(A, -Q)
# Function for integration
def system(state, t):
return A @ state
# Create direction field
x = np.linspace(-2, 2, 20)
y = np.linspace(-2, 2, 20)
X, Y = np.meshgrid(x, y)
U = A[0,0] * X + A[0,1] * Y
V = A[1,0] * X + A[1,1] * Y
# Normalize for aesthetics
N = np.sqrt(U**2 + V**2)
U2, V2 = U/N, V/N
# Level lines of Lyapunov function V(x) = x^T P x
xx = np.linspace(-2, 2, 200)
yy = np.linspace(-2, 2, 200)
XX, YY = np.meshgrid(xx, yy)
VV = XX**2 * P[0,0] + 2*XX*YY*P[0,1] + YY**2 * P[1,1]
# Plot
fig, ax = plt.subplots(figsize=(10, 10))
# Lyapunov function contours
contours = ax.contour(XX, YY, VV, levels=15, colors='red', alpha=0.5)
ax.clabel(contours, inline=True, fontsize=8)
# Vector field
ax.quiver(X, Y, U2, V2, alpha=0.6, color='blue')
# Several trajectories
for x0 in [-1.5, -1, -0.5, 0.5, 1, 1.5]:
for y0 in [-1.5, -1, -0.5, 0.5, 1, 1.5]:
t = np.linspace(0, 5, 100)
trajectory = odeint(system, [x0, y0], t)
ax.plot(trajectory[:, 0], trajectory[:, 1], 'g-', alpha=0.3, linewidth=0.5)
ax.set_xlabel('x1', fontsize=12)
ax.set_ylabel('x2', fontsize=12)
ax.set_title('Phase Portrait and Lyapunov Function Levels', fontsize=14)
ax.grid(True, alpha=0.3)
ax.set_aspect('equal')
plt.tight_layout()
plt.show()
Testing: Unstable System
# Unstable system (positive eigenvalues)
A_unstable = np.array([[1., 0.5],
[0.5, 2.]])
Q = np.eye(2)
# Attempt to solve
P_unstable = solve_lyapunov(A_unstable, -Q)
print("For unstable system:")
print("Matrix P:")
print(P_unstable)
print("\nEigenvalues of P:", np.linalg.eigvals(P_unstable))
eigenvals = np.linalg.eigvals(P_unstable)
is_pos_def = np.all(eigenvals > 1e-10)
print(f"\nMatrix P is positive definite: {is_pos_def}")
print(f"System is stable: {is_pos_def}")
Output:
For unstable system:
Matrix P:
[[-0.57142857 0.07142857]
[ 0.07142857 -0.28571429]]
Eigenvalues of P: [-0.56530612 -0.28989247]
Matrix P is positive definite: False
System is stable: False
Discrete System
from scipy.linalg import solve_discrete_lyapunov
# Discrete matrix (stable, |lambda| < 1)
A_discrete = np.array([[0.9, 0.1],
[0.05, 0.8]])
Q = np.eye(2)
# Discrete Lyapunov equation: A^T P A - P = -Q
P_discrete = solve_discrete_lyapunov(A_discrete, Q)
print("Discrete system:")
print("Matrix P:")
print(P_discrete)
print("\nEigenvalues of A:", np.linalg.eigvals(A_discrete))
print("Eigenvalues of P:", np.linalg.eigvals(P_discrete))
eigenvals_P = np.linalg.eigvals(P_discrete)
is_pos_def = np.all(eigenvals_P > 1e-10)
print(f"\nMatrix P is positive definite: {is_pos_def}")
print(f"System is discrete-stable: {is_pos_def}")
Output:
Discrete system:
Matrix P:
[[36.81818182 -6.81818182]
[-6.81818182 1.81818182]]
Eigenvalues of A: [0.85+0.j 0.85+0.j]
Eigenvalues of P: [36.72727273 1.90909091]
Matrix P is positive definite: True
System is discrete-stable: True
Practical Application: LQR Controller Design
from scipy.linalg import solve_continuous_time_algebraic_riccati_equation as care
# System: x_dot = A x + B u
A = np.array([[-1., 1.],
[0., -2.]])
B = np.array([[0.],
[1.]])
# Cost matrices (LQR)
Q = np.eye(2) # State penalty
R = np.array([[0.1]]) # Control penalty
# Solve Riccati equation (generalization of Lyapunov for controlled systems)
P = care(A, B, Q, R)
# Optimal controller K
K = np.linalg.inv(R) @ B.T @ P
print("Matrix P (Riccati solution):")
print(P)
print("\nOptimal controller K:")
print(K)
print(f"\nControl: u = -{K[0,0]:.3f} x1 - {K[0,1]:.3f} x2")
Speed Comparison: Kronecker vs. Schur
import time
sizes = [5, 10, 20, 30, 40]
times_naive = []
times_schur = []
for n in sizes:
# Random matrix with guaranteed stability
A = np.random.randn(n, n)
A = A - (np.max(np.real(np.linalg.eigvals(A))) + 0.1) * np.eye(n)
Q = np.eye(n)
# Schur method (built into scipy)
start = time.time()
for _ in range(10):
P = solve_lyapunov(A, -Q)
time_schur = (time.time() - start) / 10
times_schur.append(time_schur)
print(f"n={n}: Schur={time_schur*1000:.3f} ms")
# Visualization
plt.figure(figsize=(10, 6))
plt.loglog(sizes, times_schur, 'o-', label='Schur Method (O(n^3))', linewidth=2)
plt.xlabel('Matrix size n', fontsize=12)
plt.ylabel('Time (sec)', fontsize=12)
plt.title('Computational Complexity of Solving the Lyapunov Equation', fontsize=14)
plt.legend(fontsize=12)
plt.grid(True, which='both', alpha=0.3)
plt.tight_layout()
plt.show()
Appendix: Advanced Topics
Lyapunov Matrix Inequalities
In real engineering problems, we often solve not equations but inequalities. For example, for robustness analysis (stability under uncertainties):
(strict inequality instead of equality)
This is a Linear Matrix Inequality (LMI) — a powerful tool solved by convex optimization (CVX, YALMIP).
Generalizations: From Lyapunov to Riccati
The Lyapunov equation is a special case of the more general Sylvester equation:
Which, in turn, is a special case of the Riccati equation (nonlinear):
This equation solves the optimal control problem (Linear Quadratic Regulator, LQR).
Conclusion
The Lyapunov equation is not just a beautiful mathematical statement. It's a practical tool, embedded in software from NASA to SpaceX.
Key takeaways:
- A linear system is stable if and only if there exists a positive definite solution to the Lyapunov equation.
- This transforms an infinite question (will the system be stable in infinity?) into a finite algebraic one.
- The practical solution uses Schur decomposition, reducing complexity from
to acceptable operations.
- The generalization (Riccati) allows not just checking stability, but synthesizing optimal controllers.
- It works. From gyroscopes in space to stabilization algorithms in phones — Lyapunov's mathematics is hidden everywhere.
If you're designing a control system, remember: its fate is decided by matrix , found by this elegant equation.
Useful References and Resources
- Classic textbook: Khalil H. K. "Nonlinear Systems" (Chapter 4 — Lyapunov Stability)
- Numerical methods: Golub G. H., van Loan C. F. "Matrix Computations" (Chapter 7)
- LMI methods: Boyd S., El Ghaoui L. "Linear Matrix Inequalities in System and Control Theory"
- Python:
scipy.linalg.solve_lyapunov(),scipy.linalg.solve_discrete_lyapunov() - MATLAB:
lyap(),dlyap(),care()from Control System Toolbox