位置式与增量式PID代码(C语言实现)

   

目录

一、位置式PID

1.1遇限消弱积分法

1.2反馈抑制抗饱和PID

 1.3实现

1.3.1头文件

1.3.2 源文件

二、增量式PID

2.1实现

2.1.1头文件

2.1.2源文件

三、调用范例


一、位置式PID

在控制信号幅值受限、且给定目标出现大跳变的情况下,积分控制容易产生积分器饱和(integrator windup)的现象,使系统出现大超调和低频震荡,甚至导致不稳定。

课上所学两种抗积分饱和方法:遇限消弱积分法,反馈抑制抗饱和PID

1.1遇限消弱积分法

遇限消弱积分法是其中比较有效的一种抗饱和方法,其基本思想是:当执行器处于饱和、且误差信号与控制信号同方向(同号)时,积分器停止更新(其值保持不变),除此之外,积分器正常工作。即,在饱和情况下,只进行有助于削弱饱和程度的积分运算。在离散控制(采样周期为T)模式下,相应的控制律如下:

1.2反馈抑制抗饱和PID

如图1所示,反馈抑制抗饱和PID是把计算的控制量超出其限幅范围的偏差值通过反馈进入积分器,从而迫使控制量返回到限幅值之内。在离散时间(采样周期T)域中,其控制律可以表
示为

 1.3实现

1.3.1头文件

/*
 * AW_PID.h
 *
 *  Created on: 2021年9月29日
 *      Author: longchentian
 */

#ifndef INCLUDE_AW_PID_H_
#define INCLUDE_AW_PID_H_

typedef  struct {
    float32  Ref;           // 输入:参考输入  Input: Reference input
    float32  Fdb;           // 输入:反馈输入  Input: Feedback input
    float32  Err;           // 变量:误差信号e(k)
    float32  Err_1;          // 变量:误差信号e(k-1)   Variable: Error
    float32  umax;          // 参数:控制量的饱和限幅值
    float32  Ts;            // 控制周期

    float32  kw;            // 参数:抗饱和方案:0 (无);1(条件积分);2(反馈抑制)
    float32  Kp;            // 参数:比例增益  Parameter: Proportional gain
    float32  Ki;            // 参数:积分增益 Parameter: Integral gain
    float32  Kc;            // 参数:积分修正增益 Parameter: Integral correction gain
    float32  Kd;            // 参数:微分增益Parameter: Derivative gain

    float32  Up;            // 变量:比例输出  Variable: Proportional output
    float32  Ui;            // 变量:积分输出  Variable: Integral output
    float32  Ud;            // 变量:微分输出  Variable: Derivative output
    float32  Ud1;           // 变量:微分输出(k-1)  Variable: Derivative output
    float32  N;             // 变量:低通滤波参数

    float32  OutPreSat;     // 变量:饱和输出  Variable: Pre-saturated output
    float32  OutMax;        // 参数:最大输出  Parameter: Maximum output
    float32  OutMin;        // 参数:最小输出  Parameter: Minimum output
    float32  Out;           // 输出:AW_PID输出  Output: AW_PID output
    float32  SatErr;        // 变量:饱和差值 Variable: Saturated difference
    void  (*calc)();        // 计算函数指针  Pointer to calculation function
    } AW_PID;
typedef   AW_PID*  AW_PID_handle;
/*-----------------------------------------------------------------------------
  默认初始化   Default initalizer for the AW_PID object.
-----------------------------------------------------------------------------*/
#define  AW_PID_DEFAULTS { 0, 0, 0, 0, 0, 0, \
                           0, 0, 0, 0, 0, \
                           0, 0, 0, 0, 10, \
                           0, 0, 0, 0, 0, \
                    (void (*)(Uint32)) aw_pid_calc }
/*------------------------------------------------------------------------------
  函数原型   Prototypes for the functions in  <AW_PID.c>
------------------------------------------------------------------------------*/
void aw_pid_calc(AW_PID_handle);


#endif /* INCLUDE_AW_PID_H_ */

1.3.2 源文件

/*============================================================
    <<aw_pid.c  >>     Anti-windup PID controller
------------------------------------------------------------------------------------------------------*/
#include "dmctype.h"
#include "aw_pid.h"

// include the header for PID data structure definition

void aw_pid_calc(AW_PID * v)
{
    float32 uk;
    v->Err = v->Ref - v->Fdb;
    v->Up = v->Kp*v->Err;    // Compute the proportional output
    // Compute the integral output
    if (v->kw==0)
        v->Ui = v->Ui + v->Ki*v->Err;
    else if (v->kw==1)
    {
        if ((v->SatErr==0) || ( v->Err*v->SatErr>0))
            v->Ui = v->Ui + v->Ki*v->Err;
    }
    else
        v->Ui = v->Ui + v->Ki*v->Err + v->Kc*v->SatErr;
    // Compute the derivative output
    // v->Ud = v->Ud1/(v->N+1)+v->Kd*(v->Err - v->Err_1)*v->N/(v->N+1);
    v->Ud=v->Kd*(v->Err - v->Err_1);

    // Compute the pre-saturated output
    uk = v->Up + v->Ui + v->Ud;
    v->OutPreSat = uk;

    // Saturate the output
    if (v->OutPreSat > v->OutMax)
        v->Out =  v->OutMax;
    else if (v->OutPreSat < v->OutMin)
        v->Out =  v->OutMin;
    else
        v->Out = v->OutPreSat;

    // Compute the saturate difference
    v->SatErr = v->Out - v->OutPreSat;

    // Update the relevant variables
    v->Err_1 = v->Err;
    v->Ud1 =  v->Ud;
}


二、增量式PID

增量式PID

• 增量式算法不需要对积分项累加,控制量增量只与近几次的误差有关,计算误差对控制量计算的影响较小。而位置式算法要对近几次的偏差的进行积分累加,容易产生较大的累加误差;

• 增量式算法得出的是控制量的增量,例如在阀门控制中,只输出阀门开度的变化部分,误动作影响小,必要时还可通过逻辑判断限制或禁止本次输出,不会严重影响系统的工作;而位置式的输出直接对应对象的输出,因此对系统影响较大;

• 增量式算法控制输出的是控制量增量,并无积分作用,因此该方法适用于执行机构带积分部件的对象,如步进电机等,而位置式算法适用于执行机构不带积分部件的对象,如电液伺服阀;

积分饱和现象是位置式PID 算法应用常见的一种现象,因此对于位置式PID 算法除了需要对输出进行限幅外还需要对积分输出进行限幅,而增量式算法很好地避免了积分饱和现象,因此在增量式PID 控制算法中只需要对输出限幅,而无需积分限幅。

2.1实现

2.1.1头文件

/*
 * eh_pid.h
 *
 *  Created on: 2021年10月10日
 *      Author: longchentian
 */

#ifndef EH_PID_H_
#define EH_PID_H_

typedef  struct {
    float32  Ref;           // 输入:参考输入  Input: Reference input
    float32  Fdb;           // 输入:反馈输入  Input: Feedback input、
    float32  Err;            //变量:误差信号e(k)
    float32  Err_1;          // 变量:误差信号e(k-1)   Variable: Error
    float32  Err_2;          // 变量:误差信号e(k-2)   Variable: Error
    float32  umax;          // 参数:控制量的饱和限幅值
    float32  Ts;            // 控制周期

    float32  Kp;            // 参数:比例增益  Parameter: Proportional gain
    float32  Ki;            // 参数:积分增益 Parameter: Integral gain
    float32  Kd;            // 参数:微分增益Parameter: Derivative gain


    float32  OutPreSat;     // 变量:饱和输出  Variable: Pre-saturated output
    float32  OutMax;        // 参数:最大输出  Parameter: Maximum output
    float32  OutMin;        // 参数:最小输出  Parameter: Minimum output
    float32  Out;           // 输出:SP_PID输出  Output: SP_PID output


    void  (*calc)();        // 计算函数指针  Pointer to calculation function
    } EH_PID;
typedef   EH_PID*  EH_PID_handle;


/*-----------------------------------------------------------------------------
  默认初始化   Default initalizer for the AW_PID object.
-----------------------------------------------------------------------------*/
#define  EH_PID_DEFAULTS { 0, 0, 0, 0, 0, 0, 0,\
                           0, 0, 0, \
                           0, 0, 0, 0, \
                    (void (*)(Uint32)) eh_pid_calc }

void eh_pid_calc(EH_PID_handle);

#endif /* EH_PID_H_ */

2.1.2源文件



#include "dmctype.h"
#include "eh_pid.h"

// include the header for PID data structure definition


void eh_pid_calc(EH_PID * v)
{

    float32 Delta_Err;                  //e(k)-e(k-1)
    float32 Last_Delta_Err;             //e(k-1)-e(k-2)
    float32 uk;                         //本次调节输出值

    v->Err = v->Ref - v->Fdb;
    Delta_Err=v->Err-v->Err_1;
    Last_Delta_Err=v->Err_1-v->Err_2;

    uk=v->Out+v->Kp*Delta_Err+v->Ki* v->Err +v->Kd*(Delta_Err-Last_Delta_Err);

    v->OutPreSat = uk;
    // Saturate the output
    if (v->OutPreSat > v->OutMax)
        v->Out =  v->OutMax;
    else if (v->OutPreSat < v->OutMin)
        v->Out =  v->OutMin;
    else
        v->Out = v->OutPreSat;

    v->Err_2=v->Err_1;
    v->Err_1= v->Err ;

}


三、调用范例

//初始化
EH_PID pid3=EH_PID_DEFAULTS;
pid3.Kp = 0.459750444;
pid3.Ki = 0.0539999164;
pid3.Kd = 0.595000153;
pid3.Ts = Ts;
pid3.OutMax = 12;
pid3.OutMin =  0;
pid3.Ref = SpeedRef;

//闭环反馈
pid3.Fdb = speed;
pid3.calc(&pid3);
control_uk =   pid3.Out;

  • 6
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值