如何通过Python fmpy设置Model Exchange类型FMU的全局参数
我来帮你解决这个问题——你之前的误区是把**全局参数(parameter)当成了输入信号(input)**来处理,所以用input参数设置根本不起作用。咱们一步步来修正:
首先明确:FMI里的「参数」和「输入」是完全不同的概念。你看到GUI里用fmi2SetReal设置的l1是模型的全局参数,属于静态配置项,不是动态输入信号,所以不能通过simulate_fmu的input参数传递,得用专门的参数设置方式。
方法1:直接用simulate_fmu的start_values参数(最简单)
simulate_fmu本身就支持通过start_values参数设置模型的初始参数,你不需要自己处理value reference,直接传「变量名-数值」的字典就行,非常直观。修改你的代码如下:
from fmpy.util import plot_result import numpy as np import matplotlib.pyplot as plt from fmpy import * fmu = 'CrankCase_ME2.fmu' dump(fmu) # 定义要设置的参数值 L = 412 hPLug = 215 alphaDrvie = 60 # 直接用start_values传递参数,不用手动找value reference result = simulate_fmu( fmu, start_time=0, stop_time=0.1, relative_tolerance=1e-7, output_interval=1e-5, start_values={ 'l1': L, 'h_plug': hPLug, 'Alpha_drive': alphaDrvie }, # 可以指定输出变量,减少结果数据量 output=['time', 'expseu_.Out2'] ) # 绘图 t = result['time'] y_Force = result['expseu_.Out2'] plt.plot(t, y_Force) plt.show()
这个方法和GUI里调用fmi2SetReal的逻辑一致,simulate_fmu会在初始化FMU时自动帮你调用对应的FMI接口设置参数。
方法2:手动控制FMU实例(更灵活)
如果需要更精细地控制仿真流程(比如在初始化阶段做更多配置),可以手动实例化FMU并调用setReal方法,就像GUI里做的那样:
from fmpy import FMU2Slave, read_model_description import numpy as np import matplotlib.pyplot as plt fmu = 'CrankCase_ME2.fmu' model_description = read_model_description(fmu) # 收集变量的value reference vrs = {var.name: var.valueReference for var in model_description.modelVariables} # 定义参数值 L = 412 hPLug = 215 alphaDrvie = 60 # 实例化FMU slave fmu_slave = FMU2Slave( guid=model_description.guid, modelIdentifier=model_description.modelIdentifier, fmuResourceLocation=fmu, instanceName='CrankCaseInstance' ) # 实例化后、初始化前设置参数 fmu_slave.instantiate() # 设置l1 fmu_slave.setReal([vrs['l1']], [L]) # 设置h_plug fmu_slave.setReal([vrs['h_plug']], [hPLug]) # 设置Alpha_drive fmu_slave.setReal([vrs['Alpha_drive']], [alphaDrvie]) # 初始化仿真 fmu_slave.setupExperiment(startTime=0) fmu_slave.enterInitializationMode() fmu_slave.exitInitializationMode() # 运行仿真并收集结果 stop_time = 0.1 print_interval = 1e-5 time = 0.0 result_data = [] while time < stop_time: # 执行仿真步 fmu_slave.doStep(currentCommunicationPoint=time, communicationStepSize=print_interval) time += print_interval # 获取输出值 force = fmu_slave.getReal([vrs['expseu_.Out2']])[0] result_data.append((time, force)) # 转换结果并绘图 result = np.array(result_data, dtype=[('time', np.double), ('expseu_.Out2', np.double)]) plt.plot(result['time'], result['expseu_.Out2']) plt.xlabel('Time') plt.ylabel('Output Force') plt.show() # 清理FMU实例 fmu_slave.terminate() fmu_slave.freeInstance()
为什么之前的input参数没用?
simulate_fmu的input参数是用来定义动态输入信号的——也就是模型里标记为input类型的变量,这类变量可以在仿真运行过程中动态改变值。而你的l1是全局参数(parameter类型),属于模型的静态属性,只能在初始化阶段设置,所以用input传递完全不匹配。
内容的提问来源于stack exchange,提问作者zorRo
相关产品推荐
相关产品推荐

