如何在 Modelica 中构建液体平衡连接器?
How to construct a balanced connector for liquids in Modelica?
post 的状态:
200313 得到了代码 DEMO_v42 的答案,我接受赏金!
200310 我评论了昨天推荐的两篇关键论文。还是不明白怎么更新DEMO_v41.
200309 我想强调一下,关键问题是如何在代码中引入流的概念DEMO_v41(如果可能的话),并通过这种方式使连接器平衡。作为浓度的变量 c 应该声明为 stream,但是方程式应该如何用 inStream 或 actualStream 更新——我很乐意看到!
200226 添加了 post 示例 DEMO_v41,它是一个简化的代码,我希望代码比第一个 DEMO_v40.
更具可读性
200225 我对给出的答案进行了一些评论,并试图让读者关注实际问题,但收效甚微。
200224 我得到了一些关于 post 的一般和详细信息。详细的评论价值较低,部分原因是误解了问题。 Rene 的更笼统的回答很好,但过于笼统。在我考虑使用 Modelica.Media 等之前,我真的很想通过小例子了解如何使用流的概念。这是一个学习过程。
我想知道如何正确定义液体的连接器,该液体在溶液中具有多种不同浓度的成分,然后该溶液具有流速。液体中的压力可以忽略不计。
我长期使用的标准连接器是:
connector LiquidCon
nc=5;
Real c[nc] “Component concentrations”;
flow Real F “Flow rate”;
end LiquidCon;
连接器在 JModelica 和 OpenModelica 中运行良好,但我在 OpenModelica 中收到连接器不平衡的警告。在 Modelica 语言规范的第 9.3.1 节中,我看到我的构造实际上是不合法的,请参见 https://www.modelica.org/documents/ModelicaSpec34.pdf。如何制作满足需求的连接器?
我花了一些时间阅读了 Fritzons 书第 2n 版中关于“流”概念的第 5.10 章,但我需要更详细地研究它。
我的简单连接器发出警告的原因是,当您声明流变量时,编译器假定另一个变量是该流变量的潜在变量,即至少流和潜在变量的数量必须是在连接器中相同。那么当然在我的例子中,组件浓度不是潜在变量,而是编译器无法检测到的。
在第 5.10 章的介绍部分,“流”概念的范围似乎是“......具有相关属性的双向物质流的应用......”。在我的应用领域,我怀疑我需要考虑双向流。这意味着使用流是一种“矫枉过正”。但这似乎也暗示我也不应该使用“流”的概念,这有点可惜。我们真的应该停止使用吗这里是“流”的概念?
无论如何,我已经尝试整理一个比 Fritzson 书中关于这个主题的更基本的示例,以了解如何使用“流”的概念以及计算时间等方面的开销你得到。在下面的示例中,我模拟了从进料罐到收获罐的液体流动。流量现在由压力差控制。代码 DEMO_v41 起作用并发出连接器不平衡的警告。如果我现在声明底物浓度 c 为“流”,我现在应该如何使用 inStream 和 actualStream 更新代码以使其以相同的方式工作,但现在使用此平衡连接器?
package DEMO_v41
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
// ---------------------------------------------------------------------------------------------
// Equipment
// ---------------------------------------------------------------------------------------------
package EquipmentLib
connector LiquidCon
Real P "Pressure";
flow Real F "Flow rate";
Real c "Substance conc";
end LiquidCon;
model PipeType
LiquidCon inlet, outlet;
parameter Real area = 1;
equation
inlet.F = -outlet.F;
outlet.F = -area^2*(inlet.P - outlet.P); // Linearized Bernoulli equation
outlet.c = inlet.c;
end PipeType;
model FeedtankType
LiquidCon outlet;
parameter Real P = 0.1 "Pressure";
parameter Real V_0 = 100 "Initial feed volume";
parameter Real c_in = 1.0 "Feedtank conc";
Real V(start=V_0, fixed=true) "Feed volume";
equation
outlet.c = c_in;
outlet.P = P;
der(V) = outlet.F;
end FeedtankType;
model HarvesttankType
LiquidCon inlet;
parameter Real P = 0.0 "Pressure";
parameter Real V_0 = 1.0 "Initial harvest liquid volume";
parameter Real m_0 = 0.0 "Initial substance mass";
Real V(start=V_0, fixed=true) "Harvest liquid volume";
Real m(start=m_0, fixed=true) "Substance mass";
Real c "Substance conc";
equation
inlet.P = P;
der(V) = inlet.F;
der(m) = inlet.c*inlet.F;
c = m/V;
end HarvesttankType;
end EquipmentLib;
// ---------------------------------------------------------------------------------------------
// Example of system
// ---------------------------------------------------------------------------------------------
model Test
EquipmentLib.FeedtankType feedtank;
EquipmentLib.HarvesttankType harvesttank;
EquipmentLib.PipeType pipe;
equation
connect(feedtank.outlet, pipe.inlet);
connect(pipe.outlet, harvesttank.inlet);
end Test;
end DEMO_v41;
下面的旧示例 DEMO_v40 更笼统且更难阅读,但自从围绕此示例的一个早期回答以来保留以供参考。
我得到的编译 (JModelica 2.14) 错误消息是:“扁平模型中的错误:系统在结构上是单一的。以下变量无法与方程匹配:harvesttank.inlet.c[1]、pipe.outlet.c[1]。 OpenModelica (1.16) 给出了大致相同的信息。这里有什么问题?
package DEMO_v40
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
partial package MediumBase
constant String name "Medium name";
constant Integer nc "Number of substances";
replaceable type Concentration = Real[nc] "Substance conc";
end MediumBase;
package Medium1
extends MediumBase
(name="One component medium",
nc=1);
constant Real[nc] mw = {10} "Substance weight";
constant Integer A = 1 "Substance index";
end Medium1;
record Medium_data
constant String name = Medium1.name;
constant Integer nc = Medium1.nc;
constant Real[nc] mw = Medium1.mw;
constant Integer A = Medium1.A;
end Medium_data;
// ---------------------------------------------------------------------------------------------
// Equipment dependent on the medium
// ---------------------------------------------------------------------------------------------
package EquipmentLib
replaceable package Medium = MediumBase // formal parameter - EquipmentLib
constrainedby MediumBase;
connector LiquidCon
Real P "Pressure";
flow Real F (unit="m3/s") "Flow rate";
stream Medium.Concentration c "Substance conc";
end LiquidCon;
model PipeType
LiquidCon inlet, outlet;
parameter Real area = 1;
equation
inlet.F = -outlet.F;
outlet.F = area^2*(inlet.P - outlet.P); // Linearized Bernoulli equation
for i in 1:Medium.nc loop
outlet.c[i] = inlet.c[i];
end for;
end PipeType;
model FeedtankType
LiquidCon outlet;
parameter Real P = 0.1 "Pressure";
parameter Real V_0 (unit="m3") = 100 "Initial feed volume";
parameter Real[Medium.nc] c_in (each unit="kg/m3")
= {1.0*k for k in 1:Medium.nc} "Feed inlet conc";
Real V(start=V_0, fixed=true, unit="m3") "Feed volume";
equation
for i in 1:Medium.nc loop
outlet.c[i] = c_in[i];
end for;
outlet.P = P;
der(V) = outlet.F;
end FeedtankType;
model HarvesttankType
LiquidCon inlet;
parameter Real P = 0.0 "Pressure";
parameter Real V_0 (unit="m3") = 1.0 "Initial harvest liquid volume";
parameter Real[Medium.nc] m_0
(each unit="kg/m3") = zeros(Medium.nc) "Initial substance mass";
Real[Medium.nc] m
(start=m_0, each fixed=true) "Substance mass";
Real[Medium.nc] c "Substance conc";
Real V(start=V_0, fixed=true, unit="m3") "Harvest liquid volume";
equation
inlet.P = P;
der(V) = inlet.F;
for i in 1:Medium.nc loop
der(m[i]) = inStream(inlet.c[i])*inlet.F;
c[i] = m[i]/V;
end for;
end HarvesttankType;
end EquipmentLib;
// ---------------------------------------------------------------------------------------------
// Adaptation of package Equipment to Medium1
// ---------------------------------------------------------------------------------------------
package Equipment
import DEMO_v40.EquipmentLib;
extends EquipmentLib(redeclare package Medium=Medium1);
end Equipment;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
model Test
Medium_data medium;
Equipment.FeedtankType feedtank;
Equipment.HarvesttankType harvesttank;
Equipment.PipeType pipe;
equation
connect(feedtank.outlet, pipe.inlet);
connect(pipe.outlet, harvesttank.inlet);
end Test;
end DEMO_v40;
正确的方法是
connector LiquidCon
nc=5;
Real c[nc] “Component concentrations”;
flow Real F[nc] “Flow rate”;
end LiquidCon;
或
connector LiquidCon
Real c “Component concentrations”;
flow Real F “Flow rate”;
end LiquidCon;
取决于您要建模的内容。经验法则是:number of potentials = number of flows
。由于您只使用一种流量和多种浓度,这意味着您有多个类似水箱的组件,每个组件都有一定的浓度,并通过允许流量的类似管道的组件连接。
对于这些我会推荐我发布的第二个版本!
一些背景信息:
连接器永远不会平衡,假定与其未知数相比提供一半的方程式。每当您向组件添加连接器时,该组件都必须平衡它。原因很简单:例如具有一种电位和一种流量的连接器。信息流动的方向不清楚,但可以肯定的是,要么 flow
变量被认为是已知的,要么 potential
被认为是已知的,另一个将由组件的方程计算。对于水箱,浓度由其自身的方程计算,流量通过连接器(管道反之亦然)。
只要连接两个或多个连接器,所有电位都设置为相等,所有流量总和为零(Modelica Language Specification 第 9.2 节)。
我更改了您的示例,以便我可以实际单独测试组件。注意我给nc
添加了一个默认值,否则无法检查单个组件的一致性
package DEMO_v40
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
partial package MediumBase
constant String name "Medium name";
constant Integer nc = 1 "Number of substances";
replaceable type Concentration = Real[nc] "Substance conc";
end MediumBase;
package Medium1
extends MediumBase
(name="One component medium",
nc=1);
constant Real[nc] mw = {10} "Substance weight";
constant Integer A = 1 "Substance index";
end Medium1;
record Medium_data
constant String name = Medium1.name;
constant Integer nc = Medium1.nc;
constant Real[nc] mw = Medium1.mw;
constant Integer A = Medium1.A;
end Medium_data;
// ---------------------------------------------------------------------------------------------
// Equipment dependent on the medium
// ---------------------------------------------------------------------------------------------
package EquipmentLib
replaceable package Medium = MediumBase "formal parameter EquipmentLib";
connector LiquidCon
Real P "Pressure";
flow Real F (unit="m3/s") "Flow rate";
stream Medium.Concentration c "Substance conc";
end LiquidCon;
model PipeType
LiquidCon inlet, outlet;
parameter Real area = 1;
equation
inlet.F = -outlet.F;
outlet.F = area^2*(inlet.P - outlet.P); // Linearized Bernoulli equation
for i in 1:Medium.nc loop
outlet.c[i] = inlet.c[i];
end for;
end PipeType;
model FeedtankType
LiquidCon outlet;
parameter Real P = 0.1 "Pressure";
parameter Real V_0 (unit="m3") = 100 "Initial feed volume";
parameter Real[Medium.nc] c_in (each unit="kg/m3")
= {1.0*k for k in 1:Medium.nc} "Feed inlet conc";
Real V(start=V_0, fixed=true, unit="m3") "Feed volume";
equation
for i in 1:Medium.nc loop
outlet.c[i] = c_in[i];
end for;
outlet.P = P;
der(V) = outlet.F;
end FeedtankType;
model HarvesttankType
LiquidCon inlet;
parameter Real P = 0.0 "Pressure";
parameter Real V_0 (unit="m3") = 1.0 "Initial harvest liquid volume";
parameter Real[Medium.nc] m_0
(each unit="kg/m3") = zeros(Medium.nc) "Initial substance mass";
Real[Medium.nc] m
(start=m_0, each fixed=true) "Substance mass";
Real[Medium.nc] c "Substance conc";
Real V(start=V_0, fixed=true, unit="m3") "Harvest liquid volume";
equation
inlet.P = P;
der(V) = inlet.F;
for i in 1:Medium.nc loop
der(m[i]) = inStream(inlet.c[i])*inlet.F;
c[i] = m[i]/V;
end for;
end HarvesttankType;
end EquipmentLib;
// ---------------------------------------------------------------------------------------------
// Adaptation of package Equipment to Medium1
// ---------------------------------------------------------------------------------------------
package Equipment
import DEMO_v40.EquipmentLib;
extends EquipmentLib(redeclare package Medium=Medium1);
end Equipment;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
model Test
Medium_data medium;
Equipment.FeedtankType feedtank;
Equipment.HarvesttankType harvesttank;
Equipment.PipeType pipe;
equation
connect(feedtank.outlet, pipe.inlet);
connect(pipe.outlet, harvesttank.inlet);
end Test;
end DEMO_v40;
有了这个,我转到 OMEdit 并使用 CheckModel 按钮(OMEdit 顶部中间的绿色圆圈上的单个复选标记)分别检查每个组件。
我意识到你的连接器有 3 个未知数和 1 个方程式,这是非法的(正如我所说,它应该是 2:1 比率)。这也会导致您的所有其他组件都是非法的。
由于调试您所有的东西会很麻烦,所以我只能提供我前段时间为学生项目制作的东西,但它应该展示必须完成的工作。您不需要同时传递 pressure
和 concentration
,因为无论如何它们应该是代数连接的。我改用 height
。
请参阅以下模型答案,它不适合这个(我无法在此处添加文件)。
编辑:我刚刚创建了一个 git 存储库。实际上更容易:
HTTPS:https://github.com/kabdelhak/TankSystem
SSH: git@github.com:kabdelhak/TankSystem.git
就我个人而言,我会 "go all the way" 并使用流连接器,原因如下:
- 在过去的 15-20 年中,人们进行了许多尝试,以在 Modelica 中创建良好的热液压连接器。这一努力在 2008 年产生了
stream
个连接器,这是目前 Modelica 中最先进的。它允许您使用一个 flow
变量传输特定的焓和物质分数(或物质浓度),并启用流动反转。使用 stream
连接器 而不是 矫枉过正。
- 遵守例如
Modelica.Fluid.Interfaces.FluidPort
,您的作品将与许多现有库和模型兼容,您无需自己制作泵、管道、阀门、水箱模型等。
不过,您将面临一些挑战:
- 您需要学习
stream
连接器的语法和工作原理。您可以在 https://github.com/justnielsen/ModelicaTutorials 中找到灵感
- 您必须为将在流连接器中传输的流体实施基于
Modelica.Media
的介质模型。例如,如果您可以假设恒定密度 and/or 比热容,则介质模型不必非常复杂。如果介质模型很简单,当您指定边界条件(source/sinks)时,在 volume/mass 流量之间切换在计算上很容易。
经过一番思考,我相信以下是您转换为直接使用流变量的示例(尽管我同意让它与 MSL 兼容会很好,正如@ReneJustNielsen 所建议的)。
package DEMO_v42
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
// ---------------------------------------------------------------------------------------------
// Equipment
// ---------------------------------------------------------------------------------------------
package EquipmentLib
connector LiquidCon
Real P "Pressure";
flow Real F "Flow rate";
stream Real c_outflow "Substance conc";
end LiquidCon;
model PipeType
LiquidCon inlet, outlet;
parameter Real area = 1;
equation
inlet.F = -outlet.F;
outlet.F = -area^2*(inlet.P - outlet.P); // Linearized Bernoulli equation
outlet.c_outflow = inStream(inlet.c_outflow);
inlet.c_outflow=inStream(outlet.c_outflow);
end PipeType;
model FeedtankType
LiquidCon outlet;
parameter Real P = 0.1 "Pressure";
parameter Real V_0 = 100 "Initial feed volume";
parameter Real c_in = 1.0 "Feedtank conc";
Real V(start=V_0, fixed=true) "Feed volume";
equation
outlet.c_outflow = c_in;
outlet.P = P;
der(V) = outlet.F;
end FeedtankType;
model HarvesttankType
LiquidCon inlet;
parameter Real P = 0.0 "Pressure";
parameter Real V_0 = 1.0 "Initial harvest liquid volume";
parameter Real m_0 = 0.0 "Initial substance mass";
Real V(start=V_0, fixed=true) "Harvest liquid volume";
Real m(start=m_0, fixed=true) "Substance mass";
Real c "Substance conc";
Real inletC=actualStream(inlet.c_outflow);
equation
inlet.P = P;
inlet.c_outflow=c;
der(V) = inlet.F;
der(m) = actualStream(inlet.c_outflow)*inlet.F;
c = m/V;
end HarvesttankType;
end EquipmentLib;
// ---------------------------------------------------------------------------------------------
// Example of system
// ---------------------------------------------------------------------------------------------
model Test
EquipmentLib.FeedtankType feedtank;
EquipmentLib.HarvesttankType harvesttank;
EquipmentLib.PipeType pipe;
equation
connect(feedtank.outlet, pipe.inlet);
connect(pipe.outlet, harvesttank.inlet);
end Test;
end DEMO_v42;
我添加了 inletC 以便能够将浓度与以前的模型进行比较。
主要变化是对于流变量 c_outflow,实际上有 two/three 个不同的变量可供使用:
- 如果您想要介质流出时的浓度,请使用
c_outflow
- 如果你想要介质在使用中流动时的浓度
inStream(c_outflow)
- 如果您只想要流量中的实际浓度,请使用
actualStream(c_outflow)
所以对于你写的管道,从一个端口流出的浓度等于流入另一个端口的浓度,反之亦然。
对于水箱,您只需编写 c_outflow
的方程式,但使用 actualStream
获得流量中的实际浓度。
post 的状态:
200313 得到了代码 DEMO_v42 的答案,我接受赏金!
200310 我评论了昨天推荐的两篇关键论文。还是不明白怎么更新DEMO_v41.
200309 我想强调一下,关键问题是如何在代码中引入流的概念DEMO_v41(如果可能的话),并通过这种方式使连接器平衡。作为浓度的变量 c 应该声明为 stream,但是方程式应该如何用 inStream 或 actualStream 更新——我很乐意看到!
200226 添加了 post 示例 DEMO_v41,它是一个简化的代码,我希望代码比第一个 DEMO_v40.
更具可读性200225 我对给出的答案进行了一些评论,并试图让读者关注实际问题,但收效甚微。
200224 我得到了一些关于 post 的一般和详细信息。详细的评论价值较低,部分原因是误解了问题。 Rene 的更笼统的回答很好,但过于笼统。在我考虑使用 Modelica.Media 等之前,我真的很想通过小例子了解如何使用流的概念。这是一个学习过程。
我想知道如何正确定义液体的连接器,该液体在溶液中具有多种不同浓度的成分,然后该溶液具有流速。液体中的压力可以忽略不计。 我长期使用的标准连接器是:
connector LiquidCon
nc=5;
Real c[nc] “Component concentrations”;
flow Real F “Flow rate”;
end LiquidCon;
连接器在 JModelica 和 OpenModelica 中运行良好,但我在 OpenModelica 中收到连接器不平衡的警告。在 Modelica 语言规范的第 9.3.1 节中,我看到我的构造实际上是不合法的,请参见 https://www.modelica.org/documents/ModelicaSpec34.pdf。如何制作满足需求的连接器?
我花了一些时间阅读了 Fritzons 书第 2n 版中关于“流”概念的第 5.10 章,但我需要更详细地研究它。
我的简单连接器发出警告的原因是,当您声明流变量时,编译器假定另一个变量是该流变量的潜在变量,即至少流和潜在变量的数量必须是在连接器中相同。那么当然在我的例子中,组件浓度不是潜在变量,而是编译器无法检测到的。
在第 5.10 章的介绍部分,“流”概念的范围似乎是“......具有相关属性的双向物质流的应用......”。在我的应用领域,我怀疑我需要考虑双向流。这意味着使用流是一种“矫枉过正”。但这似乎也暗示我也不应该使用“流”的概念,这有点可惜。我们真的应该停止使用吗这里是“流”的概念?
无论如何,我已经尝试整理一个比 Fritzson 书中关于这个主题的更基本的示例,以了解如何使用“流”的概念以及计算时间等方面的开销你得到。在下面的示例中,我模拟了从进料罐到收获罐的液体流动。流量现在由压力差控制。代码 DEMO_v41 起作用并发出连接器不平衡的警告。如果我现在声明底物浓度 c 为“流”,我现在应该如何使用 inStream 和 actualStream 更新代码以使其以相同的方式工作,但现在使用此平衡连接器?
package DEMO_v41
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
// ---------------------------------------------------------------------------------------------
// Equipment
// ---------------------------------------------------------------------------------------------
package EquipmentLib
connector LiquidCon
Real P "Pressure";
flow Real F "Flow rate";
Real c "Substance conc";
end LiquidCon;
model PipeType
LiquidCon inlet, outlet;
parameter Real area = 1;
equation
inlet.F = -outlet.F;
outlet.F = -area^2*(inlet.P - outlet.P); // Linearized Bernoulli equation
outlet.c = inlet.c;
end PipeType;
model FeedtankType
LiquidCon outlet;
parameter Real P = 0.1 "Pressure";
parameter Real V_0 = 100 "Initial feed volume";
parameter Real c_in = 1.0 "Feedtank conc";
Real V(start=V_0, fixed=true) "Feed volume";
equation
outlet.c = c_in;
outlet.P = P;
der(V) = outlet.F;
end FeedtankType;
model HarvesttankType
LiquidCon inlet;
parameter Real P = 0.0 "Pressure";
parameter Real V_0 = 1.0 "Initial harvest liquid volume";
parameter Real m_0 = 0.0 "Initial substance mass";
Real V(start=V_0, fixed=true) "Harvest liquid volume";
Real m(start=m_0, fixed=true) "Substance mass";
Real c "Substance conc";
equation
inlet.P = P;
der(V) = inlet.F;
der(m) = inlet.c*inlet.F;
c = m/V;
end HarvesttankType;
end EquipmentLib;
// ---------------------------------------------------------------------------------------------
// Example of system
// ---------------------------------------------------------------------------------------------
model Test
EquipmentLib.FeedtankType feedtank;
EquipmentLib.HarvesttankType harvesttank;
EquipmentLib.PipeType pipe;
equation
connect(feedtank.outlet, pipe.inlet);
connect(pipe.outlet, harvesttank.inlet);
end Test;
end DEMO_v41;
下面的旧示例 DEMO_v40 更笼统且更难阅读,但自从围绕此示例的一个早期回答以来保留以供参考。
我得到的编译 (JModelica 2.14) 错误消息是:“扁平模型中的错误:系统在结构上是单一的。以下变量无法与方程匹配:harvesttank.inlet.c[1]、pipe.outlet.c[1]。 OpenModelica (1.16) 给出了大致相同的信息。这里有什么问题?
package DEMO_v40
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
partial package MediumBase
constant String name "Medium name";
constant Integer nc "Number of substances";
replaceable type Concentration = Real[nc] "Substance conc";
end MediumBase;
package Medium1
extends MediumBase
(name="One component medium",
nc=1);
constant Real[nc] mw = {10} "Substance weight";
constant Integer A = 1 "Substance index";
end Medium1;
record Medium_data
constant String name = Medium1.name;
constant Integer nc = Medium1.nc;
constant Real[nc] mw = Medium1.mw;
constant Integer A = Medium1.A;
end Medium_data;
// ---------------------------------------------------------------------------------------------
// Equipment dependent on the medium
// ---------------------------------------------------------------------------------------------
package EquipmentLib
replaceable package Medium = MediumBase // formal parameter - EquipmentLib
constrainedby MediumBase;
connector LiquidCon
Real P "Pressure";
flow Real F (unit="m3/s") "Flow rate";
stream Medium.Concentration c "Substance conc";
end LiquidCon;
model PipeType
LiquidCon inlet, outlet;
parameter Real area = 1;
equation
inlet.F = -outlet.F;
outlet.F = area^2*(inlet.P - outlet.P); // Linearized Bernoulli equation
for i in 1:Medium.nc loop
outlet.c[i] = inlet.c[i];
end for;
end PipeType;
model FeedtankType
LiquidCon outlet;
parameter Real P = 0.1 "Pressure";
parameter Real V_0 (unit="m3") = 100 "Initial feed volume";
parameter Real[Medium.nc] c_in (each unit="kg/m3")
= {1.0*k for k in 1:Medium.nc} "Feed inlet conc";
Real V(start=V_0, fixed=true, unit="m3") "Feed volume";
equation
for i in 1:Medium.nc loop
outlet.c[i] = c_in[i];
end for;
outlet.P = P;
der(V) = outlet.F;
end FeedtankType;
model HarvesttankType
LiquidCon inlet;
parameter Real P = 0.0 "Pressure";
parameter Real V_0 (unit="m3") = 1.0 "Initial harvest liquid volume";
parameter Real[Medium.nc] m_0
(each unit="kg/m3") = zeros(Medium.nc) "Initial substance mass";
Real[Medium.nc] m
(start=m_0, each fixed=true) "Substance mass";
Real[Medium.nc] c "Substance conc";
Real V(start=V_0, fixed=true, unit="m3") "Harvest liquid volume";
equation
inlet.P = P;
der(V) = inlet.F;
for i in 1:Medium.nc loop
der(m[i]) = inStream(inlet.c[i])*inlet.F;
c[i] = m[i]/V;
end for;
end HarvesttankType;
end EquipmentLib;
// ---------------------------------------------------------------------------------------------
// Adaptation of package Equipment to Medium1
// ---------------------------------------------------------------------------------------------
package Equipment
import DEMO_v40.EquipmentLib;
extends EquipmentLib(redeclare package Medium=Medium1);
end Equipment;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
model Test
Medium_data medium;
Equipment.FeedtankType feedtank;
Equipment.HarvesttankType harvesttank;
Equipment.PipeType pipe;
equation
connect(feedtank.outlet, pipe.inlet);
connect(pipe.outlet, harvesttank.inlet);
end Test;
end DEMO_v40;
正确的方法是
connector LiquidCon
nc=5;
Real c[nc] “Component concentrations”;
flow Real F[nc] “Flow rate”;
end LiquidCon;
或
connector LiquidCon
Real c “Component concentrations”;
flow Real F “Flow rate”;
end LiquidCon;
取决于您要建模的内容。经验法则是:number of potentials = number of flows
。由于您只使用一种流量和多种浓度,这意味着您有多个类似水箱的组件,每个组件都有一定的浓度,并通过允许流量的类似管道的组件连接。
对于这些我会推荐我发布的第二个版本!
一些背景信息:
连接器永远不会平衡,假定与其未知数相比提供一半的方程式。每当您向组件添加连接器时,该组件都必须平衡它。原因很简单:例如具有一种电位和一种流量的连接器。信息流动的方向不清楚,但可以肯定的是,要么 flow
变量被认为是已知的,要么 potential
被认为是已知的,另一个将由组件的方程计算。对于水箱,浓度由其自身的方程计算,流量通过连接器(管道反之亦然)。
只要连接两个或多个连接器,所有电位都设置为相等,所有流量总和为零(Modelica Language Specification 第 9.2 节)。
我更改了您的示例,以便我可以实际单独测试组件。注意我给nc
添加了一个默认值,否则无法检查单个组件的一致性
package DEMO_v40
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
partial package MediumBase
constant String name "Medium name";
constant Integer nc = 1 "Number of substances";
replaceable type Concentration = Real[nc] "Substance conc";
end MediumBase;
package Medium1
extends MediumBase
(name="One component medium",
nc=1);
constant Real[nc] mw = {10} "Substance weight";
constant Integer A = 1 "Substance index";
end Medium1;
record Medium_data
constant String name = Medium1.name;
constant Integer nc = Medium1.nc;
constant Real[nc] mw = Medium1.mw;
constant Integer A = Medium1.A;
end Medium_data;
// ---------------------------------------------------------------------------------------------
// Equipment dependent on the medium
// ---------------------------------------------------------------------------------------------
package EquipmentLib
replaceable package Medium = MediumBase "formal parameter EquipmentLib";
connector LiquidCon
Real P "Pressure";
flow Real F (unit="m3/s") "Flow rate";
stream Medium.Concentration c "Substance conc";
end LiquidCon;
model PipeType
LiquidCon inlet, outlet;
parameter Real area = 1;
equation
inlet.F = -outlet.F;
outlet.F = area^2*(inlet.P - outlet.P); // Linearized Bernoulli equation
for i in 1:Medium.nc loop
outlet.c[i] = inlet.c[i];
end for;
end PipeType;
model FeedtankType
LiquidCon outlet;
parameter Real P = 0.1 "Pressure";
parameter Real V_0 (unit="m3") = 100 "Initial feed volume";
parameter Real[Medium.nc] c_in (each unit="kg/m3")
= {1.0*k for k in 1:Medium.nc} "Feed inlet conc";
Real V(start=V_0, fixed=true, unit="m3") "Feed volume";
equation
for i in 1:Medium.nc loop
outlet.c[i] = c_in[i];
end for;
outlet.P = P;
der(V) = outlet.F;
end FeedtankType;
model HarvesttankType
LiquidCon inlet;
parameter Real P = 0.0 "Pressure";
parameter Real V_0 (unit="m3") = 1.0 "Initial harvest liquid volume";
parameter Real[Medium.nc] m_0
(each unit="kg/m3") = zeros(Medium.nc) "Initial substance mass";
Real[Medium.nc] m
(start=m_0, each fixed=true) "Substance mass";
Real[Medium.nc] c "Substance conc";
Real V(start=V_0, fixed=true, unit="m3") "Harvest liquid volume";
equation
inlet.P = P;
der(V) = inlet.F;
for i in 1:Medium.nc loop
der(m[i]) = inStream(inlet.c[i])*inlet.F;
c[i] = m[i]/V;
end for;
end HarvesttankType;
end EquipmentLib;
// ---------------------------------------------------------------------------------------------
// Adaptation of package Equipment to Medium1
// ---------------------------------------------------------------------------------------------
package Equipment
import DEMO_v40.EquipmentLib;
extends EquipmentLib(redeclare package Medium=Medium1);
end Equipment;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
model Test
Medium_data medium;
Equipment.FeedtankType feedtank;
Equipment.HarvesttankType harvesttank;
Equipment.PipeType pipe;
equation
connect(feedtank.outlet, pipe.inlet);
connect(pipe.outlet, harvesttank.inlet);
end Test;
end DEMO_v40;
有了这个,我转到 OMEdit 并使用 CheckModel 按钮(OMEdit 顶部中间的绿色圆圈上的单个复选标记)分别检查每个组件。 我意识到你的连接器有 3 个未知数和 1 个方程式,这是非法的(正如我所说,它应该是 2:1 比率)。这也会导致您的所有其他组件都是非法的。
由于调试您所有的东西会很麻烦,所以我只能提供我前段时间为学生项目制作的东西,但它应该展示必须完成的工作。您不需要同时传递 pressure
和 concentration
,因为无论如何它们应该是代数连接的。我改用 height
。
请参阅以下模型答案,它不适合这个(我无法在此处添加文件)。
编辑:我刚刚创建了一个 git 存储库。实际上更容易:
HTTPS:https://github.com/kabdelhak/TankSystem
SSH: git@github.com:kabdelhak/TankSystem.git
就我个人而言,我会 "go all the way" 并使用流连接器,原因如下:
- 在过去的 15-20 年中,人们进行了许多尝试,以在 Modelica 中创建良好的热液压连接器。这一努力在 2008 年产生了
stream
个连接器,这是目前 Modelica 中最先进的。它允许您使用一个flow
变量传输特定的焓和物质分数(或物质浓度),并启用流动反转。使用stream
连接器 而不是 矫枉过正。 - 遵守例如
Modelica.Fluid.Interfaces.FluidPort
,您的作品将与许多现有库和模型兼容,您无需自己制作泵、管道、阀门、水箱模型等。
不过,您将面临一些挑战:
- 您需要学习
stream
连接器的语法和工作原理。您可以在 https://github.com/justnielsen/ModelicaTutorials 中找到灵感
- 您必须为将在流连接器中传输的流体实施基于
Modelica.Media
的介质模型。例如,如果您可以假设恒定密度 and/or 比热容,则介质模型不必非常复杂。如果介质模型很简单,当您指定边界条件(source/sinks)时,在 volume/mass 流量之间切换在计算上很容易。
经过一番思考,我相信以下是您转换为直接使用流变量的示例(尽管我同意让它与 MSL 兼容会很好,正如@ReneJustNielsen 所建议的)。
package DEMO_v42
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
// ---------------------------------------------------------------------------------------------
// Equipment
// ---------------------------------------------------------------------------------------------
package EquipmentLib
connector LiquidCon
Real P "Pressure";
flow Real F "Flow rate";
stream Real c_outflow "Substance conc";
end LiquidCon;
model PipeType
LiquidCon inlet, outlet;
parameter Real area = 1;
equation
inlet.F = -outlet.F;
outlet.F = -area^2*(inlet.P - outlet.P); // Linearized Bernoulli equation
outlet.c_outflow = inStream(inlet.c_outflow);
inlet.c_outflow=inStream(outlet.c_outflow);
end PipeType;
model FeedtankType
LiquidCon outlet;
parameter Real P = 0.1 "Pressure";
parameter Real V_0 = 100 "Initial feed volume";
parameter Real c_in = 1.0 "Feedtank conc";
Real V(start=V_0, fixed=true) "Feed volume";
equation
outlet.c_outflow = c_in;
outlet.P = P;
der(V) = outlet.F;
end FeedtankType;
model HarvesttankType
LiquidCon inlet;
parameter Real P = 0.0 "Pressure";
parameter Real V_0 = 1.0 "Initial harvest liquid volume";
parameter Real m_0 = 0.0 "Initial substance mass";
Real V(start=V_0, fixed=true) "Harvest liquid volume";
Real m(start=m_0, fixed=true) "Substance mass";
Real c "Substance conc";
Real inletC=actualStream(inlet.c_outflow);
equation
inlet.P = P;
inlet.c_outflow=c;
der(V) = inlet.F;
der(m) = actualStream(inlet.c_outflow)*inlet.F;
c = m/V;
end HarvesttankType;
end EquipmentLib;
// ---------------------------------------------------------------------------------------------
// Example of system
// ---------------------------------------------------------------------------------------------
model Test
EquipmentLib.FeedtankType feedtank;
EquipmentLib.HarvesttankType harvesttank;
EquipmentLib.PipeType pipe;
equation
connect(feedtank.outlet, pipe.inlet);
connect(pipe.outlet, harvesttank.inlet);
end Test;
end DEMO_v42;
我添加了 inletC 以便能够将浓度与以前的模型进行比较。
主要变化是对于流变量 c_outflow,实际上有 two/three 个不同的变量可供使用:
- 如果您想要介质流出时的浓度,请使用
c_outflow
- 如果你想要介质在使用中流动时的浓度
inStream(c_outflow)
- 如果您只想要流量中的实际浓度,请使用
actualStream(c_outflow)
所以对于你写的管道,从一个端口流出的浓度等于流入另一个端口的浓度,反之亦然。
对于水箱,您只需编写 c_outflow
的方程式,但使用 actualStream
获得流量中的实际浓度。