C语言PID算法




1. PID算法原理

  • 如果偏差为0,则比例环节不起作用;
  • 积分环节主要是用来消除静差,即系统稳定后输出值和设定值之间的差值;
  • 微分环节则反映了偏差信号的变化规律,根据偏差信号的变化趋势来进行超前调节,从而增加系统快速性。

2. 不同类型PID算法

2.1 位置式PID:


2.2 增量式PID:


2.3 积分分离PID:

        普通PID中,引入积分环节的目的主要是为了消除静差,提高控制精度,但是在启动、结束或大幅增减设定时,短时间内系统输出有很大的偏差,会造成PID运算的积分积累,可能导致控制量超过执行机构允许的极限控制量,从而引起较大的超调甚至振荡。

        为了克服这一问题,引入了积分分离的概念,其基本思路是当被控量与设定值偏差较大时,取消积分作用;当控制量接近给定值时,引入积分控制以消除静差,提高精度。

2.4 抗积分饱和PID:

        积分饱和现象是指如果系统存在一个方向的偏差,PID控制器的输出由于积分作用不断累加而加大,从而导致执行机构达到极限位置,若控制器输出继续增大,执行器开度不可能再增大,此时计算机输出控制量超过了正常运行范围而进入饱和区。一旦系统出现反向偏差,u(k)逐渐从饱和区退出。进入饱和区越深则退出饱和区时间越长,在这段时间里,执行机构仍停留在极限位置而不随偏差反向而立即做出相应改变,系统就像失控一样,造成控制系统恶化。

        防止积分饱和的方法之一就是抗积分饱和法,该方法思路是在计算u(k)时,先判断上一时刻控制量u(k-1)是否超过了极限,如果是,则只累加反向偏差,从而避免控制量长时间停留在饱和区。

3. C语言实现


  
  
  1. #include "stdio.h"
  2. #include<stdlib.h>
  3. //定义PID结构体
  4. struct _pid{
  5. float SetSpeed;
  6. float ActualSpeed;
  7. float err;
  8. float err_last;
  9. float Kp,Ki,Kd;
  10. //位置式pid
  11. float voltage;
  12. float integral;
  13. //增量式pid
  14. float err_next;
  15. //抗积分饱和PID
  16. float umax;
  17. float umin;
  18. }pid;
  19. //初始化变量(基于位置式PID)
  20. void PID_init() {
  21. printf( "PID_init begin\n");
  22. pid.SetSpeed = 0.0;
  23. pid.ActualSpeed = 0.0;
  24. pid.err = 0.0;
  25. pid.err_last = 0.0;
  26. pid.voltage = 0.0;
  27. pid.integral = 0.0;
  28. pid.Kp = 0.2;
  29. pid.Ki = 0.015;
  30. pid.Kd = 0.2;
  31. printf( "PID_init end \n");
  32. }
  33. //编写控制算法
  34. //位置式PID
  35. float positional_PID_realize( float speed) {
  36. pid.SetSpeed = speed;
  37. pid.err = pid.SetSpeed - pid.ActualSpeed;
  38. pid.integral += pid.err;
  39. pid.voltage = pid.Kp*pid.err + pid.Ki*pid.integral + pid.Kd*(pid.err - pid.err_last);
  40. pid.err_last = pid.err;
  41. pid.ActualSpeed = pid.voltage* 1.0;
  42. return pid.ActualSpeed;
  43. }
  44. //增量式PID
  45. float incremental_PID_realize( float speed) {
  46. pid.err_next = 0.0;
  47. pid.SetSpeed = speed;
  48. pid.err = pid.SetSpeed - pid.ActualSpeed;
  49. float incrementSpeed = pid.Kp*(pid.err - pid.err_next) + pid.Ki*pid.err + pid.Kd*(pid.err - 2 * pid.err_next + pid.err_last);
  50. pid.ActualSpeed += incrementSpeed;
  51. pid.err_last = pid.err_next;
  52. pid.err_next = pid.err;
  53. return pid.ActualSpeed;
  54. }
  55. //积分分离PID
  56. float IntegralSeparatio_PID_realize( float speed) {
  57. int index;
  58. pid.Kp = 0.2;
  59. pid.Ki = 0.04;
  60. pid.Kd = 0.2;
  61. pid.SetSpeed = speed;
  62. pid.err = pid.SetSpeed - pid.ActualSpeed;
  63. if (abs(pid.err) > 200) {
  64. index = 0;
  65. }
  66. else {
  67. index = 1;
  68. pid.integral += pid.err;
  69. }
  70. pid.voltage = pid.Kp*pid.err + index*pid.Ki*pid.integral + pid.Kd*(pid.err - pid.err_last);
  71. pid.err_last = pid.err;
  72. pid.ActualSpeed = pid.voltage* 1.0;
  73. return pid.ActualSpeed;
  74. }
  75. //抗饱和PID
  76. float anti_windup_PID_realize( float speed) {
  77. pid.Kp = 0.2;
  78. pid.Ki = 0.1;
  79. pid.Kd = 0.2;
  80. pid.umax = 400;
  81. pid.umin = -200;
  82. int index;
  83. pid.SetSpeed = speed;
  84. pid.err = pid.SetSpeed - pid.ActualSpeed;
  85. if (pid.ActualSpeed > pid.umax) {
  86. if (abs(pid.err) > 200)
  87. {
  88. index = 0;
  89. }
  90. else {
  91. index = 1;
  92. if (pid.err < 0)
  93. {
  94. pid.integral += pid.err;
  95. }
  96. }
  97. }
  98. else if (pid.ActualSpeed < pid.umin) {
  99. if (abs(pid.err) > 200)
  100. {
  101. index = 0;
  102. }
  103. else {
  104. index = 1;
  105. if (pid.err > 0)
  106. {
  107. pid.integral += pid.err;
  108. }
  109. }
  110. }
  111. else {
  112. if (abs(pid.err) > 200)
  113. {
  114. index = 0;
  115. }
  116. else {
  117. index = 1;
  118. pid.integral += pid.err;
  119. }
  120. }
  121. pid.voltage = pid.Kp*pid.err + index*pid.Ki*pid.integral + pid.Kd*(pid.err - pid.err_last);
  122. pid.err_last = pid.err;
  123. pid.ActualSpeed = pid.voltage* 1.0;
  124. return pid.ActualSpeed;
  125. }
  126. //测试代码
  127. int main() {
  128. printf( "system begin\n");
  129. PID_init();
  130. int count = 0;
  131. while (count < 500)
  132. {
  133. float speed = anti_windup_PID_realize( 200.0);
  134. printf( "%f\n", speed);
  135. count++;
  136. }
  137. system( "pause");
  138. return 0;
  139. }



        </div>
            </div>
        </article># 欢迎使用Markdown编辑器写博客


猜你喜欢

转载自blog.csdn.net/u014100311/article/details/81204208