理解PID控制的基本概念和运算方法
前言
本文以自己的学习过程总结而来,将自己的经验写出来以供大家一起学习,如有错误请多指教
一、PID是什么?
PID就是比例、积分、微分,PID算法可以说是在自动控制原理中比较经典的一套算法,在现实生活中应用比较广泛。
二、PID原理
常规的模拟 PID 控制系统原理框图如下图所示:
从上图可以发现,这是一个闭环控制系统,由PID控制器、传感器、被控对象构成。
被控对象的输出就是系统的输出,而系统的输出会被传感器传感,传感器会输出反馈信号给输入;
给定输入和反馈输入经过比较之后会产生一个误差(偏差),这个误差就是PID控制器的输入;pid控制器经过运算处理之后会输出控制量(或控制量的增量)给到执行机构(上图中没有画出执行机构),从而改变被控对象的输出。
那么使用PID的目的是什么呢?
我的理解是快速调节系统,最终让系统的输出和给定输入保持一致。
PID的控制环节和参数
既然要使用PID控制器,那么肯定要涉及到三个重要环节及其参数:
环节 | 参数 |
---|---|
比例 | Kp |
积分 | Ti |
微分 | Td |
注:Kp是比例系数,Ti是积分常数,Td是微分常数
下面介绍每个环节的作用
比例环节
比例环节的作用是对偏差瞬间作出反应。偏差一旦产生控制器立即产生控制作用, 使控制量向减少偏差的方向变化。 控制作用的强弱取决于比例系数Kp, 比例系数Kp越大,控制作用越强, 则过渡过程越快, 控制过程的静态偏差也就越小; 但是Kp越大,也越容易产生振荡, 破坏系统的稳定性。 故而, 比例系数Kp选择必须恰当, 才能过渡时间少, 静差小而又稳定的效果。
积分环节
从积分部分的数学表达式可以知道, 只要存在偏差, 则它的控制作用就不断的增加; 只有在偏差e(t)=0时, 它的积分才能是一个常数,控制作用才是一个不会增加的常数。 可见,积分部分可以消除系统的偏差。
积分环节的调节作用虽然会消除静态误差,但也会降低系统的响应速度,增加系统的超调量。积分常数Ti越大,积分的积累作用越弱,这时系统在过渡时不会产生振荡; 但是增大积分常数Ti会减慢静态误差的消除过程,消除偏差所需的时间也较长, 但可以减少超调量,提高系统的稳定性。
当 Ti 较小时, 则积分的作用较强,这时系统过渡时间中有可能产生振荡,不过消除偏差所需的时间较短。所以必须根据实际控制的具体要求来确定Ti 。
微分环节
实际的控制系统除了希望消除静态误差外,还要求加快调节过程。在偏差出现的瞬间,或在偏差变化的瞬间, 不但要对偏差量做出立即响应(比例环节的作用), 而且要根据偏差的变化趋势预先给出适当的纠正。为了实现这一作用,可在 PI 控制器的基础上加入微分环节,形成 PID 控制器。
微分环节的作用使阻止偏差的变化。它是根据偏差的变化趋势(变化速度)进行控制。偏差变化的越快,微分控制器的输出就越大,并能在偏差值变大之前进行修正。微分作用的引入, 将有助于减小超调量, 克服振荡, 使系统趋于稳定, 特别对髙阶系统非常有利, 它加快了系统的跟踪速度。但微分的作用对输入信号的噪声很敏感,对那些噪声较大的系统一般不用微分, 或在微分起作用之前先对输入信号进行滤波。
总结特点
环节 | 特点 |
---|---|
比例 | 偏差一产生,控制器立即做出响应,产生控制作用,使控制量向减少偏差的方向变化 |
积分 | 消除系统的静态误差;但同时会降低系统的响应速度,增加超调量;积分时间越长,积分的积累作用越弱,消除静态误差的时间会变长;但系统过渡时不会产生振荡,可以减少超调量,提高系统的稳定性 |
微分 | 加快调节过程,阻止偏差的变化;有助于减少超调量,克服振荡,使系统趋于稳定 |
三、PID的分类
PID分为数字PID和模拟PID。
模拟PID
模拟PID控制系统的原理框图如下图所示:
r(t)是给定输入,e(t)是偏差,u(t)是控制器的输出,y(t)是被控对象的输出。
模拟PID控制器的控制规律如下:
把上面这个数学表达式剖开,
比例部分:
Kp * e(t)
积分部分:
微分部分:
数字PID
- 位置型PID算法
pid算法的数学表达式如下表达式1:
(表达式1)
将其离散化,以T作为采样周期,上述表达式可变为表达式2:
(表达式2)
把表达式2中的参数整定后得到下面的表达式3:
(表达式3)
上面的表达式中:
k ―― 采样序号, k =0, 1, 2,……;
uk ―― 第 k 次采样时刻的计算机输出值;
e(k) ―― 第 k 次采样时刻输入的偏差值;
e(k-1) ―― 第 k -1 次采样时刻输入的偏差值;
Ki ――积分系数, Ki=Kp *T / Ti ;
Kd ――微分系数, Kd=Kp *Td / T ;
- 增量型PID算法
既然u(k)的表达式确定了,那么把u(k) 减去u(k-1)就可以得到控制量的增量,所以得到的数学表达式如下:
其中,
不同PID算法的特点
算法 | 特点 1 |
---|---|
位置型 | 位置式PID控制的输出与整个过去的状态有关,用到了误差的累加值 |
增量型 | 增量式PID的输出只与当前拍和前两拍的误差有关,因此位置式PID控制的累积误差相对更大 |
算法 | 特点 2 |
---|---|
位置型 | 位置式PID适用于执行机构不带积分部件的对象,如电液伺服阀 |
增量型 | 增量式PID控制输出的是控制量增量,并无积分作用,因此该方法适用于执行机构带积分部件的对象,如步进电机 |
算法 | 特点 3 |
---|---|
位置型 | 位置式的输出直接对应对象的输出,因此对系统影响较大 |
增量型 | 由于增量式PID输出的是控制量增量,如果计算机出现故障,误动作影响较小,而执行机构本身有记忆功能,可仍保持原位,不会严重影响系统的工作 |
四、PID代码实现
位置型PID算法
源码如下:
//位置型PID算法源码
typedef struct
{
float Kp; //比例系数Proportional
float Ki; //积分系数Integral
float Kd; //微分系数Derivative
float Ek; //当前误差
float Ek1; //前一次误差 e(k-1)
float Ek2; //再前一次误差 e(k-2)
float LocSum; //累计积分位置
}PID_LocTypeDef;
/************************************************
函数名称 : PID_Loc
功 能 : PID位置(Location)计算
参 数 : SetValue ------ 给定值(期望值)
ActualValue --- 实际值(反馈值)
PID ----------- PID数据结构
返 回 值 : PIDLoc -------- PID位置
*************************************************/
float PID_Loc(float SetValue, float ActualValue, PID_LocTypeDef *PID)
{
float PIDLoc; //位置
PID->Ek = SetValue - ActualValue;
PID->LocSum += PID->Ek; //累计误差
PIDLoc = PID->Kp * PID->Ek + (PID->Ki * PID->LocSum) + PID->Kd * (PID->Ek - PID->Ek1);
PID->Ek1 = PID->Ek;
return PIDLoc;
}
上面代码中的Kp是指比例系数;
Ki = Kp * T / Ti;
Kd = Kp * Td / T。
增量型PID算法
源码如下:
//增量型pid算法
typedef struct
{
float Kp; //比例系数Proportional
float Ki; //积分系数Integral
float Kd; //微分系数Derivative
float Ek; //当前误差
float Ek1; //前一次误差 e(k-1)
float Ek2; //再前一次误差 e(k-2)
}PID_IncTypeDef;
/************************************************
函数名称 : PID_Inc
功 能 : PID增量(Increment)计算
参 数 : SetValue ------ 设置值(期望值)
ActualValue --- 实际值(反馈值)
PID ----------- PID数据结构
返 回 值 : PIDInc -------- 本次PID增量(+/-)
*************************************************/
float PID_Inc(float SetValue, float ActualValue, PID_IncTypeDef *PID)
{
float PIDInc; //增量
PID->Ek = SetValue - ActualValue;
PIDInc = (PID->Kp * PID->Ek) - (PID->Ki * PID->Ek1) + (PID->Kd * PID->Ek2); //参数已做整定
PID->Ek2 = PID->Ek1;
PID->Ek1 = PID->Ek;
return PIDInc;
}
源码如下:
//位置型PID算法源码
typedef struct
{
float Kp; //比例系数Proportional
float Ki; //积分系数Integral
float Kd; //微分系数Derivative
float Ek; //当前误差
float Ek1; //前一次误差 e(k-1)
float Ek2; //再前一次误差 e(k-2)
float LocSum; //累计积分位置
}PID_LocTypeDef;
/************************************************
函数名称 : PID_Loc
功 能 : PID位置(Location)计算
参 数 : SetValue ------ 给定值(期望值)
ActualValue --- 实际值(反馈值)
PID ----------- PID数据结构
返 回 值 : PIDLoc -------- PID位置
*************************************************/
float PID_Loc(float SetValue, float ActualValue, PID_LocTypeDef *PID)
{
float PIDLoc; //位置
PID->Ek = SetValue - ActualValue;
PID->LocSum += PID->Ek; //累计误差
PIDLoc = PID->Kp * PID->Ek + (PID->Ki * PID->LocSum) + PID->Kd * (PID->Ek - PID->Ek1);
PID->Ek1 = PID->Ek;
return PIDLoc;
}
上面代码中的Kp是指比例系数;
Ki = Kp * T / Ti;
Kd = Kp * Td / T。
源码如下:
//增量型pid算法
typedef struct
{
float Kp; //比例系数Proportional
float Ki; //积分系数Integral
float Kd; //微分系数Derivative
float Ek; //当前误差
float Ek1; //前一次误差 e(k-1)
float Ek2; //再前一次误差 e(k-2)
}PID_IncTypeDef;
/************************************************
函数名称 : PID_Inc
功 能 : PID增量(Increment)计算
参 数 : SetValue ------ 设置值(期望值)
ActualValue --- 实际值(反馈值)
PID ----------- PID数据结构
返 回 值 : PIDInc -------- 本次PID增量(+/-)
*************************************************/
float PID_Inc(float SetValue, float ActualValue, PID_IncTypeDef *PID)
{
float PIDInc; //增量
PID->Ek = SetValue - ActualValue;
PIDInc = (PID->Kp * PID->Ek) - (PID->Ki * PID->Ek1) + (PID->Kd * PID->Ek2); //参数已做整定
PID->Ek2 = PID->Ek1;
PID->Ek1 = PID->Ek;
return PIDInc;
}
在上面代码中:(参数是经过整定的)
实际上:
Kp = KP + KI + KD;
Ki = KP + 2 * KD;
KD = KD;
而KP就是比例系数
KI = KP * T / Ti; //Ti是指积分时间
KD = KP * Td / Ti //Td是指微分时间
五、调参
PID控制器参数选择的方法很多,例如试凑法、临界比例度法、扩充临界比例度法等。但是,对于PID控制而言,参数的选择始终是一件非常烦杂的工作, 需要经过不断的调整才能得到较为满意的控制效果。依据经验,PID参数确定的步骤如下:
1、确定比例系数Kp
确定比例系数Kp时,首先去掉PID的积分项和微分项,可以令Ti=0、Td=0, 使之成为纯比例调节。输入设定为系统允许输出最大值的60%~70%,比例系数Kp由0开始逐渐增大,直至系统出现振荡:再反过来,从此时的比例系数Kp逐渐减小,直至系统振荡消失。记录此时的比例系数Kp,设定PID的比例系数Kp为当前值的60% ~ 70%。
2、确定积分时间常数Ti
比例系数Kp确定之后,设定一个较 大的积分时间常数Ti,然后逐渐减小Ti,自至系统出现振荡,然后再反过来,逐渐增大Ti,直至系统振荡消失,记录此时的Ti.设定PID的积分时间常数Ti为当前值的150% ~ 180%。
3、 确定微分时间常数Td
微分时间常数Td一般不用设定,为0即可,此时PID调节转换为PI调节。如果需要设定,则与确定Ti的方法相同,取不振荡时其值的30%。
4、 系统空载、带载联调
对PID参数进行微调,直到满足性能要求。
总结
以上就是今天要讲的内容,本文简单介绍了PID的概念、PID的控制原理,以及介绍了PID不同算法的特点及其示例源码
上一篇: 为何在PID控制中较少使用D参数?
下一篇: 微分环节
推荐阅读
-
PID 控制最常见的解释和 PID 参数调整方法
-
值得收藏!从事自动化一看就懂,自动化控制中PID参数的意义和调整方法
-
Java 类加载器的作用 - 简介:类加载器是 Java™ 中一个非常重要的概念。类加载器负责将 Java 类的字节码加载到 Java 虚拟机中。本文首先详细介绍了 Java 类加载器的基本概念,包括代理模型、加载类的具体过程和线程上下文类加载器等。然后介绍了如何开发自己的类加载器,最后介绍了类加载器在 Web 容器和 OSGi™ 中的应用。 类加载器是 Java 语言的一项创新,也是 Java 语言广受欢迎的重要原因之一。它允许将 Java 类动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 开始出现,最初是为了满足 Java Applets 的需求而开发的,Java Applets 需要从远程位置下载 Java 类文件并在浏览器中执行。现在,类加载器已广泛应用于网络容器和 OSGi。一般来说,Java 应用程序的开发人员不需要直接与类加载器交互;Java 虚拟机的默认行为足以应对大多数情况。但是,如果遇到需要与类加载器交互的情况,而您又不太了解类加载器的机制,就很容易花费大量时间调试异常,如 ClassNotFoundException 和 NoClassDefFoundError。本文将详细介绍 Java 的类加载器,帮助读者深入理解 Java 语言中的这一重要概念。下面先介绍一些基本概念。 类加载器的基本概念 顾名思义,类加载器用于将 Java 类加载到 Java 虚拟机中。一般来说,Java 虚拟机以如下方式使用 Java 类:Java 源程序(.java 文件)经 Java 编译器编译后转换为 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码并将其转换为 java.lang 实例。每个实例都用来表示一个 Java 类。通过该实例的 newInstance 方法创建该类的对象。实际情况可能更加复杂,例如,Java 字节代码可能是由工具动态生成或通过网络下载的。 基本上,所有类加载器都是 java.lang.ClassLoader 类的实例。下面将详细介绍这个 Java 类。 java.lang.ClassLoader 类简介 java.lang.ClassLoader 类的基本职责是根据给定类的名称为其查找或生成相应的字节码,然后根据这些字节码定义一个 Java 类,即 java.lang.Class 类的实例。除此之外,ClassLoader 还负责加载 Java 应用程序所需的资源,如图像文件和配置文件。不过,本文只讨论它加载类的功能。为了履行加载类的职责,ClassLoader 提供了许多方法,其中比较重要的方法如表 1 所示。下文将详细介绍这些方法。 表 1.与加载类相关的 ClassLoader 方法
-
理解数据结构图的基本概念、存储方式和两种遍历方法
-
理解jmap -histo pid 命令输出中的四个类别:C、B、I、S,以及它们分别代表的方法Klass、constantPoolKlass和类信息
-
理解dB和dBm的基本概念及其计算方法
-
理解PID控制的基本概念和运算方法
-
理解PID控制器:比例、积分和微分的完美结合
-
理解取模下的除法运算和乘法逆元的计算方法
-
理解PID控制的各种算法:优点和缺点大揭秘