如何在Modelica的模型中使用unit属性? 动机
Modelica将测量单位(例如国际单位制和非国际单位制)存储为变量的属性。以下是非SI单位的示例:如何在Modelica的模型中使用unit属性? 动机,modelica,systemmodeler,Modelica,Systemmodeler,Modelica将测量单位(例如国际单位制和非国际单位制)存储为变量的属性。以下是非SI单位的示例: type Time_months = Real( quantity = "Time", unit = "mo", displayUnit = "months" ) 因为对于经济学中的模型来说,以秒为单位给出速率是非常合适的,所以我想写一个相当通用的单位转换函数,它允许转换时间单位。因此,理想情况下,转换为另一个时基的函数应使用三个输入和一个输出: input Real timeValue "t
type Time_months = Real( quantity = "Time", unit = "mo", displayUnit = "months" )
因为对于经济学中的模型来说,以秒为单位给出速率是非常合适的,所以我想写一个相当通用的单位转换函数,它允许转换时间单位。因此,理想情况下,转换为另一个时基的函数应使用三个输入和一个输出:
input Real timeValue "the value of time to be converted";
input String timeBaseA "the time base for timeValue, e.g. \"mo\" ";
input String timeBaseB "the time base to convert to, e.g. \"yr\" ";
output Real convertedTimeValue "the result of the conversion";
问题
如果我们假设某个时间值的变量已经具有特定的单位属性(例如“mo”),那么在模型中使用该元信息是有意义的
问题1:如何在模型中访问单元等元信息?
理想情况下,类似于以下内容的内容会很好:
String timeBaseA := timeValue.unit;
或
问题2:如何在函数中分配单元等元信息?
在本例中,我们当然希望以正确的时间单位返回输出值。因此,理想情况下,我们希望:
output Real convertedTime( quantity = "Time", unit = strTimeBaseB )
不幸的是,使用输入将产生错误,因为可变性不同:单位属性应具有恒定可变性,但输入变量具有参数可变性。(使用一个函数——这很好——也会因为同样的原因失败。)关于问题1:
我从未使用过Wolfram SystemModeler,但Modelica语言规范3.4在第4.8章(预定义类型和类)中说:
预定义变量类型(实数、整数、布尔值、字符串)的属性。。。无法使用点表示法访问,并且不受方程和算法部分的约束
关于问题2:
我认为只有从文字或最终参数定义声明变量的单位才有可能——至少这是我在Dymola中观察到的
备选方案-使用操作员记录
您可以使用操作员记录执行任务。这将允许您以秒为单位存储时间,并在使用该值时将其转换为所需的时间
操作员记录允许您定义多个函数来创建它们、比较或添加它们、转换为字符串等
请参阅下面的简要示例,其中定义了运算符记录时间,可以使用两个不同的构造函数从秒或天创建,并可以转换为带天或秒的字符串
operator record Time
Integer s "Second";
encapsulated operator 'constructor'
import Time;
function from_s
input Integer s "Seconds";
output Time t(s=s);
algorithm
end from_s;
function from_d
input Integer d "Days";
output Time t(s=d*24*3600);
algorithm
end from_d;
end 'constructor';
encapsulated operator 'String' "Convert Time to string"
import Time;
function formated
input Time t;
input String format = "s" annotation(choices(choice="s" "seconds", choice="d" "days"));
output String str;
algorithm
if format == "d" then
str :=String(t.s/24/3600);
else
str :=String(t.s);
end if;
end formated;
end 'String';
encapsulated operator function '==' "Compare time records"
import Time;
input Time t1;
input Time t2;
output Boolean result "= t1 == t2";
algorithm
result := t1.s == t2.s;
end '==';
end Time;
用法:
import Modelica.Utilities.Streams.print
t1 = Time(d=12) // create record using day constructor
t2 = Time(s=3600*24*2) // create record using second constructor
print(String(t1, format="s")) // prints 1036800
print(String(t1, format="d")) // prints 12
print(String(t2, format="s")) // prints 172800
print(String(t2, format="d")) // prints 2
有关详细信息,请参见Modelica规范3.4第14章“重载运算符”
注:这是使用Dymola 2019进行测试的,而不是使用Modelica中的Wolfram SystemModeler进行测试,通常每个变量都是基于国际单位制计算的。然后您可以使用displayUnits
以不同的单位绘制它们(不影响实际计算)
我不知道SystemModeler,但在Dymola中,单位
(计算)和显示单位
(仅用于打印)之间的转换由预定义脚本(displayUnit.mos
)处理。用户可以扩展它以包含自定义显示单元。与时间相关的显示单位代码如下所示。我将其扩展为在预定义的基础上增加一周(w
)
// Syntax:
// defineUnitConversion(<unit>, <derived unit>, <scale>, <opt. offset>);
// Time
defineUnitConversion("s", "ms", 1000);
defineUnitConversion("s", "min", 1/60);
defineUnitConversion("s", "h", 1/3600);
defineUnitConversion("s", "d", 1/86400);
defineUnitConversion("s", "w", 1/604800);
//语法:
//定义单位转换(,);
//时间
定义单位转换(“s”、“ms”、1000);
定义单位换算(“s”、“最小”,1/60);
定义单位转换(“s”、“h”、1/3600);
定义单位转换(“s”、“d”,1/86400);
定义单位转换(“s”、“w”,1/604800);
然后可以在绘图中手动选择,或通过Modelica.SIunits.Time t(displayUnit=“w”)=…;将其作为默认的“显示单元”代码>
缺点是,此扩展必须在安装目录中的文件中完成。因此,在重新安装工具后或使用其他计算机时,必须再次对其进行更改
如果有数字原因不在几秒钟内计算解决方案(例如,因为值会变大),则解决方案将是nominal
属性,该属性支持变量的缩放
顺便说一句:我认为月不是一个很好的时间单位,因为它们可以有28到31天。这就是我在示例中选择weeks的原因。您可以像在MSL中一样使用转换,例如函数Modelica.SIunits.Conversions.to_degC,其签名为:
function to_degC
input Temperature Kelvin "Kelvin value";
output NonSIunits.Temperature_degC Celsius "Celsius value";
end to_degC;
这是可行的,但对于每个要在其中转换的单位,您需要一个这样的函数(这就是为什么大多数计算都使用SI单位)。我在Wolfram社区交叉发布了一个类似的(尽管范围更广)问题。谢谢,这很有帮助。由于我在Wolfram社区上读到了一些关于“询问开发人员”关于包含自动转换(displayUnit)的帖子,我不确定SystemModeler中的适用性。“秒”对于系统动力学模型(我主要是这样做的)来说是akward,对于跨越10年以上的战略模型来说,关于月份的不精确性可以忽略不计(在金融领域,一年中的天数如何计算和分配还很不清楚:)。有没有办法修改这方面的内置可变时间(例如displayUnit)?不是我直接从代码中知道的。在Dymola中,至少可以通过改变启动/停止时间的单位在模拟设置中进行更改。同样地,它可以通过在图中的右击和改变“时间单位”…+ 1来改变,使我考虑操作员记录。它看起来确实优雅的转换。我的这类模型(通常以年为单位定义)的更深层次的问题似乎是一个缩放问题,因为每年计算1.585489e-7而不是5个单位似乎有点荒谬。对于缩放问题,名义属性被发明了,也许这会有所帮助。嗯,我想在这里更方便一点,避免可能由于不必要的操作而产生的数值错误。但是,当然,我总是可以通过时间到达任何时基
function to_degC
input Temperature Kelvin "Kelvin value";
output NonSIunits.Temperature_degC Celsius "Celsius value";
end to_degC;