打印
[应用相关]

PID算法

[复制链接]
976|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gygp|  楼主 | 2023-3-31 10:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1.根据我控制算法类文章中关于PID的理论的一些描述,同时也根据网络上一些其他的PID文章,以及自己最近一个项目的实践后,总结了几套基于C语言的PID算法,由于网络中很少有人进行分享完整的PID算法实现,我这里分享下。
(1)头文件,定义pid的结构体,类的概念,包含pid的属性和方法
#ifndef __PID_H_
#define __PID_H_

#include <stdint.h>



typedef struct _pid
{
    int16_t set_value;            // 给定值,rin(k)
    int16_t actual_value;         // 实际值,反馈值,rout(k)
    int16_t err;                  // 偏差值,rin(k) - rout(k)
    int16_t err_last;             // 上一次偏差值,rin(k - 1) - rout(k - 1)
    int16_t err_last_last;        // 上一次上一次的偏差值,rin(k - 2) - rout(k - 2)
    float kp;                       // 比例系数
    float ki;                       // 积分系数
    float kd;                       // 微分系数
    float uk;                       // pid公式运算结果值
    float incremental_value;      // 增量值
    float integral_value;             // 积分值
    float umax;                 // uk的上限值,抗积分饱和用
    float umin;                 // uk的下限值,抗积分饱和用
    int16_t err_up_value;         // 偏差上限值,积分分离用
    int16_t ki_k;                 // 积分的再次乘机系数,积分分离用
   
    float out_value;              //
   
    float(*position_type)(struct _pid *ppid);                       // 位置型PID算法,无积分分离、无抗积分饱和
    float(*incremental_type)(struct _pid *ppid);              // 增量型PID算法
    float(*integral_separation_type)(struct _pid *ppid);      // 积分分离PID算法
    float(*int_sep_anti_sat_type)(struct _pid *ppid);         // 积分分离 + 抗积分饱和PID算法
}_pid_t;







_pid_t *pid_create(void);



extern _pid_t *pg_pid;







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

#include "pid.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "portmacro.h"
#include "semphr.h"

#include "Debug.h"



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


/*************************************
*
* Funciton Name : pid_incremental_type_f
* Function      :增量型PID算法
*
* @author       :why
* @note         : 相较于位置型,因为与3个偏差相关,增强了系统稳定性
*
× @param         :pid
*
*
* @return       : uk + 增量值
*************************************/
static float pid_incremental_type_f(struct _pid *ppid)
{
    ppid->err = ppid->set_value - ppid->actual_value;   // 偏差
   
    //ppid->integral_value += ppid->err;                  // 积分累加
   
    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);
   
    ppid->uk += ppid->incremental_value;
   
    ppid->err_last_last = ppid->err_last;
    ppid->err_last = ppid->err;
   
    return (ppid->uk);
}


/*************************************
*
* Funciton Name : pid_integral_separation_type_f
* Function      :积分分离PID算法
*
* @author       :why
* @note         : 能解决初期系统偏差值大,累加到积分项中,引起系统超调、振荡问题。积分是为了消除静态误差的,应在误差在小范围时引入积分
*
× @param         :pid
*
*
* @return       : uk
*************************************/
static float pid_integral_separation_type_f(struct _pid *ppid)
{
    ppid->err = ppid->set_value - ppid->actual_value;   // 偏差
   
    // 误差过大去除积分效果
    if ( abs(ppid->err) > ppid->err_up_value )
    {
        ppid->ki_k = 0;
    }
    else
    {
        ppid->ki_k = 1;
        ppid->integral_value += ppid->err;              // 积分累加
    }      
   
    ppid->uk = ppid->kp * ppid->err + ppid->ki_k * ppid->ki * ppid->integral_value + ppid->kd * (ppid->err - ppid->err_last);
   
    ppid->err_last = ppid->err;
   
    return (ppid->uk);
}


/*************************************
*
* Funciton Name : pid_int_sep_anti_sat_type_f
* Function      :积分分离 + 抗积分饱和PID算法
*
* @author       :why
* @note         : 能解决初期系统偏差值大,累加到积分项中,引起系统超调、振荡问题。积分是为了消除静态误差的,应在误差在小范围时引入积分
*               : 抗积分饱和:能解决执行器到达极限值时,但uk还在增大,使得系统进入饱和,进入饱和区的时间越长,当系统出现反向偏差,解决这个反向偏差的时间就会越长,此时系统会像失控一样。
*               :进入抗积分饱和,当uk超过上限时,积分向只累加负偏差,当uk超过下限时,积分项只累加正偏差。
*
× @param         :pid
*
*
* @return       : uk
*************************************/
static float pid_int_sep_anti_sat_type_f(struct _pid *ppid)
{
    ppid->err = ppid->set_value - ppid->actual_value;   // 偏差
   
    Debug("ppid->err = %d\r\n", ppid->err);
   
    if ( ppid->out_value > ppid->umax )                    // 抗积分饱和
    {
        // 误差过大去除积分效果
        if ( abs(ppid->err) > ppid->err_up_value )  // 积分分离
        {
            ppid->ki_k = 0;
        }
        else
        {
            ppid->ki_k = 1;
            
            if ( ppid->err < 0 )                    
            {
                ppid->integral_value += ppid->err;              // 积分累加
            }
            
        }   
    }
    else if ( ppid->out_value < ppid->umin )                // 抗积分饱和
    {
        // 误差过大去除积分效果
        if ( abs(ppid->err) > ppid->err_up_value )  // 积分分离
        {
            ppid->ki_k = 0;
        }
        else
        {
            ppid->ki_k = 1;
            
            if ( ppid->err > 0 )                    
            {
                ppid->integral_value += ppid->err;              // 积分累加
            }
            
        }
    }
    else
    {
        // 误差过大去除积分效果
        if ( abs(ppid->err) > ppid->err_up_value )
        {
            ppid->ki_k = 0;
        }
        else
        {
            ppid->ki_k = 1;
            ppid->integral_value += ppid->err;              // 积分累加
        }
    }
   
    ppid->uk = ppid->kp * ppid->err + ppid->ki_k * ppid->ki * ppid->integral_value + ppid->kd * (ppid->err - ppid->err_last);
   
    ppid->err_last = ppid->err;
   
//    if ( ppid->uk >= 0.07 && ppid->uk <= 1 )
//    {
//        ppid->uk = 1;
//    }
//   
//    if ( ppid->uk <= -0.07 && ppid->uk >= -1 )
//    {
//        ppid->uk = -1;
//    }
   
    return (ppid->uk);
}

/*************************************
*
* Funciton Name    : pid_init
* Function         : pid实例构造
*
* @author       :why
*
*
*************************************/
static void pid_init(_pid_t *ppid)
{
    ppid->kp = 0.2;
    ppid->ki = 0.05;
    ppid->kd = 0;
   
    ppid->umax = 4000;
    ppid->umin = 0;
   
   
    ppid->position_type = pid_position_type_f;
    ppid->incremental_type = pid_incremental_type_f;
    ppid->integral_separation_type = pid_integral_separation_type_f;
    ppid->int_sep_anti_sat_type = pid_int_sep_anti_sat_type_f;
}


/*************************************
*
* Funciton Name    : pid_create
* Function         : pid实例创建
* @author          : why
*
* @return          : 返回pid实例
*
*************************************/
_pid_t *pid_create(void)
{
    _pid_t *ppid = (_pid_t *)pvPortMalloc(sizeof(_pid_t));
   
    memset(ppid, 0, sizeof(_pid_t));
   
    pid_init(ppid);
   
    return ppid;
}
(3)PID的实现算法有了,但还是要根据实际情况进行调试选取最适合的PID算法以及修改可能存在的不恰当的位置。

使用特权

评论回复
沙发
万图| | 2024-4-15 07:12 | 只看该作者

含有延展到远高于基本开关频率的谐波

使用特权

评论回复
板凳
Uriah| | 2024-4-15 08:15 | 只看该作者

这些引线越窄越好

使用特权

评论回复
地板
帛灿灿| | 2024-4-15 10:11 | 只看该作者

输入电容主要是起到高频能量存储器的作用

使用特权

评论回复
5
Bblythe| | 2024-4-15 11:14 | 只看该作者

输入滤波电容的公共端应作为其他交流电流地的唯一接点

使用特权

评论回复
6
周半梅| | 2024-4-15 13:10 | 只看该作者

它们对PCB布局的重要性

使用特权

评论回复
7
Pulitzer| | 2024-4-15 14:13 | 只看该作者

混淆的话,会引起电源工作不稳定

使用特权

评论回复
8
童雨竹| | 2024-4-15 16:09 | 只看该作者

把这干扰信号再次辐射出去

使用特权

评论回复
9
Wordsworth| | 2024-4-15 17:12 | 只看该作者

对变换器效率测量

使用特权

评论回复
10
Clyde011| | 2024-4-15 18:15 | 只看该作者

把纹波电流分摊到每个电容上

使用特权

评论回复
11
公羊子丹| | 2024-4-15 19:08 | 只看该作者

印制电路板(PCB)的线路设计

使用特权

评论回复
12
xiaoqi000| | 2024-8-31 23:13 | 只看该作者
使用了标准的头文件保护宏 #ifndef __PID_H_ 和 #define __PID_H_,这很好地防止了头文件被重复包含。

使用特权

评论回复
13
LOVEEVER| | 2024-9-13 17:33 | 只看该作者
PID的实现算法有了,重要的还是需要参数设置适配

使用特权

评论回复
14
xdvca| | 2024-9-17 14:36 | 只看该作者
由于网络中很少有人进行分享完整的PID算法

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

184

主题

8184

帖子

15

粉丝