PID制御の発展としてPI-D制御やI-PD制御があります。
今回はそれらについて書いていきます。
・PI-D,I-PDを初めて聞いた制御初学者
・制御対象のオーバーシュートをなくしたい方
フィードバックとフォードフォワードのメリット
PID制御はフィードバック制御ですが、フィードバック制御には以下のメリットがあります[1]。
・外乱の影響を抑制
・モデル化誤差の影響を抑制
・不安定系を安定にする.
一方でフィードフォワード制御は目標値への追従が得意です。
外乱やモデル化誤差がなければ、フィードフォワード制御で問題ないですが
不安定な系を安定にすることはできません。
二つの欠点を克服するものとして、フィードフォワード制御とフィードバック制御をともに含む2自由度制御があります。
これは、一つのコントローラーを外乱抑制を目的とし、もう片方のコントローラーを目標値追従を目的とするように設計します。
PI-D制御, I-PD制御とは
例としてPI-D制御(微分先行型PID制御)のブロック線図をFig.1に示します。
PI-D制御を式で表すと、
$$u(s)=K_{p}e(s)+\frac{k_{i}}{s}e(s)-sK_{d}y(s)$$となり、出力$t(s)$に直接微分器$sK_{d}$がかけられています。
次の章でこれをプログラムにしてPID制御と比較していきます。
PI-Dど同様によく見るのがI-PD制御です。
ブロック線図にすると、Fig.2になります。
IP-Ds制御を式で表現すると
$$u(s)=-K_{p}y(s)+\frac{K_{i}}{s}-sK_{d}y(s)$$
となります。次の章でこれらをシミュレーションしてみます。
プログラムとシミュレーション
PID,PI-D,I-PD制御それぞれを以下の図3に示す単純なモデルを例にシミュレーションしていきます。
図1、図2で示した「制御対象$P(s)$」は次のようにあらわせます。
$$\frac{X(s)}{F(s)}=\frac{1}{ms^{2}+cs+k}$$
まず、何もしない場合のPID制御のステップ入力とステップ応答を見てみます。
import control
from control.matlab import *
import matplotlib.pyplot as plt
import numpy as np
kp=2
ki=10
kd=0.1
ref=10
k=1
c = 1.5e-2
m = 1.0e-2
P = tf([0,1],[m,c,k])
K1=tf([kd,kp,ki],[1,0]) #これは普通のPID制御
Gyz=feedback(P*K1,1)
Td = np.arange(0,2,0.01)
r=1*(Td>0)
fig,axes = plt.subplots(1,2,figsize=(20,10))
y,t,_ = lsim(Gyz,r,Td,0)
ax=axes.flatten()
ax[0].plot(t,r*ref,linewidth=2)
ax[0].grid()
ax[0].set_xlabel('time',fontsize=20)
ax[0].set_ylabel('y',fontsize=20)
ax[1].plot(t,y*ref,linewidth=2)
ax[1].grid()
ax[1].set_xlabel('time',fontsize=20)
ax[1].set_ylabel('y',fontsize=20)
このような応答が二自由度制御ですとどうなるのかを見ていきます。
PI-D制御
まず、PI-D制御(微分先行型PID制御)は伝達関数を二つに分けることができます。[2]
図1を見ると、制御入力$u(t)$を次のように表せます。
\begin{align}
u(s)=&\frac{K_{p}s+K_{i}}{s}r(s)-\frac{K_{d}s^{2}+K_{p}s+K_{i}}{s}y(s)\\
&=\frac{K_{d}s^{2}+K_{p}s+K_{i}}{s}(\frac{K_{p}s+K_{i}}{K_{d}s^{2}+K_{p}s+K_{i}}r(s)-y(s))\\
&=K_{1}(s)(K_{2}(s)r(s)-y(s))
\end{align}
$K_{1}$はPID制御器です。
これらをPythonであらわすと以下になります。
入力を整形してからPID、プラントに入力しています。
import control
from control.matlab import *
import matplotlib.pyplot as plt
import numpy as np
import japanize_matplotlib
kp=2
ki=10
kd=0.1
ref=10
k=1
c = 1.5e-2
m = 1.0e-2
P = tf([0,1],[m,c,k])
K1=tf([kd,kp,ki],[1,0]) #これは普通のPID制御
# 2次遅れ系、目標値rを二次のフィルタで整形。目標値を整形する部分がフィードフォワード
K2=tf([kp,ki],[kd,kp,ki])
Gyz=feedback(P*K1,1)
Td = np.arange(0,2,0.01)
r=1*(Td>0)
#目標値rをK2で整形
z,t,_=lsim(K2,r,Td,0)
fig,axes = plt.subplots(1,2,figsize=(20,10))
#PIDの出出力
y_PID,t,_ = lsim(Gyz,r,Td,0)
#PI-Dの出出力
y_2DOF,t,_ = lsim(Gyz,z,Td,0)
ax=axes.flatten()
ax[0].plot(t,r*ref,linewidth=2)
ax[0].plot(t,z*ref,linewidth=2)
ax[0].grid()
ax[0].set_xlabel('time',fontsize=20)
ax[0].set_ylabel('入力',fontsize=20)
ax[0].legend(['PID','PI-D'])
ax[1].plot(t,y_PID*ref,linewidth=2)
ax[1].plot(t,y_2DOF*ref,linewidth=2)
ax[1].grid()
ax[1].set_xlabel('time',fontsize=20)
ax[1].set_ylabel('出力',fontsize=20)
ax[1].legend(['PID','PI-D'])
I-PD制御
I-PD制御ではPI-D制御で使った$K_{2}$の代わりに以下の$K_{3}$を使います。
$$K_{3}=\frac{K_{i}}{K_{d}s^{2}+K_{p}s+K_{i}}$$
import control
from control.matlab import *
import matplotlib.pyplot as plt
import japanize_matplotlib
import numpy as np
import warnings
warnings.filterwarnings('ignore')
#PI-D制御
kp=2
ki=10
kd=0.1
ref=10
k=1
c = 1.5e-2
m = 1.0e-2
P = tf([0,1],[m,c,k])
K1=tf([kd,kp,ki],[1,0]) #これは普通のPID制御
K2=tf([kp,ki],[kd,kp,ki])# 2次遅れ系、目標値rを二次のフィルタで整形。目標値を整形する部分がフィードフォワード
K3=tf([0,ki] ,[kd,kp,ki])
# 2次遅れ系、目標値rを二次のフィルタで整形。目標値を整形する部分がフィードフォワード
K2=tf([kp,ki],[kd,kp,ki])
Gyz=feedback(P*K1,1)
Td = np.arange(0,2,0.01)
r=1*(Td>0)
fig,axes = plt.subplots(1,2,figsize=(20,10))
#PIDの出力
y_PID,t,_ = lsim(Gyz,r,Td,0)
#PI-Dの出力 目標値rをK2で整形
z_2DOF,t,_=lsim(K2,r,Td,0)
y_2DOF,t,_ = lsim(Gyz,z_2DOF,Td,0)
#I-PDの出力
z_IPD,t,_ = lsim(K3,r,Td,0)
y_IPD,t, _ = lsim(Gyz, z_IPD, Td, 0)
ax=axes.flatten()
ax[0].plot(t,r*ref,linewidth=2)
ax[0].plot(t,z_2DOF*ref,linewidth=2)
ax[0].plot(t,z_IPD*ref,linewidth=2)
ax[0].grid()
ax[0].set_xlabel('time',fontsize=20)
ax[0].set_ylabel('入力',fontsize=20)
ax[0].legend(['PID','PI-D','I-PD'],fontsize=20)
ax[1].plot(t,y_PID*ref,linewidth=2)
ax[1].plot(t,y_2DOF*ref,linewidth=2)
ax[1].plot(t,y_IPD*ref,linewidth=2)
ax[1].grid()
ax[1].set_xlabel('time',fontsize=20)
ax[1].set_ylabel('出力',fontsize=20)
ax[1].legend(['PID','PI-D','I-PD'],fontsize=20)
ax[1].axhline(ref, linewidth=3,color = 'red')
I-PD制御の応答を見るとPIDやPI-Dと比べて緩やかであることがわかります。この働きのおかげでインパルス的な入力を抑えることができます。
今回は基本的な内容のみでしたが、今後実機を使った制御を紹介していきます。
参考文献
[1]フィードバック制御入門, 杉江俊治,藤田真之, コロナ社
[2]Pythonによる制御工学入門, 南裕樹, オーム社
コメント