基于FMPy实现无迹卡尔曼滤波前向算子的变量设置问题求助
问题分析与解决方案
报错原因
- 变量未被标记为可设置:Modelica模型编译为FMU时,默认仅暴露部分变量为可设置状态。若你的
state_keys或param_keys对应变量在FMU中被标记为settable=false(比如Modelica代码中未添加可设置注解、变量为protected类型,或导出FMU时未勾选对应选项),调用simulate_fmu时会报错无法设置。 - 变量名不匹配:Modelica源码中的变量名在编译为FMU后可能被修改(比如添加模型路径前缀,如
MyModel.x而非x),若state_keys使用的是源码中的原始名称,会因无法匹配FMU实际导出的变量名导致设置失败。 - 初始化约束冲突:若待设置的变量之间存在模型内部的代数约束或初始化方程,强行设置这些变量会破坏模型的初始化一致性,FMU会拒绝执行设置操作。
解决方法
1. 验证并修正变量名与可设置性
使用FMPy的工具导出FMU的完整变量列表,确认哪些变量支持设置:
from fmpy import read_model_description model_description = read_model_description(FMU_PATH) # 筛选可设置的连续/离散状态与参数 for var in model_description.modelVariables: if var.settable and var.variability in ['continuous', 'discrete', 'parameter']: print(f"可设置变量: {var.name} (类型: {var.variability})")
将输出的变量名替换你的state_keys和param_keys,确保完全匹配FMU导出的名称。
2. 调整Modelica模型与FMU导出设置
- 在Modelica源码中,为需要设置的变量添加可设置注解:
model MyModel Real x(start=0) annotation(Dialog(settable=true)); // 标记为可设置 parameter Real k=1 annotation(Dialog(settable=true)); equation der(x) = -k*x; end MyModel;
- 导出FMU时,在编译工具(如OpenModelica、Dymola)中勾选"导出可设置状态变量"或类似选项,确保目标变量被包含在可设置列表中。
3. 处理初始化约束冲突
避免直接设置存在约束依赖的变量,仅设置模型中的独立状态变量,让FMU自动计算依赖变量。若必须设置相关变量,需在Modelica模型中调整初始化策略(比如移除冲突的初始化方程,或使用fixed=true指定固定初始值)。
4. 使用FMPy低级API手动控制仿真流程
若simulate_fmu的封装层限制了变量设置的灵活性,可使用FMPy的低级API直接操作FMU实例,更精确地控制变量设置与仿真:
from fmpy import instantiate_fmu, free_fmu, setup_experiment, enter_initialization_mode, exit_initialization_mode, do_step def forward_operator_low_level(x, p, tstart, tend, h, state_keys, param_keys, tol=1e-8): # 实例化ModelExchange模式的FMU fmu = instantiate_fmu(FMU_PATH, fmi_type='ModelExchange') # 设置参数 for key, val in zip(param_keys, p): var_idx = fmu.variableNames[key] fmu.setReal([var_idx], [val]) # 设置状态变量 for key, val in zip(state_keys, x): var_idx = fmu.variableNames[key] fmu.setReal([var_idx], [val]) # 配置实验与初始化 setup_experiment(fmu, start_time=tstart, stop_time=tend) enter_initialization_mode(fmu) exit_initialization_mode(fmu) # 执行仿真并记录结果 current_time = tstart results = {'time': []} for key in state_keys: results[key] = [] while current_time < tend: do_step(fmu, current_time=current_time, step_size=h) current_time += h results['time'].append(current_time) # 读取并存储状态 for key in state_keys: val = fmu.getReal([fmu.variableNames[key]])[0] results[key].append(val) # 释放FMU资源 free_fmu(fmu) return results
内容的提问来源于stack exchange,提问作者Philipp Weder
相关产品推荐
相关产品推荐

