今回は番外編。この記事で遠心ポンプコンポーネントを導入したが、それを通常とは異なる目的に使う。公式に想定されているものではないと考えられるが、この遠心ポンプコンポーネントはハイドロタービンとして使用することが出来る。
遠心ポンプは、軸に動力を与えて回転翼を回すことで、流体を押し出し圧力上昇を生む機械だ。逆も当然成立し、圧力勾配を持った流れの中に回転翼を置くと、流れが翼を回し、軸から動力を取り出せる。水車の仕組みがそれだ。
本例題の目的は下記の通り。
- ModelicaStandardLibraryの遠心ポンプコンポーネントを、ハイドロタービン(=水車)として使用する方法を習得する。
手書きスケッチと作成対象物の整理
作ろうとしているものを手書きで書き下すのは、今回も定型作業として実施しておこう。
同じく定型作業として、モデル化対象物についての情報を纏める。極力簡潔に、箇条書きを並べるのがお勧め。
- 流路は分岐しない。
- 流す流体は水(液相)。
- ハイドロタービン通過による流体の圧力・比エンタルピ降下。
- 流体が失ったエネルギの機械パワーへの変換。
- ハイドロタービン下流のバルブ開閉による、流路通過質量流量とハイドロタービン出口圧力の変更。
- 質量保存。
- 熱量保存。
- ハイドロタービン入口流体圧力、固定値
- ハイドロタービン入口流体温度、固定値
- 流量調整バルブ下流圧力、固定値(大気解放)
- ハイドロタービン軸機械回転数、可変; 機械回転数を外部から拘束し、トルクをアウトプットとする。
- 流量調整バルブ開度、可変
- ハイドロタービン軸パワー
- ハイドロタービン軸トルク
- ハイドロタービン入口体積流量
- ハイドロタービン入口質量流量
- ハイドロタービン出入口差圧
内包する物理現象:
境界条件(Input):
Output(注目する出力):
model(とpackage)ファイルの作成
過去記事でも述べたように、必須ではないが、演習例題用のpackageは作成しておこう。過去記事の例で既に作成済みなら、そのpackageにmodelを作成すればOK。
コンポーネントの配置
下図の通りにコンポーネントを配置、接続する。
インスタンス名はコンポーネントを配置する際に自動で命名される(標準設定では名前を尋ねるウィンドウが出てくる)が、筆者は適宜、名前をつけた方が後々判りやすいものだけ命名している。下図のものだと解りにくければ、解りやすいように名前を変えてくれて構わない。
pumpコンポーネントの繋ぎ方
今回の例題の核心部分の1つ。pumpをハイドロタービンとして用いる場合はシステム内の接続の仕方を変える必要が有る。
pumpの場合と全く逆向きに繋ぐ。pumpで出口だった側(port_b)を上流側に、入口だった側(port_a)を下流側に置く。接続に関しては以上。flangeはpumpの場合と全く変わらない繋ぎ方をすれば良い。
これは実物・実現象と対応しているので難しく考える必要は無い。実世界でも、遠心タービンは遠心ポンプをそっくりそのまま逆にしたようなもので、遠心ポンプの出口から高圧・高エンタルピの流体を流せば軸から動力を取り出せる(原理的には動作しても遠心ポンプの翼型等の設計はタービンとして最適なものではない点に注意。使われる圧力・温度・速度等の領域が全く異なるので。)。
使用コンポーネントリスト
必要なコンポーネントを見つけるのは慣れていないと意外と苦労する作業なので、総てのコンポーネントをリストアップしておく。概要については過去記事で既出のものとセンサの類は省略する。
parameterの設定
各コンポーネントのparameter設定を示す。コンポーネントを右クリックしてparametersを選択するか、ダブルクリックするとparametersウィンドウが現れるので、必要箇所に値を設定する。
尚、デフォルト設定のままにしておいて済むコンポーネント、parameterは記載を省略する。また、parameterの意味もparameterウィンドウ上の記載から意味が理解可能なものは省略/簡潔に済ます。
- trb
- nParallel: 1
- N_nominal: 1000 [rev/min]
- allowFlowReversal(Assumptions tab): true
- checkValve(Assumptions tab): false
- V(Assumptions tab): 1 [l]
- energyDynamics(Assumptions tab): Modelica.Fluid.Types.Dynamics.DynamicFreeInitial
- massDynamics(Assumptions tab): Modelica.Fluid.Types.Dynamics.DynamicFreeInitial
- p_b_start(Initialization tab): 5*system.p_start
- m_flow_start(Initialization tab): -10
- valveLinear1
- m_flow_nominal: 1000
- dp_nominal: 100*1000 [Pa]
- boundary
- use_p_in: true (checked)
- use_T_in: true (checked)
- nPorts: 1
- boundary1
- p: 101.325*1000 [Pa]
- T: 288.15 [K]
- nPorts: 1
- ramp_N
- height: 100
- duration: 10
- offset: 1000
- startTime: 50
- ramp_p_in
- height: 0
- duration: 10
- offset: 5*101.325*1000
- startTime: 30
- ramp_T_in
- height: 50
- duration: 10
- offset: 288.15
- startTime: 30
- ramp_valve
- height: -0.5
- duration: 10
- offset: 1.0
- startTime: 10
ソースコード
上記までを行うとOpenModelicaがソースコードを自動生成してくれている。一部ソースコードを直接書かなければならない箇所が有るのと、エラーが生じた場合の比較のために、本モデルの完成状態のソースコードを示す。尚、ソースコードを直書きする作業が残っているが、その解説はソースコードの後に記載する。
完成状態のソースコード(チェック用)
コンパイルエラーや、計算結果が意図通りのものとならないような場合に比較・チェック用に参照して欲しい。尚、annotation()の部分はGUI上の配置位置や向きで値が変わるものなので、比較する必要は無い。
——————————————————————————-
model HydroTurbine_byPump_ex02 extends Modelica.Icons.Example;//---------- replaceable package fluid1 = Modelica.Media.Water.StandardWaterOnePhase; //replaceable package fluid1 = Modelica.Media.Air.DryAirNasa; //redeclare package Medium = fluid1 //---------- inner Modelica.Fluid.System system annotation( Placement(visible = true, transformation(origin = {-50, 90}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Fluid.Sources.Boundary_pT boundary(redeclare package Medium = fluid1 , T = 1000, nPorts = 1, p = 10 * 101.325 * 1000, use_T_in = true, use_p_in = true) annotation( Placement(visible = true, transformation(origin = {-110, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Fluid.Machines.Pump trb(redeclare package Medium = fluid1 ,redeclare function flowCharacteristic = Modelica.Fluid.Machines.BaseClasses.PumpCharacteristics.quadraticFlow(V_flow_nominal = {0, -0.25, -0.50}, head_nominal = {-100, -70, 0}) ,redeclare function efficiencyCharacteristic = Modelica.Fluid.Machines.BaseClasses.PumpCharacteristics.constantEfficiency(eta_nominal = 0.9) , N_nominal = 1000, V(displayUnit = "l") = 0.001, allowFlowReversal = true, checkValve = false, energyDynamics = Modelica.Fluid.Types.Dynamics.DynamicFreeInitial, m_flow_start = -10, massDynamics = Modelica.Fluid.Types.Dynamics.DynamicFreeInitial, nParallel = 1, p_b_start = 5 * system.p_start) annotation( Placement(visible = true, transformation(origin = {-30, -30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); Modelica.Mechanics.Rotational.Sensors.PowerSensor powerSensor1 annotation( Placement(visible = true, transformation(origin = {-30, 30}, extent = {{-10, 10}, {10, -10}}, rotation = -90))); Modelica.Fluid.Sensors.VolumeFlowRate volumeFlowRate1(redeclare package Medium = fluid1 ) annotation( Placement(visible = true, transformation(origin = {20, -30}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); Modelica.Fluid.Sensors.VolumeFlowRate volumeFlowRate2(redeclare package Medium = fluid1 ) annotation( Placement(visible = true, transformation(origin = {-80, -30}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); Modelica.Fluid.Sensors.MassFlowRate massFlowRate1(redeclare package Medium = fluid1 ) annotation( Placement(visible = true, transformation(origin = {50, -30}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); Modelica.Blocks.Sources.Ramp ramp_N(duration = 10, height = 100, offset = 1000, startTime = 30) annotation( Placement(visible = true, transformation(origin = {-150, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Mechanics.Rotational.Sources.Speed speed1 annotation( Placement(visible = true, transformation(origin = {-80, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Fluid.Sensors.Pressure pressure1(redeclare package Medium = fluid1 ) annotation( Placement(visible = true, transformation(origin = {80, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 180))); Modelica.Fluid.Sources.Boundary_pT boundary1(redeclare package Medium = fluid1 , T = 288.15, nPorts = 1, p = 101.325 * 1000) annotation( Placement(visible = true, transformation(origin = {140, -30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); Modelica.Blocks.Sources.Ramp ramp_p_in(duration = 10, height = 0 * 101.325 * 1000, offset = 5 * 101.325 * 1000, startTime = 30) annotation( Placement(visible = true, transformation(origin = {-150, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Blocks.Sources.Ramp ramp_T_in(duration = 10, height = 0, offset = 288.15, startTime = 30) annotation( Placement(visible = true, transformation(origin = {-150, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Blocks.Math.UnitConversions.From_rpm from_rpm1 annotation( Placement(visible = true, transformation(origin = {-120, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Fluid.Valves.ValveLinear valveLinear1(redeclare package Medium = fluid1 , dp_nominal(displayUnit = "Pa") = 100 * 1000, m_flow_nominal = 1000) annotation( Placement(visible = true, transformation(origin = {110, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); Modelica.Blocks.Sources.Ramp ramp_valve(duration = 10, height = -0.5, offset = 1.0, startTime = 10) annotation( Placement(visible = true, transformation(origin = {110, 10}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); Modelica.Fluid.Sensors.SpecificEnthalpy specificEnthalpy(redeclare package Medium = fluid1 ) annotation( Placement(visible = true, transformation(origin = {-50, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 180))); Modelica.Fluid.Sensors.SpecificEnthalpy specificEnthalpy1(redeclare package Medium = fluid1 ) annotation( Placement(visible = true, transformation(origin = {0, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 180))); Modelica.Blocks.Math.Feedback dht_trb annotation( Placement(visible = true, transformation(origin = {-70, -60}, extent = {{-10, 10}, {10, -10}}, rotation = -90))); equation connect(ramp_valve.y, valveLinear1.opening) annotation( Line(points = {{110, -1}, {110, -22}}, color = {0, 0, 127})); connect(pressure1.port, valveLinear1.port_a) annotation( Line(points = {{80, -30}, {100, -30}}, color = {0, 127, 255})); connect(valveLinear1.port_b, boundary1.ports[1]) annotation( Line(points = {{120, -30}, {130, -30}}, color = {0, 127, 255})); connect(specificEnthalpy1.h_out, dht_trb.u2) annotation( Line(points = {{-10, -40}, {-14, -40}, {-14, -60}, {-62, -60}}, color = {0, 0, 127})); connect(specificEnthalpy.h_out, dht_trb.u1) annotation( Line(points = {{-62, -40}, {-70, -40}, {-70, -52}}, color = {0, 0, 127})); connect(specificEnthalpy1.port, volumeFlowRate1.port_a) annotation( Line(points = {{0, -30}, {10, -30}, {10, -30}, {10, -30}}, color = {0, 127, 255})); connect(trb.port_a, specificEnthalpy1.port) annotation( Line(points = {{-20, -30}, {0, -30}, {0, -30}, {0, -30}}, color = {0, 127, 255})); connect(specificEnthalpy.port, trb.port_b) annotation( Line(points = {{-50, -30}, {-40, -30}, {-40, -30}, {-40, -30}}, color = {0, 127, 255})); connect(volumeFlowRate2.port_b, specificEnthalpy.port) annotation( Line(points = {{-70, -30}, {-50, -30}, {-50, -30}, {-50, -30}}, color = {0, 127, 255})); connect(powerSensor1.flange_b, trb.shaft) annotation( Line(points = {{-30, 20}, {-30, -20}})); connect(speed1.flange, powerSensor1.flange_a) annotation( Line(points = {{-70, 60}, {-30, 60}, {-30, 40}})); connect(volumeFlowRate1.port_b, massFlowRate1.port_a) annotation( Line(points = {{30, -30}, {40, -30}}, color = {0, 127, 255})); connect(massFlowRate1.port_b, pressure1.port) annotation( Line(points = {{60, -30}, {80, -30}}, color = {0, 127, 255})); connect(ramp_N.y, from_rpm1.u) annotation( Line(points = {{-139, 60}, {-132, 60}}, color = {0, 0, 127})); connect(from_rpm1.y, speed1.w_ref) annotation( Line(points = {{-108, 60}, {-92, 60}, {-92, 60}, {-92, 60}}, color = {0, 0, 127})); connect(ramp_p_in.y, boundary.p_in) annotation( Line(points = {{-139, -10}, {-130, -10}, {-130, -22}, {-122, -22}}, color = {0, 0, 127})); connect(ramp_T_in.y, boundary.T_in) annotation( Line(points = {{-139, -40}, {-133, -40}, {-133, -26}, {-123, -26}, {-123, -26}}, color = {0, 0, 127})); connect(boundary.ports[1], volumeFlowRate2.port_a) annotation( Line(points = {{-100, -30}, {-90, -30}}, color = {0, 127, 255})); annotation( experiment(StartTime = 0, StopTime = 50, Tolerance = 1e-06, Interval = 0.1), __OpenModelica_simulationFlags(lv = "LOG_STATS", outputFormat = "mat", s = "dassl"), Diagram(coordinateSystem(extent = {{-160, -80}, {160, 100}}), graphics = {Line(origin = {-64.5071, 30.002}, points = {{9.0238, -15.0238}, {7.0238, 12.9762}, {-8.9762, 14.9762}}, arrow = {Arrow.None, Arrow.Open}), Text(origin = {-170, 33}, extent = {{64, -1}, {112, -7}}, textString = "mechanical power"), Text(origin = {-132, 11}, extent = {{64, -1}, {148, -15}}, textString = "hydro turbine by 'pump' component")}), __OpenModelica_commandLineOptions = ""); end HydroTurbine_byPump_ex02;
——————————————————————————-
mediumのredeclare; 黄色ハイライト部
*OpenModelica ver 1.16.0 以降ではparameterウィンドウから設定出来るようになっている。
OpenModelica の表示を、text viewに切り替える。そして、モデルソースコード内に、前項に示したソースコード中で黄色ハイライトで示されている記述を直接書き足す。これらの記述で、使用する物性モデル(本モデルでは水であること)を指定する。
pumpingSystem_ex01の回でも述べたが、筆者はモデルの階層で一度「fluid1」というmediumを定義し、各コンポーネント内では = fluid1 と宣言している。これにより、参照した物性を変更する時に書き換える箇所を1か所で済ませる事が出来る。
pumpの揚程 vs. 体積流量、断熱効率の特性設定; 赤色ハイライト部
pumpingSystem_ex01の回と同様に、ポンプコンポーネント「PrescribedPump」には、揚程vs.体積流量と断熱効率の特性をfunctionで設定しなければならない。しかしMediaの宣言同様、OpenModelicaではGUI操作から設定出来ないため、直接コードを書く。学習の為にひとまず動くモデルを作成するだけであれば、赤色ハイライト部をコピー&ペーストすればOKだ。
この部分記述についてはpumpingSystem_ex01の回で簡単にではあるが解説したので、本記事では省略する。ただし、遠心ポンプコンポーネントをハイドロタービンとして使うためにはポンプの場合と記述形式が異なるので、その点については簡単に述べておく。
とは言っても、難しい事は何も無い。下図にコードと揚程-体積流量曲線のイメージを示すように、揚程、体積流量両方の符号を負で与えるのみ。
シミュレーション実行&結果評価
それでは、観たいvariableの値や動きを評価してゆこう。
本連載はOpenModelicaでモデルを組む演習が主目的なのでサクサク観てゆく。本記事では答え合わせとして軽い解説で進めるが、実用としてModelica,1DCAEを実物/試験を再現したり、設計予測に使えるようになったら、本来はこの段階の考察が最も重要かつ時間をかけるべきところだ。その点は憶えておいて頂きたい。
- 流量調整バルブ開度
- ハイドロタービン軸機械回転数
- ハイドロタービン軸パワー(取出しパワー==正値)
- ハイドロタービン軸トルク
- ハイドロタービン入口体積流量、質量流量
- ハイドロタービン出入口差圧
Input
inputsとして与えた(変化させた)値が意図通りvariablesに反映されているか確認。
意図通り、時刻10-20 [s]で全開から半開へとcloseさせられている。
意図通り、時刻30-40 [s]で100 [rpm] 増速させられている。
Output
それでは、観たいvariableの値や動きを評価してゆこう。
本連載はOpenModelicaでモデルを組む演習が主目的なのでサクサク観てゆく。本記事では答え合わせとして軽い解説で進めるが、実用としてModelica,1DCAEを実物/試験を再現したり、設計予測に使えるようになったら、本来はこの段階の考察が最も重要かつ時間をかけるべきところだ。その点は憶えておいて頂きたい。
予想通りの動き。10-20 [s] でバルブ閉じにより通過流量が現象した事、タービン出入口差圧が小さくなった事で軸取出しパワーが減少している。そして、30-40 [s] で機械回転数が増加して通過流量が増えること軸取出しパワーが増加する。
予想通りの動き。10-20 [s] で回転数が変化していないので軸パワーと同じ動きとなっている。30-40 [s] では軸パワーとは逆でトルクは減少する。これは、機械回転数増加に伴う流量増加でバルブ差圧が増加し、ハイドロタービン出入口差圧が減少するため。
予想通りの動き。10-20 [s] でバルブ閉じに応じて流量が減少し、30-40 [s] で機械回転数増加に応じて増加する。
予想通りで、ハイドロタービンの軸トルクと対応した挙動。10-20 [s], 30-40 [s] 共に、バルブ差圧が上昇する換わりにハイドロタービン差圧が減少している。
最後に
この記事、この記事で作成したものと殆ど変わないモデルで、機能的に全く逆の働きをするシステムを作成できる事を示した。本来想定された使い方ではなく、邪道とも言える使い方ではあるが、Modelica Standard Libraryに無い「流体からの動力取出し」を実装できるようになった。
これで、流体圧送(/圧縮)、加熱、冷却と組み合わせる事で、熱機関をモデリングするのに必要なピースが手に入った事となり、モデリングのレパートリーが激増した筈だ。是非、種々色々なモデルを作成しスキル向上を図って欲しい。
本例題は以上。
例モデルに関する情報
本記事で取り上げたモデルは専用の「WalkingInWorldOfThermoFluid」ライブラリに公開しており、その情報を記しておく。ソースコードは本記事にも記載したが、直接OpenModelicaで読み込みたい方はダウンロードしてGPL3の範囲内で自由に使っていただいて構わない。
- モデルのフルパス:
- githubのライブラリページリンク
コメント