eis/TestProject/RNG/README.md
Huamonarch 1e781a7c03 feat: add ! negation operator for boolean models
Prefix any boolean model reference with ! to negate its output.
Works with all boolean models: !toggle_2s, !valve_px_std:toggle_2s, !bool_50, etc.
2026-05-13 16:56:30 +08:00

335 lines
11 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.

# RNG — 参数化随机数生成器
为 eqpalg 监控引擎提供仿真数据的测试工具。通过 JSON 配置和 DB2 表驱动,将可复用的数学模型绑定到信号项上,生成模拟量/布尔量的实时仿真数据写入共享内存,供 eqpalg-mon 消费和评估报警规则。
## 架构
```
rng_models.json T_LOV_FDAAITEM (DB2)
│ │
│ 模型模板定义 │ 信号→模型绑定 (tables[1] 字段)
│ │
▼ ▼
ModelRegistry ──────── Generator ────── BinaryTele ────── CMemFix<PLC_DATA> ──► 共享内存
├── 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 = cc 取自 `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 + bb 取自 `defaultValue`
| 参数 | 含义 | 默认值 |
|------|------|--------|
| k | 斜率(每 tick 增量) | 0.0 |
| period_ms | 周期mst 按周期取模 | 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 + φ) + offsetoffset 取自 `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 ± deltacenter 取自 `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·tbase 取自 `defaultValue`。模拟传感器缓慢退化。
| 参数 | 含义 | 默认值 |
|------|------|--------|
| drift_rate | 每 tick 漂移量 | 0.0 |
| period_ms | 周期mst 按周期取模 | 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<ExponentialModel>(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<PLC_DATA>::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 # 本文档
```