PID的算法改进

PID的算法改进

#本系列用来记录和输出自己学习PID的记录(看的是江协)#

out(t) = Kp * error(t) + Ki *error(t)dt + Kd *

1、积分限幅(防止积分饱和):
是指对误差的积分累加器(∑error)设置最大值 Imax 和 Imin,而不是限制乘完 Ki 后的结果。
它的作用是防止执行器达到物理极限(如PWM满幅)后,积分项仍在疯狂累加。当实际值因负载过重无法跟上目标值时,积分项会将累加器撑爆,导致系统在目标值突变时产生巨大的滞后和震荡。通过在累加器上设置“天花板”,可以有效扼制这种情况,保证系统在饱和状态下依然能快速恢复控制。

// 1. 累加误差(原始数据)
integral_sum += error;

// 2. 【关键步骤】在这里限幅!限制的是累加和,而不是乘完Ki的结果
if (integral_sum > INTEGRAL_MAX) integral_sum = INTEGRAL_MAX;
if (integral_sum < INTEGRAL_MIN) integral_sum = INTEGRAL_MIN;

// 3. 最后再乘上 Ki 系数输出
integral_output = Ki * integral_sum;

2、积分分离

设置一个误差阈值,当误差值很大时候关闭I项的控制使用PD控制,当误差小的时候打开I项使用PID控制。其主要式解决过冲或者超调的问题。

那么主要是解决的呢?当我们设置PI控制后,P向目标值进发,I累计误差,当P冲到顶了,I项误差累积加起来了,I项就会有惯性了(I是之前所有时刻的误差累积)就会超出目标值就产生了超调,当我们设置了分离后,不让I提早加入,只有P到头后I在加入累积的误差很小就不会产生了。当然了,如果P给我过打也会产生超调!!!

if (abs(error) > 阈值)
{
integral = 0; // 或者不进行累加
// 此时输出 = P项 + D项
}
else
{
integral += Ki * error; // 只有接近目标时才累积
}

3、变速积分

变速积分的实质,是根据误差大小动态调节积分项的有效增益(Ki * α)。误差越大,积分增益被压缩得越小;误差越小,积分增益恢复得越大。

引入一个动态系数 α(阿尔法),取值范围 0 ~ 1。

最终参与积分的有效系数 = Ki × α

误差大时:α 趋近于 0(相当于把 Ki 临时缩小了)。

误差小时:α 趋近于 1(相当于 Ki 满血复活)。

学到这里我们知道误差越大,Ki越小;误差越小,Ki越大,但是我就有个问题不应该是误差越大Ki越大,误差越小Ki越小,我这的理解对于P项来理解是没有问题,但是放在I项来理解就错完了,因为假设目标值是100,P项为推到了95,我们距离目标值只剩下5,那么这个时候我们是不是应该让积分项工作呢,所以I项只能是趋向1而不能是0,当为0时候I项不工作的,输出值就一直停留在了95.

#define ERROR_MAX 100.0 // 设定误差的最大范围
#define ERROR_MIN 10.0 // 设定误差的最小范围(死区边界)

float get_variable_coefficient(float error)
{
float abs_err = fabs(error);

if (abs_err >= ERROR_MAX)
return 0.0; // 误差极大,放弃积分,防止超调
else if (abs_err <= ERROR_MIN)
return 1.0; // 误差很小,全额积分,消除静差
else
// 线性渐变 (误差越大,系数越接近0)
return (ERROR_MAX - abs_err) / (ERROR_MAX - ERROR_MIN);
}

// 在主循环中:
float alpha = get_variable_coefficient(error);
integral += Ki * alpha * error; // 积分累加使用了变速系数