Files
WCTDataMiner/docs/architecture/parser/Ploss解析器.md
2026-08-13 13:29:56 +08:00

242 lines
7.1 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.
# Ploss 解析器
> 所属模块:[解析器设计](./概览.md)
---
## 1. 日志格式
```
pow_loss = 3053, delta_p = 1950
FOD-> (1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16)
```
---
## 2. 字段定义
### 2.1 第一行字段
| 编号 | 字段名称 | 数据类型 | 说明 |
|------|----------|----------|------|
| (A) | PowLoss | int | 功率损耗值 |
| (B) | DeltaP | int | 功率差值 |
### 2.2 第二行字段 (FOD->)
| 编号 | 字段名称 | 数据类型 | 说明 |
|------|----------|----------|------|
| (1) | Field1 | int | 待定义 |
| (2) | Field2 | int | 待定义 |
| (3) | Field3 | int | 待定义 |
| (4) | Field4 | int | 待定义 |
| (5) | Field5 | int | 待定义 |
| (6) | Field6 | int | 待定义 |
| (7) | Field7 | int | 待定义 |
| (8) | Field8 | int | 待定义 |
| (9) | Field9 | int | 待定义 |
| (10) | Field10 | int | 待定义 |
| (11) | Field11 | int | 待定义 |
| (12) | Field12 | int | 待定义 |
| (13) | Field13 | int | 待定义 |
| (14) | Field14 | int | 待定义 |
| (15) | Field15 | int | 待定义 |
| (16) | Field16 | int | 待定义 |
---
## 3. 正则表达式
日志由两行组成,需要分别匹配:
```csharp
// Parsers/PlossParser.cs
// 第一行格式: pow_loss = 3053, delta_p = 1950
private static readonly Regex HeaderPattern = new(
@"^pow_loss\s*=\s*(\d+),\s*delta_p\s*=\s*(\d+)$",
RegexOptions.Compiled
);
// 第二行格式: FOD-> 后跟16个数字均支持负数
private static readonly Regex FodPattern = new(
@"^FOD->\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)$",
RegexOptions.Compiled
);
```
> **说明**所有16个字段均支持负数使用 `-?\d+` 匹配。
**捕获组映射:**
**第一行 (HeaderPattern)**
| 捕获组 | 字段 | 类型转换 |
|--------|------|----------|
| Group 1 | PowLoss | int.Parse() |
| Group 2 | DeltaP | int.Parse() |
**第二行 (FodPattern)**
| 捕获组 | 字段 | 类型转换 |
|--------|------|----------|
| Group 1 | Field1 | int.Parse() |
| Group 2 | Field2 | int.Parse() |
| Group 3 | Field3 | int.Parse() |
| Group 4 | Field4 | int.Parse() |
| Group 5 | Field5 | int.Parse() |
| Group 6 | Field6 | int.Parse() |
| Group 7 | Field7 | int.Parse() |
| Group 8 | Field8 | int.Parse() |
| Group 9 | Field9 | int.Parse() |
| Group 10 | Field10 | int.Parse() |
| Group 11 | Field11 | int.Parse() |
| Group 12 | Field12 | int.Parse() |
| Group 13 | Field13 | int.Parse() |
| Group 14 | Field14 | int.Parse() |
| Group 15 | Field15 | int.Parse() |
| Group 16 | Field16 | int.Parse() |
---
## 4. 解析器实现
```csharp
// Parsers/PlossParser.cs
using System.Text.RegularExpressions;
using Gpulse.WCT.DataAnalyzer.Models;
namespace Gpulse.WCT.DataAnalyzer.Parsers;
public class PlossParser : IParser<PlossRecord>
{
private static readonly Regex HeaderPattern = new(
@"^pow_loss\s*=\s*(\d+),\s*delta_p\s*=\s*(\d+)$",
RegexOptions.Compiled
);
private static readonly Regex FodPattern = new(
@"^FOD->\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)$",
RegexOptions.Compiled
);
public bool CanParse(string line) => HeaderPattern.IsMatch(line) || FodPattern.IsMatch(line);
public ParseResult<PlossRecord> Parse(string line, Guid scenarioId)
{
// 尝试匹配第一行
var headerMatch = HeaderPattern.Match(line);
if (headerMatch.Success)
{
return ParseHeaderLine(headerMatch, scenarioId);
}
// 尝试匹配第二行
var fodMatch = FodPattern.Match(line);
if (fodMatch.Success)
{
return ParseFodLine(fodMatch, scenarioId);
}
return ParseResult<PlossRecord>.Failure(
"FORMAT_MISMATCH",
"Line does not match Ploss pattern"
);
}
private ParseResult<PlossRecord> ParseHeaderLine(Match match, Guid scenarioId)
{
try
{
var record = new PlossRecord
{
ScenarioId = scenarioId,
PowLoss = int.Parse(match.Groups[1].Value),
DeltaP = int.Parse(match.Groups[2].Value),
IsHeaderLine = true
};
return ParseResult<PlossRecord>.Success(record);
}
catch (Exception ex)
{
return ParseResult<PlossRecord>.Failure(
"TYPE_CONVERSION",
$"Failed to convert header field: {ex.Message}"
);
}
}
private ParseResult<PlossRecord> ParseFodLine(Match match, Guid scenarioId)
{
try
{
var record = new PlossRecord
{
ScenarioId = scenarioId,
Field1 = int.Parse(match.Groups[1].Value),
Field2 = int.Parse(match.Groups[2].Value),
Field3 = int.Parse(match.Groups[3].Value),
Field4 = int.Parse(match.Groups[4].Value),
Field5 = int.Parse(match.Groups[5].Value),
Field6 = int.Parse(match.Groups[6].Value),
Field7 = int.Parse(match.Groups[7].Value),
Field8 = int.Parse(match.Groups[8].Value),
Field9 = int.Parse(match.Groups[9].Value),
Field10 = int.Parse(match.Groups[10].Value),
Field11 = int.Parse(match.Groups[11].Value),
Field12 = int.Parse(match.Groups[12].Value),
Field13 = int.Parse(match.Groups[13].Value),
Field14 = int.Parse(match.Groups[14].Value),
Field15 = int.Parse(match.Groups[15].Value),
Field16 = int.Parse(match.Groups[16].Value),
IsHeaderLine = false
};
return ParseResult<PlossRecord>.Success(record);
}
catch (Exception ex)
{
return ParseResult<PlossRecord>.Failure(
"TYPE_CONVERSION",
$"Failed to convert FOD field: {ex.Message}"
);
}
}
}
```
> **注意**:实际实现中,两行日志需要合并为一条完整记录。可以使用 `PlossRecordMerger` 或在业务逻辑层处理合并。
---
## 5. 核心判定逻辑
### 5.1 FOD 触发条件
```
if (Ploss > Threshold) → 计数器累积
if (Count > Limit) → 触发 FOD 报警,停止充电
```
### 5.2 安全余量计算
```csharp
// 派生属性(不落库)
Margin = Threshold - Ploss
```
| Margin 状态 | 含义 |
|-------------|------|
| Margin > 0 | 安全,损耗低于阈值 |
| Margin < 0 | 危险,损耗超过阈值,可能触发 FOD |
---
## 6. 动态阈值表
阈值根据接收功率动态查表:
| 接收功率区间 (Rx Power) | 阈值 (Threshold) | 备注 |
|------------------------|------------------|------|
| 0 ~ 5W (0-5000 mW) | 350 mW | 低功率最敏感 |
| 5 ~ 10W (5000-10000 mW) | 500 mW | |
| 10 ~ 15W (10000-15000 mW) | 750 mW | |
| 15 ~ 30W (15000-30000 mW) | 1000 mW | 示例 Log 处于此区间 |
| 30 ~ 50W (30000-50000 mW) | 1250 mW | 高功率允许更多损耗 |