我想知道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.10,0.01,0.09,-0.20,-0.30,0.00,-0.10,-0.03,0.06};
parameter MassFlowRate smallFlow = 0.01 "Small flow value used to avoid chattering problems";
equation
c1 = smoothStep(mDotSource, 1, 0, smallFlow);
end MassFlow;
因此,目标是在mDotSource
的正则化中进行更精确的近似。如果您能帮助我,我将不胜感激。
根据@matth的有用评论,我使用了spliceFunction。为了在输入负值时返回 0,我修改了拼接函数,如下所示:
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.10,0.20,1.00,2.00,0.00,0.10,0.01,0.09,-0.20,-2.0,0.00,-0.10,-0.03,-0.8};
Real c1[15];
equation
c1 = SHCLibrary.Tests.spliceFun(1,0,mDotSource,1);
end MassFlow;
但是,当我尝试在我的复杂代码中应用修改后的spliceFunction(spliceFun)时,模拟运行是无止境的。它既不会停止也不会给出错误。 我必须在这里补充一点,在我的复杂代码中,我使用了 6 倍的 spliceFun,当我用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);
而不是试图写导数。