カエデ自動機械

ちょっとしたものづくりや電子工作のメモなど。技術開発とは今は呼べないかな。

Pythonによる制御工学入門(オーム社)

書評・・・という言い方は烏滸がましいというか少し大仰な気がしますが、読んだ本についてもここで書いていきたいと思っています。
今回はオーム社「Pythonによる制御工学入門」です。

books.rakuten.co.jp

公式サイトはこちら。このページに書いたTipsなんかも書いてあるかも。

総評

  • 古典制御の復習になり、一部はそもそも知識の範囲外だったため新たに勉強になりました。
  • 現代制御に(実質)初めて触れることができました。まだしっくり来ていませんが、初めて勉強してシックリ来ることなど無いので、こんなもんかなという感じです。
  • Python(主にmatplotlibとか)に少し慣れることができました。
  • 「制御工学を学んで、Pythonで制御器を設計する本」ではなく(一部そういう部分もありますが)、 「取り扱う式をPythonで可視化しながら制御工学を学ぶ本」です。
  • 従って、例えば僕が今作っている倒立振子ロボットに制御理論を適用して・・・と考えると、この本を参照したり、他の本も読みながら、もうひと頑張り必要なようでした。
  • トータルでは、手を動かしながら学べるという観点で大変良い本でした!
  • 主に現代制御の部分?で理解が追いつかないまま終わってしまったのが悔しかったです。すぐ使う予定のある知識というわけではないので、とりあえずは深追いせずにおきます。
  • 学習所要時間:24時間くらい? 一通り読む、コード全て写経、文中の式の多くは自分でもノートに書き下す・・・という作業。

読んだ人間のレベル

  • 修士(工学)@機械工学専攻
  • 制御工学の授業は学部で2コマ受けたのみ。古典制御は初年度落として再履修した結果、なんとかB評価。現代制御は単位は取れたけどC評価。たしか持ち込みOKの試験で、直前に公式だけ書き写して臨んだような気がします。早い話が、何も身についていません。
  • 就職後、JSMEテキストシリーズ 制御工学 | JSMEテキストシリーズ | 日本機械学会の前半と絵ときでわかる 機械制御 | Ohmshaで古典制御のみ復習したが、結局実世界とのつながりが掴めず。アクチュエータ開発の論文とかでブロック線図やボード線図が出てきてもピンとこない。

使用した環境

個人的にはJupyter notebookのようなブラウザベースの環境は避けがちなので、

  • OS:Ubuntu16.04
  • エディタ:Atom
  • Python:Anaconda3-5.3.1(Python3.7.0)

を使用しました。

第1章・第2章

序論的なもの、Pythonの基礎などがまとめられています。
他の記事にあるようにPython自体はロボットの制御のために普段から使っていますが、実はMatplotlibとかは殆ど使ったことがなかったので、この部分だけでも結構ためになりました。

Pythonの基礎としては、開発環境であるJupyter notebookの導入、制御の状況をグラフで可視化するMatplotlib、行列計算等を行うNumpy、数値計算を行うScipy等の導入をしてくれます。前述の通り、Jupyter notebookは使用しませんでした。

第3章 制御のためのモデル

制御のためのモデル化の話です。各物理現象をモデル化し、式にしていく作業が第一で、そこからラプラス変換して伝達関数の形にしたり、状態空間モデルにしたりしています。

電気回路の定式化はちょっと忘れてたけど、キルヒホッフくらいはギリギリ覚えていたので微分方程式を書き下すくらいのことはできました。高校時代に微積を使って物理を教わりましたので、思い出してしまえば簡単です。

ただ、教科書には例として取り上げられないくらい複雑なシステムになってくると、何を入力 y(t) 、何を出力 u(t) にするかうまく決められず、式に書き下せない(=モデル化できない)のではないかという懸念はありました。教科書レベルと実務レベルのギャップをいかに埋めるか、という普遍的な問題ですが・・・

ラプラス変換はともかく)伝達関数モデルというのは、直感的にも使い方がなんとなくわかるというか、入力を受けて出力を吐き出すシステムそのものを定式化したものと直感的に理解ができます。

状態空間モデルというのは初めて聞いた概念でした。(現代制御論の授業で出てきたのでしょうが、聞いていませんでした) 
入力と出力だけでなく、制御対象の状態を加味した式とすることで行列が導入される代わりに微分方程式の階数が下がる・・・という理解です。普通の制御対象だと、出力は制御対象の状態の一部だと考えられますが、本書の例でもそうなっていました(出力が台車の位置、状態は台車の位置と速度、 など)

第4章 制御対象の振る舞い

前章で取り扱った各種モデルに対して、入力を加えた場合の出力遷移等を可視化していきます。
ステップ入力をした場合の系の出力の追従状況、周期的な入力をした場合の系の出力の追従状況等を可視化します。

制御系の特性に依って周波数応答性が変化します。個人的には高周波入力に対する応答性というのが少し気になるのですが、例えばバネ-ダンパ並列系だと固有角周波数はバネ定数の平方根に比例、マスの平方根に反比例しそうなので、バネ定数を上げ、マスを下げれば周波数応答性が上がりそうです。

入力によって出力が発散しないかどうかは、伝達関数モデルであれば伝達関数の分母の根(実部)の正負で判定し、状態空間モデルであればシステムのA行列の固有値(実部)の正負で判定します。 いずれにせよ、全て負であれば安定(発散はしない)です。
その他、ラウスの安定判別法というのもあるようです。

第5章 閉ループ系に注目した制御系設計

PID制御、拡張PID制御の解析。

拡張PID(微分先行型、比例微分先行型)は、数学的には制御入力を整形してから元のPID制御に入力するという意味と取れるが、その整形の部分(p161、図5.21の制御目標rを制御入力uに整形する部分)を自分では再現できなかった。
この部分だけ見れば、uはK1にPがフィードバック結合した形 : feedback(K1, P) と表せると思ったのですが・・・これがインプロパー(sの次数が分子のほうが大きい)となってしまい、計算エラーを吐くのが原因?

状態空間モデル関連の話になると中々直感的理解ができず、本を読む目も上滑りするばかりでした。一応式は追えましたが・・・
最適レギュレータを導出する関数 lqr において、numpyのバージョンが古いためエラーを吐く事象が発生しましたが、numpyのアップグレード(pip使用)で解消できました。

状態フィードバック制御の話になってくると、まあ式自体はわかるけどさあ・・・ という感じでした。そういうもんなのね、としか言えないといいますか。
この辺は、実際に使ってみる日が来るまで理解することはできないものと割り切っています。

ただ、ベースにしている行列 ABCD は、第3章とかで使っている垂直駆動アーム(図3.3)等をベースにしているようなので、そことの関連付けを明確にすると良いのかなと思いました。(図を再掲する、数値を代入するのは計算直前まで遅らせ、MやJ等の物理量を計算に使うなど・・・?)

第6章 開ループ系に注目した制御系設計

正直な所、いよいよわからなくなってきた章でした。
時間を置いて繰り返し読んだり、他の本と見比べたりしながら読んだほうが良いかも・・・?

とりあえず、閉ループ系だと伝達関数が線形でないためパラメータチューニングの影響が直感通りにならない場合が多く、その解消のために開ループ系を用いる?ということのようです。

開ループ系で一度設計してみて、位相交差周波数、ゲイン交差周波数、位相余裕、ゲイン余裕等を求めてみると、例えば開ループ系で位相余裕が90度以下なら、閉ループ系のバンド幅は開ループ系のゲイン交差周波数以上の値となる。 すなわち、閉ループ系における最悪値を開ループ系の設計を通じて決定できる? ということらしいです(?)

同様に、開ループ系の低周波ゲインを大きくすれば、閉ループ系の定常偏差を小さくできるなど、全体的に開ループ系の設計を通じて閉ループ系の最適なパラメータの見通しを立てるイメージ?でしょうか?

開ループ系で議論をしている時に低周波ゲインがゼロと言われると、閉ループ系の話と勘違いして、「ということは定常偏差ゼロだな」と思ってしまいがちで混乱しました。

とりあえず一通り式を追い、コードを書くことでなんとなくわかったようなわからないような。というところまで行きました。位相余裕というものが、振動的な入力をした際に、設計周波数までは系の追従性が担保されるとして、その時にどの程度設計余裕があるかどうかを表す指標であると直感的理解をしましたが、合っているかどうか・・・
ただ、では位相余裕が60degですと言われた時に、それがどの程度の余裕なのかはあんまりよくわからんなと思いました。

この交差周波数が振動入力に対する設計点(最低この周波数入力まではある程度追従してほしいという周波数)であると理解していますが、じゃあその点をどう決めるか、というのが難しそうと思いました。

位相遅れ補償等の概念は、「補償」というだけあって、PIDのチューニング等、基本的な制御器設計を終えた後に行うものと勘違いしていましたが、本書の例では一切設計していない生の制御器に対していきなり補償を加えていたので、むしろフィードバック制御器の設計の手法の1つと理解を改めました。
基本的な制御器設計を終えた後に、アウターループ的に(?)位相遅れ補償だけ入れてみよう、みたいな使い方もできるのかもしれませんが・・・そこがよくわかりませんでした。


第7章 アドバンストな制御系設計

さっきからずっと同じ事言っている気がしますが、いよいよ直感的な理解ができなくなり、かと言って数式だけ追えたところであまりピンとこないな・・・という状態に陥りました。
厳密な話をすれば、第3章の状態空間モデルとかそのレベルから復習すべきなのかも知れません。

伝達関数モデルでは不十分(多入力多出力系を使いたい場合など?)な時に状態空間モデルを使いたい、でも制御対象の全ての状態をセンシング可能なわけではない・・・という時に、制御対象の状態を推定するオブザーバを設計するということだけは理解しました。

ロバスト制御はいよいよわからなくなった部分の1つでした。導入部分の概念だけはなんとか理解したものの・・・ロバスト安定化問題みたいな用語が出てきたあたりからはさっぱり。


離散化、今まで入力 u(t) や出力 y(t) がコンピュータの中とはいえ連続値として取り扱われていたが、実際に制御器が出せる入力値、検知できる出力値は制御周期で離散化された値で、そのギャップを埋めるのがこの章でした。
理屈はわかるのですが、今まで制御系設計をシミュレータでやってきたという認識だったので、ここで取り扱ってきた関数そのものを離散化する必要はなくて、ここで設計が終わった制御器をマイコンに移すだけでいいのでは? と疑問が残りました。


気づいたこと(私の環境とスキル独自の問題かもしれません・・・)

  • リスト2.2の最後、 ax.show() だと 'AxesSubplot' object has no attribute 'show' というエラーが出てグラフ表示ができない。 plt.show() と書き換える必要があった。リスト2.3も同様、最後に plt.show() が必要。
  • 第4章冒頭で定義する関数plot_set(fig_ax, *args)にはグラフを表示するコマンドが含まれていないので、呼び出し元のスクリプトplt.show()を加える必要アリ(文中では省略されている?)

書いたコード(本書中該当箇所より引用)

github.com