作者:金广林
通过 Matlab 的 app designer 可以展示PID三个参数对输出的影响,在这里我并没有使用Simulink仿真的原因是因为不能实时、动态地观察到输出曲线变化,也就是说,如果我们使用Simulink,我们在搭建好仿真结构图后,需要一次又一次地手动设定KP/KI/KD,点击仿真运行后才能观察到曲线。我希望通过调整参数的同时观察到输出曲线的变化,因此采用了界面编程GUI(老版本matlab),也就是高版本的 Matlab 中的 app designer。
设计目标:在鼠标拖动滑块的同时,观察到输出曲线的变化
一、首先需要搭建一个界面图
我所设计的界面如下:
左上角是输入信号选择栏,可以选择阶跃信号或脉冲信号作为输入的信号。
左侧有三个滑块,分别对应KP、KI、KD。
左下角,一个是Generate生成图像,一个是Reset将所有参数恢复默认并清空图像。
右上角,Tab栏是被控系统传递函数的特征方程,我只设到了二次,当然大家也可以设更多次项,Tab2可以以另一种方式表示被控系统,即输入零极点(本人偷懒,若输入正数则视为未输入,毕竟右半平面的零极点不稳定,输出曲线发散,若输入了非正数,则视为填入了零极点后续将会参与运算)
右下角则是输出图像的区域。
二、代码
首先我们需要定义几个函数以便后续调用
第一个是输入特征方程系数的,第二个是输入零极点方式的。
#由于本人不希望输出曲线的纵坐标带小数点因此将输入的阶跃信号扩大了十倍,即R(s)=10/s。
function OUTPUT=PIDtest(KP,KI,KD,a,b,c,in)
syms s
%TF means Transfer_Function
GTF=(KP+KI/s+KD*s)/(c*s^2+b*s+a);
Output_TF=10*GTF/((1+GTF)*s^in);
OUTPUT=ilaplace(Output_TF);
end
function OUTPUT = PIDtest2(KP,KI,KD,p,z,in)
syms s
%TF means Transfer_Function
CTF=1;
for ii=1:length(p)
if imag(p(ii))==0
CTF=(1/(s-p(ii)))*CTF;
else
CTF=(1/(s-conj(p(ii))))*CTF;
end
end
for jj=1:length(z)
if imag(z(jj))==0
CTF=(1/(s-z(jj)))*CTF;
else
CTF=(1/(s-conj(z(jj))))*CTF;
end
end
GTF=(KP+KI/s+KD*s)*CTF;
Output_TF=10*GTF/((1+GTF)*s^in);
OUTPUT=ilaplace(Output_TF);
end
有了这两个函数时候,在app designer 中就可以轻松调用了。
KP、KI、KD三个滑块的代码几乎相同,因此只展示其中KP滑块的代码。
% Value changing function: KPSlider
function KPSliderValueChanging(app, event)
changingValue = event.Value;
KP=changingValue;
KI=app.KISlider.Value;
KD=app.KDSlider.Value;
in=app.StepButton.Value;
if app.Lamp.Color==[0 1 0]
A=app.S0Spinner.Value;
B=app.S1Spinner.Value;
C=app.S2Spinner.Value;
OUTPUT=PIDtest(KP,KI,KD,A,B,C,in);
else
p=[];
P1=app.EditField.Value;
P2=app.EditField_2.Value;
P3=app.EditField_3.Value;
P4=app.EditField_4.Value;
Z1=app.EditField_5.Value;
Z2=app.EditField_6.Value;
if P1<0||P1==0
p=[p P1];
end
if P2<0||P2==0
p=[p P2];
end
if P3<0||P3==0
p=[p P3];
end
if P4<0||P4==0
p=[p P4];
end
z=[];
if real(Z1)<0||real(Z1)==0
z=[z Z1];
end
if real(Z2)<0||real(Z2)==0
z=[z Z2];
end
OUTPUT=PIDtest2(KP,KI,KD,p,z,in);
end
fplot(app.UIAxes,OUTPUT,[0 50])
grid(app.UIAxes,"on")
end
Reset 按键代码:
% Button pushed function: ResetButton
function ResetButtonPushed(app, event)
app.KPSlider.Limits=[1,15];
app.KISlider.Limits=[0,3];
app.KDSlider.Limits=[0,20];
app.KPSlider.Value=1;
app.KISlider.Value=0;
app.KDSlider.Value=0;
app.StepButton.Value=1;
app.ImpulseButton.Value=0;
app.Spinner_4.Value=15;
app.Spinner_5.Value=3;
app.Spinner_6.Value=20;
app.XlabelSpinner.Value=20;
app.YlabelSpinner.Value=20;
app.UIAxes.XLim=[0 20];
app.UIAxes.YLim=[-10 20];
app.EditField.Value=1;
app.EditField_2.Value=1;
app.EditField_3.Value=1;
app.EditField_4.Value=1;
app.EditField_5.Value=1;
app.EditField_6.Value=1;
app.S0Spinner.Value=1;
app.S1Spinner.Value=1;
app.S2Spinner.Value=1;
GenerateButtonPushed(app, event)
end
Generate 按键代码:
% Button pushed function: GenerateButton
function GenerateButtonPushed(app, event)
KP=app.KPSlider.Value;
KI=app.KISlider.Value;
KD=app.KDSlider.Value;
in=app.StepButton.Value;
if app.Lamp.Color==[0 1 0]
A=app.S0Spinner.Value;
B=app.S1Spinner.Value;
C=app.S2Spinner.Value;
OUTPUT=PIDtest(KP,KI,KD,A,B,C,in);
else
p=[];
P1=app.EditField.Value;
P2=app.EditField_2.Value;
P3=app.EditField_3.Value;
P4=app.EditField_4.Value;
Z1=app.EditField_5.Value;
Z2=app.EditField_6.Value;
if P1<0||P1==0
p=[p P1];
end
if P2<0||P2==0
p=[p P2];
end
if P3<0||P3==0
p=[p P3];
end
if P4<0||P4==0
p=[p P4];
end
z=[];
if real(Z1)<0||real(Z1)==0
z=[z Z1];
end
if real(Z2)<0||real(Z2)==0
z=[z Z2];
end
OUTPUT=PIDtest2(KP,KI,KD,p,z,in);
end
fplot(app.UIAxes,OUTPUT,[0 50])
end
其他关于设置坐标刻度、字体大小、颜色、刻度上限等代码省略
后续文章将展示PID三个参数作用的结论。
代码已开源:
https://github.com/JihnGlyn/PID-Visualizer-crafted-by-Matlab-GUI.git