3

动机

Modelica 确实将测量单位(例如 SI 单位和非 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:如何在模型中访问单元等元信息?

理想情况下,以下内容会很棒:

String timeBaseA := timeValue.unit;

或者

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

问题 2:如何在函数中分配单元等元信息?

在示例中,我们当然希望以正确的时间单位返回输出值。所以理想情况下,我们希望拥有:

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

不幸的是,input由于可变性不同,使用 an 会产生错误:单位属性应该具有恒定可变性,但输入变量具有参数可变性。(使用一个函数——这很好——也因为同样的原因而失败。)

4

3 回答 3

5

关于问题1:

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

预定义变量类型(Real、Integer、Boolean、String)的属性......不能使用点表示法访问,并且不受方程和算法部分的约束。

关于问题2:

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

替代 - 使用操作员记录

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

运算符记录允许您定义多个函数来创建它们、比较或添加它们、转换为字符串等。

请参见下面的简短示例,其中定义了操作符记录Time,可以使用从 seconds 或 days 两个不同的构造函数创建,并且可以转换为带有 day 或 seconds 的字符串

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

于 2018-09-13T12:25:09.097 回答
4

在 Modelica 中,通常每个变量都是基于 SI 单位计算的。然后你必须displayUnits将它们绘制在不同的单位中(不影响实际计算)。

我不了解 SystemModeler,但在 Dymola 中,unit(计算的)和displayUnit(仅用于绘图的)之间的转换是由预定义的脚本 ( 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") = ...;

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

如果有数字原因不能在几秒钟内计算解决方案(例如,因为值会变大),则解决方案将是nominal属性,它可以对变量进行缩放。

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

于 2018-09-13T12:32:46.613 回答
3

您可以像在 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 单位完成的)。

于 2018-09-14T07:10:42.163 回答