Digital Implementation
用電腦或微控制器實作 PID 時,誤差每隔一個取樣週期 \(T\) 才讀一次,連續的積分與微分要改成用取樣值近似。(說明依原講義改寫)
三項的離散化 Discretizing P, I, D
記第 \(k\) 次取樣的誤差為 \(e_k = SP_k - PV_k\)。
- 比例:直接相乘,\(u_P(k) = K_p\,e_k\)。
- 積分:把每一段的面積累加起來。用矩形近似: $$u_I(k) = u_I(k-1) + K_i\,e_k\,T,\qquad u_I(0) = 0$$ 用梯形近似(取前後兩點的平均)更準,SP 或 PV 突然改變時積分項也比較平順: $$u_I(k) = u_I(k-1) + K_i\,\frac{e_k + e_{k-1}}{2}\,T$$
- 微分:用相鄰兩點的斜率,\(u_D(k) = K_d\,\dfrac{e_k - e_{k-1}}{T}\)。設定值突然改變時 \(e_k - e_{k-1}\) 會非常大,造成輸出瞬間暴衝(微分踢,derivative kick)。因為設定值通常是常數,\(\Delta e = -\Delta PV\),所以實務上改成只對量測值微分: $$u_D(k) = -K_d\,\frac{PV_k - PV_{k-1}}{T}$$
- 輸出:\(u(k) = u_P(k) + u_I(k) + u_D(k)\),再限制在致動器能接受的範圍:超過 \(u_{max}\) 就取 \(u_{max}\),低於 \(u_{min}\) 就取 \(u_{min}\)。輸出被限制時要同時停止積分(anti-windup),否則積分項會一直累積,誤差反向後要很久才「退得回來」。
編註:原講義梯形積分一段的文字提到「誤差越大、積分作用越小」的非線性調整,但所列公式只是單純的梯形積分,並沒有包含這個非線性因子。原講義的流程圖則採理想式:先算 \(E + \Sigma_I + \Delta_D\),最後才乘上 \(K_p\),其中的 \(K_I\)、\(K_D\) 相當於 \(1/T_i\)、\(T_d\)。下面的流程與程式採並聯式(三項各有增益),兩者只差增益的定義。
每個取樣週期的計算流程 Algorithm Flow
e_old = 0; S = 0 # 初始化
每隔 T 秒:
e = SP - PV # 誤差
S = S + Ki * (e + e_old) / 2 * T # 梯形積分
D = -Kd * (PV - PV_old) / T # 只對量測值微分
u = Kp * e + S + D
if u > u_max: u = u_max; S = S - Ki * (e + e_old) / 2 * T # 飽和時退回這次積分
if u < u_min: u = u_min; S = S - Ki * (e + e_old) / 2 * T
輸出 u(D/A);e_old = e;PV_old = PV
▶ 在 Colab 開啟原課程的 MATLAB 程式已改寫成 Python 筆記本(第 7 節:照這段虛擬碼寫的數位 PID,含輸出限制與防積分飽和),可以直接在瀏覽器執行、修改參數。⬇ 下載 PID.ipynb
取樣週期要遠小於受控體的時間常數(常取閉迴路上升時間的 1/10 以下);太慢的話,上面的近似失真,閉迴路會變差甚至不穩定。









