# 机械元件事件覆盖与 Amesim 对照 本次核查基于当前平台源码、八路工程的实际生成代码、本机 Amesim 2404 子模型源码及随安装提供的帮助。没有修改机械内核,也没有重新运行 Amesim;数值验收证据引用上一轮修复后的回归日志。 ## 1. UD00 修复的影响范围 生产代码改动仅在 `native/components/modules/signal.c`。MASS、接触力公式、机械事件定位及求解器重启代码没有修改。已有机械事件仍然生效,不需要因为这次信号修复而重新注册。 若机械系统由 UD00 驱动,修正信号边界的取值会影响驱动力、后续轨迹和碰撞时刻;积分步分布也可能变化。因此“机械事件机制没有改动”不代表耦合系统的每一个数值结果都保持不变。纯机械模型若没有使用 UD00,则没有这条直接数值调用依赖。 ## 2. 逐类比较 | 元件或模式 | 当前平台 | Amesim 2404 本机证据 | 判断 | | --- | --- | --- | --- | | MECMAS21 理想限位,`stoptype=1` | 注册 `NativeStop`;在接受步内用密集插值和二分定位上下界;命中后位置置于界面,速度置零,再重启积分 | `MECMAS21.c` 调用 `endst2_`;帮助说明其碰撞处理为位置等于限位、速度为零,并维护状态标记 | 撞击事件已具备,无需重复添加;应核验脱离限位、初始就在限位及同时事件 | | MECMAS21 恢复碰撞,`stoptype=3` | 注册相同的限位定位;入射速度超过阈值时按恢复系数反向,否则置零 | 调用 `endstrc_`;帮助说明恢复系数及防止无限反弹的低速阈值 | 核心撞击事件已具备;保留并补边界组合验收 | | MECMAS21 弹性限位,`stoptype=2` | 计算上下限穿透及弹簧阻尼力,未向 `NativeStop` 或其他通用事件表注册接触/脱离 | 允许负力时调用 `endst1b_`,否则调用 `mecEndStop_` 且 `handle_disc=1`;帮助说明维护接触状态 | 建议补充上下界接触/脱离事件,非负力模式还应处理原始接触力的截断边界 | | LSTP00A 弹性接触 | 用间隙计算非负穿透,再调用 `native_contact`;没有接触状态事件注册 | 与弹性限位复用上述接触工具;`mecEndStop_` 明确启用不连续处理 | 当前八路模型应优先补充这一项 | | 静摩擦、库仑摩擦、Karnopp/Stribeck 模式 | 已有 `NativeFriction`、保存的离散模式、停滑与起滑定位;密集插值定位速度阈值和净驱动力超过静摩擦阈值的时刻 | `MECMAS21.c` 调用摩擦工具;`linert1c` 帮助说明低速区、起滑阈值及保存的模式标记 | 已有基础,不是缺失整套事件;需核验换向、阈值相等、与限位/信号同时触发 | | 无限位 MASS,`stoptype=4` | 不注册限位;若启用干摩擦仍有摩擦事件 | 同样绕过限位工具,保留所选摩擦模型 | 无需人为添加上下限位事件 | | 普通双向线性弹簧、黏性阻尼 | 当前公开机械目录主要提供 LSTP00A 接触件;不能把它等同于普通双向弹簧阻尼 | Amesim `SD0000.c` 直接计算连续的弹簧、阻尼力及导数 | 将来新增这类光滑模型通常不需要事件;出现间隙、单向作用、饱和或摩擦切换时再添加 | 平台依据: - [机械力公式](../../native/components/modules/mechanics.c):`native_contact`、`native_stop_motion`。 - [机械事件定位与状态更新](../../native/runtime/common.c):`locate`、`locate_breakaway`、`native_accept`。 - [生成器的接触方程、摩擦与限位注册](../../app/simulation/native_codegen/extended.py):接触力约在 559 行,MASS 弹性力约在 571 行,限位注册约在 625 行。 - [紧凑生成路径](../../app/simulation/native_codegen/compiler.py):支持的限位模式也生成 `NativeStop`;其他模式由扩展生成路径处理。 Amesim 依据: - [MECMAS21.c](F:/AMESim2404/Amesim/libmec/submodels/MECMAS21.c:547):理想、弹性、恢复碰撞和摩擦模式的实际调用分支。 - [LSTP00A.c](F:/AMESim2404/Amesim/libmec/submodels/LSTP00A.c:294):接触工具调用及 `handle_disc=1`。 - [SD0000.c](F:/AMESim2404/Amesim/libmec/submodels/SD0000.c:267):普通弹簧阻尼连续方程。 - 本机 [amehelp.qch](F:/AMESim2404/Amesim/doc/amehelp.qch) 内的 `libmec/doc/html/utils/endst1b.html`、`mecEndStop.html`、`endst2.html`、`endstrc.html`、`linert1c.html`。这些帮助页通过只读查询 Qt 帮助数据库取得。 本机安装未提供上述接触工具的完整内部源代码。因此可以确认 Amesim 的接触状态管理和不连续处理接口,但不据此声称已完全复原其全部根函数、内部容差或同一时刻的执行顺序。 ## 3. 当前八路工程的优先级 从 `tests/data/test-mql-8-corrected.json` 实际生成得到: - 共 10 个 MECMAS21:9 个无限位,1 个理想限位;理想限位元件为 `amesim_mecmas21_10`,范围 `[0, 0.37] m`。 - 共 8 个 LSTP00A,均为数值刚度、允许负接触力;`kcont=1e11 N/m`、`rcont=1e11 N·s/m`、`Pdis≈1e-7 m`。 - 生成头文件为 `NSTATES=132`、`NSTOPS=1`、`NFRICTIONS=0`。这 1 组 `NativeStop` 包含上下两个位置界面,不代表只有一个事件时刻。 - `model_next_break` 只汇总信号时间事件,没有注册这 8 个接触件的间隙事件。接触力仍被计算,只是没有单独定位接触/脱离时刻。 建议优先顺序: 1. **先补 LSTP00A 的接触/脱离定位。** 它直接覆盖当前八路模型的 8 个接触件。 2. **复用同一机制覆盖 MASS 弹性限位。** 当前八路工程没有启用该模式,但这是平台组件能力中明显未显式覆盖的事件。 3. **完善已有理想/恢复限位和摩擦的组合边界。** 当前理想限位通过 `native_stop_motion` 的条件方程处理保持与离开,没有单独注册“约束反力消失/自由净驱动力反向”的根函数;应核验连续驱动力下的离开时刻,再补充需要的释放事件。 缺少接触事件不等于当前接触力公式错误。自适应积分可以通过缩小步长处理部分分段变化,已有温和工况也能通过对照。显式事件的目的,是更稳定地确定作用阶段、接触时刻及峰值附近的积分历史。此次核查不能证明之前八路模型的全部力峰差异均由这一缺口导致。 ## 4. 应怎样添加 这类事件由状态决定,不能像 UD00 那样只向 `model_next_break(t,end)` 添加预定时间。应扩展状态事件接口,允许组件提供事件面、穿越方向、有效模式及事件后的操作。 - **接触边界:** LSTP00A 使用带符号间隙 `gap = gap0 + x2 - x1` 的 `gap=0`;MASS 弹性限位使用 `x-xmin=0`、`x-xmax=0`。不要用已截成非负的 penetration 作为唯一找根量,否则脱离区间整段为零,失去跨越方向。 - **非负接触力边界:** 仅在 `discContactOption=2` 且处于接触区时,处理未截断力 `Fraw=0` 的分支切换。允许负力的模式没有这个截断开关,不应因力过零就重启。 - **事件动作不同:** 弹性接触只重新确认分段并重启积分,位置和速度保持连续;理想碰撞、恢复碰撞才按其模型重置状态。不能把弹性接触事件直接当成硬碰撞。 - **不需要的事件:** `Pdis` 是指数过渡尺度,不是“穿透达到它就突然切换”的阈值;也不应在 `3*Pdis` 处造事件。数值刚度/几何刚度是初始化参数模式,若运行中不切换,也不产生事件。 - **防止重复触发:** 初始恰好接触、贴边不动、离开后重新接触、同一时刻多个接触和信号跳变都需明确阶段与方向,并保证试探求值不提交离散模式。 最低验收应覆盖:单 MASS 上下碰撞及释放、单弹性限位、双质量块 LSTP00A 接触/脱离、允许/禁止负力两种模式、非零/零阻尼过渡尺度,并对 BDF/RK45、不同最大步长比较事件时刻和接触峰值。与 Amesim 对照时还需区分事件前后值。 ## 5. 已有验证能说明什么 上一轮修复后的[完整回归日志](../../test/ud00-boundaries-20260917/regression-tests.log)中,恢复碰撞双求解器测试、LSTP00A 接触测试、MASS 摩擦保持以及 `test_amesim_stick_slip_endstops_and_joint_circuits` 均通过。 最后一项使用独立 Amesim 2404 运行生成的参考数据,覆盖理想限位、弹性限位、摩擦与联合机械等场景;每个参考场景检查 40 个选定时刻,测试设置最大步长 0.002 s。它支持“相关常规数值行为仍可用”,不足以证明当前八路模型的高刚度接触全过程、所有边界组合都与 Amesim 严格一致。 ## 6. 补充接触/脱离事件的求解时间成本 ### 结论及适用范围 事件检查、定位和处理会增加计算工作,但总求解时间不一定增加。若它减少了跨接触边界的拒步、非线性迭代和反复缩步,这些节省可能抵消部分甚至全部开销。当前尚未实现接触事件,不能给出已测得的变慢百分比。 以下分析针对前文建议的“状态事件定位后重启积分”实现。单纯记录零点与切换接触阶段不是同一件事,也不应假设所有事件定位都必然要求相同的重启方式。 ### 成本来自哪里 | 环节 | 当前代码依据及新增成本 | 判断 | | --- | --- | --- | | 每个接受步检查接触状态 | `native_accept` 已经检查硬限位/摩擦;新增 LSTP00A 间隙可直接由两个位置状态及常数计算 | 对 8 个接触件,轻量状态判断预计成本较低;这是算法量级判断,不是计时结果 | | 定位实际跨越时刻 | 现有 `locate` 固定执行 60 次二分,每次调用密集插值;BDF 使用 `CVodeGetDky`,RK45 计算状态插值多项式 | 纯间隙根函数不需要重算整个气动网络;定位次数和精度决定成本 | | 截断并重启积分 | `native_accept` 可把已接受步截回事件;BDF 调用 `CVodeReInit`,RK45 重新计算导数和初始步长 | 会放弃事件之后那部分试算工作,并产生重新起步的工作;BDF 的历史重建尤其值得关注 | | 雅可比及线性求解 | BDF 原生路径使用差分雅可比和稠密线性求解器;新起步需要相应初始化与后续数值建立工作 | 成本作用于整个耦合系统,而非只作用于触发事件的那一个弹簧 | | 保存事件点及输出重放 | 若沿用现有状态事件存储流程,每个新增事件时刻会保存状态,输出阶段再次调用 `model_eval` | 通常少量事件时不突出;大量事件会增加结果体积与后处理时间,需要与纯求解耗时区分 | CVODE 7.4.0 的官方实现中,`CVodeReInit` 将当前阶次重设为 1,并重置步数/历史起点;下一次积分进入初始设置与初始步长计算。它复用已有内存,不是重新编译模型或重新分配整个求解器。见 [CVODE 7.4.0 官方源代码](https://github.com/LLNL/sundials/blob/v7.4.0/src/cvode/cvode.c#L518)。平台对应入口见 [cvode_solver.c](../../native/runtime/cvode_solver.c:357)、[rk45.c](../../native/runtime/rk45.c:57) 和 [common.c](../../native/runtime/common.c:137)。 因此,主要风险是频繁切换造成的整系统重新起步,不是“多写了几个 if 判断”。重启不清除从仿真开始以来的物理运动结果,而是从事件处的状态继续积分。 ### 既有八路运行数据能支持什么判断 早先正确性评估中的 **50 s 循环工况**记录如下,来源为 [native-summary.json](../../test/evaluation-mql8-20260917/full/native-summary.json)。这是 UD00 修复前的历史样本,仅用于估计工作量,不能作为当前代码已经完成的性能 A/B 对比。 | 指标 | 历史样本 | | --- | ---: | | 求解壁钟时间 `solveSeconds` | 12.414 s | | 接受步数 | 19,412 | | 误差测试失败次数 `rejectedSteps` | 1,511 | | 方程求值计数 `nfev` | 84,268 | | 其中雅可比差分求值 | 50,512 | | 雅可比刷新次数 | 1,804 | | 线性求解器 setup 次数,输出字段 `nlu` | 5,903 | | 求解器启动次数,含初次启动 | 20 | | 已注册状态事件的触发批次数 | 9 | 该生成模型包含 132 个状态、1,784 个输出和 27 个雅可比分色组。历史数据中每次雅可比刷新对应 28 次方程求值(27 组扰动加一个基准求值),合计 `1804 × 28 = 50512`。这说明多余的整模型求值、雅可比刷新和重新起步比单纯间隙算术更值得控制;不能把方程调用次数占比直接当作耗时占比。 若接受步数暂按历史样本不变估算,8 个接触件每步检查一次是 `8 × 19412 = 155296` 次简单间隙检查;两个端点均重算则约为其两倍。间隙直接读取位置即可,不需要为这些检查各自求解气动物性、管道流量和全部输出。 另一方面,历史的 `stateTransitions=9` 不包含当时没有注册的 LSTP00A 接触/脱离,所以不能据此预测新增事件数量。8 个接触件可能长期保持接触,也可能反复接触和脱离;真正影响重启成本的是整个仿真期间的切换次数,以及是否出现数值反复触发。 不能将 12.414 s 除以启动次数来推算单次事件成本,也不能把平台求解时间与报告中的 Amesim 完整进程时间直接比较。 ### 建议采用的成本控制措施 1. **专门生成轻量事件函数。** 直接读取位置/速度状态,批量计算间隙和需要的局部接触力;避免为了事件检查调用完整 `model_eval`。在不需要新增物理动态量时,不人为增加连续状态维度。 2. **先筛查,后定位。** 只对可能跨界的区间执行找根;同时覆盖区间内转向等情况,不能为了省时漏掉端点同号但中间跨界的情形。定位达到所需精度或浮点区间不再可分后停止,不必机械重复满 60 次。 3. **仅在阶段实际切换时处理。** 保持接触期间不反复重启;明确初始贴边、穿越方向和离开后的再次触发规则。不能以放大物理间隙、移动事件时间或粗暴忽略真实小振荡来换速度。 4. **同一时刻的多个事件批量提交、一次重启。** 包括多个接触件,以及与信号边界重合的情况;不得为了减少启动次数把有真实先后关系的事件强行合并。 5. **只注册启用模式所需的边界。** 当前八路的接触件均允许负力,不额外注册非负力截断事件;也不在 `Pdis` 或 `3*Pdis` 处造事件。 按上述实现,接触/脱离次数较少时,额外成本预期可控;频繁真实碰撞或边界数值反复触发时,成本可能明显增加。事件处理不会消除模型本身的高刚度,也不能保证 RK45 因此适合所有高刚度工况。 ### 如何验证增量成本 完成实现后,在同一份 JSON、求解器、容差、最大步长和输出设置下,对修改前后分别重复运行,使用已构建的可执行文件,比较中位数并记录波动。分别记录纯求解时间、进程总时间、事件检查/定位次数、实际切换数、启动次数、接受步/拒步、`nfev`、`njev` 和线性 setup 次数。 平台 `solveSeconds` 不包含后续全部输出重放和 JSON 写出,所以事件点增多的输出成本还应检查总进程时间。现有 `nfev` 也不统计纯密集插值调用,新增定位计数/耗时才能解释这部分成本。 除当前八路模型外,至少检查长期不接触、持续接触、单次接触/脱离及反复碰撞四种情况;在事件时刻与接触力精度得到验证的前提下评估速度。本轮仅完成成本评估,没有修改机械事件实现或进行新增事件的性能实测。