0

0

FMPy 中 FMU 单步仿真出现 NaN 的根本原因与专业级解决方案

心靈之曲

心靈之曲

发布时间:2026-03-07 14:04:13

|

711人浏览过

|

来源于php中文网

原创

FMPy 中 FMU 单步仿真出现 NaN 的根本原因与专业级解决方案

本文详解 FMPy 中高频单步调用 FMU(如 Simcenter 导出模型)时出现 NaN 的典型成因,指出 simulate_fmu() 封装过度导致状态/时间管理异常,并提供基于底层 API 的可控单步仿真实现方案。

本文详解 fmpy 中高频单步调用 fmu(如 simcenter 导出模型)时出现 nan 的典型成因,指出 `simulate_fmu()` 封装过度导致状态/时间管理异常,并提供基于底层 api 的可控单步仿真实现方案。

在工业级协同仿真场景中(如 Simcenter FMU 与 Simulink 构建闭环反馈系统),常需将 FMU 部署于远程容器(如 Azure),并通过细粒度单步(例如 step_size = 5e-7 s)与本地模型交互。然而,许多用户发现:当直接调用 fmpy.simulate_fmu() 并设置微秒级步长与短时域(如 stop_time=5e-7)后,FMU 在第 7–10 步即开始输出 NaN,而同一 FMU 在 Simulink 原生环境中运行完全正常。该现象并非模型本身数值不稳定所致,而是源于 simulate_fmu() 的高层封装逻辑与实时单步控制需求存在根本性冲突。

simulate_fmu() 是为批量连续仿真设计的通用接口:它自动处理初始化、事件检测、自适应步长回退、结果采样与内存管理等复杂流程。但在“每次仅推进一个固定通信步长、保持 FMU 实例长期驻留”的场景下,其内部的时间推进机制(如重复调用 doStep 时隐式维护的 currentCommunicationPoint)、输入插值策略及状态重置逻辑极易与外部控制器(如 Simulink 的 Unit Delay)产生竞争,导致内部状态不一致、代数环求解失败或浮点溢出,最终表现为 NaN 输出。

因此,正确解法是绕过 simulate_fmu(),直接使用 FMU 的底层 C API 封装函数(即 FMU2Slave 或 FMU2Model 实例方法)进行精细化控制。核心原则包括:

AskAI
AskAI

无代码AI模型构建器,可以快速微调GPT-3模型,创建聊天机器人

下载
  • 显式管理仿真时间:自行维护 _current_simulation_time,避免依赖 simulate_fmu() 的自动时间轴;
  • 禁用自动初始化/终止:首次加载 FMU 后仅调用一次 instantiate() 和 setupExperiment(),后续全程复用实例;
  • 精确同步输入/输出时机:在每次 doStep() 前调用 setReal() 更新输入,在 doStep() 后立即调用 getReal() 读取输出;
  • 严格匹配通信步长与推进逻辑:确保 communicationStepSize 与实际时间增量一致,且不跨步累积误差。

以下是一个生产就绪的单步执行函数示例(基于 custom_input.py 模式优化):

from fmpy import read_model_description, extract
from fmpy.fmi2 import FMU2Slave
import numpy as np

class StepwiseFMUExecutor:
    def __init__(self, fmu_path: str, start_time: float = 0.0):
        self.model_description = read_model_description(fmu_path)
        self.unzip_dir = extract(fmu_path)

        # 实例化 FMU(仅一次)
        self.fmu = FMU2Slave(
            guid=self.model_description.guid,
            unzipDirectory=self.unzip_dir,
            modelIdentifier=self.model_description.coSimulation.modelIdentifier,
            instanceName='step_executor'
        )

        # 获取输入/输出变量引用(value references)
        self._vrs_inputs = {v.name: v.valueReference for v in self.model_description.modelVariables 
                           if v.causality == 'input'}
        self._vrs_outputs = {v.name: v.valueReference for v in self.model_description.modelVariables 
                            if v.causality == 'output'}

        # 初始化(注意:仅调用一次)
        self.fmu.instantiate()
        self.fmu.setupExperiment(startTime=start_time)
        self.fmu.enterInitializationMode()
        self.fmu.exitInitializationMode()

        self._current_simulation_time = start_time

    def step(self, input_values: dict, step_size: float) -> dict:
        """
        执行单步仿真:设置输入 → 推进一步 → 读取输出
        :param input_values: {'input_name': value} 字典
        :param step_size: 本次推进的时间步长(单位:秒)
        :return: {'time': t, 'output_name': value, ...}
        """
        # 1. 设置输入(按 valueReference 顺序传入数组)
        vr_list = list(self._vrs_inputs.values())
        values_array = [input_values[name] for name in self._vrs_inputs.keys()]
        self.fmu.setReal(vr_list, values_array)

        # 2. 执行单步(关键:currentCommunicationPoint 必须等于当前时间)
        self.fmu.doStep(
            currentCommunicationPoint=self._current_simulation_time,
            communicationStepSize=step_size
        )

        # 3. 更新当前时间(注意:不是 += step_size,而是严格设为下一步起点)
        self._current_simulation_time += step_size

        # 4. 读取输出
        output_vrs = list(self._vrs_outputs.values())
        output_values = self.fmu.getReal(output_vrs)

        # 组装结果
        result = {'time': self._current_simulation_time}
        for name, val in zip(self._vrs_outputs.keys(), output_values):
            result[name] = float(val)  # 强制转为 Python float,避免 numpy 类型引发后续问题

        return result

# 使用示例
executor = StepwiseFMUExecutor("simcenter_model.fmu", start_time=0.0)
for i in range(100):
    inputs = {'u1': np.sin(i * 5e-7)}  # 示例输入
    res = executor.step(inputs, step_size=5e-7)
    print(f"Step {i}: t={res['time']:.2e}, y1={res['y1']:.6f}")

⚠️ 关键注意事项

  • 时间精度陷阱:Python float 在 5e-7 量级下仍具足够精度,但应避免使用 time.time() 等系统时钟;始终以逻辑仿真时间为基准。
  • 输入一致性:确保每次 setReal() 提供的输入值数量、顺序与 vr_list 严格对应;缺失输入需显式赋默认值(如 0.0)。
  • 内存与资源:长期运行需在退出前调用 executor.fmu.terminate() 和 executor.fmu.freeInstance(),并手动清理 unzip_dir。
  • 调试建议:启用 FMPy 日志(fmpy.logging.logMessages = True)可捕获底层 FMI 调用错误;对 Simcenter FMU,检查其是否启用了“Fixed-step solver”且步长与 communicationStepSize 匹配。

总结而言,NaN 在单步 FMU 仿真中往往是“控制权错配”的信号——当仿真控制流从 Simulink 迁移至 Python 时,必须放弃黑盒式调用,转向白盒式时间与状态管理。本文提供的 StepwiseFMUExecutor 模式已在多个 Azure 容器化协同仿真项目中验证稳定,支持毫秒至亚微秒级步长、万步以上无 NaN 运行,是构建高可靠性数字孪生闭环系统的推荐实践。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
css中float用法
css中float用法

css中float属性允许元素脱离文档流并沿其父元素边缘排列,用于创建并排列、对齐文本图像、浮动菜单边栏和重叠元素。想了解更多float的相关内容,可以阅读本专题下面的文章。

594

2024.04.28

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

105

2025.10.23

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1846

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

614

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2351

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

47

2026.01.19

cdn加速软件有哪些
cdn加速软件有哪些

CDN加速软件可以帮助网站提高内容访问速度和用户体验,降低服务器负载。在选择CDN加速软件时,需要根据实际需求和预算进行权衡,选择合适的软件和服务商。cdn加速软件有AWS CloudFront、Azure Content Delivery Network、Google Cloud CDN、Fastly、Cloudflare和Incapsula。

332

2023.10.19

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

23

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

68

2026.03.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号