Как использовать атрибут модуля в модели в Modelica? - PullRequest
0 голосов
/ 13 сентября 2018

Мотивация

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;

или

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

Вопрос 2: Как мета-информация, такая как единица , может быть назначена внутри функции?

В этом примере мы, конечно, хотели бы вернуть значение output с правильной единицей времени. Поэтому в идеале мы хотели бы иметь:

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

К сожалению, использование input приведет к ошибке, поскольку изменчивость отличается: атрибут unit должен иметь постоянную переменную , но входная переменная имеет параметр изменчивость . (Использование функции - что было бы неплохо - также не работает по той же причине.)

Ответы [ 3 ]

0 голосов
/ 13 сентября 2018

В Modelica обычно каждая переменная вычисляется на основе единиц СИ.Затем у вас есть 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 дня.Вот почему я выбрал недели в моем примере.

0 голосов
/ 14 сентября 2018

Вы можете использовать преобразование, как это делается в MSL, например, функцию Modelica.SIunits.Conversions.to_degC, которая имеет подпись:

function to_degC
  input Temperature Kelvin "Kelvin value";
  output NonSIunits.Temperature_degC Celsius "Celsius value";
end to_degC;

Это работает, но вам нужна одна такая функция для каждойединицы, между которыми вы хотите конвертировать (поэтому большинство расчетов выполняется с использованием единиц СИ).

0 голосов
/ 13 сентября 2018

По вопросу 1:

Я никогда не использовал Wolfram SystemModeler, но спецификация языка Modelica 3.4 в главе 4.8 (Предопределенные типы и классы) гласит:

Атрибутыпредопределенные типы переменных (Real, Integer, Boolean, String) ... не могут быть доступны с использованием точечной нотации и не ограничены уравнениями и разделами алгоритма.

По вопросу 2:

Я думаю, что можно определить единицу переменной только при объявлении из литерала или из конечного параметра - по крайней мере, это то, что я наблюдалв Димоле.

Альтернатива - использовать записи операторов

Вы можете использовать записи операторов для своей задачи.Это позволит вам хранить время в секундах и преобразовывать его в то, что когда-либо понадобится, когда значение будет использоваться.

Записи оператора позволяют вам определить несколько функций для их создания, сравнения или добавления, преобразования в String.и т. д.

См. краткий пример ниже, где определена запись оператора Время , которая может быть создана с помощью двух различных функций конструктора из секунд или дней и может быть преобразована в строки со днемили секунды

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...