本文属于入门级的教程,适合刚入坑的萌新看。在写之前我在网上找了一下相关的文章,发现没有一个写得很直观的答案,刚好最近在研究MPC,于是决定自己写一个,针对最简单的线性约束系统,推导其优化的过程原理,揭示其简单的结构。另外关于MPC的理论,可以自行参考相关教材,这里不再赘述。
首先要介绍一下一个基于Matlab的工具MPT3,这是一个优化工具箱,同样也能调用MPC,感兴趣的同学可以自己点进去看一下。今天要用的模型也是来自这里面的一个demo,可以参考这个网址https://www.mpt3.org/UI/RegulationProblem
这里用最简单的线性模型来进行解释,用差分方程进行描述如下:
x + = A x + B u x^{+}=Ax+Bu x+=Ax+Bu
其中, A = [ 1 1 0 1 ] A=\begin{bmatrix}1& 1\\ 0& 1\end{bmatrix} A=[1011], B = [ 1 0.5 ] B=\begin{bmatrix} 1\\ 0.5\end{bmatrix} B=[10.5]. 初始状态 x 0 = [ 4 0 ] ′ x_0=\begin{bmatrix} 4 &0\end{bmatrix}' x0=[40]′. 然后是状态量以及控制量的约束限制:
[ − 5 − 5 ] ≤ x ≤ [ 5 5 ] , − 1 ≤ u ≤ 1 \begin{bmatrix} -5\\ -5\end{bmatrix}\leq x\leq \begin{bmatrix} 5\\ 5\end{bmatrix}, -1\leq u\leq1 [−5−5]≤x≤[55],−1≤u≤1
一般的线性MPC中用的是二次优化,分别包含了针对状态量的代价函数 x k ′ Q x k x_k'Qx_k xk′Qxk项以及针对控制量的代价函数 u k ′ R u k u_k'Ru_k uk′Ruk:
J ( k , N p ) = m i n ∑ t = k k + N p ( x t ′ Q x t + u t ′ R u t ) J_{(k,N_p)}=\mathrm {min} \sum_{t=k}^{k+N_p}(x_t'Qx_t+u_t'Ru_t) J(k,Np)=mint=k∑k+Np(xt′Qxt+ut′Rut)
表示的是在时刻 t t t,滚动时域步长为 N p N_p Np的优化目标函数,目的是要让状态量 x x x以及控制量 u u u尽量的小,即使用最少的能量使系统状态量尽快稳定到零点(或者是稳定到某一个状态,这也是一般优化问题的目的)。其中代价系数矩阵的取值分别为:
Q = [ 1 0 0 1 ] , R = 1 Q=\begin{bmatrix}1& 0\\ 0& 1\end{bmatrix}, R=1 Q=[1001],R=1
其取值可以根据设计要求在状态量与控制量的大小之间平衡。预测时域的长度选为 N p = 5 N_p=5 Np=5,模型及参数准备完毕开始进行下一步。
为了使用Matlab中的quadprog函数进行在线二次优化,求解Matlab中的优化问题,需要对优化目标进行转换,变换为关于控制量 u t u_t ut的优化函数,回顾优化目标函数,里面包含了在 N p N_p Np步后的未来系统状态量 x t x_t xt,这里需要将其描述为关于优化目标 u t u_t ut的函数。由于是线性系统,通过不停的迭代可以很容易得到 x t x_t xt关于 u t u_t ut的表达式:
x k + 1 ∣ k = A x k + B u k x k + 2 ∣ k = A x k + 1 ∣ k + B u k + 1 = A 2 x k + A B u k + B u k + 1 … … x k + N p ∣ k = A x k + N p − 1 ∣ k + B u k + N p − 1 = A N p x k + A N p − 1 B u k + … … + A B u k + N p − 2 + B u k + N p − 1 x_{k+1|k}=Ax_{k}+Bu_k \\ x_{k+2|k}=Ax_{k+1|k}+Bu_{k+1}=A^2x_k+ABu_k+Bu_{k+1} \\ …… \\ x_{k+N_p|k}=Ax_{k+N_p-1|k}+Bu_{k+N_p-1}=A^{N_p}x_{k}+A^{N_p-1}Bu_k+……+ABu_{k+N_p-2}+Bu_{k+N_p-1} xk+1∣k=Axk+Bukxk+2∣k=Axk+1∣k+Buk+1=A2xk+ABuk+Buk+1……xk+Np∣k=Axk+Np−1∣k+Buk+Np−1=ANpxk+ANp−1Buk+……+ABuk+Np−2+Buk+Np−1
如果感兴趣可以自己尝试推导一下。然后将其描述为矩阵形式:
[ x k + 1 ∣ k x k + 2 ∣ k . . . x k + N p ∣ k ] = [ A A 2 . . . A N p ] x k + [ B 0 . . . 0 A B B . . . 0 . . . . . . . . . . . . A N p − 1 B A N p − 2 B . . . B ] [ u k u k + 1 . . . u k + N p − 1 ] \begin{bmatrix}x_{k+1|k}\\ x_{k+2|k}\\ ...\\ x_{k+N_p|k}\end{bmatrix}=\begin{bmatrix}A\\ A^2\\ ...\\ A^{N_p}\end{bmatrix}x_k+\begin{bmatrix}B& 0 & ... &0 \\ AB& B & ... &0 \\ ...& ... & ... & ...\\ A^{N_p-1}B& A^{N_p-2}B & ... &B \end{bmatrix}\begin{bmatrix}u_k\\ u_{k+1}\\ ...\\ u_{k+N_p-1}\end{bmatrix} ⎣⎢⎢⎡xk+1∣kxk+2∣k...xk+Np∣k⎦⎥⎥⎤=⎣⎢⎢⎡AA2...ANp⎦⎥⎥⎤xk+⎣⎢⎢⎡BAB...ANp−1B0B...ANp−2B............00...B⎦⎥⎥⎤⎣⎢⎢⎡ukuk+1...uk+Np−1⎦⎥⎥⎤
简化表示为:
X = A ~ x k + B ~ U X=\tilde{A}x_k+\tilde{B}U X=A~xk+B~U
其中 X = [ x k + 1 ∣ k ′ , x k + 2 ∣ k ′ , . . . , x k + N p ∣ k ′ ] ′ , U = [ u k ′ , u k + 1 ′ , . . . , u k + N p − 1 ′ ] ′ X=[x'_{k+1\mid k},x'_{k+2\mid k},...,x'_{k+N_{\textrm{p}}\mid k}]', U=[u'_k,u'_{k+1},...,u'_{k+N_{\textrm{p}}-1}]' X=[xk+1∣k′,xk+2∣k′,...,xk+Np∣k′]′,U=[uk′,uk+1′,...,uk+Np−1′]′, A ~ , B ~ \tilde{A},\tilde{B} A~,B~为对应的矩阵,这样就将将来的状态量表示为了关于优化目标 U U U的表达式,可以代入优化目标中进行求解了。这里值得注意的是在Matlab中,通过适当的技巧可以得到 A t , B t A_t,B_t At,Bt,具体方法可以参考后文的代码。
在完成了未来状态量的变量替换之后,进一步将优化目标函数替换为全部关于优化目标 u t u_t ut以及当前状态量 x k x_k xk的表达式。将前文中的优化目标函数重新表示为:
J ( k , N p ) = m i n X ′ Q ~ X + U ′ R ~ U J_{(k,N_p)}=\mathrm {min} \ X'\tilde{Q}X+U'\tilde{R}U J(k,Np)=min X′Q~X+U′R~U
其中 Q ~ , R ~ \tilde{Q},\tilde{R} Q~,R~是适当增广变换之后的优化代价系数矩阵,感兴趣的同学可以自己推导。具体的变化方法在后文Matlab代码中可见。总之就是尽量将优化目标简化,使其能够直接传递到quadprog函数的参数中。参考Matlab中quadprog函数的形式,调用方法为:
[ x , f v a l , e x i t f l a g ] = q u a d p r o g ( H , f , A , b , A e q , b e q , l b , u b , x 0 , o p t i o n s ) m i n x 1 2 x ′ H x + f ′ x s . t . A x ≤ b A e q ∗ x = b e q l b ≤ x ≤ u b [x,fval,\mathrm {exitflag}]=quadprog(H,f,A,b,Aeq,beq,lb,ub,x_0,options) \\ \underset{x}{\mathrm {min}} \ \frac{1}{2}x'Hx+f'x \\ s.t. \ \ \ \ Ax\leq b \\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Aeq*x=beq \\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lb\leq x \leq ub [x,fval,exitflag]=quadprog(H,f,A,b,Aeq,beq,lb,ub,x0,options)xmin 21x′Hx+f′xs.t. Ax≤b Aeq∗x=beq lb≤x≤ub
为了将优化目标函数表示为标准形式,将 x t x_t xt的表达式代入其中得到:
J ( k , N p ) = ( A ~ x k + B ~ U ) ′ Q t ( A ~ x k + B ~ U ) + U ′ R t U = U ′ ( B ~ ′ Q t B ~ + R t ) U + 2 x k ′ A ~ ′ Q ~ B ~ U + x k ′ A ~ ′ Q ~ A ~ x k J_{(k,N_p)}=(\tilde{A}x_k+\tilde{B}U)'Q_t(\tilde{A}x_k+\tilde{B}U)+U'R_tU \\ =U'(\tilde{B}'Q_t\tilde{B}+R_t)U+2x'_k\tilde{A}'\tilde{Q}\tilde{B}U+x_k'\tilde{A}'\tilde{Q}\tilde{A}x_k J(k,Np)=(A~xk+B~U)′Qt(A~xk+B~U)+U′RtU=U′(B~′QtB~+Rt)U+2xk′A~′Q~B~U+xk′A~′Q~A~xk
其中, U U U为优化目标,第三项与优化目标无关,故可以将其省略掉,所以有
H = 2 ( B ~ ′ Q ~ B ~ + R ~ ) f = ( 2 x k ′ A ~ ′ Q ~ B ~ ) H=2(\tilde{B}'\tilde{Q}\tilde{B}+\tilde{R}) \\ f=(2x_k'\tilde{A}'\tilde{Q}\tilde{B}) H=2(B~′Q~B~+R~)f=(2xk′A~′Q~B~)
再根据状态量 x t x_t xt的约束得到A,b(注意这里的A要与系统系数矩阵区别开来)的表达式:
− 5 ≤ A ~ x k + B ~ U ≤ 5 ⇒ { B ~ U ≤ 5 − A ~ x k − B ~ U ≤ 5 + A ~ x k ⇒ [ B ~ − B ~ ] U ≤ [ 5 − A ~ x k 5 + A ~ x k ] -5\leq \tilde{A}x_k+\tilde{B}U\leq 5 \\ \Rightarrow \left\{\begin{matrix} \tilde{B}U\leq 5-\tilde{A}x_k\\ -\tilde{B}U\leq 5+\tilde{A}x_k \end{matrix}\right. \\ \Rightarrow \begin{bmatrix} \tilde{B}\\ -\tilde{B}\end{bmatrix}U\leq \begin{bmatrix}5-\tilde{A}x_k\\5+\tilde{A}x_k\end{bmatrix} −5≤A~xk+B~U≤5⇒{B~U≤5−A~xk−B~U≤5+A~xk⇒[B~−B~]U≤[5−A~xk5+A~xk]
故可得到:
A = [ B ~ − B ~ ] , b = [ 5 − A ~ x k 5 + A ~ x k ] A=\begin{bmatrix} \tilde{B}\\ -\tilde{B}\end{bmatrix},b=\begin{bmatrix}5-\tilde{A}x_k\\5+\tilde{A}x_k\end{bmatrix} A=[B~−B~],b=[5−A~xk5+A~xk]
同样地,可以由输入的约束轻易得到 l b , u b lb,ub lb,ub。至此准备工作完成,可以开始用Matlab实现MPC的优化过程了。
clear; clc; close all;
% 线性系统系数矩阵
A=[1 1; 0 1]; B=[1; 0.5];
% 初始状态量-如果不能在下一步回到约束范围内,则会造成无解
x0=[4; 0];
% 预测步长
Np=5;
% 优化目标参数,加权矩阵
Q=eye(2); R=1;
% 转化为用控制量ut表示的,关于状态量的推导方程的矩阵
At=[]; Bt=[]; temp=[];
% 转换后的加权矩阵
Qt=[]; Rt=[];
% 加权矩阵的计算过程,以及推导方程矩阵的叠加过程
for i=1:Np
At=[At; A^i];
Bt=[Bt zeros(size(Bt,1), size(B,2));
A^(i-1)*B temp];
temp=[A^(i-1)*B temp];
Qt=[Qt zeros(size(Qt,1),size(Q,1));
zeros(size(Q,1),size(Qt,1)) Q];
Rt=[Rt zeros(size(Rt,1),size(R,1));
zeros(size(R,1),size(Rt,1)) R];
end
% 控制量ut的上下限
lb=-1*ones(Np,1);
ub=1*ones(Np,1);
% 控制量ut的初始值
u0=zeros(Np,1);
% 转换后的优化目标函数矩阵,循环优化函数中H后的表达式为优化目标的另一项
H=2*(Bt'*Qt*Bt + Rt);
% 转换后的优化中的不等式约束左边系数矩阵,后面循环中的bi为不等式右边
Ai=[Bt; -Bt];
% 声明u来保存每一步采用的控制量
u=[];
x=x0;
xk=x0;
for k=1:50
% 关于ut的不等式约束,实际上约束的是状态量,常数4就是状态量约束的上下边界
bi=[5-At*xk; 5+At*xk];
% 一切准备就绪,进行二次优化
[ut, fval, exitflag]=quadprog(H,(2*xk'*At'*Qt*Bt)',Ai,bi,[],[],lb,ub,u0);
% 显示求解结果是否正常
fprintf('%d\n', exitflag)
% 采用优化得到的控制量的第一个元素作为实际作用的控制量,代入到原系统中得到下一个时刻的状态量
u(k) = ut(1);
x(:, k+1) = A*x(:, k) + B*u(k);
xk = x(:, k+1);
% 对优化初始值进行修改,采用预测值的后段作为下一步的初始值
u0 = [ut(2:Np); ut(Np)];
end
figure();
plot(x');
legend('x_1','x_2');
figure();
plot(u);
legend('u');
本文只是针对线性系统的MPC做了仿真,并且简化了很多内容。在后期大家可以根据自身的需求,在此基础上进行修改,比如考虑非线性系统,增加输出约束,增加终端代价函数和终端约束来保证稳定性等。或者进一步考虑跟踪,改变预测步长 N p N_p Np来观察其对优化性能的影响,改变优化目标中的代价矩阵观察控制量的变化等等。尽情探索吧,如果有时间我会再更新进一步关于MPC的内容。最后欢迎大家来一起讨论!
应一些朋友的要求,在本文的基础上又更新了一篇关于定点跟踪的文章——自编Matlab代码实现MPC定点跟踪,基本原理不变,对本文的代码做了一些修改,增加了一个作图的功能,感兴趣的朋友可以看看。