diff --git a/docs/architecture/parser/Ploss解析器.md b/docs/architecture/parser/Ploss解析器.md index 7faf0c9..053f9f1 100644 --- a/docs/architecture/parser/Ploss解析器.md +++ b/docs/architecture/parser/Ploss解析器.md @@ -28,15 +28,15 @@ FOD-> (1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) | (1) | Field1 | int | 待定义 | | (2) | Field2 | int | 待定义 | | (3) | Field3 | int | 待定义 | -| (4) | Field4 | int | 待定义 | -| (5) | Field5 | int | 待定义 | +| (4) | Field4 | int | RX power - 接收端功率 | +| (5) | Field5 | int | TX power - 发射端功率 | | (6) | Field6 | int | 待定义 | | (7) | Field7 | int | 待定义 | | (8) | Field8 | int | 待定义 | -| (9) | Field9 | int | 待定义 | -| (10) | Field10 | int | 待定义 | -| (11) | Field11 | int | 待定义 | -| (12) | Field12 | 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 | 待定义 | @@ -99,127 +99,78 @@ private static readonly Regex FodPattern = new( ## 4. 解析器实现 +> 当前实现位于 `src/Gpulse.WCT.DataAnalyzer.Core/Application/Parsing/PlossParser.cs`,实现 `IParser` 接口。 + +解析分两步: + +1. **单行识别**:`TryMatch(line)` 依次尝试 `HeaderPattern` → `FodPattern` → `LegacyPattern`,返回匹配类型(`None/Header/Fod/Legacy`),避免重复正则匹配。 +2. **多行合并**:`ParseService` 检测到 header 行后暂存,下一行为 Ploss 行时调用 `ParseMultiLine([header, fod], scenarioId)` 合并为一条完整记录;文件末尾残留的 header 行记为解析错误。 + ```csharp -// Parsers/PlossParser.cs -using System.Text.RegularExpressions; -using Gpulse.WCT.DataAnalyzer.Models; +public enum MatchType { None, Header, Fod, Legacy } -namespace Gpulse.WCT.DataAnalyzer.Parsers; - -public class PlossParser : IParser +public (MatchType Type, Match Match) TryMatch(string line) { - private static readonly Regex HeaderPattern = new( - @"^pow_loss\s*=\s*(\d+),\s*delta_p\s*=\s*(\d+)$", - RegexOptions.Compiled - ); + var headerMatch = HeaderPattern.Match(line); + if (headerMatch.Success) return (MatchType.Header, headerMatch); - 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 - ); + var fodMatch = FodPattern.Match(line); + if (fodMatch.Success) return (MatchType.Fod, fodMatch); - public bool CanParse(string line) => HeaderPattern.IsMatch(line) || FodPattern.IsMatch(line); + var legacyMatch = LegacyPattern.Match(line); + if (legacyMatch.Success) return (MatchType.Legacy, legacyMatch); - public ParseResult Parse(string line, Guid scenarioId) - { - // 尝试匹配第一行 - var headerMatch = HeaderPattern.Match(line); - if (headerMatch.Success) - { - return ParseHeaderLine(headerMatch, scenarioId); - } + return (MatchType.None, Match.Empty); +} - // 尝试匹配第二行 - var fodMatch = FodPattern.Match(line); - if (fodMatch.Success) - { - return ParseFodLine(fodMatch, scenarioId); - } +public bool CanParse(string line) => TryMatch(line).Type != MatchType.None; +public bool IsMultiLineStart(string line) => TryMatch(line).Type == MatchType.Header; - return ParseResult.Failure( - "FORMAT_MISMATCH", - "Line does not match Ploss pattern" - ); - } +public ParseResult? ParseMultiLine(string[] lines, Guid scenarioId) +{ + if (lines.Length < 2 || lines[0] == null || lines[1] == null) + return null; - private ParseResult 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.Success(record); - } - catch (Exception ex) - { - return ParseResult.Failure( - "TYPE_CONVERSION", - $"Failed to convert header field: {ex.Message}" - ); - } - } + var headerMatch = HeaderPattern.Match(lines[0].Trim()); + var fodMatch = FodPattern.Match(lines[1].Trim()); + if (!headerMatch.Success || !fodMatch.Success) + return null; - private ParseResult 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.Success(record); - } - catch (Exception ex) - { - return ParseResult.Failure( - "TYPE_CONVERSION", - $"Failed to convert FOD field: {ex.Message}" - ); - } - } + // 第一行 header 组1/组2 → PowLoss/DeltaP + // 第二行 FOD 组1~16 → Field1~Field16 + return ParseResult.Success(new PlossRecord { /* ... */ }); } ``` -> **注意**:实际实现中,两行日志需要合并为一条完整记录。可以使用 `PlossRecordMerger` 或在业务逻辑层处理合并。 +**多行合并(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 (Ploss > Threshold) → 计数器累积 -if (Count > Limit) → 触发 FOD 报警,停止充电 +if (Field9 > Field10) → Field11 计数累积 +if (Field11 > 5) → 触发 FOD 报警,停止充电 ``` +> **说明**:触发条件统一为 `Field9 > Field10`(ploss > threshold),实体 `Field11` 注释已同步此口径。 + ### 5.2 安全余量计算 ```csharp -// 派生属性(不落库) -Margin = Threshold - Ploss +// 派生属性(不落库) = Field10 - Field9 +Margin = Field10 - Field9 ``` | Margin 状态 | 含义 | diff --git a/docs/data-model/entities/Ploss记录.md b/docs/data-model/entities/Ploss记录.md index fd55b21..9ce3f4a 100644 --- a/docs/data-model/entities/Ploss记录.md +++ b/docs/data-model/entities/Ploss记录.md @@ -8,34 +8,44 @@ **表名**:`ploss_record` -**描述**:存储 Ploss FOD 格式解析数据,对应日志格式 `FOD-> (1)...(13)` +**描述**:存储 Ploss FOD 格式解析数据,对应两行日志格式: + +``` +pow_loss = X, delta_p = Y +FOD-> (1) (2) ... (16) +``` --- ## 2. 字段定义 -> **类型修正说明**:需求文档中 rx_power, tx_power, vcoil, vin, isns, pwm_duty 为 `uint16`(0-65535),但 SQLite 不支持无符号类型。实际数据如 vcoil=35377 超出了 SMALLINT(-32768~32767)范围,因此这些字段使用 INT 类型存储。 - | 列名 | 类型 | 约束 | 说明 | |------|------|------|------| | id | UUID | PK, NOT NULL | 主键 | | scenario_id | UUID | FK, NOT NULL | 关联测试场景 | -| rx_type | TINYINT | NOT NULL | 接收端类型标识 | -| rx_power | INT | NOT NULL | 接收端功率(mW),原 uint16 | -| tx_power | INT | NOT NULL | 发射端功率(mW),原 uint16 | -| vcoil | INT | NOT NULL | 发射线圈电压,原 uint16 | -| vin | INT | NOT NULL | 输入电压,原 uint16 | -| isns | INT | NOT NULL | 输入电流采样值,原 uint16 | -| ploss | INT | NOT NULL | **核心值**:计算损耗(负数=安全) | -| threshold | INT | NOT NULL | **安全红线**:当前功率段阈值 | -| trigger_count | INT | NOT NULL, DEFAULT 0 | 触发计数器 | -| fod_result | INT | NOT NULL, DEFAULT 0 | FOD判定结果 | -| protocol_type | TINYINT | NOT NULL | 充电协议类型 | -| pwm_duty | INT | NOT NULL | PWM占空比,原 uint16 | -| coil_index | TINYINT | NOT NULL | 充电线圈索引 | +| pow_loss | INT | NULL | 第一行:功率损耗值 | +| delta_p | INT | NULL | 第一行:功率差值 | +| field_1 | INT | NOT NULL | Field1(语义待定义) | +| field_2 | INT | NOT NULL | Field2(语义待定义) | +| field_3 | INT | NOT NULL | Field3(语义待定义) | +| field_4 | INT | NOT NULL | Field4: RX power - 接收端功率 | +| field_5 | INT | NOT NULL | Field5: TX power - 发射端功率 | +| field_6 | INT | NOT NULL | Field6(语义待定义) | +| field_7 | INT | NOT NULL | Field7(语义待定义) | +| field_8 | INT | NOT NULL | Field8(语义待定义) | +| field_9 | INT | NOT NULL, DEFAULT 0 | Field9: ploss - 功率损耗计算值 | +| field_10 | INT | NOT NULL, DEFAULT 0 | Field10: threshold - 阈值 | +| field_11 | INT | NOT NULL | Field11: 触发次数 - 当 Field9 > Field10 时计数,超过5次触发FOD保护 | +| field_12 | INT | NOT NULL | Field12: PFOD result 标志 - 触发时置位 | +| field_13 | INT | NOT NULL, DEFAULT 0 | Field13(语义待定义) | +| field_14 | INT | NOT NULL, DEFAULT 0 | Field14(语义待定义) | +| field_15 | INT | NOT NULL, DEFAULT 0 | Field15(语义待定义) | +| field_16 | INT | NOT NULL, DEFAULT 0 | Field16(语义待定义) | | is_deleted | BOOLEAN | NOT NULL, DEFAULT FALSE | 软删除标记 | | created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() | 创建时间 | +> **字段语义**以 `PlossRecord` 实体注释为准。 + --- ## 3. 外键 @@ -52,9 +62,9 @@ | 字段 | 计算公式 | 说明 | |------|----------|------| -| margin | threshold - ploss | 安全余量(>0 安全,<0 危险) | +| margin | field_10 - field_9 | 安全余量(>0 安全,<0 危险) | -> **使用限制**:`Margin` 属性通过 EF Core `Ignore()` 排除映射,仅用于内存计算。不可在数据库查询中直接使用(如 `WHERE Margin > 0`),需改用 `WHERE (threshold - ploss) > 0` 或先加载到内存再计算。 +> **使用限制**:`Margin` 属性通过 EF Core `Ignore()` 排除映射,仅用于内存计算。不可在数据库查询中直接使用(如 `WHERE Margin > 0`),需改用 `WHERE (field_10 - field_9) > 0` 或先加载到内存再计算。 --- @@ -63,10 +73,12 @@ | 索引名 | 字段 | 用途 | |--------|------|------| | idx_ploss_scenario | scenario_id | 按测试场景查询 | -| idx_ploss_rx_power | rx_power | 阈值表匹配 | -| idx_ploss_ploss | ploss | 损耗值查询 | -| idx_ploss_threshold | threshold | 阈值查询 | -| idx_ploss_fod_result | fod_result | FOD结果筛选 | +| idx_ploss_field_2 | field_2 | 字段查询 | +| idx_ploss_field_7 | field_7 | 字段查询 | +| idx_ploss_field_8 | field_8 | 字段查询 | +| idx_ploss_field_10 | field_10 | 字段查询 | +| idx_ploss_pow_loss | pow_loss | 第一行损耗值查询 | +| idx_ploss_delta_p | delta_p | 第一行功率差值查询 | --- @@ -75,51 +87,73 @@ ### 实体类 ```csharp -// Models/PlossRecord.cs -namespace Gpulse.WCT.DataAnalyzer.Models; +// Domain/Local/PlossRecord.cs +namespace Gpulse.WCT.DataAnalyzer.Core.Domain.Local; public class PlossRecord { public Guid Id { get; set; } = Guid.NewGuid(); public Guid ScenarioId { get; set; } - public byte RxType { get; set; } - public short RxPower { get; set; } - public short TxPower { get; set; } - public short Vcoil { get; set; } - public short Vin { get; set; } - public short Isns { get; set; } - /// 核心判定值:负数表示安全 - public int Ploss { get; set; } + // ===== 第一行字段(nullable,兼容旧数据) ===== + /// 功率损耗值(来自第一行) + public int? PowLoss { get; set; } - /// 安全红线:当前功率段阈值 - public int Threshold { get; set; } + /// 功率差值(来自第一行) + public int? DeltaP { get; set; } + + // ===== 第二行字段(16个通用字段,均支持负数) ===== + public int Field1 { get; set; } + public int Field2 { get; set; } + public int Field3 { get; set; } + + /// Field4: RX power - 接收端功率 + public int Field4 { get; set; } + + /// Field5: TX power - 发射端功率 + public int Field5 { get; set; } + + public int Field6 { get; set; } + public int Field7 { get; set; } + public int Field8 { get; set; } + + /// Field9: ploss - 功率损耗计算值 + public int Field9 { get; set; } + + /// Field10: threshold - 阈值 + public int Field10 { get; set; } + + /// Field11: 触发次数 - 当 Field9 > Field10(ploss 大于阈值)时计数,超过5次触发FOD保护 + public int Field11 { get; set; } + + /// Field12: PFOD result 标志 - 触发时置位 + public int Field12 { get; set; } + + public int Field13 { get; set; } + public int Field14 { get; set; } + public int Field15 { get; set; } + public int Field16 { get; set; } - public short TriggerCount { get; set; } = 0; - public short FodResult { get; set; } = 0; - public byte ProtocolType { get; set; } - public short PwmDuty { get; set; } - public byte CoilIndex { get; set; } public bool IsDeleted { get; set; } = false; public DateTime CreatedAt { get; set; } = DateTime.UtcNow; // Navigation Properties public TestScenario Scenario { get; set; } = null!; - /// 派生属性:安全余量(不落库) - public int Margin => Threshold - Ploss; + /// 派生属性:安全余量(不落库) = Field10 - Field9 + public int Margin => Field10 - Field9; } ``` ### 配置类 ```csharp -// Data/Configurations/PlossRecordConfiguration.cs +// Infrastructure/LocalData/Configurations/PlossRecordConfiguration.cs using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Gpulse.WCT.DataAnalyzer.Models; +using Gpulse.WCT.DataAnalyzer.Core.Domain.Local; -namespace Gpulse.WCT.DataAnalyzer.Data.Configurations; +namespace Gpulse.WCT.DataAnalyzer.Core.Infrastructure.LocalData.Configurations; public class PlossRecordConfiguration : IEntityTypeConfiguration { @@ -134,59 +168,27 @@ public class PlossRecordConfiguration : IEntityTypeConfiguration .IsRequired() .HasColumnName("scenario_id"); - builder.Property(e => e.RxType) - .IsRequired() - .HasColumnName("rx_type"); + // ===== 第一行字段(nullable) ===== + builder.Property(e => e.PowLoss).IsRequired(false).HasColumnName("pow_loss"); + builder.Property(e => e.DeltaP).IsRequired(false).HasColumnName("delta_p"); - builder.Property(e => e.RxPower) - .IsRequired() - .HasColumnName("rx_power"); - - builder.Property(e => e.TxPower) - .IsRequired() - .HasColumnName("tx_power"); - - builder.Property(e => e.Vcoil) - .IsRequired() - .HasColumnName("vcoil"); - - builder.Property(e => e.Vin) - .IsRequired() - .HasColumnName("vin"); - - builder.Property(e => e.Isns) - .IsRequired() - .HasColumnName("isns"); - - builder.Property(e => e.Ploss) - .IsRequired() - .HasColumnName("ploss"); - - builder.Property(e => e.Threshold) - .IsRequired() - .HasColumnName("threshold"); - - builder.Property(e => e.TriggerCount) - .IsRequired() - .HasDefaultValue((short)0) - .HasColumnName("trigger_count"); - - builder.Property(e => e.FodResult) - .IsRequired() - .HasDefaultValue((short)0) - .HasColumnName("fod_result"); - - builder.Property(e => e.ProtocolType) - .IsRequired() - .HasColumnName("protocol_type"); - - builder.Property(e => e.PwmDuty) - .IsRequired() - .HasColumnName("pwm_duty"); - - builder.Property(e => e.CoilIndex) - .IsRequired() - .HasColumnName("coil_index"); + // ===== 第二行字段(通用命名) ===== + builder.Property(e => e.Field1).IsRequired().HasColumnName("field_1"); + builder.Property(e => e.Field2).IsRequired().HasColumnName("field_2"); + builder.Property(e => e.Field3).IsRequired().HasColumnName("field_3"); + builder.Property(e => e.Field4).IsRequired().HasColumnName("field_4"); + builder.Property(e => e.Field5).IsRequired().HasColumnName("field_5"); + builder.Property(e => e.Field6).IsRequired().HasColumnName("field_6"); + builder.Property(e => e.Field7).IsRequired().HasColumnName("field_7"); + builder.Property(e => e.Field8).IsRequired().HasColumnName("field_8"); + builder.Property(e => e.Field9).IsRequired().HasDefaultValue(0).HasColumnName("field_9"); + builder.Property(e => e.Field10).IsRequired().HasDefaultValue(0).HasColumnName("field_10"); + builder.Property(e => e.Field11).IsRequired().HasColumnName("field_11"); + builder.Property(e => e.Field12).IsRequired().HasColumnName("field_12"); + builder.Property(e => e.Field13).IsRequired().HasDefaultValue(0).HasColumnName("field_13"); + builder.Property(e => e.Field14).IsRequired().HasDefaultValue(0).HasColumnName("field_14"); + builder.Property(e => e.Field15).IsRequired().HasDefaultValue(0).HasColumnName("field_15"); + builder.Property(e => e.Field16).IsRequired().HasDefaultValue(0).HasColumnName("field_16"); builder.Property(e => e.IsDeleted) .IsRequired() @@ -195,7 +197,7 @@ public class PlossRecordConfiguration : IEntityTypeConfiguration builder.Property(e => e.CreatedAt) .IsRequired() - .HasDefaultValueSql("NOW()") + .HasDefaultValueSql("datetime('now')") .HasColumnName("created_at"); // 派生属性不落库 @@ -203,16 +205,21 @@ public class PlossRecordConfiguration : IEntityTypeConfiguration // 索引 builder.HasIndex(e => e.ScenarioId).HasDatabaseName("idx_ploss_scenario"); - builder.HasIndex(e => e.RxPower).HasDatabaseName("idx_ploss_rx_power"); - builder.HasIndex(e => e.Ploss).HasDatabaseName("idx_ploss_ploss"); - builder.HasIndex(e => e.Threshold).HasDatabaseName("idx_ploss_threshold"); - builder.HasIndex(e => e.FodResult).HasDatabaseName("idx_ploss_fod_result"); + builder.HasIndex(e => e.Field2).HasDatabaseName("idx_ploss_field_2"); + builder.HasIndex(e => e.Field7).HasDatabaseName("idx_ploss_field_7"); + builder.HasIndex(e => e.Field8).HasDatabaseName("idx_ploss_field_8"); + builder.HasIndex(e => e.Field10).HasDatabaseName("idx_ploss_field_10"); + builder.HasIndex(e => e.PowLoss).HasDatabaseName("idx_ploss_pow_loss"); + builder.HasIndex(e => e.DeltaP).HasDatabaseName("idx_ploss_delta_p"); // 关系配置 builder.HasOne(e => e.Scenario) .WithMany(e => e.PlossRecords) .HasForeignKey(e => e.ScenarioId) - .IsRequired(); + .OnDelete(DeleteBehavior.Cascade); + + // 全局查询过滤器 + builder.HasQueryFilter(e => !e.IsDeleted); } } ``` @@ -221,7 +228,7 @@ public class PlossRecordConfiguration : IEntityTypeConfiguration ## 7. 动态阈值表 -> 阈值根据 RxPower 动态查表(不落库) +> 阈值根据 RxPower 动态查表(不落库,业务规则) | Rx Power 区间 | Threshold | 备注 | |---------------|-----------|------| @@ -230,15 +237,3 @@ public class PlossRecordConfiguration : IEntityTypeConfiguration | 10000-15000 mW | 750 mW | | | 15000-30000 mW | 1000 mW | | | 30000-50000 mW | 1250 mW | 高功率 | - -```csharp -// Services/ThresholdCalculator.cs -public static int GetThresholdByPower(int rxPower) -{ - if (rxPower <= 5000) return 350; - if (rxPower <= 10000) return 500; - if (rxPower <= 15000) return 750; - if (rxPower <= 30000) return 1000; - return 1250; -} -``` \ No newline at end of file diff --git a/src/Gpulse.WCT.DataAnalyzer.Core/Application/Parsing/PlossParser.cs b/src/Gpulse.WCT.DataAnalyzer.Core/Application/Parsing/PlossParser.cs index 7609dc0..858aecc 100644 --- a/src/Gpulse.WCT.DataAnalyzer.Core/Application/Parsing/PlossParser.cs +++ b/src/Gpulse.WCT.DataAnalyzer.Core/Application/Parsing/PlossParser.cs @@ -144,19 +144,19 @@ public class PlossParser : IParser PowLoss = null, DeltaP = null, // 映射到新字段名 - Field1 = int.Parse(match.Groups[1].Value), // RxType - Field2 = int.Parse(match.Groups[2].Value), // RxPower - Field3 = int.Parse(match.Groups[3].Value), // TxPower - Field4 = int.Parse(match.Groups[4].Value), // Vcoil - Field5 = int.Parse(match.Groups[5].Value), // Vin - Field6 = int.Parse(match.Groups[6].Value), // Isns - Field7 = int.Parse(match.Groups[7].Value), // Ploss - Field8 = int.Parse(match.Groups[8].Value), // Threshold - Field9 = int.Parse(match.Groups[9].Value), // TriggerCount - Field10 = int.Parse(match.Groups[10].Value), // FodResult - Field11 = int.Parse(match.Groups[11].Value), // ProtocolType - Field12 = int.Parse(match.Groups[12].Value), // PwmDuty - Field13 = int.Parse(match.Groups[13].Value), // CoilIndex + 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), // RX power + Field5 = int.Parse(match.Groups[5].Value), // TX power + 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), // ploss + Field10 = int.Parse(match.Groups[10].Value), // threshold + Field11 = int.Parse(match.Groups[11].Value), // 触发次数 + Field12 = int.Parse(match.Groups[12].Value), // PFOD result + Field13 = int.Parse(match.Groups[13].Value), // 旧格式没有Field14-16,使用默认值 Field14 = 0, Field15 = 0, diff --git a/src/Gpulse.WCT.DataAnalyzer.Core/Domain/Local/PlossRecord.cs b/src/Gpulse.WCT.DataAnalyzer.Core/Domain/Local/PlossRecord.cs index 0f1b0b5..8a14c19 100644 --- a/src/Gpulse.WCT.DataAnalyzer.Core/Domain/Local/PlossRecord.cs +++ b/src/Gpulse.WCT.DataAnalyzer.Core/Domain/Local/PlossRecord.cs @@ -19,7 +19,6 @@ public class PlossRecord public int? DeltaP { get; set; } // ===== 第二行字段(16个通用字段,均支持负数) ===== - /// Field1: RX_TYPE - 接收端类型 public int Field1 { get; set; } public int Field2 { get; set; } @@ -33,10 +32,9 @@ public class PlossRecord public int Field6 { get; set; } - /// 核心判定值:Field7 (原Ploss) - 负数表示安全 + public int Field7 { get; set; } - /// 安全红线:Field8 (原Threshold) - 当前功率段阈值 public int Field8 { get; set; } /// Field9: ploss - 功率损耗计算值 @@ -45,7 +43,7 @@ public class PlossRecord /// Field10: threshold - 阈值 public int Field10 { get; set; } - /// Field11: 触发次数 - 当 Field7 > Field8(损耗大于阈值)时计数,超过5次后触发FOD保护 + /// Field11: 触发次数 - 当 Field9 > Field10(ploss 大于阈值)时计数,超过5次后触发FOD保护 public int Field11 { get; set; } /// Field12: PFOD result 标志 - 触发时置位 @@ -62,6 +60,6 @@ public class PlossRecord // Navigation Properties public TestScenario Scenario { get; set; } = null!; - /// 派生属性:安全余量(不落库) = Field8 - Field7 - public int Margin => Field8 - Field7; + /// 派生属性:安全余量(不落库) = Field10 - Field9(Threshold - Ploss) + public int Margin => Field10 - Field9; } \ No newline at end of file diff --git a/src/Gpulse.WCT.DataAnalyzer.Core/Infrastructure/LocalData/Configurations/PlossRecordConfiguration.cs b/src/Gpulse.WCT.DataAnalyzer.Core/Infrastructure/LocalData/Configurations/PlossRecordConfiguration.cs index 9338744..e946d20 100644 --- a/src/Gpulse.WCT.DataAnalyzer.Core/Infrastructure/LocalData/Configurations/PlossRecordConfiguration.cs +++ b/src/Gpulse.WCT.DataAnalyzer.Core/Infrastructure/LocalData/Configurations/PlossRecordConfiguration.cs @@ -111,12 +111,12 @@ public class PlossRecordConfiguration : IEntityTypeConfiguration // 索引 builder.HasIndex(e => e.ScenarioId).HasDatabaseName("idx_ploss_scenario"); - builder.HasIndex(e => e.Field2).HasDatabaseName("idx_ploss_field_2"); // 原 rx_power - builder.HasIndex(e => e.Field7).HasDatabaseName("idx_ploss_field_7"); // 原 ploss - builder.HasIndex(e => e.Field8).HasDatabaseName("idx_ploss_field_8"); // 原 threshold - builder.HasIndex(e => e.Field10).HasDatabaseName("idx_ploss_field_10"); // 原 fod_result - builder.HasIndex(e => e.PowLoss).HasDatabaseName("idx_ploss_pow_loss"); // 新增 - builder.HasIndex(e => e.DeltaP).HasDatabaseName("idx_ploss_delta_p"); // 新增 + builder.HasIndex(e => e.Field2).HasDatabaseName("idx_ploss_field_2"); + builder.HasIndex(e => e.Field7).HasDatabaseName("idx_ploss_field_7"); + builder.HasIndex(e => e.Field8).HasDatabaseName("idx_ploss_field_8"); + builder.HasIndex(e => e.Field10).HasDatabaseName("idx_ploss_field_10"); + builder.HasIndex(e => e.PowLoss).HasDatabaseName("idx_ploss_pow_loss"); + builder.HasIndex(e => e.DeltaP).HasDatabaseName("idx_ploss_delta_p"); // 关系配置 builder.HasOne(e => e.Scenario)