Modelica 中的正则化

问题描述

我想知道 Modelica 中是否存在其他正则化技术(例如双曲正切)而不是 smoothStep 函数。我处理了一个复杂的代码,我多次使用 smoothStep 以避免在我的模型中颤抖;但是,我在我的模型结果中看到了这个函数的一些副作用,我宁愿采用其他技术。为了更清楚地说明,我只是包含了我的代码的一部分,如下所示:

model MassFlow
  import Modelica.SIunits.MassFlowRate;
  import Modelica.Media.Common.smoothStep;
  Real c1[15];
  parameter MassFlowRate mDotSource[15]={0.00,-0.10,0.10,1.00,2.00,0.00,0.01,0.09,-0.20,-0.30,-0.03,0.06};

  parameter MassFlowRate smallFlow = 0.01 "Small flow value used to avoid chattering problems";
equation 
  c1 = smoothStep(mDotSource,1,smallFlow);
end MassFlow;

因此,目标是对 mDotSource 的正则化进行更精确的近似。如果您能帮助我,我将不胜感激。

根据@matth 的有用评论,我使用了 spliceFunction。为了在输入负值时返回0,我修改了spliceFunction如下:

function spliceFun "Spline interpolation of two functions"
  extends Modelica.Icons.Function;
  input Real pos "Returned value for x-deltax >= 0";
  input Real neg "Returned value for x+deltax <= 0";
  input Real x "Function argument";
  input Real deltax=1 "Region around x with spline interpolation";
  output Real out;
protected 
  Real scaledX;
  Real scaledX1;
  Real y;
algorithm 
  scaledX1 := x/deltax;
  scaledX := scaledX1*Modelica.Math.asin(1);
  if scaledX1 <= -0.00000001 then
    y := 0;
  elseif scaledX1 >= 0.999999 then
    y := 1;
  else
    y := (Modelica.Math.tanh(Modelica.Math.tan(scaledX)) + 1)/2;
  end if;
  out := pos*y + (1 - y)*neg;
  annotation (derivative=spliceFun_der);
end spliceFun;

如所见,与原始 spliceFunction 相比,只有 scaledX1 <= -0.00000001 时更改了“if 语句”。它适用于示例输入数据(mDotSource):

model MassFlow
  import Modelica.SIunits.MassFlowRate;

  parameter MassFlowRate mDotSource[15]={0.00,0.20,-2.0,-0.8};
  Real c1[15];

equation 
  c1 = SHCLibrary.Tests.spliceFun(1,mDotSource,1);

end MassFlow;

然而,当我尝试在我的复杂代码中应用修改后的 spliceFunction(spliceFun)时,模拟运行是无止境的。它既不停止也不给出错误。 我必须在这里补充一点,在我的复杂代码中,我使用了 spliceFun 的 6 倍,当我用 smoothStep 函数替换其中的 5 个并仅使用 1 个 spliceFun 时,它可以工作,但我没有收到准确的结果我所期望的。
请您就这个问题提出建议吗?

解决方法

您可以使用 spliceFun 以外的其他正则化,但有两个要求:

  • 边缘平滑
  • 正确的导数

如果我们查看您的函数,我们会发现 scaledX1=0 给出 y=0,scaledX1=1 给出 y=1;这很好,但是如果我们查看正则化分支中的 scaledX,我们有:

(Modelica.Math.tanh(Modelica.Math.tan(scaledX1*asin(1))) + 1)/2;

对于 scaledX1=0 给出 y=0.5,对于 scaledX1=1 给出 y=1;根本不规则,并且 0 处的斜率不是 0。基本上看起来你有一个转变,你想要这样的东西:

scaledX := (scaledX1-0.5)*Modelica.Math.asin(1);
...
y:= Modelica.Math.tan(scaledX)) + 1)/2;

所以 scaledX1=0 给出 scaledX=-0.5*Modelica.Math.asin(1) 给出 y=0,但不幸的是在边缘处没有零导数。使用 tanh 时,它变得更加混乱,但仍然要求 scaledX=0 和 1 的限制应匹配。

是使用的想法

   scaledX := (2*scaledX1-1)*Modelica.Math.asin(1);
   ...
     y := (Modelica.Math.tanh(Modelica.Math.tan(scaledX)) + 1)/2;

好像边在 -1 和 1 而不是 0 和 1?这个变体似乎从 0 到 1 并且在过渡时很平滑。

第二部分很容易通过写:annotation (smoothOrder=2);而不是试图写一个导数来纠正。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...