15 KiB
System XML v3 协议
文档版本:1.1.1;核对日期:2026-09-13;代码基线:b6c22a5。此版本标注文档修订,不改变 XML Schema 3。
System XML v3 是 SystemSimulationApp 当前唯一的 XML 求解输入格式。它只描述可执行模型,不再承担 ReactFlow 画布存档职责。
机器可读结构见 schemas/system-simulation-v3.xsd。当前校验、解析、编译和仿真接口固定按 v3 处理,不会根据 schemaVersion 自动切换到 v1 或 v2。
1. 设计边界
v3 遵循一条简单规则:
XML 保存“求解什么”,工程 JSON 保存“怎样编辑和显示”。
因此 XML 保留:
- 仿真起止时间、结果采样间隔、内部最大步长和积分方法;
- 组件实例 ID、后端模型类型、模型版本和完整 SI 参数;
- 每条连接的两个端点。
XML 不保存:
- 组件显示名称、画布坐标、旋转、镜像;
- 图标、端口显示侧和显示顺序;
- 端口的
kind/domain/nominalRole/positiveFlowDirection/variables快照; - 参数表达式、显示单位、科学记数法偏好;
- ReactFlow 的选择状态、撤销历史或仿真结果。
这些信息中,编辑器状态留在工程 JSON;端口物理合同由 Component.type + Endpoint.port 从后端组件注册表恢复。
2. 完整结构示例
下面的例子包含一条信号连接和一条机械连接,展示 v3 的全部结构元素。它通过 XML 语义校验,但不是可求解算例:机械组没有惯性锚点,原生生成会报 mechanical group has no inertia anchor。实际仿真应增加符合方程的质量/惯性连接;不要用结构校验通过代替原生能力验收。
<?xml version="1.0" encoding="UTF-8"?>
<System name="signal-force-demo" schemaVersion="3" unitSystem="SI">
<Simulation
tStart="0"
tStop="1"
sampleStep="0.01"
maxStep="0.001"
method="BDF"/>
<Components>
<Component id="step_1" type="amesim_step0" modelVersion="0.1.0">
<Parameter name="initial" value="0"/>
<Parameter name="final" value="0"/>
<Parameter name="time" value="0.5"/>
</Component>
<Component id="force_1" type="amesim_forc" modelVersion="0.2.0">
<Parameter name="direction" value="1"/>
</Component>
<Component id="zero_1" type="amesim_f000" modelVersion="0.1.0"/>
</Components>
<Connections>
<Connection id="signal-1">
<Endpoint component="step_1" port="out"/>
<Endpoint component="force_1" port="res"/>
</Connection>
<Connection id="mechanical-1">
<Endpoint component="force_1" port="port_2"/>
<Endpoint component="zero_1" port="port_1"/>
</Connection>
</Connections>
</System>
XML 的外形是一棵树,模型本身仍是一张连接图。组件平铺在 Components 中,Connections 再用 (component, port) 地址建立拓扑。
固定骨架为:
System
├─ Simulation
├─ Components
│ └─ Component *
│ └─ Parameter *
└─ Connections
└─ Connection *
├─ Endpoint
└─ Endpoint
顶层顺序固定为 Simulation → Components → Connections。每条 Connection 恰好包含两个 Endpoint。
3. System 根元素
| 属性 | 是否必填 | 规则 |
|---|---|---|
schemaVersion |
是 | 固定为 3 |
unitSystem |
是 | 固定为 SI |
name |
否 | 非空工程名称;省略后解析模型使用 untitled |
schemaVersion="3" 已经表示唯一的介质引用和 AMESim 离散参数编码语义。根元素不接受额外的版本提示字段,也不会据此触发兼容猜测。
4. Simulation
| 属性 | 含义 | 主要校验 |
|---|---|---|
tStart |
仿真开始时刻 | 必须是有限数值 |
tStop |
仿真结束时刻 | 必须有限且大于 tStart |
sampleStep |
结果相邻采样点的时间间隔 | 必须大于 0;不设置固定的采样点数上限 |
maxStep |
自适应积分器单个内部步的上限 | 必须大于 0 |
method |
积分方法 | 当前语义校验及 C 执行仅接受 RK45、BDF |
XSD 将 method 定义为必填的 NonEmptyString,只检查它是否为非空字符串,没有枚举可用求解方法。app/system_xml.py::SUPPORTED_SOLVER_METHODS 在语义层仅接受 RK45、BDF;其他值(例如 RK23、DOP853、Radau、LSODA 或任意未知名称)即使通过 XSD 检查,也会以 SIMULATION_METHOD_UNSUPPORTED 拒绝。原生 runner、Python CLI 和 C 程序同样仅支持 RK45、BDF。因此,通过 XSD 校验不代表该方法可执行。
XML 当前没有 rtol/atol/firstStep 属性;网页和 XML API 由 backends.simulation_config() 设置 rtol=1e-8,绝对误差采用生成的逐状态尺度,见求值与精度规范。
sampleStep 和 maxStep 不是一回事:
sampleStep决定结果曲线多久保存一个点;maxStep限制求解器内部一次最多前进多久;- 自适应求解器可以因为误差、事件或试探状态失败而走得比
maxStep更短。
采样点数量会在创建时间数组前计算。若区间长度不可表示为有限数、点数超过当前
运行时可表示的集合大小,或在当前浮点精度下无法得到包含 tStart/tStop 的严格
递增时间序列,输入会在仿真前被拒绝。采样点不再受固定业务上限约束,但结果内存、
序列化体积和浏览器负载仍会随“采样点数 × 输出变量数”线性增长。
工程 JSON 为兼容现有前端仍把采样字段命名为 simulation.step;导出 v3 时必须映射为 Simulation/@sampleStep。
5. Component 与 Parameter
5.1 Component
| 属性 | 是否必填 | 含义 |
|---|---|---|
id |
是 | 当前系统内唯一的实例 ID;连接通过它引用组件 |
type |
是 | 后端组件注册键,例如 amesim_forc |
modelVersion |
是 | 该 type 的模型合同版本 |
语义校验要求 modelVersion 与当前注册表完全一致。版本不匹配时返回 COMPONENT_MODEL_VERSION_MISMATCH,不会静默套用新模型默认值或自动改写旧参数。
v3 不保存 name/componentType/x/y/rotation/mirrored。其中:
- 显示名称和画布位置只属于工程 JSON;
componentType在当前系统中与后端type重复;- 旋转和镜像只属于画面布局,不再改变求解方程。
5.2 Parameter
平台压力统一采用绝压,默认显示单位为 Pa,可切换为 kPa、MPa 或 bar。这些显示单位只作比例换算,不增加或减去大气压偏移,1 bar = 100000 Pa。工程 JSON v2 中数值和表达式均按 parameterUnits 解释,统一换算为 SI;v1 兼容保留旧数值的 SI 含义。例如输入 2.5 bar 时,XML 的压力参数值为 250000。后端仿真输入与压力结果均使用绝压 Pa。
<Parameter name="direction" value="-1"/>
每个参数只保存稳定参数名和已经换算到 SI 基准单位的数值。v3 要求组件显式列出当前模型注册表中的全部参数:
- 参数名重复会报错;
- 缺少注册参数会报
PARAMETER_REQUIRED_MISSING; - 出现未知参数会报
PARAMETER_UNSUPPORTED; - 超范围或不在枚举集合内会报
PARAMETER_VALUE_INVALID。
前端和后端导出器会先用注册默认值补齐工程 JSON 中省略的参数,再写入 XML。XML 解析器本身不替缺失参数猜默认值。
网页、HTTP 和 CLI 的 JSON 输入均在适配层计算受限数学表达式并按格式版本换算到 SI。v2 的 p0: 2.5、p0: "2.5"、p0: "=2.5" 配合 bar 均为 250000 Pa;v1 数字仍为旧 SI 存档含义,不可直接更改格式版本。组件旧版本在 JSON 输入层警告后采用当前模型生成 XML,XML 本身继续严格检查版本及有限 SI 数字。完整规则见接口规范。
5.3 AMESim 介质引用
介质仍用普通参数表达,不增加额外 XML 层级:
gi=0:内置理想空气;- 对普通气动组件,
gi=1..99引用同一 XML 中显式介质定义组件的索引; - 对介质定义组件自身,
gi=1..99表示它所定义的索引; - 介质定义的
gi必须唯一; - 一个连通气动网络只能使用同一
gi; property_model也是普通必填参数,由对应介质模型注册表解释。
6. 端口与连接
6.1 为什么 v3 没有 Port 元素
端口不是组件实例的自由数据,而是组件模型合同的一部分。后端根据:
Component.type + Endpoint.port
从注册表恢复:
kind:物理或信号;domain:气动、机械或信号;nominalRole:输入、输出或物理名义角色;positiveFlowDirection:物理流变量统一以进入组件为正;- 端口变量、单位和
equal/sumToZero/streamMix/directed连接规则。
XML 不能通过写一个新端口名来扩展组件,也不能通过修改字符串把气动口变成机械口。
6.2 Connection
Connection/@id 可省略。省略时解析器按文档顺序生成 connection_1、connection_2 等内部 ID;显式 ID 和生成 ID 都必须唯一。
连接本身不再保存 kind 或 domain。语义层解析两个端点的注册端口后检查:
- 组件和端口存在;
- 两端同为物理端口或同为信号端口;
- 两端
domain和完整变量合同一致; - 信号连接恰好连接一个
output和一个input; - 固定气动接口的变量供需互补,节点参考温度/压力来源没有闭合引用环;详见 气动端口变量供需合同;
- XML 与后端网络允许一个信号输出驱动多个输入,但每个输入只能有一个驱动;当前网页模型检查仍要求每个显示端口恰好一条边,不能据此承诺网页也已支持扇出;
- 同一物理端口只使用一次;分支必须使用显式 Tee/节点组件;
- 不允许自连接或重复端点对。
6.3 两个 Endpoint 的顺序
物理连接的两个端点无序,交换顺序不改变方程或实际流向。
信号连接也不写 role="source" 或 role="target"。发送方和接收方由注册端口的 output/input 合同确定,而不是由 XML 中的先后顺序决定。导出器可以为了便于阅读把输出端写在前面,但求解器不能依赖这一顺序。
7. AmesimForc.direction
amesim_forc 从模型版本 0.2.0 开始使用显式物理参数:
<Parameter name="direction" value="1"/>
它只允许:
+1:默认方向,方程为port_2.f + inputForce = 0;-1:反向,方程为port_2.f - inputForce = 0。
组件的图标旋转和镜像不会改变该参数,也不会改变求解结果。用户要反转施力方向时必须修改 direction,而不是旋转图标。
7.1 MECMAS21 离散选项编码
amesim_mecmas21 只使用 AMESim 原生的 1/2 编码。以两个布尔选项为例:
| 参数 | 1 |
2 |
|---|---|---|
useFriction |
不启用摩擦 | 启用摩擦 |
strib |
不使用 Stribeck 效应 | 使用 Stribeck 效应 |
工程 JSON v1/v2 和 System XML v3 都直接保存上述值。后端不会把 0/1 自动换算成
1/2,也不会根据缺失的兼容标记猜测工程含义;不在目录选项集合内的值会被拒绝。
8. 工程 JSON 与 System XML 的分工
| 信息 | 工程 JSON | System XML v3 |
|---|---|---|
| 组件实例 ID、模型类型 | 保存 | 保存 |
| 模型版本 | 每个节点显式保存并与目录核对 | 每个组件显式保存 |
| 数值参数 | v2 数值和表达式均按所选单位;v1 数字兼容 SI | 保存完整 SI 数值 |
| 组件显示名、坐标、旋转、镜像 | 保存 | 不保存 |
端口快照与 side |
保存供编辑器使用;目录 order 不保证原样留在快照中 |
不保存 |
ReactFlow source/target/handle |
保存 | 转成两个 Endpoint |
| 端口物理合同 | 目录快照用于前端检查 | 不重复保存,由注册表恢复 |
| 参数表达式、显示单位 | 保存 | 不保存 |
| 仿真结果 | 不作为模型输入 | 不保存 |
因此 /api/system-xml/parse 返回的是规范化执行模型,不是可无损恢复原画布的 ReactFlow 工程文件。需要继续编辑时,应保存和打开工程 JSON;需要校验、交换或求解时,使用 System XML v3。
9. 校验与 API
校验固定分三层:
| 层级 | 负责内容 |
|---|---|
| XML | 5 MiB 大小限制、语法、安全解析、禁止 DTD/实体和网络访问 |
| XSD | 元素顺序、必填属性、数量、基础数值类型、非空字符串(含 method)、schemaVersion=3、unitSystem=SI |
| semantic | 支持的求解方法、仿真设置合法性、模型及版本、完整参数、端点引用、注册端口兼容性、介质引用和拓扑占用 |
当前相关接口都直接接收 Content-Type: application/xml 的原始 v3 XML:
POST /api/system-xml/validate:返回三层校验报告;POST /api/system-xml/parse:返回规范化执行模型;POST /api/system-xml/compile-model:返回编译后的网络和仿真设置;POST /api/system-xml/simulate:同步运行并返回完整结果;POST /api/system-xml/simulate-stream:通过 NDJSON 返回心跳、进度和最终结果。
POST /api/reactflow/system-xml 可将工程 JSON 导出为 v3;当前前端也能在浏览器中直接生成同一结构。
通过 XML/XSD/语义校验只说明输入合同正确。compile-model 构造的是 Python 网络和接口信息,不编译 C 可执行文件;仿真时还要通过具体原生生成路径的状态/惯性来源、必接端口、方程及输出映射检查。紧凑路径不支持的部分拓扑会转入扩展路径,不应把紧凑路径的储气直连限制写成全系统统一禁令。信号源可使用无物理状态的内部占位状态,不是所有模型都必须有动态储能组件。
前端检查、XML 语义检查和原生能力检查相互独立。XML 对一般未连接活动端口报告警告;缺少固定参考来源等情况仍可报错。原生生成按模型的必接要求检查,例如 PNVO 信号口有 opening0 的专用缺省处理;网页仍会拦截未连接显示端口。
10. 旧版本处理边界
当前 API 不读取或自动转换 System XML v1/v2,也不会为不匹配的
Component/@modelVersion 选择旧模型实现。旧输入会在 XSD 或语义层被明确拒绝。
本阶段不定义转换步骤、迁移注册表或兼容承诺。仓库不再保存旧版 XSD、规范或示例; 需要进入当前系统的模型必须由来源端重新导出为 v3,不能只修改版本号。
11. 事实来源
- XSD:
schemas/system-simulation-v3.xsd - XML 数据类、解析和三层校验:
app/system_xml.py - 后端 JSON→XML 导出及 XML 仿真路由:
app/main.py - 前端 XML 生成:
frontend/src/App.tsx中的buildSystemXml() - 组件和端口事实来源:
app/simulation/registry.py、app/simulation/core/ports.py - 网络最终兼容检查:
app/simulation/systems/network.py
12. 修订记录
- 2026-09-13 / 1.1.1:纠正“XSD 枚举六种求解方法”的错误描述,明确 XSD 的非空字符串检查与语义层、执行层的 RK45/BDF 支持范围。仅修正文档,未修改 XSD、校验器或求解实现。