西門子自帶的PID效果很好,但是會比較吃性能,使用次數有限,很多地方需要PID但不需要這么精准的PID,所以網上找個簡單的算法自己調用。
新建數據類型
前三個就是PID三個參數
新建FC塊:
#PIDInfo.Step += 1; IF #PIDInfo.Step >= #PIDInfo.MaxStep-1 THEN #PIDInfo.Step := 0; #PIDInfo.Ek := #SetValue - #ActualValue; #PIDInfo.LocSum += #PIDInfo.Ek; //累計誤差 #PIDResult := #PIDInfo.Kp * #PIDInfo.Ek + (#PIDInfo.Ki * #PIDInfo.LocSum) + #PIDInfo.Kd * (#PIDInfo.Ek1 - #PIDInfo.Ek); #PIDInfo.Ek1 := #PIDInfo.Ek; END_IF;
調用:
DB塊內增加變量
Step和MaxStep用於控制掃描多少次調用一次,以及可以錯開調用
左邊填入設置值,實際值,和剛才添加的變量,右邊輸出PID,PID輸出值沒有明確的范圍,自己用Limite限制范圍,調整P值讓輸出值在范圍內浮動
附C#實現
class PID_Info { float Kp = 1; //比例系數Proportional float Ki = 0.2f; //積分系數Integral float Kd = 0.1f; //微分系數Derivative float Ek; //當前誤差 float Ek1; //前一次誤差 e(k-1) float Ek2; //再前一次誤差 e(k-2) float LocSum; //累計積分位置 public static float PID_Calc1(float SetValue, float ActualValue, PID_Info PID) { float PIDLoc; //位置 PID.Ek = SetValue - ActualValue; PID.LocSum += PID.Ek; //累計誤差 PIDLoc = PID.Kp * PID.Ek + (PID.Ki * PID.LocSum) + PID.Kd * (PID.Ek1 - PID.Ek); PID.Ek1 = PID.Ek; return PIDLoc; } public float Calc1(float SetValue, float ActualValue) { return PID_Calc1(SetValue, ActualValue, this); } public static float PID_Inc(float SetValue, float ActualValue, PID_Info PID) { float PIDInc; //增量 PID.Ek = SetValue - ActualValue; PIDInc = (PID.Kp * PID.Ek) - (PID.Ki * PID.Ek1) + (PID.Kd * PID.Ek2); PID.Ek2 = PID.Ek1; PID.Ek1 = PID.Ek; return PIDInc; } public float Inc(float SetValue, float ActualValue) { return PID_Inc(SetValue, ActualValue, this); } }
算法來自
blog。csdn。net/weibo1230123/article/details/80812211