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

时间:2018-09-13 11:15:49

标签: modelica systemmodeler

动机

Modelica确实将度量单位(例如SI单位和Non-SI单位)存储为变量的属性。这是一个非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:如何在模型中访问诸如 unit 之类的元信息?

理想情况下,以下内容将非常有用:

String timeBaseA := timeValue.unit;

String timeBaseA := getUnit( timeValue ) "some function to read unit information";

问题2:如何在功能内分配诸如 unit 之类的元信息?

在该示例中,我们当然想返回带有正确 unit 时间的 output 值。因此,理想情况下,我们希望拥有:

output Real convertedTime( quantity = "Time", unit = strTimeBaseB )

不幸的是,使用input会导致错误,因为变异性是不同的: unit 属性应具有恒定变异性,但是输入变量具有参数可变性。 (由于同样的原因,使用一个功能会很好-也会失败。)

2 个答案:

答案 0 :(得分:5)

关于问题1:

我从未使用过Wolfram SystemModeler,但是Modelica语言规范3.4在第4.8章(预定义类型和类)中说:

  

预定义变量类型(实型,整数,布尔型,字符串)的属性无法使用点表示法访问,并且不受方程式和算法部分的约束。

关于问题2:

我认为只能从文字或最终参数的声明中定义变量的单位-至少这是我在Dymola中观察到的。

替代-使用运算符记录

您可以将操作员记录用于任务。这样一来,您可以以秒为单位存储时间,并将其转换为使用该值时所需的时间。

操作员记录允许您定义几个函数来创建它们,比较或添加它们,转换为String等。

请参见下面的简短示例,其中定义了操作员记录 Time ,可以使用秒或天的两个不同的构造函数来创建该记录,并可以将日期或秒转换为字符串

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 Spec 3.4第14章“重载的运算符”。

注意:这是使用Dymola 2019而不是Wolfram SystemModeler测试的

答案 1 :(得分:4)

在Modelica中,通常每个变量都是基于SI单位计算的。然后,您有displayUnits可以将它们绘制为其他单位(不影响实际计算)。

我不了解SystemModeler,但是在Dymola中,unit(用于计算)和displayUnit(仅用于绘图)之间的转换是由预定义的脚本({{ 1}})。用户可以扩展它以包含自定义displayUnits。与时间相关的人机界面代码如下所示。我将其扩展为除了预定义的周外还有周(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); 将该默认值选择为“ displayUnit”

缺点是,此扩展名必须在安装目录中的文件中完成。因此,在重新安装该工具或使用其他计算机时,必须再次更改它。

如果有数字上的原因无法在几秒钟内计算出解决方案(例如,因为值变大),则解决方案将是Modelica.SIunits.Time t(displayUnit = "w") = ...;属性,该属性可以缩放变量。

顺便说一句:我认为几个月不是一个很好的时间单位,因为它们可以有28到31天。这就是为什么我在示例中选择了几周。