From 71feae9e79bacc9713234874946f16963c8b6fae Mon Sep 17 00:00:00 2001 From: Huamonarch Date: Wed, 13 May 2026 14:32:58 +0800 Subject: [PATCH] docs: add RNG parameterized models design spec Config-driven random number generation with model templates in JSON and signal-to-model binding via DB2 tables[1] field. Supports 9 analog modes, 4 boolean modes including valve_pair timing simulation. --- ...6-05-13-rng-parameterized-models-design.md | 234 ++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-13-rng-parameterized-models-design.md diff --git a/docs/superpowers/specs/2026-05-13-rng-parameterized-models-design.md b/docs/superpowers/specs/2026-05-13-rng-parameterized-models-design.md new file mode 100644 index 0000000..0d5c0e8 --- /dev/null +++ b/docs/superpowers/specs/2026-05-13-rng-parameterized-models-design.md @@ -0,0 +1,234 @@ +# RNG 参数化随机数生成 — 设计规格 + +## 概述 + +将 RNG 从硬编码的信号→数据源映射重构为配置驱动的参数化模型架构,使随机数/仿真数据的生成完全由外部配置控制,无需修改 C++ 代码即可定义新的信号行为。 + +## 核心设计决策 + +- **模型模板与信号绑定分离**:模型模板定义在 `rng_models.json`,每个信号通过 DB2 表 `T_LOV_FDAAITEM` 的 `tables[1]` 字段引用模型名 +- **每个信号独立实例化**:即使 100 个信号用同一个模型模板,各自创建独立实例,状态不共享 +- **基值参数取自 defaultValue**:`TeleItem.defaultValue` 天然作为 `c`(constant)、`b`(linear)、`offset`(sine)、`base`(spike/drift)、`mean`(normal) 的默认值 +- **纯 JSON 参数透传**:模型构造函数直接解析 JSON params key-value,工厂不关心具体参数内容 + +## 模型模式 + +### 模拟量模式 + +| mode | 函数 | 从 defaultValue 取的基值 | 模板 params | +|------|------|------------------------|------------| +| `constant` | y = c | c | — | +| `linear` | y = k·t + b | b | k | +| `sine` | y = A·sin(ω·t + φ) + offset | offset | A, ω, φ | +| `normal` | y = μ + σ·N(0,1) | μ | σ | +| `uniform` | y = random(−Δ, +Δ) + center | center | Δ | +| `spike` | y = base + spike(t) | base | amplitude, probability | +| `drift` | y = base + rate·t | base | drift_rate | +| `csv` | y = csv(t, col) | — | file, column | +| `composite` | y = base(t) + noise(t) | — | base_model, noise_model | + +t 为时间索引,从进程启动起每周期(~20ms)递增。 + +### 布尔量模式 + +| mode | 行为 | 模板 params | +|------|------|------------| +| `bool_random` | 随机 0/1,可配置为 1 的概率 | prob_true (default 0.5) | +| `bool_toggle` | 固定周期 0/1 翻转 | period_ms | +| `bool_csv` | CSV 数据回放(int 列) | file, column | +| `valve_pair` | 跟随另一个信号,加延迟/闪断 | on_delay_ms, off_delay_ms, flash_prob | + +### spike 毛刺行为 + +- 每个周期以 `probability` 概率触发毛刺 +- 触发时 y = base ± amplitude(符号随机) +- 毛刺持续 1 个周期后恢复 + +### drift 漂移行为 + +- y = base + drift_rate × t +- 漂移累加无上限,模拟传感器退化趋势 + +### valve_pair 时序模型 + +不模拟动作信号本身,而是通过模型名引用另一个信号(如 `bool_toggle`)的当前值,模拟传感器对动作的响应延迟。 + +``` +动作信号 A (如 toggle_2s): +t: 0 1 2 3 4 5 6 7 8 9 + 0────1──────────────────────────────0────────── + +到位传感器 B (valve_px_std:toggle_2s): + 0─────────1────────────────────0───1──0──────── + ↑ on_delay=200ms ↑闪断(2%) ↑ off_delay=150ms +``` + +- B 在 A 变为 1 后延迟 `on_delay_ms` 才变为 1 +- B 在 A 变为 0 后延迟 `off_delay_ms` 才变为 0 +- B 在高电平期间有 `flash_prob` 概率出现短暂闪断(单周期归零后自动恢复) + +配对方式:B 的 `tables[1]` = `valve_px_std:toggle_2s`,其中 `toggle_2s` 是 A 的模型名。运行时通过模型名查找动作信号的 IModel 实例。 + +一对多自然支持:同一个动作信号可被多个 valve_pair 传感器跟随,各自维护独立的延迟/闪断状态。 + +## JSON 配置格式 + +文件路径:`/rng_models.json` + +```json +{ + "models": { + "normal_tiny": { "mode": "normal", "params": { "sigma": 0.01 } }, + "normal_med": { "mode": "normal", "params": { "sigma": 0.5 } }, + "linear_slow": { "mode": "linear", "params": { "k": 0.001 } }, + "linear_fast": { "mode": "linear", "params": { "k": 0.05 } }, + "sine_ecc1": { "mode": "sine", "params": { "A": 5.0, "omega": 0.314, "phi": 0 } }, + "sine_ecc2": { "mode": "sine", "params": { "A": 3.0, "omega": 0.628, "phi": 1.57 } }, + "spike_sharp": { "mode": "spike", "params": { "amplitude": 50, "probability": 0.05 } }, + "spike_mild": { "mode": "spike", "params": { "amplitude": 10, "probability": 0.15 } }, + "drift_slow": { "mode": "drift", "params": { "drift_rate": 0.0001 } }, + "drift_fast": { "mode": "drift", "params": { "drift_rate": 0.005 } }, + "toggle_2s": { "mode": "bool_toggle", "params": { "period_ms": 2000 } }, + "toggle_5s": { "mode": "bool_toggle", "params": { "period_ms": 5000 } }, + "toggle_10s": { "mode": "bool_toggle", "params": { "period_ms": 10000 } }, + "valve_px_std": { "mode": "valve_pair", "params": { "on_delay_ms": 200, "off_delay_ms": 150, "flash_prob": 0.02 } }, + "valve_px_fast": { "mode": "valve_pair", "params": { "on_delay_ms": 80, "off_delay_ms": 60, "flash_prob": 0.01 } } + } +} +``` + +## DB2 信号绑定 + +每个信号在 `T_LOV_FDAAITEM` 表中通过 `tables[1]` 字段指定模型引用。 + +### tables[1] 语法 + +| 格式 | 含义 | 示例 | +|------|------|------| +| `model_name` | JSON 中定义的模型 | `normal_tiny` | +| `csv:file_name:col` | CSV 文件回放(内联简写) | `csv:C308速度毛刺仿真.csv:1` | +| `base_model+noise_model` | 组合模型 | `linear_slow+normal_tiny` | +| `pair_model:action_model` | 布尔配对模型(仅 valve_pair) | `valve_px_std:toggle_2s` | +| 空 / `default` | 默认模型 `normal_tiny` | — | + +### 示例数据行 + +| item | defaultValue | tables[1] | 说明 | +|------|-------------|-----------|------| +| BR1_1_V_act | 100.0 | `normal_tiny` | 均值100的正态噪声 | +| BR1_2_V_act | 120.0 | `normal_tiny` | 同上模板,独立实例 | +| BR2_2_I_act | 0.0 | `csv:spbdata:1` | CSV第1列回放 | +| TCM-4-82-BD-1-101 | 80.0 | `sine_ecc1` | 幅值5周期0.314的正弦 | +| TCM-72-150-BD-5-117 | 75.0 | `sine_ecc1` | 同上模板,独立实例 | +| RW_o_Drv_SpdErr | 0.0 | `linear_slow+spike_mild` | 线性爬升叠加毛刺 | +| 3G-DSA-B01-01B | 0 | `toggle_2s` | 2秒周期翻转(动作阀) | +| 3G-PX-B01-01 | 0 | `valve_px_std:toggle_2s` | 跟随动作阀的到位传感器 | + +## 软件架构 + +### 文件结构 + +``` +TestProject/RNG/ +├── model/ +│ ├── IModel.h # 统一接口 +│ ├── ModelRegistry.h/cc # 工厂 + tables[1] 解析 +│ ├── NormalModel.h +│ ├── LinearModel.h +│ ├── SineModel.h +│ ├── UniformModel.h +│ ├── SpikeModel.h +│ ├── DriftModel.h +│ ├── CsvReplayModel.h +│ ├── BoolRandomModel.h +│ ├── BoolToggleModel.h +│ ├── BoolCsvModel.h +│ ├── ValvePairModel.h +│ └── CompositeModel.h +├── json/ # nlohmann_json (已有) +├── Generator.h/cc # 重构:去掉硬编码,走 ModelRegistry +├── RNG_icei.h/cc # 不变 +├── RNG.h/cc # 启动时加载 rng_models.json +├── RandT.h # 保留,底层数学工具 +├── read_csv.hpp # 保留,CsvReplayModel 内部使用 +└── CMakeLists.txt # 新增 model/ 源文件 +``` + +### 关键接口 + +```cpp +// IModel.h — 所有模型的基类 +class IModel { +public: + virtual ~IModel() = default; + virtual float evaluate(size_t t_index); // 模拟量,默认返回0 + virtual bool evaluateBool(size_t t_index); // 布尔量,默认返回false + virtual void linkPeers(ModelRegistry& reg); // 配对信号关联,默认空 + virtual void reset(); // 重置内部状态 +}; + +// ModelRegistry — 单例 +class ModelRegistry { +public: + using Ctor = std::function(const json& params, float defaultVal)>; + + void loadModels(const std::string& jsonPath); // 加载 rng_models.json + IModel* getOrCreate(const std::string& tables1Spec, // 解析并创建实例 + float defaultValue); + + // 按模型名查找所有使用该模型的信号实例(valve_pair 查询动作信号用) + std::vector findByModelName(const std::string& modelName); + + void registerMode(const std::string& mode, Ctor ctor); // 注册新模型类型 +}; +``` + +### 数据流(每周期 TimeNotify) + +``` +TimeNotify(eventNo) + → BinaryTele.ReBuild(eventNo) + → for i in 0..BinaryTele.size(): + item = BinaryTele[i] + spec = item.tables[1] + model = ModelRegistry::getOrCreate(spec, atof(item.defaultValue)) + if item.type[0] == 'b': + item = model->evaluateBool(timeIndex) + else: + item = model->evaluate(timeIndex) (float) + → BinaryTele.GetTeleData() → m_mapfix[eventNo]->push(buff) +``` + +### 启动流程 + +``` +RNG::start() + → con_mag_->dbLogin() + → ModelRegistry::instance().loadModels("rng_models.json") + → RNG_server = new RNGICEI() + → PACE 服务注册 +``` + +## 扩展流程 + +新增一个模型模式(如指数衰减 `exponential`)只需要: + +1. 新建 `model/ExponentialModel.h`,实现 `IModel::evaluate(t)` +2. 在 `ModelRegistry` 构造函数中注册一行:`reg("exponential", ExponentialModel::create)` +3. 在 `rng_models.json` 中添加模板:`"exp_decay": { "mode": "exponential", "params": { "lambda": 0.01 } }` + +JSON params 以通用 map 形式透传给模型构造函数,工厂不需要理解新参数。 + +## 存量兼容 + +- `RandT.h` 保留,底层随机数工具被各 Model 内部使用 +- `read_csv.hpp` 保留,`CsvReplayModel` 内部使用 +- `Generator.cc` 中所有硬编码的 if-else 信号映射删除 +- `BinaryTele` + `CMemFix` 共享内存写入逻辑保持不变 +- ICE 接口 `RNGICEI` 不变 +- DB2 中已有的 `tables[1]` 为空的行走默认模型 `normal_tiny`,保持向后兼容 + +## 约束 + +- `tables[1]` 字段长度 40 字符(`name_type` = `char[40]`),模型名 + 引用语法需控制在此范围内 +- 时间索引 `t_index` 从进程启动起单调递增,每周期(~20ms)加 1,不持久化