[应用相关] PID算法

[复制链接]
1591|14
 楼主| gygp 发表于 2023-3-31 10:00 | 显示全部楼层 |阅读模式
1.根据我控制算法类文章中关于PID的理论的一些描述,同时也根据网络上一些其他的PID文章,以及自己最近一个项目的实践后,总结了几套基于C语言的PID算法,由于网络中很少有人进行分享完整的PID算法实现,我这里分享下。
(1)头文件,定义pid的结构体,类的概念,包含pid的属性和方法
  1. #ifndef __PID_H_
  2. #define __PID_H_

  3. #include <stdint.h>



  4. typedef struct _pid
  5. {
  6.     int16_t set_value;            // 给定值,rin(k)
  7.     int16_t actual_value;         // 实际值,反馈值,rout(k)
  8.     int16_t err;                  // 偏差值,rin(k) - rout(k)
  9.     int16_t err_last;             // 上一次偏差值,rin(k - 1) - rout(k - 1)
  10.     int16_t err_last_last;        // 上一次上一次的偏差值,rin(k - 2) - rout(k - 2)
  11.     float kp;                       // 比例系数
  12.     float ki;                       // 积分系数
  13.     float kd;                       // 微分系数
  14.     float uk;                       // pid公式运算结果值
  15.     float incremental_value;      // 增量值
  16.     float integral_value;             // 积分值
  17.     float umax;                 // uk的上限值,抗积分饱和用
  18.     float umin;                 // uk的下限值,抗积分饱和用
  19.     int16_t err_up_value;         // 偏差上限值,积分分离用
  20.     int16_t ki_k;                 // 积分的再次乘机系数,积分分离用
  21.    
  22.     float out_value;              //
  23.    
  24.     float(*position_type)(struct _pid *ppid);                       // 位置型PID算法,无积分分离、无抗积分饱和
  25.     float(*incremental_type)(struct _pid *ppid);              // 增量型PID算法
  26.     float(*integral_separation_type)(struct _pid *ppid);      // 积分分离PID算法
  27.     float(*int_sep_anti_sat_type)(struct _pid *ppid);         // 积分分离 + 抗积分饱和PID算法
  28. }_pid_t;







  29. _pid_t *pid_create(void);



  30. extern _pid_t *pg_pid;







  31. #endif
(2).c文件,包含头文件中4个PID算法的实现,包含位置型PID算法、增量型PID算法、积分分离PID算法、积分分离+抗饱和PID算法
  1. #include <stdlib.h>
  2. #include <string.h>

  3. #include "pid.h"

  4. #include "FreeRTOS.h"
  5. #include "task.h"
  6. #include "queue.h"
  7. #include "portmacro.h"
  8. #include "semphr.h"

  9. #include "Debug.h"



  10. /*************************************
  11. *
  12. * Funciton Name : pid_position_type
  13. * Function      :位置型PID算法,无积分分离、无抗积分饱和
  14. *
  15. * [url=home.php?mod=space&uid=187600]@author[/url]       :why
  16. * [url=home.php?mod=space&uid=536309]@NOTE[/url]         : 积分分离:能解决初期系统偏差值大,累加到积分项中,引起系统超调、振荡问题。积分是为了消除静态误差的,应在误差在小范围时引入积分
  17. *               : 抗积分饱和:能解决执行器到达极限值时,但uk还在增大,使得系统进入饱和,进入饱和区的时间越长,当系统出现反向偏差,解决这个反向偏差的时间就会越长,此时系统会像失控一样。
  18. *               :进入抗积分饱和,当uk超过上限时,积分向只累加负偏差,当uk超过下限时,积分项只累加正偏差。
  19. *
  20. × @param         :pid
  21. *
  22. *
  23. * [url=home.php?mod=space&uid=266161]@return[/url]       : uk
  24. *************************************/
  25. static float pid_position_type_f(struct _pid *ppid)
  26. {
  27.     ppid->err = ppid->set_value - ppid->actual_value;   // 偏差
  28.    
  29.     ppid->integral_value += ppid->err;                  // 积分累加
  30.    
  31.     ppid->uk = ppid->kp * ppid->err + ppid->ki * ppid->integral_value + ppid->kd * (ppid->err - ppid->err_last);
  32.    
  33.     ppid->err_last = ppid->err;
  34.    
  35.     return (ppid->uk);
  36. }


  37. /*************************************
  38. *
  39. * Funciton Name : pid_incremental_type_f
  40. * Function      :增量型PID算法
  41. *
  42. * @author       :why
  43. * @note         : 相较于位置型,因为与3个偏差相关,增强了系统稳定性
  44. *
  45. × @param         :pid
  46. *
  47. *
  48. * @return       : uk + 增量值
  49. *************************************/
  50. static float pid_incremental_type_f(struct _pid *ppid)
  51. {
  52.     ppid->err = ppid->set_value - ppid->actual_value;   // 偏差
  53.    
  54.     //ppid->integral_value += ppid->err;                  // 积分累加
  55.    
  56.     ppid->incremental_value = ppid->kp * ( ppid->err - ppid->err_last) + ppid->ki * ppid->err + ppid->kd * (ppid->err - 2 * ppid->err_last + ppid->err_last_last);
  57.    
  58.     ppid->uk += ppid->incremental_value;
  59.    
  60.     ppid->err_last_last = ppid->err_last;
  61.     ppid->err_last = ppid->err;
  62.    
  63.     return (ppid->uk);
  64. }


  65. /*************************************
  66. *
  67. * Funciton Name : pid_integral_separation_type_f
  68. * Function      :积分分离PID算法
  69. *
  70. * @author       :why
  71. * @note         : 能解决初期系统偏差值大,累加到积分项中,引起系统超调、振荡问题。积分是为了消除静态误差的,应在误差在小范围时引入积分
  72. *
  73. × @param         :pid
  74. *
  75. *
  76. * @return       : uk
  77. *************************************/
  78. static float pid_integral_separation_type_f(struct _pid *ppid)
  79. {
  80.     ppid->err = ppid->set_value - ppid->actual_value;   // 偏差
  81.    
  82.     // 误差过大去除积分效果
  83.     if ( abs(ppid->err) > ppid->err_up_value )
  84.     {
  85.         ppid->ki_k = 0;
  86.     }
  87.     else
  88.     {
  89.         ppid->ki_k = 1;
  90.         ppid->integral_value += ppid->err;              // 积分累加
  91.     }      
  92.    
  93.     ppid->uk = ppid->kp * ppid->err + ppid->ki_k * ppid->ki * ppid->integral_value + ppid->kd * (ppid->err - ppid->err_last);
  94.    
  95.     ppid->err_last = ppid->err;
  96.    
  97.     return (ppid->uk);
  98. }


  99. /*************************************
  100. *
  101. * Funciton Name : pid_int_sep_anti_sat_type_f
  102. * Function      :积分分离 + 抗积分饱和PID算法
  103. *
  104. * @author       :why
  105. * @note         : 能解决初期系统偏差值大,累加到积分项中,引起系统超调、振荡问题。积分是为了消除静态误差的,应在误差在小范围时引入积分
  106. *               : 抗积分饱和:能解决执行器到达极限值时,但uk还在增大,使得系统进入饱和,进入饱和区的时间越长,当系统出现反向偏差,解决这个反向偏差的时间就会越长,此时系统会像失控一样。
  107. *               :进入抗积分饱和,当uk超过上限时,积分向只累加负偏差,当uk超过下限时,积分项只累加正偏差。
  108. *
  109. × @param         :pid
  110. *
  111. *
  112. * @return       : uk
  113. *************************************/
  114. static float pid_int_sep_anti_sat_type_f(struct _pid *ppid)
  115. {
  116.     ppid->err = ppid->set_value - ppid->actual_value;   // 偏差
  117.    
  118.     Debug("ppid->err = %d\r\n", ppid->err);
  119.    
  120.     if ( ppid->out_value > ppid->umax )                    // 抗积分饱和
  121.     {
  122.         // 误差过大去除积分效果
  123.         if ( abs(ppid->err) > ppid->err_up_value )  // 积分分离
  124.         {
  125.             ppid->ki_k = 0;
  126.         }
  127.         else
  128.         {
  129.             ppid->ki_k = 1;
  130.             
  131.             if ( ppid->err < 0 )                    
  132.             {
  133.                 ppid->integral_value += ppid->err;              // 积分累加
  134.             }
  135.             
  136.         }   
  137.     }
  138.     else if ( ppid->out_value < ppid->umin )                // 抗积分饱和
  139.     {
  140.         // 误差过大去除积分效果
  141.         if ( abs(ppid->err) > ppid->err_up_value )  // 积分分离
  142.         {
  143.             ppid->ki_k = 0;
  144.         }
  145.         else
  146.         {
  147.             ppid->ki_k = 1;
  148.             
  149.             if ( ppid->err > 0 )                    
  150.             {
  151.                 ppid->integral_value += ppid->err;              // 积分累加
  152.             }
  153.             
  154.         }
  155.     }
  156.     else
  157.     {
  158.         // 误差过大去除积分效果
  159.         if ( abs(ppid->err) > ppid->err_up_value )
  160.         {
  161.             ppid->ki_k = 0;
  162.         }
  163.         else
  164.         {
  165.             ppid->ki_k = 1;
  166.             ppid->integral_value += ppid->err;              // 积分累加
  167.         }
  168.     }
  169.    
  170.     ppid->uk = ppid->kp * ppid->err + ppid->ki_k * ppid->ki * ppid->integral_value + ppid->kd * (ppid->err - ppid->err_last);
  171.    
  172.     ppid->err_last = ppid->err;
  173.    
  174. //    if ( ppid->uk >= 0.07 && ppid->uk <= 1 )
  175. //    {
  176. //        ppid->uk = 1;
  177. //    }
  178. //   
  179. //    if ( ppid->uk <= -0.07 && ppid->uk >= -1 )
  180. //    {
  181. //        ppid->uk = -1;
  182. //    }
  183.    
  184.     return (ppid->uk);
  185. }

  186. /*************************************
  187. *
  188. * Funciton Name    : pid_init
  189. * Function         : pid实例构造
  190. *
  191. * @author       :why
  192. *
  193. *
  194. *************************************/
  195. static void pid_init(_pid_t *ppid)
  196. {
  197.     ppid->kp = 0.2;
  198.     ppid->ki = 0.05;
  199.     ppid->kd = 0;
  200.    
  201.     ppid->umax = 4000;
  202.     ppid->umin = 0;
  203.    
  204.    
  205.     ppid->position_type = pid_position_type_f;
  206.     ppid->incremental_type = pid_incremental_type_f;
  207.     ppid->integral_separation_type = pid_integral_separation_type_f;
  208.     ppid->int_sep_anti_sat_type = pid_int_sep_anti_sat_type_f;
  209. }


  210. /*************************************
  211. *
  212. * Funciton Name    : pid_create
  213. * Function         : pid实例创建
  214. * @author          : why
  215. *
  216. * @return          : 返回pid实例
  217. *
  218. *************************************/
  219. _pid_t *pid_create(void)
  220. {
  221.     _pid_t *ppid = (_pid_t *)pvPortMalloc(sizeof(_pid_t));
  222.    
  223.     memset(ppid, 0, sizeof(_pid_t));
  224.    
  225.     pid_init(ppid);
  226.    
  227.     return ppid;
  228. }
(3)PID的实现算法有了,但还是要根据实际情况进行调试选取最适合的PID算法以及修改可能存在的不恰当的位置。
万图 发表于 2024-4-15 07:12 | 显示全部楼层

含有延展到远高于基本开关频率的谐波
Uriah 发表于 2024-4-15 08:15 | 显示全部楼层

这些引线越窄越好
帛灿灿 发表于 2024-4-15 10:11 | 显示全部楼层

输入电容主要是起到高频能量存储器的作用
Bblythe 发表于 2024-4-15 11:14 | 显示全部楼层

输入滤波电容的公共端应作为其他交流电流地的唯一接点
周半梅 发表于 2024-4-15 13:10 | 显示全部楼层

它们对PCB布局的重要性
Pulitzer 发表于 2024-4-15 14:13 | 显示全部楼层

混淆的话,会引起电源工作不稳定
童雨竹 发表于 2024-4-15 16:09 | 显示全部楼层

把这干扰信号再次辐射出去
Wordsworth 发表于 2024-4-15 17:12 | 显示全部楼层

对变换器效率测量
Clyde011 发表于 2024-4-15 18:15 | 显示全部楼层

把纹波电流分摊到每个电容上
公羊子丹 发表于 2024-4-15 19:08 | 显示全部楼层

印制电路板(PCB)的线路设计
xiaoqi000 发表于 2024-8-31 23:13 | 显示全部楼层
使用了标准的头文件保护宏 #ifndef __PID_H_ 和 #define __PID_H_,这很好地防止了头文件被重复包含。
LOVEEVER 发表于 2024-9-13 17:33 | 显示全部楼层
PID的实现算法有了,重要的还是需要参数设置适配
xdvca 发表于 2024-9-17 14:36 来自手机 | 显示全部楼层
由于网络中很少有人进行分享完整的PID算法
您需要登录后才可以回帖 登录 | 注册

本版积分规则

209

主题

8549

帖子

16

粉丝
快速回复 在线客服 返回列表 返回顶部