# RNG — 参数化随机数生成器 为 eqpalg 监控引擎提供仿真数据的测试工具。通过 JSON 配置和 DB2 表驱动,将可复用的数学模型绑定到信号项上,生成模拟量/布尔量的实时仿真数据写入共享内存,供 eqpalg-mon 消费和评估报警规则。 ## 架构 ``` rng_models.json T_LOV_FDAAITEM (DB2) │ │ │ 模型模板定义 │ 信号→模型绑定 (tables[1] 字段) │ │ ▼ ▼ ModelRegistry ──────── Generator ────── BinaryTele ────── CMemFix ──► 共享内存 │ ├── ConstantModel (y = c) ├── NormalModel (y = μ + σ·N(0,1)) ├── LinearModel (y = k·t + b) ├── SineModel (y = A·sin(ω·t + φ) + offset) ├── UniformModel (y = random(center±delta)) ├── SpikeModel (随机毛刺注入) ├── DriftModel (线性漂移) ├── CsvReplayModel (CSV 历史数据回放) ├── BoolRandomModel (概率随机布尔) ├── BoolToggleModel (固定周期翻转) ├── BoolCsvModel (CSV 布尔回放) ├── ValvePairModel (阀动作→到位传感器 时序仿真) └── CompositeModel (base + noise 组合) ``` **设计原则**:模型模板与信号绑定分离。模型定义在 JSON 中,可复用;每个信号通过 DB2 的 `tables[1]` 字段选择模型,独立实例化,互不干扰。 ## 编译 ```bash cd TestProject/RNG && mkdir -p build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release make -j$(nproc) # 可执行文件: ~/bin/RNG ``` 依赖:GCC 10+, CMake 3.8+, vcpkg (nlohmann_json, mlpack, Armadillo), PACE/iPlature 框架。 ## 配置 ### rng_models.json 路径:`/users/dsc/code/TestProject/RNG/json/rng_models.json` 定义可复用的模型模板。每个模板有 `mode`(模型类型)和 `params`(模型参数)。信号项的 `defaultValue` 自动作为模型的基值参数。 ```json { "models": { "模板名称": { "mode": "模型类型", "params": { "参数名": 值 } } } } ``` ### DB2 信号绑定 在 `T_LOV_FDAAITEM` 表中,`tables[1]` 字段(char[40])填写模型引用。语法: | 格式 | 含义 | 示例 | |------|------|------| | `模型名` | 引用 JSON 中的模型模板 | `normal_tiny` | | `csv:文件:列号` | 内联 CSV 数据回放 | `csv:spbdata:1` | | `基模型+噪声模型` | 组合模型(叠加噪声) | `linear_slow+normal_tiny` | | `pair模型:动作模型` | 阀到位传感器引用动作信号 | `valve_px_std:toggle_2s` | | `!模型引用` | 布尔量取反 | `!toggle_2s` | | 空或 `default` | 默认模型 `normal_tiny` | — | ## 模型参考 ### 模拟量模型 所有模拟量模型实现 `evaluate(size_t t) -> float`,`t` 为时间索引(每 ~20ms 递增)。 #### constant — 固定值 y = c,c 取自 `defaultValue`。 ```json "constant_zero": { "mode": "constant", "params": {} } ``` #### normal — 正态分布 y = μ + σ·N(0,1),μ 取自 `defaultValue`。 | 参数 | 含义 | 默认值 | |------|------|--------| | sigma | 标准差 | 0.01 | ```json "normal_tiny": { "mode": "normal", "params": { "sigma": 0.01 } } ``` #### linear — 线性变化 y = k·t + b,b 取自 `defaultValue`。 | 参数 | 含义 | 默认值 | |------|------|--------| | k | 斜率(每 tick 增量) | 0.0 | | period_ms | 周期(ms),t 按周期取模 | 0(无限) | `period_ms > 0` 时,t = (实际 tick) % (period_ms / 20),模拟每周期重复的线性过程(如带钢卷取时张力逐渐增大然后释放)。`period_ms = 0` 时不取模。 ```json "linear_slow": { "mode": "linear", "params": { "k": 0.001, "period_ms": 600000 } } ``` #### sine — 正弦波 y = A·sin(ω·t + φ) + offset,offset 取自 `defaultValue`。 | 参数 | 含义 | 默认值 | |------|------|--------| | A | 振幅 | 1.0 | | omega | 角频率 | 1.0 | | phi | 初相位 | 0.0 | ```json "sine_ecc1": { "mode": "sine", "params": { "A": 5.0, "omega": 0.314, "phi": 0 } } ``` #### uniform — 均匀随机 y = center ± delta,center 取自 `defaultValue`。 | 参数 | 含义 | 默认值 | |------|------|--------| | delta | 随机范围 | 0.01 | #### spike — 随机毛刺 每个周期以 `probability` 概率触发一次幅值为 ±amplitude 的瞬时毛刺。 | 参数 | 含义 | 默认值 | |------|------|--------| | amplitude | 毛刺幅度 | 1.0 | | probability | 每周期触发概率 | 0.01 | ```json "spike_sharp": { "mode": "spike", "params": { "amplitude": 50, "probability": 0.05 } } ``` #### drift — 线性漂移 y = base + drift_rate·t,base 取自 `defaultValue`。模拟传感器缓慢退化。 | 参数 | 含义 | 默认值 | |------|------|--------| | drift_rate | 每 tick 漂移量 | 0.0 | | period_ms | 周期(ms),t 按周期取模 | 0(无限) | `period_ms > 0` 时形成锯齿波漂移:每个周期内从 base 线性漂移到 base + drift_rate·period_ticks,然后复位,模拟每个生产周期内的退化-复位行为。 ```json "drift_slow": { "mode": "drift", "params": { "drift_rate": 0.0001, "period_ms": 3600000 } } ``` #### csv — CSV 数据回放 从 CSV 文件读取指定列,循环回放。通常通过 `tables[1]` 内联语法使用,无需在 JSON 定义。 ```json "csv_example": { "mode": "csv", "params": { "file": "C308速度毛刺仿真.csv", "column": 0 } } ``` CSV 文件存放路径:`/users/dsc/code/TestProject/data_files/` ### 布尔量模型 所有布尔量模型实现 `evaluateBool(size_t t) -> bool`。 #### bool_random — 概率随机 | 参数 | 含义 | 默认值 | |------|------|--------| | prob_true | 返回 true 的概率 | 0.5 | #### bool_toggle — 固定周期翻转 | 参数 | 含义 | 默认值 | |------|------|--------| | period_ms | 翻转周期(毫秒) | 2000 | 周期前半段为 true,后半段为 false。 ```json "toggle_2s": { "mode": "bool_toggle", "params": { "period_ms": 2000 } } ``` #### bool_csv — CSV 布尔回放 从 CSV 读取整数列,非零值为 true。 #### valve_pair — 阀动作→到位传感器 时序仿真 模拟液压阀/气动阀动作信号与到位接近开关之间的时序关系。使用了四态状态机: ``` 动作信号 A: ────────────┐ ┌──────────────── │ │ ├── on_delay ──→ ├── off_delay ──→ 到位传感器 B: │ ±jitter │ ±jitter ────────────┘ └──────────────── └─ 阀芯移动 ──→ └─ 阀芯复位 ──→ ``` | 参数 | 含义 | 默认值 | |------|------|--------| | on_delay_ms | 阀开到位延迟(ms) | 200 | | off_delay_ms | 阀关到位延迟(ms) | 150 | | delay_jitter_ms | 延迟抖动范围(±均匀随机) | 0 | | flash_prob | 高电平期间每周期闪断概率 | 0 | | delay_over_prob | 每次动作触发超时的概率 | 0 | | delay_over_ms | 超时时的延迟值(ms) | 0 | 状态机: - **IDLE_LOW**:等待动作信号上升沿 - **WAITING_RISE**:动作上升,计数延迟,期间冻结边沿检测 - **HIGH**:到位,监测动作下降沿或随机闪断 - **WAITING_FALL**:动作下降,计数关延迟,期间冻结边沿检测 **绑定方式**:到位传感器信号的 `tables[1]` 使用配对语法: ``` tables[1] = "valve_px_std:toggle_2s" ↑ ↑ valve_pair 模板 动作信号的模型名 ``` 运行时通过模型名查找动作信号的 IModel 实例,每个周期读取其 `evaluateBool()` 值。 一对多支持:同一个动作信号可被多个 valve_pair 传感器跟随,各自独立维护状态机。 ### 组合模型(Composite) 通过 `+` 连接两个模型名,构成 base + noise 组合: ``` tables[1] = "linear_slow+normal_tiny" ``` `CompositeModel` 将两个模型的 `evaluate()` 结果相加。只适用于模拟量。 ## 添加新模型 三步,不改现有代码逻辑: 1. **创建模型类**:在 `model/` 下新建头文件,继承 `IModel`,实现 `evaluate()` 或 `evaluateBool()` ```cpp struct ExponentialModel : IModel { float lambda, base; ExponentialModel(const json& p, float d) : lambda(p.value("lambda", 1.0f)), base(d) {} float evaluate(size_t t) override { return base * expf(-lambda * t); } }; ``` 2. **注册到工厂**:在 `ModelRegistry.cc` 构造函数中添加一行 ```cpp registerMode("exponential", [](const json& p, float d) { return std::make_unique(p, d); }); ``` 3. **JSON 中添加模板**(可选,也可以直接用 `tables[1]` 内联语法) ```json "exp_decay": { "mode": "exponential", "params": { "lambda": 0.01 } } ``` ## 数据流 ``` PACE 定时器 (每 20ms) │ TimeNotify(eventNo) ▼ Generator::wtite_in_shm(eventNo) │ ├─ BinaryTele.ReBuild(eventNo) ← 从 DB2 读取电文结构 │ ├─ Pass 1: for each item: │ ModelRegistry::getOrCreate(tables[1], defaultValue, item.name) │ → 按信号 item 名创建独立模型实例 │ ├─ Pass 2: for each item: │ model->linkPeers(registry) │ → valve_pair 模型查找动作信号实例 │ ├─ Pass 3: for each item: │ model->evaluate(t) / evaluateBool(t) │ → 生成值写入 binary_tele[i].value │ └─ BinaryTele.GetTeleData() → CMemFix::push() → 写入共享内存环形缓冲 ``` 共享内存区由 `T_LOV_FDAAITEM` 的事件号区分,eqpalg-mon 按同样的事件号读取。 ## 目录结构 ``` TestProject/RNG/ ├── json/ │ └── rng_models.json # 模型模板配置 ├── model/ │ ├── IModel.h # 模型基类接口 │ ├── ConstantModel.h # 固定值 │ ├── NormalModel.h # 正态分布 │ ├── LinearModel.h # 线性变化 │ ├── SineModel.h # 正弦波 │ ├── UniformModel.h # 均匀随机 │ ├── SpikeModel.h # 随机毛刺 │ ├── DriftModel.h # 线性漂移 │ ├── CsvReplayModel.h # CSV 模拟量回放 │ ├── BoolRandomModel.h # 布尔随机 │ ├── BoolToggleModel.h # 布尔周期翻转 │ ├── BoolCsvModel.h # CSV 布尔回放 │ ├── ValvePairModel.h # 阀动作-到位传感器 │ ├── CompositeModel.h # 组合模型 │ ├── ModelRegistry.h # 工厂注册表(声明) │ └── ModelRegistry.cc # 工厂注册表(实现) ├── RNG.h / RNG.cc # PACE 组件入口 ├── RNG_icei.h / RNG_icei.cc # ICE 接口实现 ├── Generator.h / Generator.cc # 数据生成 + 共享内存写入 ├── RandT.h # 底层随机数工具 ├── read_csv.hpp # CSV 文件读取 ├── CMakeLists.txt # CMake 构建 └── README.md # 本文档 ```