连续时间内的 Modelica 布尔变量
Modelica Boolean variable in continuous time
下面的Modelica模型检查和模拟。
model boolCheck_OK1
Real a = sin(time);
Real b = cos(time);
Real c;
//protected
// Boolean isInReg = inRegionCheck(a, b);
equation
c = if inRegionCheck(a, b) then 1.3*a^b else 0.7*b^a;
end boolCheck_OK1;
RegionCheck()中的函数returns一个布尔值,这里是简化版:
function inRegionCheck
input Real a;
input Real b;
output Boolean c;
algorithm
c := a>b;
end inRegionCheck;
在实际代码中,该函数的输入较多,名称较长,有几行长,并且多次使用相同的检查,因此为了可读性,我想引入一个中间变量,如注释中的protected部分,但这会导致错误 "Non-real equation in continuous time are not legal".
对优雅的解决方法有什么建议吗?
函数调用在 isInReg
的等式中引入了 noEvent
。
这是 Dymola 2019 FD01 在使用布尔值时报告的内容:
Non-real equation in continuous time are not legal:
isInReg = noEvent(a > b);
因此,您的等式简化为
isInReg = noEvent(a > b)
这是不允许的,因为布尔值只能根据事件发生变化。
您必须摆脱函数调用,从而摆脱 noEvent。
也许有更好的解决方案,但您可以尝试在块而不是函数中定义检查。至少对于您的最小示例,它工作得很好。
那么您的代码可能如下所示:
model boolCheck_OK1
Real a = sin(time);
Real b = cos(time);
Real c;
protected
InRegionCheck check(a=a, b=b);
Boolean isInReg=check.c;
equation
c = if isInReg then 1.3*a^b else 0.7*b^a;
end boolCheck_OK1;
block InRegionCheck
input Real a;
input Real b;
output Boolean c;
equation
c = a>b;
end InRegionCheck;
基于没有函数可以转换为布尔值而只有一个块的事实,我建议 marco 的答案是可行的方法。
通过变通方法,您仍然可以在函数内执行此操作,但不能使用 Boolean
类型。而是使用 Real
并在 if 子句中比较它是否大于零。为了显示布尔值的切换行为,这很好用。如果您依赖函数并且不经常使用布尔值,这可能是一个选项。
model boolCheck_OK1
Real a = sin(time);
Real b = cos(time);
Real c;
function inRegionCheck
input Real a;
input Real b;
output Real c;
algorithm
c := if a>b then 1 else 0;
end inRegionCheck;
protected
Real isInReg = inRegionCheck(a, b);
equation
c = if inRegionCheck(a, b)>Modelica.Constants.eps then 1.3*a^b else 0.7*b^a;
end boolCheck_OK1;
如果函数 inRegionCheck 由 annotation(GenerateEvents=true);
注释,则在 SimulationX 中工作(使用受保护的布尔变量 isInReg)。在 Dymola 中,您需要设置 annotation(Inline=true,GenerateEvents=true);
才能使其正常工作。
下面的Modelica模型检查和模拟。
model boolCheck_OK1
Real a = sin(time);
Real b = cos(time);
Real c;
//protected
// Boolean isInReg = inRegionCheck(a, b);
equation
c = if inRegionCheck(a, b) then 1.3*a^b else 0.7*b^a;
end boolCheck_OK1;
RegionCheck()中的函数returns一个布尔值,这里是简化版:
function inRegionCheck
input Real a;
input Real b;
output Boolean c;
algorithm
c := a>b;
end inRegionCheck;
在实际代码中,该函数的输入较多,名称较长,有几行长,并且多次使用相同的检查,因此为了可读性,我想引入一个中间变量,如注释中的protected部分,但这会导致错误 "Non-real equation in continuous time are not legal".
对优雅的解决方法有什么建议吗?
函数调用在 isInReg
的等式中引入了 noEvent
。
这是 Dymola 2019 FD01 在使用布尔值时报告的内容:
Non-real equation in continuous time are not legal:
isInReg = noEvent(a > b);
因此,您的等式简化为
isInReg = noEvent(a > b)
这是不允许的,因为布尔值只能根据事件发生变化。 您必须摆脱函数调用,从而摆脱 noEvent。
也许有更好的解决方案,但您可以尝试在块而不是函数中定义检查。至少对于您的最小示例,它工作得很好。
那么您的代码可能如下所示:
model boolCheck_OK1
Real a = sin(time);
Real b = cos(time);
Real c;
protected
InRegionCheck check(a=a, b=b);
Boolean isInReg=check.c;
equation
c = if isInReg then 1.3*a^b else 0.7*b^a;
end boolCheck_OK1;
block InRegionCheck
input Real a;
input Real b;
output Boolean c;
equation
c = a>b;
end InRegionCheck;
基于没有函数可以转换为布尔值而只有一个块的事实,我建议 marco 的答案是可行的方法。
通过变通方法,您仍然可以在函数内执行此操作,但不能使用 Boolean
类型。而是使用 Real
并在 if 子句中比较它是否大于零。为了显示布尔值的切换行为,这很好用。如果您依赖函数并且不经常使用布尔值,这可能是一个选项。
model boolCheck_OK1
Real a = sin(time);
Real b = cos(time);
Real c;
function inRegionCheck
input Real a;
input Real b;
output Real c;
algorithm
c := if a>b then 1 else 0;
end inRegionCheck;
protected
Real isInReg = inRegionCheck(a, b);
equation
c = if inRegionCheck(a, b)>Modelica.Constants.eps then 1.3*a^b else 0.7*b^a;
end boolCheck_OK1;
如果函数 inRegionCheck 由 annotation(GenerateEvents=true);
注释,则在 SimulationX 中工作(使用受保护的布尔变量 isInReg)。在 Dymola 中,您需要设置 annotation(Inline=true,GenerateEvents=true);
才能使其正常工作。