参考资料 :刘金琨《先进PID控制MATLAB仿真(第四版)》
一、位置式与增量式
% 基础 PID 控制器
% PID 控制器分为 位置式和增量式
% 位置式 u = kp*e + ki*ei + kd*(e - e_1)/ts ei = ei + e*ts
% 增量式 u = u_1 + delta_u delta_u = kp*(e - e_1) + ki*e + kd*(e - 2*e_1 + e_2)
clear all;
close all;
ts = 0.01;
a = 25;
b = 133;
sys = tf(a,[1 b 0]);
dsys = c2d(sys,ts,'z');
[num,den] = tfdata(dsys,'v');
upos_2 = 0; upos_1 = 0;
ypos_2 = 0; ypos_1 = 0;
epos_2 = 0; epos_1 = 0;
ei = 0;
uinc_2 = 0; uinc_1 = 0;
yinc_2 = 0; yinc_1 = 0;
einc_2 = 0; einc_1 = 0;
kp_pos = 80; ki_pos = 1; kd_pos = 0;
kp_inc = 140; ki_inc = 0.3; kd_inc = 0;
for k = 1:1:2000
time(k) = k*ts;
if k <= 500 % 输入信号
r(k) = sin(time(k));
else
r(k) = 1;
end
ypos(k) = -den(3)*ypos_2 - den(2)*ypos_1 + num(3)*upos_2 + num(2)*upos_1;
yinc(k) = -den(3)*yinc_2 - den(2)*yinc_1 + num(3)*uinc_2 + num(2)*uinc_1;
epos(k) = r(k) - ypos(k); % 位置式 PID 的误差以及ki的乘积项ei
ei = ei + epos(k)*ts;
einc(k) = r(k) - yinc(k); % 增量式 PID 的误差以及ki的乘积项ei
u_pos(k) = kp_pos*epos(k) + ki_pos*ei + kd_pos*(epos(k) - epos_1)/ts; % 位置式 PID 控制器
deltau(k) = kp_inc*(einc(k) - einc_1) + ki_inc*einc(k) + kd_inc*(einc(k) - 2*einc_1 + einc_2); % 增量式 PID 控制器 ∆u + u_1
u_inc(k) = uinc_1 + deltau(k);
upos_2 = upos_1; upos_1 = u_pos(k); % 位置式 PID 状态、输出、误差更新
ypos_2 = ypos_1; ypos_1 = ypos(k);
epos_2 = epos_1; epos_1 = epos(k);
uinc_2 = uinc_1; uinc_1 = u_inc(k); % 增量式 PID 状态、输出、误差更新
yinc_2 = yinc_1; yinc_1 = yinc(k);
einc_2 = einc_1; einc_1 = einc(k);
end
figure(1)
plot(time,r,'k',time,ypos,'b',time,yinc,'r');grid
仿真结果如图所示:
如果PID参数都改成相同(kp = 80; ki = 1; kd = 0;)的话:
数据还是有所区别的
二、几种基础的PID控制器
以位置式PID为例:
clear all;
close all;
ts = 0.01;
a = 25;
b = 133;
sys = tf(a,[1 b 0]);
dsys = c2d(sys,ts,'z');
[num,den] = tfdata(dsys,'v');
A = 0.04;
B = 0.06;
u_max = 8;
u_min = -8;
u_2 = 0; u_1 = 0;
y_2 = 0; y_1 = 0;
e_2 = 0; e_1 = 0;
ei = 0;
kp = 80; ki = 0.35; kd = 0;
for k = 1:1:2000
time(k) = k*ts;
r(k) = sin(time(k));
dr(k) = cos(time(k));
ddr(k) = -sin(time(k));
y(k) = -den(3)*y_2 - den(2)*y_1 + num(3)*u_2 + num(2)*u_1;
e(k) = r(k) - y(k);
% 变速积分PID(未使用)
% 系统对积分的要求是:系统偏差大时积分作用应减弱;偏差小时应加强
% 通过 fe 参数控制 fe*ki
% if abs(e(k)) <= B
% fe = 1;
% elseif abs(e(k)) > A + B
% fe = 0;
% else
% fe = (A - abs(e(k) + B))/A;
% end
% 带死区的PID
% 避免控制作用过于频繁,从而消除由于频繁动作所引起的震荡
if abs(e(k)) <= 0.005
e(k) = 0;
end
% ei = ei + fe*e(k)*ts;
ei = ei + e(k)*ts;
% 积分分离PID : 当误差过大时
% 采用PD控制,可避免产生超调;
% 否则采用PID控制
% 通过 beta*ki 实现
if abs(e(k)) >= 0.1
beta = 0;
elseif abs(e(k)) <= 0.05
beta = 1;
end
u(k) = kp*e(k) + beta*ki*ei + kd*(e(k) - e_1)/ts;
% 抗积分饱和PID
% 当状态达到饱和情况时不再增大,只累计负偏差
% 可以避免控制量长时间停留在饱和区
if u(k) > u_max
u(k) = u_max;
elseif u(k) < u_min
u(k) = u_min;
end
% 基于前馈补偿的PID
% 在高精度伺服系统中,前馈控制可用来提高系统的跟踪性能
% 前馈环节与闭环系统的传递函数之积为1,从而实现在输出处完全复现输入
% ut = up + uf;
uf = 25/133*dr(k) + 1/133*ddr(k);
u(k) = u(k) + uf;
u_2 = u_1; u_1 = u(k);
y_2 = y_1; y_1 = y(k);
e_2 = e_1; e_1 = e(k);
end
figure(1)
plot(time,r,'k',time,y,'b');grid
figure(2)
plot(time,e,'b')
figure(3)
plot(time,u,'b')
仿真结果如下:
1、输出跟踪输入
2、误差 e(t)
3、状态变量 u(t)
Ps: 我个人认为这几种基础的控制器实现方式是只加上了一些限制条件,好像确实有些道理,可能我现在只是仍然处于仿真阶段,在实际应用中这些控制器的作用可能会更加重要