我正在使用Dymola 2019将我的Modelica模型转换为FMU,然后使用JModelica模拟(我使用的是2018-03-15的JModelica 2.2版)。我的目标是能够模拟一个特定的时期,分析结果,基于这些结果修改某些参数,然后在使用新参数值的同时从中断处继续进行先前的模拟。
我知道从技术上讲get_fmu_state
和set_fmu_state
可以做到这一点,但是当我尝试实现它时,我并没有设法使其起作用,而且似乎没有是使用这些功能之一的PyFMI目录中的任何示例。我尝试了以下操作:
from pyfmi import load_fmu
model = load_fmu("FMU_generated_by_Dymola.fmu")
res1 = model.simulate(final_time=5.0)
state = model.get_fmu_state()
#Here I would ideally like to use res1 to vary some parameters
model = load_fmu("FMU_generated_by_Dymola.fmu")
model.initialize()
opts = model.simulate_options()
opts['initialize'] = False
model.set_fmu_state(state)
res2 = model.simulate(start_time=5.0,final_time=10.0,options=opts)
上面的代码在不引发任何异常的范围内起作用,尽管它确实在末尾打印以下警告:WARNING:root:The simulation start time (5.000000) and the current time in the model (0.000000) is different. Is the simulation start time correctly set?
。但是更重要的是,当在相对复杂的模型上使用离散的Real变量(通过Modelica的sample()
函数定期更改)尝试进行此操作时,该离散变量的状态在第二次仿真中似乎变得不可变。它的初始值从第一个模拟结束时开始保留,但之后不再更改。因此,先前代码中的res2
与下面代码中的res3
会产生实质上不同的结果:
from pyfmi import load_fmu
model = load_fmu("FMU_generated_by_Dymola.fmu")
res3 = model.simulate(final_time=10.0)
即使将res3
的通信点数量加倍以更准确地反映res2
,仍然存在差异。我迷茫了,为什么在使用set_fmu_state()
后启动仿真时,我的真实离散变量似乎变成常量。有人有什么想法吗?我没有正确使用set_fmu_state()
吗?
值得注意的是,我也曾经研究过this question,但这显然需要使用compile_fmu()
而不是load_fmu()
才能使用"state_initial_equations": True
选项(更不用说它似乎不适用于仿真结果中未包含的变量)。我也看过this question,但这是专门针对Dymola而不是JModelica的,并且依赖于结果文件中存在的所需状态,并非总是如此。
为使我的问题更清楚,我在下面提供了一个示例模型。
model DiscreteContinuous
discrete Real discr "Discrete variable";
Real cont "Continuous variable";
initial equation
discr=0;
cont=0;
equation
when sample(0,2) then
discr=pre(discr)+1;
end when;
der(cont)=1;
end DiscreteContinuous;
之后,Dymola 2019用于将该模型转换为FMU格式,然后使用JModelica运行我所问的Python。首先,来自res3
的以下结果符合预期:
In [1]: res3['discr'][-1]
Out [1]: 6.0
In [2]: res3['discr'][0]
Out [2]: 1.0
但是,来自res2
的以下结果表明,尽管 continuous 变量在使用set_fmu_state()
时的行为符合预期,但 discrete 变量在在第二次仿真中,另一只手不变:
In [3]: res2['discr'][-1]
Out [3]: 3.0
In [4]: res2['discr'][0]
Out [4]: 3.0
In [5]: res2['cont'][-1]
Out [5]: 9.9999999999999929
In [6]: res2['cont'][0]
Out [6]: 4.9999999999999964