#Pythonで学ぶ制御工学< 2自由度制御 >
はじめに
基本的な制御工学をPythonで実装し,復習も兼ねて制御工学への理解をより深めることが目的である.
その第16弾として「2自由度制御」を扱う.
PID制御の改良版
PID制御には,改良版が存在し,2自由度制御を説明するにあたって,以下では,PID制御の改良版であるPI-D制御とI-PD制御について説明を導入している.
PI-D制御
名前のとおり,微分器は信号が目標値と合流する前に分岐したところに,先行する形で配置されている.よって,線形和をとるときには,負の符号をつけて併せていることがブロック線図からも分かる.
I-PD制御
先ほどのPI-D制御だけでは,まだP制御において改善の余地があるということから,P制御部分も先行する形をとっている.どういった部分で改善の余地があるのかは実装のときに記述する.
2自由度制御
先ほどの2つの改良版は,2自由度制御といわれるものだが,以下では導出過程も含めて,2自由度制御とはどういったものなのかを説明している.
急激に変化する(ステップ状)目標値を整形することで,制御入力$u$が過大になることを防ぐ.
※図中のFF, FBはぞれぞれ,フィードフォワード,フィードバックを表す.
実装
前回(https://qiita.com/Yuya-Shimizu/items/8570640e6e03c3d1e09a )同様,垂直駆動アームの角度制御を例に従来のPID制御と改良版のPID制御との比較を行い,どの点で改良されているのかを実装する中で確認する.以下にソースコードとそのときの出力を示す.
ソースコード
"""
2021/03/14
@Yuya Shimzu
PID制御と2自由度制御の比較{PI-D・I-PD制御}(アーム)
"""
import numpy as np
import matplotlib.pyplot as plt
from control import tf, feedback
from control.matlab import lsim
from tf_arm import arm_tf #自作関数
# https://qiita.com/Yuya-Shimizu/items/c7b69b4dfd63fb8facfa
from for_plot import plot_set #自作関数
# https://qiita.com/Yuya-Shimizu/items/f811317d733ee3f45623
## パラメータ設定
g = 9.8 #重力加速度[m/s^2]
l = 0.2 #アームの長さ[m]
M = 0.5 #アームの質量[kg]
mu = 1.5e-2 #粘性摩擦係数[kg*m^2/s]
J = 1.0e-2 #慣性モーメント[kg*m^2]
# 制御対象
P = arm_tf(J, mu, M, g, l)
# 目標値(指示値=refference)
ref = 30 #目標角度30[deg]
# 比例・積分・微分ゲイン
kp = 2
ki = 10
kd = 0.1
K1 = tf([kd, kp, ki], [1, 0]) #PID制御器
K2 = [tf([kp, ki], [kd, kp, ki]), #PI-D制御の目標値整形フィードフォワード制御器
tf([ki], [kd, kp, ki])]
# zからyへの伝達関数
Gyz = feedback(P*K1, 1)
Td = np.arange(0, 2, 0.01)
r = 1*(Td>0)
## PID制御とPI-D制御
# 目標値rをK2で整形
z, t, _ = lsim(K2[0], r, Td, 0)
# PID制御(z=rとした場合)
y1, _, _ = lsim(Gyz, r, Td, 0)
# 描画(PID制御)
fig, ax = plt.subplots(1, 2)
ax[0].plot(t, r*ref, color = 'k') #入力信号の様子
ax[1].plot(t, y1*ref, ls = '--', label = 'PID', color = 'k') #応答信号の様子
# PI-D制御
y2, _, _ = lsim(Gyz, z, Td, 0)
# 描画(PI-D制御)
ax[0].plot(t, z*ref) #入力信号の様子
ax[1].plot(t, y2*ref, label = 'PI-D') #応答信号の様子
ax[0].set_title(f"INPUT PID vs PI-D: $k_P$={kp} $k_I$={ki} $k_D$={kd}")
ax[1].set_title(f"OUTPUT PID vs PI-D: $k_P$={kp} $k_I$={ki} $k_D$={kd}")
ax[1].axhline(ref, color='k', linewidth=0.5)
plot_set(ax[0], 't', 'r')
plot_set(ax[1], 't', 'y', 'best')
plt.show()
## PID制御とI-PD制御
# 目標値rをK2で整形
z, t, _ = lsim(K2[1], r, Td, 0)
# 描画(PID制御)
fig, ax = plt.subplots(1, 2)
ax[0].plot(t, r*ref, color = 'k') #入力信号の様子
ax[1].plot(t, y1*ref, ls = '--', label = 'PID', color = 'k') #応答信号の様子
# I-PD制御
y2, _, _ = lsim(Gyz, z, Td, 0)
# 描画(I-PD制御)
ax[0].plot(t, z*ref) #入力信号の様子
ax[1].plot(t, y2*ref, label = 'I-PD') #応答信号の様子
ax[0].set_title(f"INPUT PID vs I-PD: $k_P$={kp} $k_I$={ki} $k_D$={kd}")
ax[1].set_title(f"OUTPUT PID vs I-PD: $k_P$={kp} $k_I$={ki} $k_D$={kd}")
ax[1].axhline(ref, color='k', linewidth=0.5)
plot_set(ax[0], 't', 'r')
plot_set(ax[1], 't', 'y', 'best')
plt.show()
出力
これらにより,PI-D制御・I-PD制御とPID制御を比較した図2つを出力する.
PID vs PI-D
確かに入力は滑らかになってはいるが,P制御系の影響か,整形した目標値が振動的で元の目標値を超える部分もある.これは,整形部$\kappa_{2}$において,零点が存在していることが要因である.零点があることにより振動的になっている.応答信号についてもその特徴が表れていることが分かる.この振動的な部分というのが,上で述べたまだ改善の余地があるというところにあたる.
PID vs I-PD
I-PD制御における$\kappa_2$には零点が存在しない.ゆえに振動が生じない.したがって,上のように元の目標値に向かって滑らかな曲線で目標値が近づく形状をしている.それによって,応答信号における挙動も滑らかに振動もなく目標値に近づいていることが分かる.またここでは,収束速度もそれほど変化しておらず,振動的な部分の安定性が大きく改善されていることは一目瞭然である.
感想
PID制御は知っていたが,PID制御の改良版については知らなかった.また,その改良の仕方を通して,ブロック線図が表すことやフィードフォワードの使いどころなどの理解も深められたと感じている.また微分器などの配置を変えることでシステム全体に及ぼす影響を変化させ,挙動をも制御できるということを学んだ.制御設計のときには重要になってくるアイデアの1つではないかと思う.
参考文献
Pyhtonによる制御工学入門 南 祐樹 著 オーム社