【问题标题】:How to use boolean switches in Modelica to prevent draining a stock below zero?如何在 Modelica 中使用布尔开关来防止库存低于零?
【发布时间】:2019-02-15 19:11:45
【问题描述】:

问题描述

我正在构建一个库来支持System Dynamics (SD),就像在 Modelica 中建模一样。与 Cellier 等人的 freely available library 不同。我相信人们可以很好地利用非因果连接器:通过连接器将库存值作为“潜在”传递可以构建紧凑的组件(例如流程 = 流程)。

在 SD 中,我们可能会将物质(“大众”)股票与可能变为负数的信息股票区分开来。为了支持这一点,我对 ma​​ss port 使用了以下定义(这里给出了 StockPort 的定义 - 其对应的 FlowPort 将仅具有布尔输入变量而不是输出变量稍后给出):

 connector StockPort "Used to represent stock and flow connections"
    Real stock "Current value of material in the stock";
    flow Real rate "Flow that affects the stock";
    // Boolean switches
    output Boolean stopInflow "True indicates that nothing can flow into the stock";
    output Boolean stopOutflow "True indicates that nothing can flow out of the stock";
 end StockPort;

布尔开关指示库存的每个端口是否允许填充或排放。

对于“材料库存”,stopOutflow 开关应防止库存低于零。不幸的是,在以下示例中,这将无法解决:库存将略低于零。

使用连接器的最小示例

以下TestModel 使用这些构建块:

  • function constrainedRate( indicated rate, stopInflow, stopOutflow) 用于返回符合给定约束(即布尔开关)的速率

  • connector StockPort 如上所述

  • connector FlowPort 对应于 StockPort
  • model MaterialStock 一个带有一个 StockPort 的库存组件,在零以下不能排空
  • model LinearDecline 一个带有一个 FlowPort(即 Sink)的流元素,它模拟以恒定速率(此处设置为 1)排出连接的股票

主模型简单地用initialValue = 5启动一个stock,它连接到一个用declineRate = 1线性下降的process

model TestModel "Stop draining a stock below zero"

  function constrainedRate "Set rate for a port according to signals from stock" 
    input Real indicatedRate "Proposed rate for port of flow element";
    input Boolean stopInflow "Signal from connected stock";
    input Boolean stopOutflow "Signal from connected stock";
    output Real actualRate "The rate to use";
  protected
    // check whether indicated rate is negative (e.g. an inflow to the connected stock)
    Boolean indRateIsInflow = indicatedRate < 0;
  algorithm
    // set rate to zero if stopSignal matches character of flow
    actualRate := if indRateIsInflow and stopInflow 
          then 0 
        elseif not indRateIsInflow and stopOutflow 
          then 0 
        else indicatedRate;
  end constrainedRate;

  connector FlowPort "Used to represent stock and flow connections"
    Real stock "The current stock level (e.g. Potential) of a connected stock or flow data for special stocks";
    flow Real rate "Flows that affect the material stock";
    input Boolean stopInflow "True indicates that nothing can flow into the stock";
    input Boolean stopOutflow "True indicates that nothing can flow out of the stock";
  end FlowPort;

  connector StockPort "Used to represent stock and flow connections"
    Real stock "Current value of stock";
    flow Real rate "Flow that affects the stock";
    output Boolean stopInflow "True indicates that nothing can flow into the stock";
    output Boolean stopOutflow "True indicates that nothing can flow out of the stock";
  end StockPort;

  model MaterialStock "Stock that cannot be drained below zero"
    StockPort outflow;
    parameter Real initialValue;
  protected
    Real x(start = initialValue);
  equation
    // rate of change for the stock
    der(x) = outflow.rate;
    // ports shall have level information for stock
    outflow.stock = x;
    // inflow to stock is unrestricted
    outflow.stopInflow = false;
    // provide Boolean signal in case of negative stock
    outflow.stopOutflow = x <= 0;
  end MaterialStock;

  model LinearDecline "Decline of stock at a constant rate"
    FlowPort massPort;
    parameter Real declineRate(min = 0) "Rate of decline (positive rate diminishes stock)";
  protected
    // a positive rate should drain the stock (which here matches Modelica's rule for flows)
    Real rate(min = 0);
  equation
    rate = declineRate;
    // observe stock signals and constraints
    assert(rate >= 0, "Rate must be positive and will be set to zero", level = AssertionLevel.warning);
  // set the rate according to constraints given by stock
    massPort.rate = constrainedRate( max(rate, 0), massPort.stopInflow, massPort.stopOutflow );
  end LinearDecline;

  // main model
  MaterialStock stock( initialValue = 5 );
  LinearDecline process( declineRate = 1 );
equation
  connect( stock.outflow, process.massPort );
end TestModel;

使用从StartTime = 0StopTime = 10 的DASSL 模拟模型揭示了变量stock.outflow.stock 的预期行为:

不幸的是,t = 5.0 和更高版本的值略低于零。

以某种方式检测到事件(库存值

(到目前为止,imo 不优雅的解决方法是使用when 事件(状态事件)将reinit 库存值归零。我在if 语句和布尔条件上使用noEvent 包装器的实验也没有成功。)

【问题讨论】:

  • 您是否尝试过设置布尔值,而不是通过与 0 进行比较,而是使用一些像 Modelica.Constants.eps 或类似的小值?例如:stopOutflow = x
  • @f.wue 谢谢。我只是尝试过,但不幸的是没有成功。

标签: events modelica openmodelica systemmodeler


【解决方案1】:

您能测试一下这个解决方案吗?使用 Modelica.Constants.eps 对我有用。我还使用了 Dassl,它适用于不同的步长。 我更改了以下行:

// provide Boolean signal in case of negative stock
outflow.stopOutflow = x <= 0;

// provide Boolean signal in case of negative stock
outflow.stopOutflow = x <= Modelica.Constants.eps;

然后,输出数组(这篇文章用python查看):

Output using a zero instead of eps:
[ 5.00000000e+00  4.00000000e+00  3.00000000e+00  2.00000000e+00
  1.00000000e+00  0.00000000e+00 -7.37276906e-12 -7.37276906e-12
 -7.37276906e-12 -7.37276906e-12 -7.37276906e-12 -7.37276906e-12
 -7.37276906e-12 -7.37276906e-12]
Output using eps:
[5. 4. 3. 2. 1. 0. 0. 0. 0. 0. 0. 0. 0.]

【讨论】:

  • 我已经尝试过 DASSL(固定间隔大小)和 Euler(不同步长),但您的解决方案在 Wolfram System Modeler (4.3) 或 Open Modelica 中都行不通。我添加了assert( x &gt;= 0, "Stock must always be positive") 以在出现负面情况时停止模拟。它总是停止。
  • 好的。我在 dymola 中对其进行了测试,也许这就是结果不同的原因。您机器上的负值是否也很小(例如 e-12)或更大?
  • 拥有outflow.stock = noEvent(if x &gt; 0 then x else 0) 有效。在这种情况下,数字“问题”保留在组件内部,如果绝对需要,when x &lt;= eps then reinit( x, 0 ); end when; 可能会处理它。
  • 好的。最后,这取决于您要建模的内容。如果经常出现接近零的股票价值(接近零我的意思是 e-4 左右),您可能需要使用 noEvent 或 when 解决方案。但是,如果您对更大的值建模,那么您的模型很可能对如此小的数字无效。因此,您可以使用大于 eps 的值(我相信是 e-15)。在我看来,像
  • 我不明白为什么建模更大的值会使非零检查无效 - 它们根本不适用?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-12
  • 1970-01-01
  • 2013-07-03
  • 2012-11-11
  • 2020-08-04
  • 2022-12-13
  • 2012-10-15
相关资源
最近更新 更多