3. 联合仿真架构与接口原理

联合仿真的本质,是让两个或多个各自独立求解的仿真器在时间推进过程中交换数据、协调步长。控制系统(如 Simulink 中的控制器)与被控物理对象(如 AMESim、Dymola、Adams 中的机械/液压/热力模型)往往由不同工具建模,它们各自有独立的求解器和积分算法。要让它们"协同工作",就必须在架构层面确定:谁主导时间推进、数据以什么形式交换、交换发生在什么时刻、接口如何保证一致性。本节围绕四类主流接口机制展开:FMI/FMU、S-Function、共享内存与 Socket 通信。

一、FMI/FMU:跨工具联合仿真的标准接口

FMI(Functional Mock-up Interface)是目前应用最广的跨工具联合仿真标准,它定义了一套与工具无关的 C 语言接口规范。遵循该规范导出的模型包称为 FMU(Functional Mock-up Unit),本质上是一个压缩包,内部包含模型描述文件 modelDescription.xml、编译好的动态库(Windows 下为 .dll,Linux 下为 .so)以及可选的资源文件。任何支持 FMI 的工具都能加载 FMU,无需知道原建模工具是什么。

FMI 有两个关键版本分支,理解它们的区别对架构选型至关重要:

  • FMI 1.0 / 2.0 的模型交换(Model Exchange, ME):FMU 只提供方程右端项,不包含求解器,由导入方(如 Simulink)用自己的求解器统一积分。适合模型规模小、需要与主模型紧密耦合的场景。
  • FMI 2.0 / 3.0 的联合仿真(Co-Simulation, CS):FMU 自带求解器,作为独立仿真器运行,通过接口与主仿真器交换输入输出。适合模型规模大、自带专用求解器的场景(如液压、多体动力学)。

在 CS 模式下,接口交互遵循固定节奏:主仿真器在每个通信步长点把输入量写入 FMU,调用 fmi2DoStep 让 FMU 推进一个步长,再从 FMU 读回输出量。通信步长(Communication Step Size)是核心参数——它不必等于 FMU 内部求解步长,FMU 内部可以自行细分。例如主仿真器通信步长设为 1 ms,而 FMU 内部以 0.1 ms 积分,则每次 fmi2DoStep 内部推进 10 个子步。通信步长过大,会引入接口延迟,导致耦合系统不稳定或精度下降;过小则通信开销剧增。工程上常取被控对象最快时间常数的 1/10~1/20 作为初始值,再通过仿真对比调整。

二、S-Function:Simulink 原生的模型集成机制

S-Function(System Function)是 Simulink 提供的用户自定义模块接口,允许用 C/C++、MATLAB 或 Fortran 编写自定义模块。在联合仿真中,它常被用作"胶水层":把外部求解器或 FMU 包装成一个 Simulink 模块,使其融入 Simulink 的求解循环。

一个 S-Function 需要实现若干回调函数,其中与联合仿真最相关的是:mdlInitializeSizes(声明输入输出端口数量与维度)、mdlInitializeSampleTimes(声明采样时间)、mdlOutputs(计算输出)、mdlUpdate(更新离散状态)。当 S-Function 封装外部求解器时,通常在 mdlOutputs 中把 Simulink 的输入传给外部模型、推进外部求解器、再读回输出。若外部模型是连续系统,还需在 mdlDerivatives 中返回状态导数,让 Simulink 求解器统一积分。

S-Function 的优势是深度集成、可访问 Simulink 全部求解能力;代价是需要编写和维护 C 代码,且外部模型的求解器与 Simulink 求解器之间可能存在代数环,需要引入单位延迟或代数约束处理。实际项目中,若外部模型已导出为 FMU,更推荐直接用 Simulink 的 FMU Import 模块,而非手写 S-Function。

三、共享内存与 Socket:进程级通信机制

当两个仿真器以独立进程运行时(例如一个 Windows 进程跑 Simulink,另一个 Linux 进程跑 Dymola 导出的可执行模型),就需要进程间通信(IPC)。共享内存和 Socket 是两种典型方案。

共享内存在同一台机器上开辟一块双方都能访问的内存区域,数据交换延迟极低(微秒级),适合高频、大数据量的耦合。其难点在于同步:必须用信号量或互斥锁保证"写方写完、读方再读",否则会读到半更新数据。典型实现是双缓冲:一块写、一块读,交替切换。

Socket 通信基于 TCP/UDP 协议,可跨机器、跨操作系统,灵活性最高,但延迟高于共享内存(局域网通常百微秒到毫秒级)。TCP 保证可靠有序,适合对数据一致性要求高的耦合;UDP 延迟更低但可能丢包,适合对实时性要求高、可容忍少量丢包的场景。Socket 方案需要自行定义应用层协议:数据帧格式、字节序、时间戳、握手与超时重传机制。

下面这张图概括了四类接口机制在联合仿真架构中的位置与数据流向关系。

联合仿真接口机制与数据流 主仿真器 Simulink / 控制器模型 主导时间推进 从仿真器 AMESim / Dymola / Adams 被控物理对象 接口层(四类机制) FMI/FMU · S-Function 共享内存 · Socket 输入写入 → 步进 → 输出读回 u(t) u y y(t) FMI / FMU 标准 C 接口 ME:外部求解器积分 CS:FMU 自带求解器 通信步长决定耦合精度 S-Function Simulink 原生模块 mdlOutputs / mdlUpdate 融入 Simulink 求解循环 注意代数环处理 共享内存 同机进程间通信 延迟微秒级 双缓冲 + 信号量同步 需防半更新数据 Socket 跨机 / 跨系统 TCP 可靠 / UDP 低延迟 自定义帧协议 需握手与超时机制 t₀ t₀+h t₀+2h t₀+3h t 通信步长 h:每个同步点交换一次 u / y h 过大 → 接口延迟、耦合失稳;h 过小 → 通信开销上升 (图中 h 为示意,实际取值需结合被控对象时间常数整定)

四、机制选型与工程判断

四类机制并非互斥,实际项目常组合使用。选型时可参考以下判断逻辑:若两个模型来自不同建模工具、需要标准化复用,优先选 FMI/FMU;若外部模型需要深度嵌入 Simulink 求解循环、且能接受 C 代码维护成本,选 S-Function;若两个仿真器同机运行、数据交换频率高,选共享内存;若跨机器或跨操作系统,选 Socket。

无论采用哪种机制,都需要关注三个共性问题。第一是时间同步:主从仿真器必须对"当前仿真时刻"有一致理解,通常由主仿真器广播时间戳,从仿真器据此推进。第二是数据一致性:交换的输入输出量必须有明确的单位、量纲和符号约定,例如控制器输出为正表示执行器伸出,这一约定必须在两侧模型和接口文档中统一,否则会出现方向相反的隐蔽错误。第三是步长匹配:通信步长、从仿真器内部步长、主仿真器求解步长三者需要协调,一般让通信步长为从仿真器内部步长的整数倍,避免插值误差累积。

调试建议:初次搭建联合仿真时,先把通信步长设得较小(如 0.1 ms),确认数据能正确双向流动、量纲一致后,再逐步放大步长观察结果变化,找到精度与效率的平衡点。若放大步长后出现发散或高频振荡,说明耦合过强或存在代数环,需要引入接口滤波或降低步长。

理解这四类机制的差异,是后续搭建具体联合仿真工程的基础。FMI/FMU 提供标准化封装,S-Function 提供 Simulink 内深度集成,共享内存与 Socket 提供进程级通信能力,它们共同构成了联合仿真架构的接口层。