6.2 KiB
6.2 KiB
Ploss 解析器
所属模块:解析器设计
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 | RX power - 接收端功率 |
| (5) | Field5 | int | TX power - 发射端功率 |
| (6) | Field6 | int | 待定义 |
| (7) | Field7 | int | 待定义 |
| (8) | Field8 | int | 待定义 |
| (9) | Field9 | int | ploss - 功率损耗计算值 |
| (10) | Field10 | int | threshold - 阈值 |
| (11) | Field11 | int | 触发次数 - 当 Field9 > Field10(ploss 大于阈值)时计数,超过5次触发FOD保护 |
| (12) | Field12 | int | PFOD result 标志 - 触发时置位 |
| (13) | Field13 | int | 待定义 |
| (14) | Field14 | int | 待定义 |
| (15) | Field15 | int | 待定义 |
| (16) | Field16 | int | 待定义 |
3. 正则表达式
日志由两行组成,需要分别匹配:
// 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. 解析器实现
当前实现位于
src/Gpulse.WCT.DataAnalyzer.Core/Application/Parsing/PlossParser.cs,实现IParser<PlossRecord>接口。
解析分两步:
- 单行识别:
TryMatch(line)依次尝试HeaderPattern→FodPattern→LegacyPattern,返回匹配类型(None/Header/Fod/Legacy),避免重复正则匹配。 - 多行合并:
ParseService检测到 header 行后暂存,下一行为 Ploss 行时调用ParseMultiLine([header, fod], scenarioId)合并为一条完整记录;文件末尾残留的 header 行记为解析错误。
public enum MatchType { None, Header, Fod, Legacy }
public (MatchType Type, Match Match) TryMatch(string line)
{
var headerMatch = HeaderPattern.Match(line);
if (headerMatch.Success) return (MatchType.Header, headerMatch);
var fodMatch = FodPattern.Match(line);
if (fodMatch.Success) return (MatchType.Fod, fodMatch);
var legacyMatch = LegacyPattern.Match(line);
if (legacyMatch.Success) return (MatchType.Legacy, legacyMatch);
return (MatchType.None, Match.Empty);
}
public bool CanParse(string line) => TryMatch(line).Type != MatchType.None;
public bool IsMultiLineStart(string line) => TryMatch(line).Type == MatchType.Header;
public ParseResult<PlossRecord>? ParseMultiLine(string[] lines, Guid scenarioId)
{
if (lines.Length < 2 || lines[0] == null || lines[1] == null)
return null;
var headerMatch = HeaderPattern.Match(lines[0].Trim());
var fodMatch = FodPattern.Match(lines[1].Trim());
if (!headerMatch.Success || !fodMatch.Success)
return null;
// 第一行 header 组1/组2 → PowLoss/DeltaP
// 第二行 FOD 组1~16 → Field1~Field16
return ParseResult<PlossRecord>.Success(new PlossRecord { /* ... */ });
}
多行合并(ParseMultiLine)捕获组映射:
| 来源 | 捕获组 | 字段 |
|---|---|---|
| 第一行 header | Group 1 / Group 2 | PowLoss / DeltaP |
| 第二行 FOD | Group 1 ~ Group 16 | Field1 ~ Field16 |
旧单行格式:无 header 行,
Field1~13直接来自FOD->后 13 个数字,Field14~16补默认值 0,PowLoss/DeltaP为 null。字段语义以PlossRecord实体注释为准。
5. 核心判定逻辑
字段语义以
PlossRecord实体注释为准:Field9= ploss(功率损耗计算值)、Field10= threshold(阈值)、Field11= 触发次数。
5.1 FOD 触发条件
if (Field9 > Field10) → Field11 计数累积
if (Field11 > 5) → 触发 FOD 报警,停止充电
说明:触发条件统一为
Field9 > Field10(ploss > threshold),实体Field11注释已同步此口径。
5.2 安全余量计算
// 派生属性(不落库) = Field10 - Field9
Margin = Field10 - Field9
| 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 | 高功率允许更多损耗 |