Matlab仿真PID控制(带M文件、simulink截图和参数分析)

文章目录

  • 0.符号说明
  • 1.如何根据连续系统建立差分方程
    • 1.1.获取连续系统的传递函数
    • 1.2.获取离散系统的传递函数
    • 1.3.转换为差分方程
  • 2.基本PID控制原理
  • 3.比较PID输出,分析参数产生的影响
  • 4.改进PID算法(遇限削弱积分法)
  • 5.simulink仿真

0.符号说明

  1. y(k)——系统响应输出的离散值
  2. u(k)——数字PID控制输出的离散值
  3. r(k)——期望输出的离散值(事先已知),在本例中为常数(即阶跃输入)
  4. e(k)——e(k)=r(k)-y(k),为期望值-实际值,是单位负反馈的误差比较信号
    图片来源于百度百科
    注:图片来源于百度百科

1.如何根据连续系统建立差分方程

1.1.获取连续系统的传递函数

线性定常系统的控制中,PID是个非常常见的控制方式,如果可以通过Matlab仿真出PID的控制效果图,那么对系统设计时的实时调试将会容易得多。在这里我们将会以一个利用系统辨识参数的PID设计为为例展示Matlab仿真PID的过程。
首先需要对一个未知的系统的参数进行辨识,以延迟环节可以忽略不计的电机调速系统为例。将时间戳导入xdata向量,对应的时刻转速导入ydata向量,进行系统辨识

链接:Matlab的系统辨识

我们就以上文链接中辨识的系统传递函数为例:
G(s)=0.9980.021s+1G(s)=\frac{0.998}{0.021s+1}G(s)=0.021s+10.998因此通过tf函数建立系统结构体如下:

sys=tf(0.998,[0.021,1]);   %建立被控对象传递函数,即式4.1

1.2.获取离散系统的传递函数

由于是数字PID仿真,我们需要选取一个采样时间,本案例选用的是0.005s(注意,采样周期应该小于系统纯滞后时间的0.1倍)。在对其进行数字PID控制前,我们需要将这个系统离散化:

ts=0.005;  %采样时间=0.005s
dsys=c2d(sys,ts,'z');      %离散化

dsys即我们根据采样周期离散化的Z变换系统。首先我们需要提取这个Z变化d那系统的参数方便后面的计算:

[num,den]=tfdata(dsys,'v');%'v'代表强制以向量的格式(默认为元胞数组)输出num和den

1.3.转换为差分方程

求解出的Z变换表达式为dsys=num(1)⋅z+num(2)den(1)⋅z+den(2)=0.2114z−0.7881dsys=\frac{num(1)\cdot z +num(2)}{den(1)\cdot z+den(2)}=\frac{0.2114}{z-0.7881}dsys=den(1)z+den(2)num(1)z+num(2)=z0.78810.2114
在PID仿真的过程中我们需要求解出时域表达式 ,因此需要借助差分方程解决,对于以下的Z变换:

\begin{equation}
Y(z)=dsys\cdot U(z)=\frac{num(2)}{den(1)\cdot z+den(2)}\cdot U(z)
\label{eq:Sample1}
\end{equation}

\begin{equation}
zY(z)+den(2)Y(z)=num(1)zU(z)+num(2)U(z)
\label{eq:Sample2}
\end{equation}
对上式进行反Z变换,可以得到以下的差分方程:

\begin{equation}
y(k+1)+den(2)y(k)=num(1)u(k+1)+num(2)u(k)
\label{eq:Sample3}
\end{equation}

\begin{equation}
y(k+1)=-den(2)y(k)+num(1)u(k+1)+num(2)u(k)
\label{eq:Sample4}
\end{equation}
位置型PID仿真时实际上可以不需要保存前一个数据(u(k)和y(k)),增量型PID必须要保存前一个数据。这里我们使用了位置型PID,但仍然利用u1u_1u1y1y_1y1保存了上一个数据,仅仅是为了演示这一过程。\begin{equation}
y(k+1)=-den(2)y(k)+num(1)u(k+1)+num(2)u(k)
\end{equation}
可以转换为下面的式子:
\begin{equation}
y(k)=-den(2)y_1+num(1)u(k)+num(2)u_1
\label{eq:Sample5}
\end{equation}
我们的差分方程就这样建立完毕。注意,此差分方程仅仅是描述系统模型的运算规律的,和我们的控制无关。因此是y(k)和u(k)的映射关系。我们下面的控制则是利用负反馈信号e(k)导出u(k)的输出,求解的是控制器u(k)的序列值。

2.基本PID控制原理

以位置型PID控制为例。将连续的PID控制转换为数字式时,微分环节被用差分代替,积分环节被累加和代替,比例环节则保持不变。差分的实现非常简单,只需要用e(k+1)−e(k)e(k+1)-e(k)e(k+1)e(k)e(k)−e1e(k)-e_1e(k)e1等效即可。积分的实现在每一次运算的后面都累加原来的误差,即Ee=Ee+e_1;即可。PID的控制器输出u(k)=Kp⋅e(k)+Kd⋅(e(k)−e1)+Ki⋅Eeu(k)=Kp\cdot e(k)+Kd\cdot (e(k)-e_1)+Ki\cdot Eeu(k)=Kpe(k)+Kd(e(k)e1)+KiEe
PID控制器构造完毕,我们需要通过r(k)和y(k)得到e(k),再通过e(k)得出u(k),进而再求解出y(k),再结合r(k)求解出e(k),…以此循环,求解出离散的响应点。
详细的代码如下:

ts=0.005;  %采样时间=0.005s
sys=tf(0.998,[0.021,1]);   %建立被控对象传递函数,即式4.1
dsys=c2d(sys,ts,'z');      %离散化
[num,den]=tfdata(dsys,'v');   %
e_1=0;      %前一时刻的偏差      
Ee=0;       %累积偏差
u_1=0.0;    %前一时刻的控制量
y_1=0;       %前一时刻的输出
%PID参数
kp=0.22;    
ki=0.13;
kd=0;
u=zeros(1,1000);%预先分配内存
time=zeros(1,1000);%时刻点(设定1000个)
for k=1:1:1000time(k)=k*ts;   %时间参数r(k)=1500;      %期望值y(k)=-1*den(2)*y_1+num(2)*u_1+num(1)*u(k);%系统响应输出序列e(k)=r(k)-y(k);   %误差信号u(k)=kp*e(k)+ki*Ee+kd*(e(k)-e_1); %系统PID控制器输出序列Ee=Ee+e(k);    %误差的累加和u_1=u(k);    	%前一个的控制器输出值y_1=y(k);    	%前一个的系统响应输出值e_1=e(k);		%前一个误差信号的值
end
%(仅绘制过渡过程的曲线,x坐标限制为[0,1])
p1=plot(time,r,'-.');xlim([0,1]);hold on;%指令信号的曲线(即期望输入)
p2=plot(time,y,'--');xlim([0,1]);%不含积分分离的PID曲线
hold on;

输出的PID控制曲线如下:
PID控制

3.比较PID输出,分析参数产生的影响

一个基本的PID就完成了。下面如果我们想要知道修改PID的三个参数kp,ki,kd会带来什么效果,只需要在程序中修改即可。为了方便起见,我们建立一个PID的数组,kp,ki,kd每次都取数组的一个值,然后设定一个大循环开始循环仿真。再利用subplot输出子图的方式将所有的PID效果都输出到一个图进行对比。该代码根据上述代码修改已经很容易,PID比较图的代码如下:

close all
PID=[0.22,0.13,0;0.4,0.13,0;0.4,0.25,0;0.8,0.23,0.4;0.8,0.2,1;0.7,0.2,0.9];%初始化PID参数
for pid=1:1:6
ts=0.005;  %采样时间=0.005s
sys=tf(0.998,[0.021,1]);   %建立被控对象传递函数,即式4.1
dsys=c2d(sys,ts,'z');      %离散化
[num,den]=tfdata(dsys,'v');   %
e_1=0;      %前一时刻的偏差      
Ee=0;       %累积偏差
u_1=0.0;    %前一时刻的控制量
y_1=0;       %前一时刻的输出
%PID参数
kp=PID(pid,1);    
ki=PID(pid,2);
kd=PID(pid,3);
u=zeros(1,1000);
time=zeros(1,1000);
for k=1:1:1000time(k)=k*ts;   %时间参数r(k)=1500;      %给定量y(k)=-1*den(2)*y_1+num(2)*u_1+num(1)*u(k);e(k)=r(k)-y(k);   %偏差u(k)=kp*e(k)+ki*Ee+kd*(e(k)-e_1);   Ee=Ee+e(k);    u_1=u(k);    y_1=y(k);    e_1=e(k);
end
subplot(2,3,pid);
p1=plot(time,r,'-.');xlim([0,1]);hold on;
p2=plot(time,y,'--');xlim([0,1]);
title(['Kp=',num2str(kp),' Ki=',num2str(ki),' Kd= ',num2str(kd)]);
hold on;
end

输出的子图矩阵如下:
PID子图矩阵
可以发现,修改Kp会造成上升时间的缩短,但是有可能也会带来较大的超调。积分的增加是一个严重的滞后环节,会减小相位裕度,也会带来超调(超调量并不是绝对的,相对于较小的Kp可能会产生较大的超调,而Kp较大时超调会减小(例如第一行的1图和2图的对比))。然而积分的引入也是必要的,否则将会很长时间无法削弱误差e(k)(例如第二行第二个图)。微分的引入相当于一个超前校正,会减少超调,但是过渡的微分很可能会造成尾部振荡,系统逐渐变得不稳定。因此微分和积分之间需要一个平衡,当满足这个平衡的时候,系统几乎没有振荡,同时响应速度也较快。(第一行的图3是积分过多,产生超调,第二行的图1和图3就比较理想)
综合上述,PID的调节经验可以归结为以下几点:

  • Kp较小时,系统对微分和积分环节的引入较为敏感,积分会引起超调,微分可能会引起振荡,而振荡剧烈的时候超铁也会增加。
  • Kp增大时,积分环节由于滞后产生的超调逐渐减小,此时如果想要继续减少超调可以适当引入微分环节。继续增大Kp系统可能会不太稳定,因此在增加Kp的同时引入Kd减小超调,可以保证在Kp不是很大的情况下也能取得较好的稳态特性和动态性能。
  • Kp较小时,积分环节不宜过大,Kp较大时积分环节也不宜过小(否则调节时间会非常地长),在下面这个例子中我们还会介绍到,当使用分段PID,在恰当的条件下分离积分,可以取得更好的控制效果。原因在于在稳态误差即将满足要求时,消除了系统的滞后。因此系统超调会明显减少。本例中采样的抗积分饱和的方法是遇限削弱积分法。

4.改进PID算法(遇限削弱积分法)

遇限削弱积分法的原理是
u(k)>umaxu(k)>u_{max}u(k)>umax时,若e(k)>0即输出值还未到达指定值,则认为积分会带来滞后,不再积分。
u(k)<0u(k)<0u(k)<0时,若e(k)<0即输出值超过了指定值,则认为积分会带来滞后,不再积分。
在本案例中认为umax=r(k)u_{max}=r(k)umax=r(k)
改进PID算法如下(需要些两个循环,当然也可以用一个循环,将其中的PID设为一个子过程调用):

close all
ts=0.005;  %采样时间=0.005s
sys=tf(0.998,[0.021,1]);   %建立被控对象传递函数,即式4.1
dsys=c2d(sys,ts,'z');      %离散化
[num,den]=tfdata(dsys,'v');   %
e_1=0;      %前一时刻的偏差      
Ee=0;       %累积偏差
u_1=0.0;    %前一时刻的控制量
y_1=0;       %前一时刻的输出
%PID参数
kp=0.22;    
ki=0.13;
kd=0;
u=zeros(1,1000);
time=zeros(1,1000);
for k=1:1:1000time(k)=k*ts;   %时间参数r(k)=1500;      %给定量y(k)=-1*den(2)*y_1+num(2)*u_1+num(1)*u(k);e(k)=r(k)-y(k);   %偏差u(k)=kp*e(k)+ki*Ee+kd*(e(k)-e_1);   Ee=Ee+e(k);    u_1=u(k);    y_1=y(k);    e_1=e(k);
end
p1=plot(time,r,'-.');xlim([0,1]);hold on;
p2=plot(time,y,'--');xlim([0,1]);
hold on;
a=1;%控制积分分离的二值数
e_1=0;Ee=0;u_1=0.0;y_1=0;%重新初始化       
for k=1:1:1000time(k)=k*ts;   %时间参数r(k)=1500;      %给定量y(k)=-1*den(2)*y_1+num(2)*u_1;e(k)=r(k)-y(k);   %偏差u(k)=kp*e(k)+ki*Ee+kd*(e(k)-e_1);   if ((u(k)>r(k)) && (e(k)>0))||((u(k)<0) && (e(k)<0))a=0;else a=1;end     Ee=Ee+a*e(k);    u_1=u(k);    y_1=y(k);    e_1=e(k);
end
p3=plot(time,y,'-');xlim([0,1]);
title('含积分分离与不含积分分离的对比');
legend([p1,p2,p3],'指令信号','不含积分分离','含积分分离');

输出的曲线对比图如下:
积分分离之后的改进PID
可以发现,系统的超调量明显减少了,调节时间也减少了一点。原因在于我们采用了分段PID的手段,既消除了稳态误差还削弱了积分环节带来的滞后影响。

5.simulink仿真

需要的模块名称(不区分大小写)如下:

  • gain(参数分别为0.22和0.13/0.005)
  • sum(参数分别为"|±"和"|++")
  • integrator
  • scope
    注意:本文使用的是离散PID仿真,而simulink使用的是连续系统仿真,转换PID参数时P参数不变,I参数应该除以仿真间隔Ts=0.005,D参数应该乘Ts。

以表中第一组PI参数为例:
在这里插入图片描述
得到的示波器曲线如下:
在这里插入图片描述

希望本文对您有帮助,谢谢阅读。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544533.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

再见 Postman!Apifox 才是 YYDS!

作为开软件开发从业者&#xff0c;API 调试是必不可少的一项技能&#xff0c;在这方面 Postman 做的非常出色。但是在整个软件开发过程中&#xff0c;API 调试只是其中的一部分&#xff0c;还有很多事情 Postman 无法完成&#xff0c;或者无法高效完成&#xff0c;比如&#xf…

Python operator.not_()函数与示例

operator.not_()函数 (operator.not_() Function) operator.not_() function is a library function of operator module, it is used to perform "NOT operation" on a given value and returns True if the given value is zero or any falsy value, False, otherw…

jprofiler安装与使用

1&#xff1a; 修改/etc/profile 增加以下内容&#xff1a; JPROFILER_HOME/opt/jprofiler9/bin/linux-x64export LD_LIBRARY_PATH$LD_LIBRARY_PATH:$JPROFILER_HOME 2&#xff1a;tomcat /bin/catalina.sh 增加以下内容&#xff1a; CATALINA_OPTS"$CATALINA_OPTS -Xms12…

Matlab【可视化作图】绘制线电压相电压辅助线

目录引言绘图原理采点绘图设置坐标轴标尺引言 学习电力电子的同学可能在私下里练习的时候非常需要三相线电压和相电压的辅助线。最近我随便找了一本书把Matlab可视化编程恶补了一下&#xff0c;给大家介绍一下这个波形辅助线是怎么做的。 三相线电压辅助线就是一组相位相差60的…

SpringBoot实现Excel导入导出,好用到爆,POI可以扔掉了!

在我们平时工作中经常会遇到要操作Excel的功能&#xff0c;比如导出个用户信息或者订单信息的Excel报表。你肯定听说过POI这个东西&#xff0c;可以实现。但是POI实现的API确实很麻烦&#xff0c;它需要写那种逐行解析的代码&#xff08;类似Xml解析&#xff09;。今天给大家推…

Python datetime __str __()方法与示例

Python datetime .__ str __()方法 (Python datetime.__str__() Method) datetime.__str__() method is used to manipulate objects of datetime class of module datetime. datetime .__ str __()方法用于操作模块datetime的datetime类的对象。 It uses a datetime class o…

Facebook升级到MySQL 8.0付出的代价

近日&#xff0c;Facebook 官博公布了他们的数据库版本从 MySQL 5.6 升级到了 MySQL 8.0&#xff0c;并且在官博记录了复盘详细的升级过程。Facebook 称&#xff0c;他们最近的一次大版本升级到 MySQL 5.6 花了一年多时间才完成&#xff0c;还在 5.6 版上开发 LSM 树存储引擎&a…

Matlab制作朱利表

朱利判据 其中 {bn−kan−k−ana0∗akcn−kbn−k−bnb0∗bk...qn−kpn−k−pnp0∗pk\begin{cases} b_{n-k}a_{n-k}-\frac{a_n}{a_0}*a_k\\ c_{n-k}b_{n-k}-\frac{b_n}{b_0}*b_k\\ ...\\ q_{n-k}p_{n-k}-\frac{p_n}{p_0}*p_k \end{cases}⎩⎪⎪⎪⎨⎪⎪⎪⎧​bn−k​an−k​−a0…

HDOJ 1047 Integer Inquiry

JAVA睑板.... Integer Inquiry Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 12042 Accepted Submission(s): 3037Problem DescriptionOne of the first users of BITs new supercomputer was Chip Diller. …

高并发下秒杀商品,必须知道的9个细节

高并发下如何设计秒杀系统&#xff1f;这是一个高频面试题。这个问题看似简单&#xff0c;但是里面的水很深&#xff0c;它考查的是高并发场景下&#xff0c;从前端到后端多方面的知识。秒杀一般出现在商城的促销活动中&#xff0c;指定了一定数量&#xff08;比如&#xff1a;…

weakhashmap_Java WeakHashMap keySet()方法与示例

weakhashmapWeakHashMap类的keySet()方法 (WeakHashMap Class keySet() method) keySet() method is available in java.util package. keySet()方法在java.util包中可用。 keySet() method is used to retrieve all the key exists in this map to be viewed in a set. keySet…

最小拍控制系统详细解读(阶跃输入+速度输入2个案例)【Simulink仿真】

目录索引1.符号说明与结构框图2.最小拍控制系统构造原则2.1数字控制器D(z)的构造3.简单控制对象的最小拍控制器设计3.1阶跃输入3.2速度输入1.符号说明与结构框图 y(k)——系统响应输出的离散值u(k)——数字PID控制输出的离散值r(k)——期望输出的离散值&#xff08;事先已知&a…

php中重写和final关键字的使用

为什么把重写和final放在一起&#xff0c;原因就是一条&#xff1a;final的意思是不可更改的&#xff0c;也就是说final定义的东西是不可改变的&#xff0c;下面具体来说一下。 来看一段简单的代码&#xff1a; 1 class BaseClass {2 final public function test() {3 …

java vector_Java Vector lastElement()方法与示例

java vector向量类的lastElement()方法 (Vector Class lastElement() method) lastElement() method is available in java.util package. lastElement()方法在java.util包中可用。 lastElement() method is used to return the last element of this Vector. lastElement()方法…

SpringBoot官方热部署和远程调试神器,真带劲!

平时使用SpringBoot开发应用时&#xff0c;修改代码后需要重新启动才能生效。如果你的应用足够大的话&#xff0c;启动可能需要好几分钟。有没有什么办法可以加速启动过程&#xff0c;让我们开发应用代码更高效呢&#xff1f;今天给大家推荐一款SpringBoot官方的热部署工具spri…

【Python】输入任意个数元素并保存至列表

目录1.导入任意个数元素到列表1.1.编程思路1.2.代码片2.查找一个重复元素在列表中的所有位置2.1.编程思路2.2代码片1.导入任意个数元素到列表 1.1.编程思路 输入未知个数的元素需要用列表来存储&#xff0c;由于Python具有内存的动态分配能力&#xff0c;列表不需要手动动态分…

MySQL 性能优化的 9 种姿势,面试再也不怕了!

大家好&#xff0c;我是磊哥&#xff01;今天给大家分享一些简单好用的数据库优化方式&#xff01;1、选择最合适的字段属性Mysql是一种关系型数据库&#xff0c;可以很好地支持大数据量的存储&#xff0c;但是一般来说&#xff0c;数据库中的表越小&#xff0c;在它上面执行的…

containsall_Java Vector containsAll()方法与示例

containsall向量类containsAll()方法 (Vector Class containsAll() method) containsAll() method is available in java.util package. containsAll()方法在java.util包中可用。 containsAll() method is used to test the existence of all the elements of this Vector in t…

Excel的规划求解【详细步骤】

本文目录1.说明2.准备加载项步骤1步骤2步骤33.线性规划问题步骤4步骤5步骤61.说明 使用Lingo程序也可以实现线性规划、非线性规划以及0-1规划&#xff0c;但是在缺少Lingo程序的情况下&#xff0c;我们使用Excel照样可以很容易地完成。在这里我给大家提供了解决此类问题的详细…

4 种方法!检查字符串是否为合法的日期格式

哈喽大家好&#xff0c;今天咱们来讲一下&#xff0c;Java 中如何检查一个字符串是否是合法的日期格式&#xff1f;为什么要检查时间格式&#xff1f;后端接口在接收数据的时候&#xff0c;都需要进行检查。检查全部通过后&#xff0c;才能够执行业务逻辑。对于时间格式&#x…