如何在Modelica的模型中使用unit属性? 动机

如何在Modelica的模型中使用unit属性? 动机,modelica,systemmodeler,Modelica,Systemmodeler,Modelica将测量单位(例如国际单位制和非国际单位制)存储为变量的属性。以下是非SI单位的示例: type Time_months = Real( quantity = "Time", unit = "mo", displayUnit = "months" ) 因为对于经济学中的模型来说,以秒为单位给出速率是非常合适的,所以我想写一个相当通用的单位转换函数,它允许转换时间单位。因此,理想情况下,转换为另一个时基的函数应使用三个输入和一个输出: input Real timeValue "t

Modelica将测量单位(例如国际单位制和非国际单位制)存储为变量的属性。以下是非SI单位的示例:

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;