增量式PID是什么?不知道你就落伍了

2023-11-05

目录

  • 1 什么是增量式PID?

  • 2 举个例子

    • 2.1 位置式PID

    • 2.2 增量式PID

  • 3 伪算法

  • 4 C语言实现

  • 5 总结

在之前一篇博客中( 简易PID算法的快速扫盲 )简单介绍了PID算法的基本原理位置式算法的实现过程,由于部分推导过程已经在上一篇文章做过介绍,所以推导过程本文不再赘述,重点将对离散增量式PID的算法进行实现。

1 什么是增量式PID?

先看一下增量式PID的离散公式如下:

:比例系数
:积分系数
:微分系数
:偏差

对于所谓的位置式增量式的算法,这两者只是在算法的实现上的存在差异,本质的控制上对于系统控制的影响还是相同,单纯从输入和输出的角度来比较,具体如下表所示;

这里简单的说明一下;

  • 位置式:位置式算法较为简单,直接输入当前的偏差 ,即可得到输出

  • 增量式:增量式算法需要保存历史偏差, ,即在第 次控制周期时,需要使用第 和第 次控制所输入的偏差,最终计算得到 ,此时,这还不是我们所需要的PID输出量;所以需要进行累加;

不难发现第一次控制周期时,即 时;

由以上公式我们可以推导出下式;

所以可以看出,最终PID的输出量 ,满足以下公式;

可见增量式算法,就是所计算出的PID增量的历史累加和;

2 举个例子

2.1 位置式PID

下面从一个简单的例子中去理解一下增量式PID,这里依然举一个不是很恰当的例子;如果是位置式PID算法的话:

  • 隆哥对一个直流电机进行调速,设定了转速为 1000

  • 这时由于反馈回来的速度和设定的速度偏差为

  • 经过位置式PID计算得到

  • 作为Process的输入值(可以是PWM的占空比),最终Process输出相应的PWM驱动直流电机;

  • 反馈装置检测到电机转速,然后重复以上步骤;

整体框图如下所示;

2.2 增量式PID

对于增量式PID来说;

  • 隆哥对一个直流电机进行调速,设定了转速为 1000

  • 这时由于反馈回来的速度和设定的速度偏差为 ,系统中保存上一次的偏差 和上上次的偏差 ,这三个输入量经过增量PID计算得到

  • 系统中还保存了上一次的PID输出 ,所以 加上增量 ,就是本次控制周期的PID输出——

  • 作为Process的输入值(可以是PWM的占空比),最终Process输出相应的PWM驱动直流电机;

  • 反馈装置检测到电机转速,然后重复以上步骤;

整体框图如下所示;

所以这里不难发现,所谓增量式PID,它的特点有:

  • 需要输入历史的偏差值;

  • 计算得到的是PID输出增量,因此每一次需要累加历史增量最为当前的PID输出;

下面简单介绍一下如何实现增量式PID算法;

3 伪算法

previous02_error := 0  //上上次偏差
previous01_error := 0  //上一次偏差
integral := 0   //积分和
pid_out := 0   //pid增量累加和
//循环 
//采样周期为dt
loop:
 //setpoint 设定值
 //measured_value 反馈值
    error := setpoint − measured_value //计算得到偏差
    proportion := error - previous01_error //计算得到比例输出
    integral := error × dt //计算得到积分累加和
    derivative := (error − 2*previous01_error + previous02_error) / dt //计算得到微分
    pid_delta := Kp × error + Ki × integral + Kd × derivative //计算得到PID增量
    pid_out := pid_out + pid_delta //计算得到PID输出

    //保存当前的偏差和上一次偏差作为下一次采样所需要的历史偏差
    previous02_error := previous01_error 
    previous01_error := error    //保存当前偏差为下一次采样时所需要的历史偏差
    wait(dt) //等待下一次采用
    goto loop


4 C语言实现

这里直接使用了TI公司的PID算法,做了积分抗饱和;具体可以参考controlSUITE\libs\app_libs\motor_control\math_blocks\v4.2\pid_grando.h

具体代码如下所示;

pid_grando.h

/* =================================================================================
File name:       PID_GRANDO.H 
===================================================================================*/


#ifndef __PID_H__
#define __PID_H__

typedef struct {  _iq  Ref;      // Input: reference set-point
      _iq  Fbk;      // Input: feedback
      _iq  Out;      // Output: controller output 
      _iq  c1;      // Internal: derivative filter coefficient 1
      _iq  c2;      // Internal: derivative filter coefficient 2
    } PID_TERMINALS;
    // note: c1 & c2 placed here to keep structure size under 8 words

typedef struct {  _iq  Kr;    // Parameter: reference set-point weighting 
      _iq  Kp;    // Parameter: proportional loop gain
      _iq  Ki;       // Parameter: integral gain
      _iq  Kd;           // Parameter: derivative gain
      _iq  Km;           // Parameter: derivative weighting
      _iq  Umax;   // Parameter: upper saturation limit
      _iq  Umin;   // Parameter: lower saturation limit
    } PID_PARAMETERS;

typedef struct {  _iq  up;    // Data: proportional term
      _iq  ui;    // Data: integral term
      _iq  ud;    // Data: derivative term
      _iq  v1;    // Data: pre-saturated controller output
      _iq  i1;    // Data: integrator storage: ui(k-1)
      _iq  d1;    // Data: differentiator storage: ud(k-1)
      _iq  d2;    // Data: differentiator storage: d2(k-1) 
      _iq  w1;    // Data: saturation record: [u(k-1) - v(k-1)]
    } PID_DATA;


typedef struct {  PID_TERMINALS term;
      PID_PARAMETERS param;
      PID_DATA  data;
    } PID_CONTROLLER;

/*-----------------------------------------------------------------------------
Default initalisation values for the PID objects
-----------------------------------------------------------------------------*/                     

#define PID_TERM_DEFAULTS {    \
                           0,  \
                           0,  \
                           0,  \
                           0,  \
                           0   \
                   }

#define PID_PARAM_DEFAULTS {         \
                           _IQ(1.0), \
                           _IQ(1.0), \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(1.0), \
                           _IQ(1.0), \
                           _IQ(-1.0) \
                   }

#define PID_DATA_DEFAULTS {          \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(1.0)  \
                   }


/*------------------------------------------------------------------------------
  PID Macro Definition
------------------------------------------------------------------------------*/

#define PID_MACRO(v)                                              \
                                                                  \
/* proportional term */                                           \
v.data.up = _IQmpy(v.param.Kr, v.term.Ref) - v.term.Fbk;          \
                                                                  \
/* integral term */                                               \
v.data.ui = _IQmpy(v.param.Ki, _IQmpy(v.data.w1,                  \
(v.term.Ref - v.term.Fbk))) + v.data.i1;                          \
v.data.i1 = v.data.ui;                                            \
                                                                  \
/* derivative term */                                             \
v.data.d2 = _IQmpy(v.param.Kd, _IQmpy(v.term.c1,                  \
(_IQmpy(v.term.Ref, v.param.Km) - v.term.Fbk))) - v.data.d2;      \
v.data.ud = v.data.d2 + v.data.d1;                                \
v.data.d1 = _IQmpy(v.data.ud, v.term.c2);                         \
                                                                  \
/* control output */                                              \
v.data.v1 = _IQmpy(v.param.Kp,                                    \
(v.data.up + v.data.ui + v.data.ud));                             \
v.term.Out= _IQsat(v.data.v1, v.param.Umax, v.param.Umin);        \
v.data.w1 = (v.term.Out == v.data.v1) ? _IQ(1.0) : _IQ(0.0);      \
 
#endif // __PID_H__




example

/* Instance the PID module */ 
 
PID   pid1={ PID_TERM_DEFAULTS, PID_PARAM_DEFAULTS, PID_DATA_DEFAULTS }; 
 
main() { 
 
    pid1.param.Kp = _IQ(0.5);     
    pid1.param.Ki  = _IQ(0.005);    
    pid1.param.Kd = _IQ(0);      
    pid1.param.Kr  = _IQ(1.0);     
    pid1.param.Km =_IQ(1.0);     
    pid1.param.Umax= _IQ(1.0);      
    pid1.param.Umin= _IQ(-1.0); 
 
} 
 
void interrupt periodic_interrupt_isr() {  

    pid1.Ref = input1_1;   // Pass _iq inputs to pid1 
    pid1.Fbk = input1_2;   // Pass _iq inputs to pid1   
    PID_MACRO(pid1);  // Call compute macro for pid1        
    output1 = pid1.Out;  // Access the output of pid1     
}
 

5 总结

本文简单总结了位置式PID算法增量式PID算法的差异,参考了TI公司的增量式PID算法实现,对于不同的控制对象可以根据系统要求选择合适的PID算法

-END-

往期好文合集

PID到底是个啥?来给你讲个故事

再论PID,PID其实很简单。。。

电子设计竞赛(4)-常用的两种PID算法

  最 后  

 

若觉得文章不错,转发分享,也是我们继续更新的动力。

5T资源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,PCB、FPGA、DSP、labview、单片机、等等

在公众号内回复「更多资源」,即可免费获取,期待你的关注~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

增量式PID是什么?不知道你就落伍了 的相关文章

随机推荐

  • Android开发之RecyclerView的使用全解

    转自 http blog csdn net dmk877 article details 50816933 自Android 5 0之后 谷歌公司推出了RecylerView控件 RecylerView 我想看到一个新名词后大部分人会首先发
  • 微分动态规划

    from https en wikipedia org wiki Differential dynamic programming 深入理解DDP DDP是一种轨迹优化类别问题中的最优控制算法 这种算法在1966年被Mayne提出 该算法使
  • PostgreSQL 性能优化

    提出问题 PostgreSQL数据库如何进行简单的性能调优 解决问题 前言 PostgreSQL的配置参数作为性能调优的一部分 起着重要的位置 有时候一个简单的配置参数就会决定应用的性能 因此有必要简单了解下其相关的配置参数 查询Linux
  • Hadoop(三)读写流程

    Remote Procedure Call RPC 远程过程调用协议 它是一种通过网络从远程计算机程序上请求服务 而不需要了解底层网络技术的协议 RPC协议假定某些传输协议的存在 如TCP或UDP 为通信程序之间携带信息数据 在OSI网络通
  • 数据库基础命令

    SELECT 从数据库中提取数据 SELECT column name column name FROM table name SELECT DISTINCT column name column name FROM table name
  • Numpy

    文章目录 1 Numpy是什么 2 ndarray 2 1 什么是ndarray 2 2 ndarray的属性 2 3 ndarray的类型 3 Numpy基本操作 3 1 生成0或1的数组 3 2 从现有数组生成数组 拓展 浅拷贝和深拷贝
  • 在Excel中如何引用其他的工作表或者工作簿

    http www office68 com excel 426 html 公式中对单元格和单元格区域的引用不必非得针对同一个工作表中的单元格和单元格区域 如果要引用另外的工作表中的单元格 那么就在单元格引用的前面加上工作表的名称以及一个感叹
  • ssl协议及开源实现openssl

    转载地址 https blog csdn net jinbusi blog article details 76039206 locationNum 4 fps 1 ssl协议 SSL Secure Socket Layer 安全套接层 s
  • Rsync的核心算法

    一 什么是Rsync 1 rsync 是 unix linux 下同步文件的一个高效算法 它能同步更新两处计算机的文件和目录 并适当的利用查找文件中的不同块以减少数据传输 2 rsync中一项与其他大部分类似程序或协定中所未见的重要特性是镜
  • Delphi 对象的创建(create)与释放(free/destory)

    create后一定要free吗 简单举例 procedure a var x TX begin x TX create do someting x free 如果我这里不free 到了这个end不就是相当于C中的 自动释放吗 也就是说在此处
  • Android 基础知识4-3.10 ScrollView(滚动条)详解

    一 简介 首先来看google官方对他的介绍 翻译过来就是可以滚动的用户布局容器 如果手机显示不下子布局 那么可以使用scrollView 当然谷歌也说NestedscrollView已经提供了更好的用户体验 这个我们以后再详细总结下 谷歌
  • 批量处理sql表

    1 批量CRUD表字段 DECLARE V SQL VARCHAR2 2000 V TABLE NAME VARCHAR2 30 CURSOR C1 IS 查询当前用户下 ZFPT40 STATISTIC ANALYSIS 的所有表 SEL
  • 数据结构:循环链表的使用

    循环链表 循环链表 将单链表中终端结点的指针端由空指针改为指向头结点 就使整个单链表形成一个环 这种头尾相接的单链表称为单循环链表 简称循环链表 如图所示 非空的循环链表如图 循环链表与单链表的主要差异在于循环的判断上 原来是判断p gt
  • c语言的结构体是面向对象吗,基于面向对象的思想来使用结构体,将会有意想不到的效果...

    程序开发过程中 很多人都会接触到客户服务端模型 通常客户服务端模型是基于socket的网络通信 而网络通信是需要定义通信协议 通信协议结构一般是用结构体的方式来表示 而数据内容有的可能会使用json格式 对于嵌入式设备 数据内容更多的还是采
  • mysql8.0.19.0是不是免费的_mysql8.0.19 免安装版本的相关配置

    1 下载好对应的数据库版本 网址 https dev mysql com downloads mysql 2 下载解压到一个目录 例如 D zyf mysql8 说一下遇到的一个问题 当我设置成D zyf soft mysql8的时候遇到一
  • 重写介绍。

    1 方法重写的作用和使用 方法重写子类继承了父类的方法后 如果发现在需求下 父类的某些方法不太强大 我们就可以在子类中进行重写 宠物自白 Override 注解不报错 说明你写的就是方法重写 规范 必须要加 public void show
  • 拷贝函数访问本类的私有变量的问题

    chap 5 h ifndef CHAP 5 H define CHAP 5 H include string include iostream using namespace std class B public B int a int
  • 数据库命令行导入方式及部分问题的解决办法

    0 写在前面 以下内容仅为个人的经验谈 没有任何学术性 可能存在一些翻译不准确的情况 仅作为一些问题的解决办法参考 1 基本步骤 用管理员模式打开cmd 登录数据库 mysql u
  • qt的QLabel中的字体越界

    今天使用文泉驿的中文库wqy zenhei ttc 发现QLabel中的汉字上面切顶了 但是如果一个QLabel和一个QLineEdit并排就不会出现这种现象 最后对QLabel使用样式解决了这个问题 MyLabel gt setStyle
  • 增量式PID是什么?不知道你就落伍了

    目录 1 什么是增量式PID 2 举个例子 2 1 位置式PID 2 2 增量式PID 3 伪算法 4 C语言实现 5 总结 在之前一篇博客中 简易PID算法的快速扫盲 简单介绍了PID算法的基本原理和位置式算法的实现过程 由于部分推导过程