システムとモデリング

SysML, Matlab/Simulink,他モデリング全般について。たまにプロジェクトマネジメント。

渦巻ポンプの構造をSysMLブロック定義図風にモデリングする

今回は唐突ですが渦巻ポンプの構造についてSysMLでモデリングしてみます。

渦巻ポンプの構造

渦巻ポンプの構造は例えば図のようになります。この図は下記サイトから引用させていただきました。

www.fukui-pump.com

f:id:Otepipi:20180815202642p:plain

ブロック定義図

これをSysMLのブロック定義図"風"にPlantUMLで書いたものが下図になります。"風"としたのは一部SysMLに規定されていない使い方をしているためです。

f:id:Otepipi:20180815202946p:plain

コードは次のようになりました。

@startuml

hide circle
hide empty members

package "bdd 渦巻ポンプ" <<Frame>> {
class 羽根車 <<block >>{
    Text=回転して液に遠心力を与える
}
class ケーシング <<block >>{
    Text=液の通り道をつくる
}
class グランドパッキン <<block >>
class メカニカルシール <<block>>
class スリーブ <<block >>
class ベアリングハウジング <<block >>
class ボールベアリング <<block >>
class 本体部 <<block >>
class 軸シール部 <<block >>{
   Text=主軸とケーシングの貫通部から液が漏れないようにする
}
class 軸受け部 <<block >>{
    Text=主軸を支える
    }
class 渦巻ポンプ <<block >>
class 主軸 <<block >>{
    Text=駆動部からトルクを伝える
}
class モーター <<block >>
class 電源 <<block >>
class 駆動部 <<block >>

}

渦巻ポンプ *-- 本体部
渦巻ポンプ *-- 軸シール部
渦巻ポンプ *-- 軸受け部
渦巻ポンプ *-- 駆動部

駆動部 *-- モーター
駆動部 *-- 電源


本体部 *-- 羽根車
本体部 *-- ケーシング
本体部 *-- 主軸

軸シール部 *-- グランドパッキン
軸シール部 *-- メカニカルシール
軸シール部 *-- スリーブ

軸受け部 *-- ベアリングハウジング 
軸受け部 *-- ボールベアリング

モーター --> 主軸 :トルクを伝える
主軸 --> 羽根車:トルクを伝える

@enduml

今回はここまでになります。

mermaidでガントチャートを描く

今日はPlantUMLのようにテキストベースで各種チャートを作成できるmermaidを紹介します。

mermaid · GitBook

PlantUMLでガントチャートを描いた例については↓で解説しています。

otepipi.hatenablog.com

今回はPlant UMLの時と同じ題材を扱います。

f:id:Otepipi:20180727231343p:plain

実装方法

VScordにプラグインMarkdown Preview Enhanced」を入れて動作させました。

今回は使用しませんでしたがWEBで作図することもできるようです。

mermaidjs.github.io

実装

下図のようになりました。

f:id:Otepipi:20180806204238p:plain

コードは下記になります。

gantt
    title A Gantt Diagram
    dateFormat  MM-DD
    section 基本設計
    基本設計を考える           :a1, 07-26, 10d
    基本設計資料を作る     :a2, after a1  , 3d
    section 詳細設計
    詳細設計を考える      :a3, after a2 , 5d
    詳細設計資料を作る      : a4, after a3, 3d

感想

Plant UMLと比較して ○本文と同じ.md内に書けるので管理が楽 ○チャートのデザインが美しい ☓マイルストーンやタスク順序を示す矢印がないなどとにかく機能が少ない

個人的にはPlantUMLのほうが使い勝手が良いと感じました。

今日はこれまでになります。

PlantUMLでSysMLユースケース図の練習

PlantUMLを使ってSysMLのユースケース図を書いてみます。

PlantUMLについては↓
plantuml.com

過去の記事は↓

otepipi.hatenablog.com

otepipi.hatenablog.com

otepipi.hatenablog.com

お題

今回参考にさせていただく図は、下記サイトのものになります。

「SysMLを活用した要求分析」 | 株式会社オージス総研

f:id:Otepipi:20180803195017p:plain

PlantUMLによる実装

PlantUMLによるコードは下記になります。

@startuml
package "uc システムレベルユースケース"  {
left to right direction
skinparam packageStyle rectangle
actor 文字入力装置
actor 利用者
rectangle 電光掲示板 {
文字入力装置 -- (表示する文字列を設定する)
利用者 -- (文字列を表示する) 
(文字列を表示する) <. (スクロールする): extends
}
}
@enduml

これによって生成される図は下のようになります。
f:id:Otepipi:20180803200728p:plain

ユースケースの位置は多少異なるもののおおよそ再現できました。 本日はここまでにします。

Open Modelicaで状態機械をシミュレーションする。その2

今日は再びOpen Modelicaで状態機械のシミュレーションをしてみます。 Open Modelicaで状態機械をシミュレーションするには設定が必要で、それについては過去の記事で解説しています。

otepipi.hatenablog.com

サンプルコード

今回使わせてもらうサンプルコードは下記PDFにありましたものです。

https://openmodelica.org/images/docs/openmodelica2015/OpenModelica2015-talk14-OMStateMachines_Bernhard%20Thiele.pdf

model Simple_NoAnnotations "Simple state machine"
inner Integer i(start =0);
block State1
outer output Integer i;
output Integer j(start =10);
equation
i = previous(i) + 2;
j = previous(j) - 1;
end State1;
State1 state1;
block State2
outer output Integer i;
equation
i = previous(i) - 1;
end State2;
State2 state2;
equation
transition(state1 ,state2 ,i > 10, immediate =false ,
reset=true , synchronize =false ,priority =1);
transition(state2 ,state1 ,i < 1, immediate =false ,
reset=true , synchronize =false , priority =1);
initialState(state1);
end Simple_NoAnnotations ;

これは状態機械図で次のようになります(PDFより)。

f:id:Otepipi:20180803053005p:plain

今回のコードをOpen Modelicaに流し込んだ場合、問題なくシミュレーションすることができ、次のようなグラフになります。

f:id:Otepipi:20180803053143p:plain

コードの勉強

ここからは今回のコードの中身を考えていきたいと思います。

previous()は指定した変数の1Clock(離散時間を扱う)前の値になります。今回はClock=1秒となっているようです。これを変更するにはClock()を弄ればできそうです。

blockはそのまま状態機械のブロックを扱う部分です。

transitionは状態機械のブロックからブロックへの移動を扱います。immediate = falseは"weak transition"と言われるもので、ブロック内でアクションを行った後に移動することを指しています。immediate = trueは"strong transition"で、ブロック内でのアクションを実行する前に移動してしまいます。

priorityは複数のtransition条件がかぶった場合の優先順位で、値が低いtransitionが実行されます。

resetsynchronizeは下記のように説明されてはいますがまだ理解できていません。

If reset = true, the states of the target state are reinitialized, i.e. state machines are restarted in initial state and state variables are reset to their start values. If synchronize=true, any transition is disabled until all state machines of the from-state have reached final states, i.e. states without outgoing transitions.

今日はここまでにします。

Open Modelicaで流量のPIDコントロール その3

今日もOpen Modelicaで流量のPIDコントロールをしていきます。
前回の記事はこちら↓

otepipi.hatenablog.com

前回ではバルブが線形動作だったためにPIDが一瞬で調整を完了してしまいました。

f:id:Otepipi:20180730211410p:plain
f:id:Otepipi:20180730211559p:plain

これでは面白くないので、このモデルに遅れ時間を設定してやります。

遅れ時間の設定

Blocks -> Nonlinear -> FixedDelayで固定時間遅れを設定します。

f:id:Otepipi:20180801104001p:plain

これをPIDのアウトプットとバルブのインプットの間に設置してやることで、PIDからの命令を遅らせてモデル全体に非線形性を与えてやります。

f:id:Otepipi:20180801104225p:plain

また固定遅れ時間は1秒とします。

f:id:Otepipi:20180801104334p:plain

PIDの設定

PIDの設定を下のように変更してみます。遅れ時間に意味を持たせるため、PIDのアウトプット初期値が0になるように設定しました。

f:id:Otepipi:20180801104457p:plain

シミュレーション結果

シミュレーションの結果、遅れ時間の設定により下図のようにPIDがうまく調整できず不安定な挙動になりました。

f:id:Otepipi:20180801104651p:plain

短いですが今回もここまでにしたいと思います。

Open Modelicaで流量のPIDコントロール その2 失敗編

本日も昨日に引き続きOpen ModelicaでPIDコントロールをしてみたいと思います。
前回の記事はこちらです。

otepipi.hatenablog.com

前回下図の状態まで実施しましたので、あとはステップ入力の部分をPID動作に変更します。 f:id:Otepipi:20180729203531p:plain

PID操作器

Blocks -> Continuous -> LimPID でPID操作器を設定します。今回、バルブが受け付ける信号が0~1までの数値になりますので、出力の最大最小を設定できるLimPIDを使用します。
f:id:Otepipi:20180730210611p:plain

PIDの設定は適当に次のように入れます。最小(yMin)、最大(yMax)の値を0と1に設定するようにしてください。

f:id:Otepipi:20180730210924p:plain

目標値設定

流量の目標値を設定しなくてはいけませんので、前回同様にステップ入力で目標値を設定してやります。流量の目標値を300kg/sとしました。

f:id:Otepipi:20180730211138p:plain

結線

下図のように結線を行います。今回結ぶコネクタは流体ではなく信号なので、前回のようにredeclare~を書き込む必要はありません。

f:id:Otepipi:20180730211410p:plain

シミュレーションの実行

シミュレーションした結果の流量の経時変化は下図のようになりました
f:id:Otepipi:20180730211559p:plain

なんと一瞬で目標の300kg/sに到達しています。これは、バルブの流量挙動が0~1の開度司令に対して完全に線形なため、PID調節がとてもとても簡単なタメだと思われます。完全に問題設定を間違えてしまいました。 次はこのモデルに一工夫加えてPIDらしさを表現できればと思います。

今日はここらで終わりにします。

Open Modelicaで流量のPIDコントロール その1

こんばんは。Otepipiです。 今日はModelica標準ライブラリを使用して流量のコントロールを検討してみます。 図のように圧力の高いところから圧力の低いところに流体を流し、その流量を流量計で測定し、望ましい流量になるようにバルブの開度を変更するフィードバック制御をかけます。 f:id:Otepipi:20180729201338p:plain

今日はフィードバック制御をかける前段階まで実施していきたいと思います。

機器の設置

まず機器を設置するところからはじめます。

境界

境界はModelica標準ライブラリのFluid -> Souces -> Boudary_pTを使います。 f:id:Otepipi:20180729201703p:plain

圧力の高い方の境界には下のように25barの圧力を設定してみます。 f:id:Otepipi:20180729201853p:plain

逆に圧力の低い境界には10barで設定します。 f:id:Otepipi:20180729201943p:plain

これで⊿P=25bar-10bar=15barを駆動力として流体が移動するようになります。

バルブ

流量調整バルブはFluid -> Valves -> ValveLinerを選択します。 f:id:Otepipi:20180729202104p:plain
これは1を全開、0を全閉として0~1の制御信号を入力すれば、その数値に沿って線形に流体抵抗がかかるようになります。 また全開時の抵抗として、仮に流量40kg/sのとき1barの圧損がかかると設定してやります。 f:id:Otepipi:20180729202409p:plain

バルブの制御信号

本来はフィードバック制御をかけるのですが、今回は試運転としてステップ信号をかけることにします。 シミュレーション開始から5秒間は0を出力(バルブ全閉)、その後は1を出力(バルブ全開)するとします。 ステップ信号は'Blocks -> Sources -> Step`を選択します。
f:id:Otepipi:20180729202916p:plain
またステップ信号の動作を下のように設定します。
f:id:Otepipi:20180729203143p:plain

流量計

流量計は'Fluid -> Sensors -> MassFlowRate`を選択します。 f:id:Otepipi:20180729202525p:plain
これは特に設定はありません。

これで下図のように配置できたと思います。 f:id:Otepipi:20180729203229p:plain

結線

各部品をコネクタで接続します。 boundaryのコネクタは小さい円のものを使います。接続時下のような選択肢が出てきますが、とりあえず[1]を選択しましょう。
f:id:Otepipi:20180729203452p:plain
これで下図のように結線できたと思います。 f:id:Otepipi:20180729203531p:plain

モデルのチェック

結線しましたらツールバーからモデルチェックを行います。するとエラーとなり下のようなメッセージが表示されます。

component boundary contains the definition of a partial class Medium. Please redeclare it to any package compatible with Modelica.Media.Interfaces.PartialMedium.

おそらく、流体が何かを指定していないので計算できていないのだと推測できます。ただダイアグラムビューからは流体を指定できるそれらしい箇所が見つかりませんでした。今回これが王道かどうかはわかりませんが、ModelicaのExampleなどから下記のような対応を実施しました。

エラーになったとき、今回のモデルをテキストビューで確認すると下記のようになっていると思います。

model PIDtest
  Modelica.Fluid.Sources.Boundary_pT boundary(redeclare package Medium = Medium, nPorts = 1, p = 2.5e6) annotation(
    Placement(visible = true, transformation(origin = {-64, -14}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Fluid.Valves.ValveLinear valveLinear1( dp_nominal = 100000, m_flow_nominal = 40)  annotation(
    Placement(visible = true, transformation(origin = {-10, -14}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Fluid.Sources.Boundary_pT boundary1(nPorts = 1, p = 1e6) annotation(
    Placement(visible = true, transformation(origin = {84, -16}, extent = {{-10, 10}, {10, -10}}, rotation = 180)));
  Modelica.Fluid.Sensors.MassFlowRate massFlowRate1 annotation(
    Placement(visible = true, transformation(origin = {34, -14}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Blocks.Sources.Step step1(height = 1, offset = 0, startTime = 5)  annotation(
    Placement(visible = true, transformation(origin = {-34, 26}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
equation
  connect(massFlowRate1.port_b, boundary1.ports[1]) annotation(
    Line(points = {{44, -14}, {74, -14}, {74, -16}, {74, -16}}, color = {0, 127, 255}));
  connect(valveLinear1.port_b, massFlowRate1.port_a) annotation(
    Line(points = {{0, -14}, {24, -14}, {24, -14}, {24, -14}}, color = {0, 127, 255}));
  connect(boundary.ports[1], valveLinear1.port_a) annotation(
    Line(points = {{-54, -14}, {-20, -14}, {-20, -14}, {-20, -14}}, color = {0, 127, 255}, thickness = 0.5));
  connect(step1.y, valveLinear1.opening) annotation(
    Line(points = {{-22, 26}, {-10, 26}, {-10, -6}, {-10, -6}}, color = {0, 0, 127}));
  annotation(
    uses(Modelica(version = "3.2.2")));
end PIDtest;

これに対して。まず冒頭でpackage Medium = Modelica.Media.Water.ConstantPropertyLiquidWater;と宣言することで、今回の流体が水だと宣言します。 次に、各機器のパラメーターにredeclare package Medium = Mediumを追加します。 すると以下のようになります。

model PIDtest
 package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater;
  Modelica.Fluid.Sources.Boundary_pT boundary(redeclare package Medium = Medium, nPorts = 1, p = 2.5e6) annotation(
    Placement(visible = true, transformation(origin = {-64, -14}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Fluid.Valves.ValveLinear valveLinear1(redeclare package Medium = Medium, dp_nominal = 100000, m_flow_nominal = 40)  annotation(
    Placement(visible = true, transformation(origin = {-10, -14}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Fluid.Sources.Boundary_pT boundary1(redeclare package Medium = Medium, nPorts = 1, p = 1e6) annotation(
    Placement(visible = true, transformation(origin = {84, -16}, extent = {{-10, 10}, {10, -10}}, rotation = 180)));
  Modelica.Fluid.Sensors.MassFlowRate massFlowRate1(redeclare package Medium = Medium) annotation(
    Placement(visible = true, transformation(origin = {34, -14}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Blocks.Sources.Step step1(height = 1, offset = 0, startTime = 5)  annotation(
    Placement(visible = true, transformation(origin = {-34, 26}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
equation
  connect(massFlowRate1.port_b, boundary1.ports[1]) annotation(
    Line(points = {{44, -14}, {74, -14}, {74, -16}, {74, -16}}, color = {0, 127, 255}));
  connect(valveLinear1.port_b, massFlowRate1.port_a) annotation(
    Line(points = {{0, -14}, {24, -14}, {24, -14}, {24, -14}}, color = {0, 127, 255}));
  connect(boundary.ports[1], valveLinear1.port_a) annotation(
    Line(points = {{-54, -14}, {-20, -14}, {-20, -14}, {-20, -14}}, color = {0, 127, 255}, thickness = 0.5));
  connect(step1.y, valveLinear1.opening) annotation(
    Line(points = {{-22, 26}, {-10, 26}, {-10, -6}, {-10, -6}}, color = {0, 0, 127}));
  annotation(
    uses(Modelica(version = "3.2.2")));
end PIDtest;

これでシミュレーションできるようになります。なぜredeclare~が必要なのかはわかりません……

シミュレーション

ツールバーからシミュレーションを行うことで下図のように無事シミュレーションすることができました。 開始から5秒後にバルブが全開になり、600 kg/sの流量で水が流れる様子が確認できます。

f:id:Otepipi:20180729210145p:plain

無事にフィードバック制御の前段階までできましたので今日はここまでにしたいと思います。