eis/TestProject/RNG/README.md

334 lines
11 KiB
Markdown
Raw Normal View History

# 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` |
| 空或 `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 # 本文档
```