目次 — 知りたいところから読む
PIDの式を読むだけでは、ゲインを上げたときや出力が頭打ちになったときの挙動を想像しにくい。ここでは条件を固定した小さなモデルを動かし、同じ目標値に対する応答を比較する。2026年9月7日にPython 3.12.3で実行した数値例であり、実際のモータの同定結果ではない。
比較するモデルと条件
制御対象は \ddot y+2\dot y+y=u とする。yは正規化した出力、uは正規化した操作量、時間は秒である。初期位置・速度・積分値は0。目標値は0秒から1、6秒から0.4へ変更する。刻み幅は0.005秒、計算区間は0〜12秒、各条件2,401サンプルである。
制御則は u=K_pe+K_iI-K_d\dot y_m、e=r-y_m。y_mは観測値であり、微分は目標値でなく観測値へかける。K_p=3、K_i=2、K_d=1を基準にする。刻み幅を陽に使って積分・微分を計算し、対象は半陰的Euler法で更新する。原理はPID制御入門を参照。
コードを実行する
pid_lab.pyを空の作業フォルダへ保存し、次を実行する。Python標準ライブラリだけで動作する。同名の結果ファイルは上書きされる。
python3 --version
python3 pid_lab.py
CSVと集計JSONが生成される。グラフを再作成する場合は、同じフォルダへplot_pid.pyを保存して実行する。作図の検証環境はmatplotlib 3.6.3である。CSVの列は条件名、時刻、目標値、出力、操作量、積分値の順。
遅延と飽和を比較する
図の上段は出力、下段は操作量。黒線が目標値で、英語の条件名はCSVと共通である。awはアンチワインドアップを表す。
| 条件 | 変更点 | 12秒の出力 | 誤差絶対値の時間積分 |
|---|---|---|---|
| nominal | 遅延なし、操作量±3 | 0.4008 | 1.7913 |
| delay_0.4s | 観測を0.4秒遅らせる | 0.3883 | 1.8860 |
| limit_0.8_aw | 操作量±0.8、積分抑制あり | 0.4003 | 3.3424 |
| limit_0.8_no_aw | 操作量±0.8、積分抑制なし | 0.6602 | 5.0996 |
集計値は同じ計算から得たもので、誤差の時間積分は0〜12秒を左端の矩形則で求めた。正規化出力×秒の量であり、実機の位置誤差[m]ではない。12秒の一点だけで整定性能を判断せず、振動と操作量も見る。
積分を抑えても能力の上限は変わらない
この対象では定常時に y=u となるため、操作量上限0.8では目標1へ到達できない。誤差を積分し続けると、目標を0.4へ下げても蓄積分が大きな入力を要求する。コードでは、飽和を悪化させる方向への積分を止め、飽和から戻す方向は許可する。これが条件付き積分の具体例である。
積分抑制は電源やモータの能力を増やさない。目標値を実現可能な範囲へ変えることと、制御器の内部状態を扱うことを分ける。
ゲインを一つずつ変える演習
from pid_lab import simulate
for kp in (1., 3., 6.):
rows = simulate("gain", kp=kp)
print(kp, max(row[3] for row in rows if row[1] < 6))
この演習では最初の目標値区間の最大出力を比較する。次にkiだけ、kdだけを変え、操作量の最大値も記録する。ゲインが大きいほど必ず良いわけではない。遅延・飽和と組み合わせた結果を見てから判断する。
数値例の限界と次の確認
ここには測定ノイズ、摩擦、量子化、通信周期の揺らぎ、微分フィルタを入れていない。刻み幅を半分にして応答が大きく変わるなら、数値近似を先に疑う。実機へ移す際は、ここで使ったゲインを流用せず、対象の単位と時間スケールを合わせて同定する。MPCへ進むと、制約を制御問題の中で扱う考え方を学べる。
コメント
コメントの投稿にはログインが必要です
まだコメントはありません。