JavaProjectRepo/business-css/情景模拟分析结果v3.md
2026-03-19 11:18:15 +08:00

78 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 情景模拟分析结果 v3针对“几个疑问”
对应问题来源:[几个疑问.md](file:///e:/projectJava/JavaProjectRepo/business-css/%E5%87%A0%E4%B8%AA%E7%96%91%E9%97%AE.md)
## 1. 初始化顺序与优先级:静态值、事件值、影响计算如何排布?
### 1.1 三类数据的“角色定义”
- **静态值(设备表/物料表/拓扑 static**:系统的“默认底色/初值基线”。没有事件、没有影响计算时,也必须能给出一个自洽的初始状态。
- **事件值(始发事件/attr_changes**:系统的“外部输入”。既可能是一次性的设定(某一步将某属性改成某值),也可能代表持续的干预(在一段时间内强制维持某值)。
- **影响计算influence 公式)**:系统的“内部传播/派生规则”。它根据来源属性计算得到目标属性,是一个“生成值”的过程。
### 1.2 当前代码实现的顺序(实际行为)
`ProjectServiceImpl.initSimulation` 里,单帧生成顺序是:
1) 注入尺寸Device.size
2) 写入设备静态值
3) 执行设备 influence 计算并写入 state
4) 写入物料静态值DB + topology
5) 执行物料 influence 计算并写入 state
6) **最后对 device/material 应用事件覆盖overrideWithEvents**
这相当于:**Static → Influence → Event(最终覆盖)**。代码位置见:[ProjectServiceImpl.initSimulation](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L614-L767) 与 [overrideWithEvents/readValue](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L998-L1114)。
另外,`readValue()` 在计算 influence 时会“优先读事件、再读静态”,但最终仍会被 `overrideWithEvents()` 再覆盖一次,这意味着事件在该实现里拥有“最终裁决权”。见:[readValue](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L998-L1035)。
### 1.3 推荐的合理顺序(建议落地的“标准管线”)
建议将初始化/每步演进统一成一个明确的“管线”,并对事件类型做区分:
**推荐管线:**
1) **Static 基线**:加载设备/物料静态值(含 DB 补全)作为默认状态。
2) **Event输入/初始条件)**:应用在当前时刻生效的事件(尤其是 t=0 或 step=1 的“初始条件事件”)。
3) **Influence派生计算**:基于当前状态执行影响关系计算,得到派生值。
4) **Event强制覆盖/锁定)**:仅对“强制锁定类事件”再次覆盖(可选,但强烈建议引入),确保“外部强制干预”不会被公式计算反覆盖。
这样做的好处:
- 既能让事件作为“输入”影响传播(步骤 2 发生在计算前),又能让“强制事件”在输出阶段生效(步骤 4
- 能解释并覆盖两类业务直觉:
- “我设了初始浓度,后续按公式变化”(步骤 2 + 3
- “我强制把某槽位液位锁死,不管公式怎么算”(步骤 4
### 1.4 关键补充:时间轴/采样点也属于优先级的一部分
当前 `initSimulation` 的帧生成时间点来自事件时间集合:`collectTimePoints(valueProviders)`,若没有事件时间点会直接返回“无法生成帧”。见:[collectTimePoints](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L1037-L1061) 与 [initSimulation timePoints 为空处理](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L667-L675)。
建议:
- 当没有事件时,允许通过参数指定 `start/end/stepInterval`,生成基础时间网格(否则“纯静态模拟”永远跑不起来)。
- 对于 ramp/linear 事件,当前只把 start/end 加入时间点(中间不采样),但 `readValue` 支持任意 t 的线性插值。若希望输出更“连续”的曲线,必须补齐采样点(例如每 1s/每步都采样)。
## 2. 合理性分析:为什么推荐上述顺序?
### 2.1 从“因果关系”角度
- 静态值是**先验事实**(设备尺寸、物料基础参数),应先进入状态。
- 事件是**外部驱动/输入**,会改变系统边界条件,应在影响传播前进入状态,否则传播用的仍是旧值。
- influence 是**系统内部响应**,应在输入就绪后计算。
- 强制覆盖事件是**高优先级干预**,必须在计算后仍能维持,否则“强制”二字失去意义。
### 2.2 从“可维护性/可解释性”角度
把事件分成两类最关键:
- **Event-Input输入型**:参与计算的输入(初值设定、控制变量变化)。
- **Event-Override强制型**:输出阶段的锁定/强制(故障注入、人工接管)。
如果不区分,只能在“事件最高”与“公式最高”之间二选一,最终会在不同业务场景下反复打补丁。
## 3. SimController 及相关接口分析(并给出建议)
### 3.1 现状SimController 是“半成品/原型”,当前不可用
[SimController.java](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/controller/SimController.java#L1-L43) 体现了一套更清晰的分层意图:`Controller -> Repo 装配 -> Builder -> SimService -> 推理输入`,但存在几处硬性问题:
- 依赖的 `ProjectRepository / EventRepository / InfluenceRepository / InferenceConverter` 在项目代码中找不到定义,无法编译/运行(当前仓库中仅此文件引用这些类型)。
- `SimBuilder` 中对应的 `buildUnits/buildEvents/buildInfluenceNodes` 方法是注释掉的,占位未实现。见:[SimBuilder.java](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/build/SimBuilder.java#L1-L44)。
- `SimService` 当前实现仅是 KV 级别的简化引擎,且采用 **事件先写、后计算覆盖** 的顺序(会导致“事件设定失效”)。见:[SimService.runSimulation](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/SimService.java#L9-L51)。
### 3.2 与当前线上接口的关系
当前“初始化/运行模拟”入口实际在 `ProjectController`/simulation/init、/simulation/run并调用 `ProjectServiceImpl`。例如 `runSimulation`:见 [ProjectController.java:L289-L300](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/controller/ProjectController.java#L289-L300)。
### 3.3 建议:保留 SimController 的分层方向,但必须补齐三件事
1) **补齐依赖与 Builder**:明确 Repo 层要读什么(拓扑、事件、影响关系)并落地成可编译的类/接口;实现 `SimBuilder` 的构建方法或直接复用 `ProjectServiceImpl` 的解析器。
2) **统一优先级管线**:让 `SimService` 采用“Static → Event(Input) → Influence → Event(Override)”(见第 1 章建议),避免出现“事件被公式反覆盖”。
3) **统一对外 API**:建议最终以 `/sim/*` 作为唯一入口。