14回目(2015年度)
制御シミュレーションの数値解放
これから学ぶであろう,制御工学について情報処理演習の観点から扱ってみたいと思います.
制御工学で学ぶのは,線形系であるため,基本は解析解が求められる状態を扱います.紙と
鉛筆で解けるので,例えば,オペアンプ等の電気回路を組めば制御系を構成することが可能
なのです.
しかしながら,昨今の制御系はディジタルのディバイスを利用するため,離散量を基にした制御を
考えておく必要があります.
制御理論のごく基礎(知っていて損はありません)
設定したとおりに対象を制御する方法の基本は,フィードバック制御と呼ばれます.
動作原理はいたってシンプルで,制御対象の状態をセンサなどで観測し,設定した値と比較して
ズレ(偏差)があれば修正を行います.以下の原理図を示します.
上記の図の記号は,
となっており,制御対象の特性に合わせて制御器を工夫することで制御特性が改善されます.
モータ回転数の制御
制御対象として一般的に用いられるモータを考えましょう.
モータの応答はかけた電圧に対して一次遅れと呼ばれる応答を示すことが知られています.
ちょうど以下の応答がその例であり,
数式で示すと,
y(t) = K (1 - exp(-t / T))
となるものであり,Kはゲイン係数(定数),Tは時定数と呼ばれるもので,1次遅れの基本的な
特性を示しています.時定数Tは応答の遅れ具合と考えればよいのです.
ある値に向かってはじめは急に応答し,徐々に穏やかに回転が上昇します.
P制御コントローラ
制御器の感度を調整することで,応答の様子を変化させることが可能です.いちばん基本的な
ものを比例(Propotional)制御と呼び,偏差e(入力-応答)に比例ゲインKpをかけて操作量MVを
生成します.これは,
MV = Kp e = Kp (y(t) -SV)
で示されます.
速度型ディジタル制御アルゴリズム
ディジタル制御を行うため,周期的な演算を繰り返します.制御周期Δtを決め,その間に,計測,
演算,操作量MVの出力を周期的に繰り返して実行します.
詳細は省略しますが,計算量を少なくする制御アルゴリズムに速度型制御アルゴリズムがあり,
以下の式で操作量を示すことが可能です.
MVn = MVn-1 + ΔMVn ---(a)
この式の意味は,前回の操作量MVに今回の変化分だけを加える,という意味です.
P制御においては,偏差の変化量と考えることができるので,
ΔMVn = en - en-1 ---(b)
と計算することができます.
1次遅れモデルの離散表現
アナログ値では1次遅れ系においてTは時定数で,目標値と操作量は以下の関係にあります.
(d/dt)PV + (1/T) PV = MV
周期Δtごとに制御するため,n周期後の応答は以下の式で示されます.
PVn = (T / (T + Δt)) PVn-1 + (Δt / (T + Δt)) MVn ---(c)
なお,P制御をかけているので,今与えるべき操作量は
MVn = Kp en = Kp (SV - PVn-1) ---(d)
シミュレーションプログラム作成にあたって
上記のように速度型制御アルゴリズムを扱っているため,以下のような変数のみを用意すれば
制御できます.
を用意すればよいのです.
nやn-1と言っても全周期分用意する必要はなく,現制御周期と前制御周期に関するデータを
一時的に記録しておけばよく,fprintfを用いてファイルに書き出してしまえば良いのです.
もちろん演算結果をすべて配列に記録してからファイルに書き出してもかまいません.
以上が,制御に関するシミュレーションについての説明です.かなり簡素化していますが,プログラム
もやってみるとそれほど大変ではないことが分かると思います.
関数ポインタ
変数を関数で渡す方法は既に学んでいると思いますが,実は関数もポインタを利用してやりとりをする
ことが可能なのです.
以下に例を示したいと思います.
double fnc(double x){ return x; } main(){ double x; double (*pfnc)(double); pfnc=fnc; x=10.0; *pfnc(x); } |
通常の関数を宣言します. メイン関数内で関数ポインタを宣言します. 先の関数のアドレスを関数ポインタに送ります. 関数ポインタに引数を渡し,先の関数を実行します. |
または,
double fnc(double x){ return x; } main(){ double x; double (*pf)(double); *pf=fnc; x=10.0; } |
通常の関数を宣言します. メイン関数内で関数のポインタを宣言します. 先の関数を関数のポインタの中身に送ります. |
のようにしてもやりとりができます.
関数をわざわざポインタにする理由は何かというと,
既に作っておいた関数を利用する際,ポインタで受け渡しをすることで,例えば関数名が合わなくても
その制約をなくして利用できるので再利用性が向上します.また,関数をモジュール(ユニット)のような
ものとして利用できるので関数内のアルゴリズムの構造を何度も形を変えて利用できるという点があり
ます.何かの数値を算出するための関数ではなく,計算するための仕組みとしての関数にでき,汎用性,
再利用性が格段に上がります.
授業の課題であれば,プログラムが小規模な上に,あまり再利用する機会がないのでメリットがつかみ
にくいと思いますが,自作のプログラムを作る際は大変便利ですので参考にしてみて下さい.
関数ポインタ(補足)
関数ポインタを関数に呼び込む方法が分かりにくいと思いますので,追加説明します.以下の例を見て
下さい.
fnc_1の引数として関数ポインタを用いています.メイン関数内では関数fnc_A,
fnc_Bをこのfnc_1に渡して
います.
fnc_1の引数(*fnc)(double)は関数ポインタの中身を表しているので,
(*fnc) = fnc_Aとして関数ごと引き渡すことができると考えて下さい.
#include <stdio.h> double fnc_1(double (*fnc)(double), double a){ double
fnc_A(double a){ double fnc_B(double a){ main(){ printf("fnc_A=%f\n", fnc_1(fnc_A, h)); |
課題1 上記のアルゴリズムを基に速度法の関数を作成せよ.
使う式は,(c), (d)ですので,それぞれ関数を作ります.
周期Δtごとに制御するため,n周期後の応答は以下の式で示されます.
PVn = (T / (T + Δt)) PVn-1 + (Δt / (T + Δt)) MVn ---(c)
なお,P制御をかけているので,今与えるべき操作量は
MVn = Kp en = Kp (SV - PVn-1) ---(d)
もし可能であれば,引数に関数ポインタを使ってみてください.
参考例(オイラー法)
double euler(double (*fnc)(double, double), double t, double x, double h)
引数は
double(* fnc)(double, double): やりとりする関数のポインタを示します.
double t: 時刻を示します.
double x: 変数を示します.
double h: 時間刻みを示します.
となっています.
課題2 上記の関数を使って,シミュレーションを行ってみましょう.
SV=1.0, T=1.0, シミュレーション時間は5〜10[sec]程度,Δt 3通り,Kp 3通り変化させ,シミュレーションを
行います.なお,数値データはファイルに出力し,Excelでグラフを作成して応答を確認しましょう.
大雑把な流れですが,
1)シミュレーションの定数を決める
2)ループを設定し,刻み時間Δt間隔で
-MVnの値を求める.
-PVnの値を求め,ファイルに書き出す.
3)シミュレーション時間までループを繰り返す.
により計算できると思います.なお,初期値P0以前は0とすればよく,前回の応答値PVn-1は何らかの変数に
一時的に格納すればよいのです.
提出するデータは
課題1のの関数を収めたソースファイル
課題2のシミュレーション結果と考察を記したデータ
である.