目录
分析积分项的积分饱和
这么做的意义
参数解释
注意
/*************************************** 功能:电流环PID 形参:电流参考、电流反馈、新电流输出、积分累积值、FOC周期 说明:根据电流误差调节电流输出 Current_PID_Calc(Id_ref, Id_fdb, &Vd_out, Current_Kp, Current_Ki, &Current_I_Sum_d, dt); 目标Id轴, 采样计算反馈Id, I环计算新d轴电流 , Kp , Ki , 电流环d轴积分项 , 周期时间 Current_PID_Calc(Iq_ref, Iq_fdb, &Vq_out, Current_Kp, Current_Ki, &Current_I_Sum_q, dt); 目标Iq轴, 采样计算反馈Iq , I环计算新q轴电流 , Kp , Ki , 电流环q轴积分项 , 周期时间 ***************************************/ void Current_PID_Calc(float ref_temp, float fdb_temp, float *out_temp, float PI_Kp, float PI_Ki, float *I_Sum, float FOC_PERIOD) { float error, temp; // 计算误差 error = ref_temp - fdb_temp; // erro = 目标Id轴 - 采样计算反馈Id // PID计算 temp = PI_Kp * error + *I_Sum; // temp = Kp * error + Ki * 电流环d轴积分项 // 限制输出范围 if (temp > Current_Max_Output) { *out_temp = Current_Max_Output; } else if (temp < Current_Min_Output) { *out_temp = Current_Min_Output; } else { *out_temp = temp; } // 更新积分项 // q/d轴积分项 += ((输出值 - 预测值)* Current_PI_B + Ki*误差) * 周期时间 *I_Sum += ((*out_temp - temp) * Current_PI_B + PI_Ki * error) * FOC_PERIOD; }// 更新积分项
// q/d轴积分项 += ((输出值 - 预测值)* Current_PI_B + Ki*误差) * 周期时间
*I_Sum += ((*out_temp - temp) * Current_PI_B + PI_Ki * error) * FOC_PERIOD;
分析积分项的积分饱和
它使用的是一种名为“ 反计算抗饱和 ”的算法。
“ 积分限幅 ”和“ 积分分离 ”的结合,这行代码正是为了防止“积分饱和(Windup)”导致电机失控而设计的。
代码拆解开来看:
*I_Sum += ((*out_temp - temp) * Current_PI_B + PI_Ki * error) * FOC_PERIOD;
1. 正常情况下的积分(当没有超出限制时)
假设 temp(计算出的输出)没有超过 Current_Max_Output(20)。
此时 *out_temp = temp。
所以 (*out_temp - temp) == 0。
公式就退化成了标准的积分:*I_Sum += PI_Ki * error * FOC_PERIOD;
这完全符合常理:积分项 = 积分系数 × 误差 × 时间周期。
2. 饱和情况下的积分(抗饱和机制)
假设电机堵转了,误差 error极大,算出来的 temp 狂飙到了 50,而你的最大输出限制是 20。
此时代码会进行限幅,*out_temp = 20(限制后的值),而 temp 依然是 50(计算出的原始值)。
此时 (*out_temp - temp) 的结果是 20 - 50 = -30(一个负数)。
这个负数乘以 Current_PI_B(反计算系数,比如0.1,就变成了 -3),会作为“ 惩罚项 ”加到积分累加中。
结果: 积分项 *I_Sum 不仅不会继续往上狂涨,反而会被这个负数狠狠地“踩一脚刹车”往回拉。
这次的误差error太大,如果加入积分会导致积分项过大;
然而,积分项作用一般位于调控后期,所以这次的误差error不作为正累计,反而是作为负数,惩罚地拉会积分项。
电机堵转:电机通电了,也在拼命输出扭矩,但转子却因为某种原因转不动(转速为 0)
这么做的意义
如果没有这行抗饱和代码,当电机被卡住(堵转)时:
1. 误差 error 一直很大。
2. 积分项 *I_Sum 会疯狂累积,变成天文数字(这就是“深度饱和”)。
3. 当你突然移开障碍物时,虽然误差瞬间变小了,但那个巨大的 *I_Sum 还在。
4. 输出 temp = Kp*error + *I_Sum 依然极大,会继续维持在 20。
5. 电机将像疯了一样满血输出,等积分慢慢降下来时,电机已经超调跑偏,甚至撞坏机械结构。
只要输出被限制在 20 死区外,它就会自动生成一个负反馈,把积分项拉回到一个合理的范围。一旦输出回到 20 以内,惩罚项消失,积分继续正常工作。
参数解释
Current_PI_B:抗饱和反馈系数。这个值决定了“刹车”的力度。值越大,积分拉回来的速度越快;值太小,抗饱和效果不明显。
FOC_PERIOD:FOC 控制周期时间(比如50微秒)。积分在物理意义上是对时间的累积,所以必须乘以时间。
注意
严格来说,在 PID 理论中,反计算抗饱和的公式应该是:
`积分更新 = Ki * error * T + Kb * (输出受限值 - 输出未受限值)`
你这行代码将它合并成了:
*I_Sum += (PI_Ki * error + (*out_temp - temp) * Current_PI_B) * FOC_PERIOD;
它在数学上完全行得通,但把 `Current_PI_B` 也乘进了 `FOC_PERIOD`(时间)。这意味着如果修改了控制周期,抗饱和的力度也会随之变化。在实操中,只要 Current_PI_B`调得合适(比如0.1~0.5),电机运行起来不会有任何问题。
积分饱和完美解决了“堵转时积分爆炸”的问题,保护了 MOSFET 不被烧毁,也防止了机械结构的失控。