In this control engineering and control theory tutorial, we explain how to easily solve the Lyapunov equation by using the Kronecker product. We provide a detailed explanation with Python codes.
The YouTube video tutorial accompanying this page is given here. All the codes are posted on our GitHub page given here.
Background on Lyapunov Equation and Kronecker Product
The Lyapunov equation for continuous-time systems has the following form:
(1)
where
(2)
where
Problem: Given the matrices
In a number of scenarios, we are not only seaching for any solution of the Lyapunov equation. Often, we are searching for a symmetric positive definite matrix
Now, let us focus on the Kronecker product. Let
(3)
Then, the Kronecker product is defined by following matrix
(4)
where
(5)
The vectorization operator and Kronecker product are related to each other. Namely, let us consider the following matrix equation
(6)
Let us apply the vectorization operator to both left-hand and right-hand sides of this equation:
(7)
Now, it can be shown that the following formula is valid
(8)
This formula is very important since if we want to solve the matrix equation (6) for the matrix
Solve the Lyapunov Equation by Using Kronecker Product
here, we will apply everything we learned in the previous section to the problem of solving the Lyapunog equation. Let us first apply the vectorization operator to our Lyapunov equation (1)
(9)
Since the vectorization operator is a linear operator, we have
(10)
Next, by using the formula (8), we have
(11)
where
(12)
Let us introduce the matrix
(13)
Then, the last system can be writen as
(14)
Under the assumption that the matrix
(15)
The solution (15) is the solution of our Lyapunov equation. Once we determine this solution we can de-vectorize
Python Codes for Solving the Lyapunov Equation
First, we explain how to compute the Kronecker product in Python, and how to perform the vectorization and de-vectorization. The following code lines are self-explanatory and they explain how to compute the Kronecker product, as well as how to vectorize and de-vecotorize matrices and vectors.
import numpy as np
import control as ct
# test of the Kronecker product in Python
Atest=np.array([[1,2],[3,4]])
Btest=np.array([[2,1],[3,4]])
Cmatrix=np.kron(Atest,Btest)
# test of vectorization
AtestVectorized=Atest.flatten('F').reshape(4,1)
np.matmul(Cmatrix,AtestVectorized)
# test of de-vectorization
Atest1=AtestVectorized.reshape(2,2,order='F')
Here, we need to mention that we are using the NumPy library for matrix computations, and we are using the Python control systems library in order to construct the matrix
The following Python code lines are used to construct a stable transfer function, and then to transform this transfer function into a state-space model, and then to extract the matrix
# now test the Lyapunov Equation solution
# define a stable transfer function
tfTest = ct.zpk([1], [-1,-2,-3], gain=1)
print(tfTest)
# create a state-space model
ssTest=ct.tf2ss(tfTest)
print(ssTest)
# extract the A matrix
A=ssTest.A
The following piece of code will first verify that the matrix
(16)
This complete expression should be equal to zero or very close to zero if the solution
# check the eigenvalues of A
np.linalg.eig(A)
# create the matrix Q that is positive definite
Q=np.array([[10, -0.2, -0.1],[-0.2, 20, -0.2],[-0.1, -0.2, 3]])
# Lyapunov equation A'*X+X*A=-Q
Qvectorized=Q.flatten('F').reshape(9,1)
S=np.kron(np.eye(3,3),A.T)+np.kron(A.T,np.eye(3,3))
Xvectorized=-np.matmul(np.linalg.inv(S),Qvectorized)
X=Xvectorized.reshape(3,3,order='F')
# check the eigenvalues
np.linalg.eig(X)
# confirm that the solution actually satisfies
# Lyapunov equation A'*X+X*A=-Q
# LHS=A'*X+X*A
# LHS+Q=0 -> equivalent form
# the Lyapunov equation
LHS=np.matmul(A.T,X)+np.matmul(X,A)
# this should be zero or close to zero if X is the
# correct solution
LHS+Q