Wolfram Computation Meets Knowledge

階層モデル水槽システム

平坦な水槽三槽システム
コンポーネントベースの水槽次の章
PID制御器を持つ水槽

インストールと設定 | はじめに | マルチドメイン | コンポーネント | カスタムコンポーネント | Hello World | 外部関数 | 階層モデル |

この例は,System Modelerを使って階層モデルを構築し,新しいライブラリを作成する方法を示すものである.ここでは,平坦な水槽のモデルをまず作成してから,同じようなコンポーネントベースの水槽モデルを作成する.その後,新しい状況をテストすることを可能にする柔軟性について検討する.

このチュートリアルに使用されているモデル
FlatTank | TankPI | TankPID | TankSystem

平坦な水槽

まず,下の図にあるような,制御器付きの単一水槽システムを考える.

1.gif

水槽システムの図解.

モデルを実装するためには,系の方程式を設定しなければならない.水槽の水位hは,水槽からの流入量と流出量,および水槽の面積の関数である:

この例では,最初の150秒間は一定で,その後3倍の量になる流入量を選ぶ.このqin(t)の式において,q0はパラメータである:

流出量を制御することによって,水槽の水位を望ましい基準値refに保つ.これを行うために,以下のPI制御器を実装する.ここで,eは制御エラー,Kは制御器のゲイン,Tは制御器の時間定数である:

制御器は,流れuが水槽の中に入るように要求し,制御器が出力バルブを介した流れを制御するので,これが-qoutについて要求された値である.しかし,実際の流出量qoutは,最小値minFlowと最大値maxFlowによって制限され,水槽が空の場合には,qoutqinを超えることができないことが観察される.このことから,平坦なModelicaコードを実装することができる.

model FlatTank "Flat model of a tank"
parameter Real q0(unit = "m3/s") = 0.15 "Scaling of input flow";
parameter Real A(unit = "m2") = 1 "Tank bottom area";
parameter Real K(unit = "V/m") = 0.1 "PI controller gain";
parameter Real T(unit = "s") = 10 "PI controller integrator time constant";
parameter Real minFlow(unit = "m3/s") = 0 "Minimum flow through output valve";
parameter Real maxFlow(unit = "m3/s") = 0.5 "Maximum flow through output valve";
parameter Real ref(unit = "m") = 0.25 "Reference level for control";
Real h(start = 0, unit = "m") "Tank level";
Real qIn(unit = "m3/s") "Flow through input valve";
Real qOut(unit = "m3/s") "Flow through output valve";
Real qOutMax(unit = "m3/s") "Maximum output flow considering that the tank level cannot be negative";
Real u(unit = "m3/s") "Output flow demanded by controller";
Real e(unit = "m") "Deviation from reference level";
Real x(unit = "m") "State variable for controller";
equation
assert(minFlow >= 0, "minFlow - minimum flow through output valve must be >= 0");
der(h) = (qIn - qOut) / A;
qIn = if time > 150 then 3 * q0 else q0;
qOutMax = if h > 0 then maxFlow else min(qIn, maxFlow);
qOut = if (-u) < minFlow then minFlow elseif (-u) > qOutMax then qOutMax else -u;
e = ref - h;
der(x) = e / T;
u = K * (e + x);
end FlatTank;

モデルのシミュレーションを350秒間行うと,水槽の水位が上がり,望ましい基準水位に達してから,それをさらに超えることが分かる.一旦望ましい水位を超えると,流出が始まり,だいたい100秒ぐらいで水位が安定化する.しかし,150秒で流入量が突然増え,この場合には、制御信号が飽和状態にあるため,制御器の水位が安定化するのに,より長い時間がかかる. 下の図ではこれが示されている.

5.gif

水槽の水位,およびデフォルトのパラメータ値を持つ平坦な水槽の流入量と流出量のプロット.

コンポーネントベースの水槽

コンポーネントベースの水槽の実装には,最初の作業には少し時間がかかるが,一旦水槽を使って実験し,いろいろな状況についてテストし始めると,最初にかかった時間のロスを回復することができる.

オブジェクト指向でコンポーネントベースのアプローチをモデリングに使用する場合には,まず系の構造と分解を階層的なトップダウンの方法で理解しようとする.一旦系のコンポーネントと,コンポーネント間の相互作用が大体つかめたら,変数と方程式を識別する最初の従来のモデリング段階を,これらのモデルコンポーネントのそれぞれに対して適用することができる.

この章の最初にある図を見ると,この水槽システムは自然なコンポーネント構造を持つことが分かる.

水槽自体,液体源,水位センサ,バルブ,制御器という5つのコンポーネントを図の中に見出すことができる.しかし,ここでは水位センサとバルブについては非常に簡単な表記,つまりそれぞれについて簡単なスカラー変数を選ぶので,これらの変数を,それぞれが単一の変数を含む2つの新しいクラスを作成する代りに,水槽モデルのタイプRealの簡単な変数であるとする.

次に,コンポーネント間の相互作用と通信経路を見極める.液体がパイプを通してソースの水槽から流れ込んでいるのは明らかである.液体は,バルブによって制御される排水口を通って水槽から流れ出る.制御器は,センサから液体の水位の測定値を得る必要がある.このため,水槽のセンサと制御器の通信経路が設定されなければならない.

通信経路を繋ぐためには,コネクタのインスタンスが繋がれているコンポーネント用に作成されなければならず,制御器のクラスが必要なときに宣言されなければならない.実際,系のモデルは,コンポーネントと系の残りの部分との通信が制御器を通してのみ行われるような設計でなければならない.

最後に,コンポーネントの再利用および一般化について考慮すべきである.例えば,コンポーネントの変異形がいくつか将来必要になるだろうかということである.水槽システムの場合,PI制御器の他にも制御器の変異形をいくつか繋ぐことが予想される.したがって,水槽システムの制御器について,基本のクラスを作成すると便利である.

オブジェクト指向でコンポーネントベースの方法を使って開発された水槽システムモデルの構造が,分かりやすく下の図に示されている.

6.gif

オブジェクト指向でコンポーネントベースの水槽システムを図で表したもの.

インターフェース,関数,コンポーネントという,モデルで使われる3つの異なるタイプのクラスを識別することができる.したがって,3つのサブパッケージを含むパッケージを作成する.パッケージを作成するには,クラスブラウザユーザクラスルート上を右クリックして,以下のスクリーンショットにあるように,新規クラス...を選ぶ.また,自分のパッケージを追加したいパッケージを右クリックして,新規クラス...を選ぶこともできる.

7.gif

新しいクラスを作成するためのメニュー.

開くダイアログボックスで,クラス指定をPackageに設定し,パッケージ名をHierarchicalとする.OKボタンをクリックして,新しいパッケージを作成する.このパッケージは,クラスブラウザユーザクラスツリー内に表示されるようになる.この新しいパッケージの名前を右クリックすることによって,モデルやパッケージを作成してこれに加えることができる.

インターフェース

今度は,コネクタと呼ばれるインターフェースを作成する.まず,Hierarchicalパッケージ内に新しいパッケージInterfacesを作成する.もうすでに開かれているのでなければ,クラスブラウザ内でHierarchicalパッケージを開き,その内容を見る.新規クラスダイアログを使って,Interfacesパッケージ内にコネクタクラスを作成する.クラスの名前の他に,Connectorをクラス指定として指定し,Real拡張フィールドに入力し,ショートクラス定義チェックボックスにチェックマークを入れて定義の基本的な部分が正しくなるようにする.

液体の水位を読み取るためのコネクタクラスを作成する.まず入力コネクタを作成し,これを新規クラスダイアログの中でReadSignalInputと呼ぶ.

connector ReadSignalInput = Real;

inputRealの前にタイプすることで定義を変更して,コネクタの方向を指定し,単位をメーターに指定し,適切なドキュメント文字列を加える(モデルのテキストを編集し,モデルのアイコンを作成する方法については,HelloWorldの例を参照されたい).

connector ReadSignalInput = input Real(unit = "m") "Input reading of tank level";

入力コネクタを複製し,少し変更を加えることで,これに合った出力コネクタを作成する.

connector ReadSignalOutput = output Real(unit = "m") "Output reading of tank level";

要求された流れのアクチュエータへの信号のための,コネクタクラスも必要である.まず入力コネクタを作成する.

connector ActSignalInput = input Real(unit = "m3/s") "Input of signal to actuator for setting valve position";

ここでも,これにあった出力コネクタを作成する.

connector ActSignalOutput = output Real(unit = "m3/s") "Output of signal to actuator for setting valve position";

最後に,流入口と流出口での流水量のコネクタクラスも必要である.1つのコンパートメントから別のコンパートメントへ一方向にだけ液体が流れるシステムの物理的な性質により,水槽の水位の読み取りとアクチュエータ信号に同じタイプの入力と出力のコネクタを使用することができる.液体の流れの因果関係がこれほどはっきりしていない場合には,流れと圧力の両方の変数を含む非因果的コネクタを使わなければならないこともある.

アクチュエータ信号と液体の流れのコネクタは同じ単位を使う(このため,それらの定義は名前も含めて同じである)が,2つのタイプのコネクタはそれぞれ異なる目的を果たすものであるため,区別する必要がある.前者は,制御信号と交信するためのものであり,後者は液体の実際の流れを表す.まず入力コネクタを作成する.

connector LiquidFlowInput = input Real(unit = "m3/s") "Input of liquid flow at inlets";

入力コネクタにマッチする出力コネクタをここでも作成する.

connector LiquidFlowOutput = output Real(unit = "m3/s") "Output of liquid flow at outlets";

水槽のコンポーネント

次に,システムの3つのコンポーネントを作成する.まず,Hierarchicalパッケージ内にComponentsパッケージを作成する.Componentsパッケージ内に,Tankという名前の水槽モデルを作成する.この水槽モデルには,流入量qIn,流出量qOut,液体の水位の値を提供するy,水槽の排水口にあるバルブを介する流れを要求するuという,4つのインターフェース(Modelicaではコネクタ)がある.水槽の動作を調整する中心とする方程式は,質量収支方程式であり,この例にある簡単な形式では,一定の圧力を想定する.流出量は,符号の変更によって要求された流れと,LimitValue関数を通して取り扱う物理的な制約に関係している.

model Tank "Model of a simple tank holding liquid"
parameter Real A(unit = "m2") = 1 "Bottom area";
parameter Real minFlow(unit = "m3/s") = 0 "Minimum flow through output valve";
parameter Real maxFlow(unit = "m3/s") = 0.5 "Maximum flow through output valve";
Interfaces.ActSignalInput u "Actuator controlling output flow, connector";
Interfaces.LiquidFlowInput qIn "Flow through input valve, connector";
Interfaces.ReadSignalOutput y "Sensor reading tank level, connector";
Interfaces.LiquidFlowOutput qOut "Flow through output valve, connector";
Real h(start = 0.0, unit = "m") "Liquid level";
Real qOutMax(unit = "m3/s") "Maximum output flow considering that the tank level cannot be negative";
equation
assert(minFlow >= 0, "minFlow - minimum flow through output valve must be >= 0");
der(h) = (qIn - qOut) / A;
qOutMax = if h > 0 then maxFlow else min(qIn, maxFlow);
qOut = Functions.LimitValue(minFlow, qOutMax, -u);
y = h;
end Tank;

モデルは,すでに定義されたコネクタおよびLimitValue関数(未定義)を使う.これは,Functionsという名前の新しいパッケージの中に次のような関数を作ることで定義される.これは関数なので,作成の際にクラス指定をFunctionに設定する.厳密にどこで境界のいずれかを制限値が越えるかを数値ソルバが調べることができるように,InlineGenerateEventsの注釈を使う.

function LimitValue "Limiting function"
input Real pMin;
input Real pMax;
input Real p;
output Real pLim;
algorithm
pLim := if p < pMin then pMin elseif p > pMax then pMax else p;
annotation(Inline = true, GenerateEvents = true);
end LimitValue;

水槽に流れ込む液体は,どこかから流れてこなければならない.このため,最初は一定の流出量で流れ,t=150で3倍に急増する,液体源コンポーネントがある.これは,水槽の制御器が対処しなければならない興味深い制御問題を生み出す.以下のモデルは,Componentsパッケージ内に作成される.

model LiquidSource "Source of liquid with varying output"
parameter Real q0(unit = "m3/s") = 0.15 "Scaling of input flow";
Interfaces.LiquidFlowOutput qOut "Output flow, connector";
equation
qOut.lflow = if time > 150 then 3 * q0 else q0;
end LiquidSource;

制御器

最後に,制御器を指定しなければならない.最初はPI制御器を選ぶが,後でこれを別の種類の制御器に変える. 平坦なモデルのPI(比例と積分)制御器の動作は,次の2つの方程式によって定義されていた.

この場合,2つの方程式は,制御器クラスPIController内に置かれるが,このクラスは後で定義されるBaseControllerクラスの拡張である.

model PIController "Elementary PI controller"
extends BaseController;
parameter Real K(unit = "m2/s") = 0.1 "Gain";
parameter Real T(unit = "s") = 10 "Integrator time constant";
Real x(unit = "m") "Integrator state";
equation
der(x) = e / T;
u = K * (e + x);
end PIController;

後で定義されるPI制御器とPID制御器はどちらも,共通のパラメータ,状態変数,2つのコネクタ(センサを読み取るコネクタとバルブアクチュエータを制御するコネクタ)を含む部分的な制御器クラスBaseControllerを継承する.

partial model BaseController "Base class for tank level controllers"
parameter Real ref(unit = "m") "Reference level";
Interfaces.ActSignalOutput u "Control to actuator, connector";
Interfaces.ReadSignalInput y "Input sensor level, connector";
Real e(unit = "m") "Deviation from reference level";
equation
e = ref - y;
end BaseController;

小さな水槽システム

これらの作業が終ったら,ドラッグアンドドロップで水槽システムのモデルを構築することができる.

10.gif

IntroductoryExamples.Hierarachical.TankPIモデルのダイアグラムビュー

350秒間のシミュレーションを行うと,平坦な水槽システムと同じ結果が得られる.

11.gif

水槽の水位,およびデフォルトのパラメータ値を持つPI制御器で制御された水槽の流入量と流出量のプロット.

PID制御器を持つ水槽

今度はTankPIDシステムを定義する.このシステムは,PI制御器がPID制御器に置き換わっているということ以外は,TankPIシステムと同じである.ここで,従来のモデルベースのアプローチに比べて,オブジェクト指向でコンポーネントベースのアプローチが優れていることが明らかである.後者のアプローチでは,システムのコンポーネントをプラグアンドプレイの機能を使って簡単に置き換えたり変更したりすることができる.

PID(比例,積分,微分)制御器のモデルは,PI制御器と同じような方法で導き出すことができる.ここで使用される基本的なPID制御法則は以下の通りである.

これは,次の方程式を使って実装される.

これらの方程式とBaseControllerクラスを使って,PID 制御器を作成する.

model PIDController "Elementary PID controller"
extends BaseController;
parameter Real K(unit = "m2/s") = 0.1 "Gain";
parameter Real T(unit = "s") = 10 "Integrator time constant";
parameter Real Td(unit = "s") = 5 "Derivative gain";
Real x(unit = "m") "Integrator state";
equation
der(x) = e / T;
u = K * (e + x + Td * der(e));
end PIDController;

これで,ドラッグアンドドロップを使い,PID制御器付きの水槽システムを作成することができる.

15.gif

IntroductoryExamples.Hierarchical.TankPIDモデルのダイアグラムビュー

また350秒間のシミュレーションを行い,先の結果と比べる.

16.gif

TankPIモデルとTankPIDモデルにおける水槽の水位の比較.

三槽システム

最後に,オブジェクト指向でコンポーネントベースのアプローチを利用して,より大きなシステムを簡単に作成することができる.

17.gif

IntroductoryExamples.Hierarchical.TankSystemモデルのダイアグラムビュー

このシステムのシミュレーションを行い,それぞれの水槽の水位がどのように制御されているかを調べることができる.

18.gif

TankSystemモデルにおける水槽の水位の漸進的変化.

2つ目の水槽の基準水位は0.4メートルであるが,他の水槽の基準水位は0.2メートルであることに注意する.PI制御器内の積分器の飽和現象によって,150秒より後の入力流量の変化に対する反応がにぶくなるので,動作の重要な部分を捉えるためには,合計で1000秒間のシミュレーションが必要となってしまう.

次の章

»

インストールと設定 | はじめに | マルチドメイン | コンポーネント | カスタムコンポーネント | Hello World | 外部関数 | 階層モデル |