野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 11646|回复: 20

PID算法实现(c 语言)

[复制链接]
发表于 2013-9-7 13:36:03 | 显示全部楼层 |阅读模式

[code=cpp]
#include <stdio.h>
#include<math.h>

//定义PID 的结构体
struct _pid
{
    int pv; //integer that contains the process value 过程量
    int sp; //*integer that contains the set point   设定值
    float integral; // 积分值 -- 偏差累计值
    float pgain;
    float igain;
    float dgain;
    int deadband;    //死区
    int last_error;
};

struct _pid warm,*pid;
int process_point, set_point,dead_band; float p_gain, i_gain, d_gain,integral_val,new_integ;;

/*----------------------------------------------
pid_init DESCRIPTION This function initializes the
pointers  in  the  _pid  structure  to  the  process  variable
and the setpoint. *pv and *sp are integer pointers.
---------------------------------------------- */

void pid_init(struct _pid *warm, int process_point, int set_point)
{
    struct _pid *pid;
    pid = warm;
    pid->pv = process_point;
    pid->sp = set_point;
}

/*----------------------------------------------
pid_tune DESCRIPTION Sets the proportional gain
(p_gain), integral gain (i_gain),
derivitive  gain  (d_gain),  and  the  dead  band  (dead_band)
of a pid control structure _pid.  

设定PID参数 ---- P,I,D,死区
---------------------------------------------- */

void pid_tune(struct _pid *pid, float p_gain, float i_gain, float d_gain, int dead_band)
{
    pid->pgain = p_gain;
    pid->igain = i_gain;
    pid->dgain = d_gain;
    pid->deadband = dead_band;
    pid->integral= integral_val;
    pid->last_error=0;
}

/*----------------------------------------------
pid_setinteg DESCRIPTION Set a new value for the
integral term of the pid equation.
This is useful for setting the initial output of the
pid controller at start up.

设定输出初始值
---------------------------------------------- */

void pid_setinteg(struct _pid *pid,float new_integ)
{
    pid->integral = new_integ;
    pid->last_error = 0;
}

/*----------------------------------------------
pid_bumpless DESCRIPTION Bumpless transfer
algorithim.
When suddenly changing setpoints, or when restarting
the PID equation after an extended pause,
the derivative of the equation can cause a bump in the controller output. This function will help smooth out
that bump.
The process value in *pv should be the updated just
before this function is used.

pid_bumpless 实现无扰切换
当突然改变设定值时,或重新启动后,将引起扰动输出。这
个函数将能实现平顺扰动, 在调用该函数之前需要先更新 PV值
----------------------------------------------*/

void pid_bumpless(struct _pid *pid)
{
    pid->last_error = (pid->sp)-(pid->pv);  //设定值与反馈值偏差
}

/*----------------------------------------------
pid_calc  DESCRIPTION  Performs  PID  calculations  for  the
_pid structure *a. This function uses the positional form of the pid
equation, and incorporates an integral windup
prevention algorithim.
Rectangular  integration  is  used,  so  this  function  must
be repeated on a consistent time basis for accurate
control.
RETURN VALUE The new output value for the pid loop.
USAGE #include "control.h"
本函数使用位置式PID计算方式,并且采取了积分饱和限制运算
PID计算
----------------------------------------------*/

float pid_calc(struct _pid *pid)
{
int err;
float pterm, dterm, result, ferror;

// 计算偏差
err = (pid->sp) - (pid->pv);
// 判断是否大于死区
    if (abs(err) > pid->deadband)
    {
        ferror = (float) err;   //do integer to float conversion only once 数据类型转换
         
        // 比例项
        pterm = pid->pgain * ferror;
         
        if (pterm > 100 || pterm < -100)
        {
            pid->integral = 0.0;
        }
        else
        {
            // 积分项
            pid->integral += pid->igain * ferror;
            
            // 输出为0--100%
            // 如果计算结果大于100,则等于100
            if (pid->integral > 100.0)
            {
                pid->integral = 100.0;
            }
            // 如果计算结果小于0.0,则等于0
            else if (pid->integral < 0.0)
            {
                pid->integral = 0.0;
            }
         
        }
     
        // 微分项
        dterm  =  ((float)(err  -  pid->last_error))  *  pid->dgain;
         
        result = pterm + pid->integral + dterm;
    }
    else
    {
        result = pid->integral; // 在死区范围内,保持现有输出
    }
     
    // 保存上次偏差
    pid->last_error = err;
     
    // 输出PID值(0-100)
    return (result);
}
  
//----------------------------------------------
void main(void)
{
    float display_value;
    int count=0;
    pid = &warm;
     
    // printf("Enter the values of Process point, Set point, P gain, I gain, D gain \n");
    // scanf("%d%d%f%f%f", &process_point, &set_point,&p_gain, &i_gain, &d_gain);
     
    // 初始化参数
    process_point = 30;
    set_point = 40;
    p_gain = (float)(5.2);
    i_gain = (float)(0.77);
    d_gain = (float)(0.18);
    dead_band = 2;  
    integral_val =(float)(0.01);
     
    printf("The  values  of  Process  point,  Set  point,  P  gain, I gain, D gain \n");
    printf(" %6d %6d %4f %4f %4f\n", process_point,
    set_point, p_gain, i_gain, d_gain);
    printf("Enter the values of Process point\n");
    while(count<=20)
    {
        scanf("%d",&process_point);
         
        // 设定PV,SP 值
        pid_init(&warm, process_point, set_point);
         
        // 初始化PID 参数值
        pid_tune(&warm, p_gain,i_gain,d_gain,dead_band);
         
        // 初始化PID 输出值
        pid_setinteg(&warm,0.0);
        //pid_setinteg(&warm,30.0);
         //Get input value for process point
        pid_bumpless(&warm);
         
        // how to display output
        display_value = pid_calc(&warm);
         
        printf("%f\n", display_value);
        //printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,wa
        rm.dgain);
         
        count++;
    }
}[/code]
回复

使用道具 举报

发表于 2013-10-17 22:40:33 | 显示全部楼层
不错,怎么没人顶啊?
回复 支持 反对

使用道具 举报

发表于 2013-11-21 21:54:01 | 显示全部楼层
顶起来,很有用的东西。
回复 支持 反对

使用道具 举报

发表于 2014-4-28 21:53:19 | 显示全部楼层
这么好 顶一顶
回复 支持 反对

使用道具 举报

发表于 2014-7-11 03:53:38 | 显示全部楼层
帅呆了,赞一个
回复 支持 1 反对 0

使用道具 举报

发表于 2014-7-11 08:07:20 | 显示全部楼层
走过路过,不能错过
回复 支持 反对

使用道具 举报

发表于 2015-1-11 20:44:50 | 显示全部楼层
好东西啊!
回复

使用道具 举报

发表于 2015-1-20 10:47:00 | 显示全部楼层
很好,收藏起来
回复 支持 反对

使用道具 举报

发表于 2015-1-23 11:01:09 | 显示全部楼层
回复

使用道具 举报

发表于 2015-7-21 16:21:40 | 显示全部楼层
楼主,你的死区是什么意思?
回复 支持 反对

使用道具 举报

发表于 2015-8-14 01:00:08 | 显示全部楼层
并不能看懂
回复 支持 反对

使用道具 举报

发表于 2016-1-4 09:34:00 | 显示全部楼层
超帅,虽然还没理解,先赞一个。
回复 支持 反对

使用道具 举报

发表于 2016-1-4 09:36:32 | 显示全部楼层
感觉要确定PID参数还是有一定难度的。
回复 支持 反对

使用道具 举报

发表于 2016-8-21 18:30:01 | 显示全部楼层
微粒子,你好!关于PID的那篇,我把你的程序复制进去,可以运行。设定值为40,刚开始的过程值是30,那么怎么验证30会向40靠拢呢??
回复 支持 反对

使用道具 举报

发表于 2016-8-21 20:55:25 | 显示全部楼层
其实 我全都没看懂。。
回复 支持 反对

使用道具 举报

发表于 2016-8-22 11:27:23 | 显示全部楼层
感觉挺好的  。。。还没测试   
回复 支持 反对

使用道具 举报

发表于 2016-9-26 20:39:44 | 显示全部楼层
PID参数设定本身就有一定的难度,通用算法还是要做一定的改进才能用
回复 支持 反对

使用道具 举报

发表于 2017-2-22 19:21:50 | 显示全部楼层
先收藏,慢慢学
回复 支持 反对

使用道具 举报

发表于 2017-2-23 09:18:28 | 显示全部楼层
感谢分享                 
回复 支持 反对

使用道具 举报

发表于 2017-2-23 09:52:38 | 显示全部楼层
先收藏了,慢慢摸索
回复 支持 反对

使用道具 举报

发表于 2017-8-18 14:40:37 | 显示全部楼层
感谢楼主的分享
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-5-13 19:06 , Processed in 0.036142 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表