eis/docs/superpowers/specs/2026-05-13-rng-parameterized-models-design.md
Huamonarch 302aa82e38 docs: add valve_pair jitter/over-delay fault simulation params
delay_jitter_ms for natural timing variation, delay_over_prob/delay_over_ms
for simulating occasional valve timeout faults (e.g. once per day).
2026-05-13 14:47:35 +08:00

11 KiB
Raw Blame History

RNG 参数化随机数生成 — 设计规格

概述

将 RNG 从硬编码的信号→数据源映射重构为配置驱动的参数化模型架构,使随机数/仿真数据的生成完全由外部配置控制,无需修改 C++ 代码即可定义新的信号行为。

核心设计决策

  • 模型模板与信号绑定分离:模型模板定义在 rng_models.json,每个信号通过 DB2 表 T_LOV_FDAAITEMtables[1] 字段引用模型名
  • 每个信号独立实例化:即使 100 个信号用同一个模型模板,各自创建独立实例,状态不共享
  • 基值参数取自 defaultValueTeleItem.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, delay_jitter_ms, flash_prob, delay_over_prob, delay_over_ms

spike 毛刺行为

  • 每个周期以 probability 概率触发毛刺
  • 触发时 y = base ± amplitude符号随机
  • 毛刺持续 1 个周期后恢复

drift 漂移行为

  • y = base + drift_rate × t
  • 漂移累加无上限,模拟传感器退化趋势

valve_pair 时序模型

不模拟动作信号本身,而是通过模型名引用另一个信号(如 bool_toggle)的当前值,模拟传感器对动作的响应延迟。

参数说明:

参数 含义 默认值
on_delay_ms 阀开到位延迟ms信号 0→1 后传感器多久变 1 必填
off_delay_ms 阀关到位延迟ms信号 1→0 后传感器多久变 0 必填
delay_jitter_ms 延迟抖动范围,实际延迟 = delay ± random(0, jitter) 0
flash_prob 高电平期间每周期出现闪断的概率 0
delay_over_prob 每次阀动作时触发超时的概率on/off 独立判断) 0
delay_over_ms 超时时的延迟值,替代正常延迟 0

正常时序(无超时,有抖动):

动作信号 A:
    ────────────┐                  ┌────────────────
                │                  │
                ├── on_delay ──→   ├── off_delay ──→
传感器 B:       │  ±jitter        │  ±jitter
    ────────────┘                  └────────────────
                └─ 阀芯移动 ──→    └─ 阀芯复位 ──→

超时场景delay_over_prob 触发时):

动作信号 A:
    ────────────┐
                │
                ├──────── on_delay_over (4000ms) ────────→   正常 off_delay
传感器 B:       │                                          ┌────── ...
    ────────────┘                                          │
                                                           └── 超时! 远超正常范围
  • 每次 A 跳变时0→1 或 1→0delay_over_prob 概率独立判断是否超时
  • 超时时延迟 = delay_over_ms,未超时时延迟 = delay_ms ± random(0, delay_jitter_ms)
  • 闪断:高电平期间以 flash_prob 概率单周期归零后自动恢复
  • delay_over_prob = 0 = 永不超时;delay_jitter_ms = 0 = 无抖动
  • on 和 off 方向各自由各自概率独立触发超时

配对方式B 的 tables[1] = valve_px_std:toggle_2s,其中 toggle_2s 是 A 的模型名。运行时通过模型名查找动作信号的 IModel 实例。

一对多自然支持:同一个动作信号可被多个 valve_pair 传感器跟随,各自维护独立的延迟/闪断状态。

JSON 配置格式

文件路径:/users/dsc/code/TestProject/RNG/json/rng_models.jsonLinux 运行环境固定路径)

{
  "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, "delay_jitter_ms": 20, "flash_prob": 0.02, "delay_over_prob": 0.0001, "delay_over_ms": 4000 } },
    "valve_px_fast":  { "mode": "valve_pair", "params": { "on_delay_ms": 80,  "off_delay_ms": 60,  "delay_jitter_ms": 10, "flash_prob": 0.01, "delay_over_prob": 0,       "delay_over_ms": 0 } }
  }
}

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/ 源文件

关键接口

// 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<std::unique_ptr<IModel>(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<IModel*> 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("/users/dsc/code/TestProject/RNG/json/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<PLC_DATA> 共享内存写入逻辑保持不变
  • ICE 接口 RNGICEI 不变
  • DB2 中已有的 tables[1] 为空的行走默认模型 normal_tiny,保持向后兼容

约束

  • tables[1] 字段长度 40 字符(name_type = char[40]),模型名 + 引用语法需控制在此范围内
  • 时间索引 t_index 从进程启动起单调递增,每周期(~20ms加 1不持久化