问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Matlab自动化控制-Adrc自抗扰控制

创作时间:
作者:
@小白创作中心

Matlab自动化控制-Adrc自抗扰控制

引用
1
来源
1.
https://cloud.tencent.com/developer/article/2058051

自抗扰控制(ADRC)是一种结合了经典PID控制和现代控制理论的新型控制方法。它由韩京清教授提出,具有对被控对象的数学模型要求低、抗干扰能力强等特点。本文将详细介绍ADRC的三个主要组成部分:跟踪微分器(TD)、非线性状态反馈和扩张观测器(ESO),并提供MATLAB/Simulink的实现代码。

跟踪微分器(TD)

跟踪微分器是一个单输入双输出的模块,主要作用有两个:

  1. 避免输入量突变,便于实际系统实时跟踪
  2. 过滤高频噪声

其输出效果图如下(输入为阶跃信号):

蓝色为处理后的阶跃信号,黄色为微分。

TD公式

Simulink仿真模型中,TD可以用以下代码实现:

function out = hfst(u1,u2,r,h)
d=r*h;
d0=h*d;
y=u1+h*u2;
a0=sqrt(d*d+8*r*abs(y));
a=0;
out1=0;
if abs(y)>d0
    a=u2+(a0-d)/2*sign(y);
end
if abs(y)<=d0
    a=u2+y/h;
end
if abs(a)>d
    out1=-r*sign(a);
end
if abs(a)<=d
    out1=-r*a/d;
end
out=out1;
end  

或者,也可以直接用M脚本实现:

function [y1k,y2k] = fcn(u)
persistent y1k_1 y2k_1
h=0.01;
delta=10;
if isempty(y1k_1)
    y1k_1=0;
end
if isempty(y2k_1)
    y2k_1=0;
end
y1k=y1k_1+h*y2k_1;
% hfst计算内容
d=delta*h;
d0=h*d;
y=y1k_1-u+h*y2k_1;
a0=sqrt(d*d+8*delta*abs(y));
a=0;
out1=0;
if abs(y)>d0
    a=y2k_1+(a0-d)/2*sign(y);
end
if abs(y)<=d0
    a=y2k_1+y/h;
end
if abs(a)>d
    out1=-delta*sign(a);
end
if abs(a)<=d
    out1=-delta*a/d;
end
out=out1;
% 更新变量
y2k=y2k_1+h*out;
y1k_1=y1k;
y2k_1=y2k;
end  

验证效果的代码如下:

t = 0:0.01:2;
u = zeros(length(t), 1);
u (t >=1) = 1;
figure
plot(t,u)
y1k = zeros(length(t), 1);
y2k = zeros(length(t), 1);
for i = 1:length(t)
    [y1k(i),y2k(i)] = fcn(u(i));
end
figure
plot(t,y1k)
figure
plot(t,y2k)  

TD模型涉及两个调参:δ和h,h为采样周期,δ决定跟踪快慢(δ越大,过滤后的输出越接近输入)。一般的仿真模型r可以尽量大一些,在100~500范围内基本相同,即使再大效果也基本不会有大的提升。

非线性组合

这一部分对应第一张图中的非线性组合模块,这一模块为双输入单输出,输入的是两个误差,分别是指令信号差和指令信号微分的差,参考指令信号和参考指令信号的微分均由TD产生。

传统的PID或者PD控制就是比例、积分、微分的线性加权之和,但这种线性的组合不是最佳的,后来发现三者的非线性组合效果更好。最常用的就是PD形式的非线性组合:

对比一下传统PID和非线性PID:

sys = tf([133],[1,25,0])
dsys = c2d(sys,0.001,'z');
[num,den]=tfdata(dsys,'v');  

非线性PD控制的函数模块代码如下:

function y =nonlinear_pd(e1,e2)
alfa1=0.75;
alfa2=1.5;
delta=0.002;
beta1=150;
beta2=1;
fal1=1;
fal2=1;
if abs(e1)<=delta
    fal1=e1/(delta^(1-alfa1));
end
if abs(e1)>delta
    fal1=(abs(e1))^(alfa1)*sign(e1);
end
if abs(e2)<=delta
    fal2=e2/(delta^(1-alfa2));
end
if abs(e2)>delta
    fal2=(abs(e2))^(alfa2)*sign(e2);
end
y=beta1*fal1+beta2*fal2;
end  

可见效果好多了,因此非线性PID有效果!!!!!!

ESO扩张观测器

ESO是一个双输入单输出模块,输入的值为对象的输出以及对象的控制输入,见第一张图,而输出有三个,分别是对象输出的估计值、对象输出的估计值的一阶导数、对象输出的估计值的二阶导数。而对象输出的估计值、对象输出的估计值的一阶导数将反馈给最开始的跟踪微分器(TD),而对象输出的估计值的二阶导数将反馈给非线性组合的输出上用于弥补扰动。

一般观测器仅观测系统的状态,只有输出和输出的导数(速度)。但是这里对输出的导数的导数(加速度)也进行了观测,这里也就是所谓的扰动(即第一张图中的w),对扰动进行了观测。观测器的状态量也由此扩张了一维,因此叫做扩张观测器。

ESO的公式见下图:

Simulink fcn模型的代码如下:

function [z1_k,z2_k,z3_k] = ESO(yk,uk)
%%参数初始化
persistent  z1_k_1 z2_k_1 z3_k_1
bata01=30;
beta02=300;
beta03=1000;
b=5;
h=0.001;
alfa1=0.25;
alfa2=0.5;
delta=0.002;
fal1=1;
fal2=1;
if isempty(z1_k_1)
    z1_k_1=0;
end
if isempty(z2_k_1)
    z2_k_1=0;
end
if isempty(z3_k_1)
    z3_k_1=0;
end
e1=z1_k_1-yk;
z1_k=z1_k_1+h*z2_k_1-bata01*e1;
z1_k_1=z1_k; %%迭代更新z1_k_1
%%计算fal函数
if abs(e1)<=delta
    fal1=e1/(delta^(1-alfa1));
end
if abs(e1)>delta
    fal1=(abs(e1))^(alfa1)*sign(e1);
end
if abs(e1)<=delta
    fal2=e1/(delta^(1-alfa2));
end
if abs(e1)>delta
    fal2=(abs(e1))^(alfa2)*sign(e1);
end
z2_k=z2_k_1+h*(z3_k_1+b*uk)-beta02*fal1;
z2_k_1=z2_k;%%迭代更新z2_k_1
z3_k=z3_k_1-h*beta03*fal2;
z3_k_1=z3_k;%%迭代更新z3_k_1
end  

但要注意:因为ESO的公式里面已经加入了b*u,所以在搭最后的模型时第一张图中的b0就不要了,即不用再乘上b0,直接将补偿后的u输入ESO。同理,如果你要在similink模型里要显示用上b0这个比例系数,那么ESO里的公式里就要改为:

z2_k=z2_k_1+h*(z3_k_1-beta02*fal1+uk);即去掉最后的uk前的系数b

完整的ADRC

这一节将把前面的组合起来构成一个完整的ADRC,也就是第一张图中的形式。搭好的结构如下:

注意点:

  1. 因为这是一个离散的模型,所以确保所有模块的采样时间一致
  2. 注意检查所有的求和模块的正负
  3. 注意上面第三节的黑色注意部分

开始仿真,报错了:

翻译过来就是说存在代数环的原因

这个问题很很好理解,我们知道,我们在求解反馈环的时候,首先反馈的初始值是为o的,也就是反馈系统的顺序是:我们先根据主路输入计算得到主路的输出(即得到反馈路的输入),在根据反馈路的输入计算出反馈路的输出(即反馈值),然后进行下一次循环。而在simulink中,他不像我们之前写的m脚本(我们自己写脚本就是从主路开始),他不知道首先应该计算主路还是首先计算反馈路,所以我们需要告诉他,解决办法就是在反馈路的输出端加上单位延迟,也就是告诉反馈路你等等,别太急,等主路先走。

其实我们还可以这样去理解代数环,将其理解为初始状态时反馈量没有初始值,我们以前的控制模型比如pid啥的,我们反馈的反馈量都会有一个初始值,而这个模型的ESO的输出作为反馈量是没有初始值的,所以他报错的原因还可以理解为反馈量没有初始值,所以我们就去给反馈量设一个初始值,我们就可以用memory模块(这个模块的作用就是有输入时输出=输入,没输入时输出保持原先状态,且当输入改变时输出才改变,否则一直保持输出不变),在memory模块里设置一个初始值,这样反馈量就有初始值了。而上面我们用的单位延迟模块就是一个memory模块,二者本来就是一样的。所以上面用单位延迟模块也可以这样理解。

修改后的simulink为:

或者(两者等价):

仿真后结果没报错,且结果令人满意:

其中黄色为初始阶跃信号,红色为经过TD的信号,蓝色为控制输出。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号