# ploss_record 实体 > 所属模块:[数据模型概览](../概览.md) --- ## 1. 表定义 **表名**:`ploss_record` **描述**:存储 Ploss FOD 格式解析数据,对应日志格式 `FOD-> (1)...(13)` --- ## 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 | 充电线圈索引 | | is_deleted | BOOLEAN | NOT NULL, DEFAULT FALSE | 软删除标记 | | created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() | 创建时间 | --- ## 3. 外键 | 外键 | 引用表 | 说明 | |------|--------|------| | scenario_id | test_scenario.id | 关联测试场景(必需) | --- ## 4. 派生字段 > **注意**:以下字段不落库,查询时动态计算 | 字段 | 计算公式 | 说明 | |------|----------|------| | margin | threshold - ploss | 安全余量(>0 安全,<0 危险) | > **使用限制**:`Margin` 属性通过 EF Core `Ignore()` 排除映射,仅用于内存计算。不可在数据库查询中直接使用(如 `WHERE Margin > 0`),需改用 `WHERE (threshold - ploss) > 0` 或先加载到内存再计算。 --- ## 5. 索引 | 索引名 | 字段 | 用途 | |--------|------|------| | 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结果筛选 | --- ## 6. EF Core 模型 ### 实体类 ```csharp // Models/PlossRecord.cs namespace WCTDataMiner.Models; 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; } /// 安全红线:当前功率段阈值 public int Threshold { 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; } ``` ### 配置类 ```csharp // Data/Configurations/PlossRecordConfiguration.cs using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using WCTDataMiner.Models; namespace WCTDataMiner.Data.Configurations; public class PlossRecordConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ToTable("ploss_record"); builder.HasKey(e => e.Id); builder.Property(e => e.Id).HasColumnName("id"); builder.Property(e => e.ScenarioId) .IsRequired() .HasColumnName("scenario_id"); builder.Property(e => e.RxType) .IsRequired() .HasColumnName("rx_type"); 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.IsDeleted) .IsRequired() .HasDefaultValue(false) .HasColumnName("is_deleted"); builder.Property(e => e.CreatedAt) .IsRequired() .HasDefaultValueSql("NOW()") .HasColumnName("created_at"); // 派生属性不落库 builder.Ignore(e => e.Margin); // 索引 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.HasOne(e => e.Scenario) .WithMany(e => e.PlossRecords) .HasForeignKey(e => e.ScenarioId) .IsRequired(); } } ``` --- ## 7. 动态阈值表 > 阈值根据 RxPower 动态查表(不落库) | Rx Power 区间 | Threshold | 备注 | |---------------|-----------|------| | 0-5000 mW | 350 mW | 低功率最敏感 | | 5000-10000 mW | 500 mW | | | 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; } ```