SSPC-Tester/Docs/开发文档.md
2026-06-30 12:10:29 +08:00

17 KiB
Raw Permalink Blame History

固态功率控制器动态参数测试系统 — 开发文档

版本 v1.1 技术栈:C# + WPF + .NET 8 口径:以当前仓库代码为准

本文档描述当前仓库的真实结构、配置方式、核心流程和维护约定。 若文档与代码冲突,以代码实现为准,并应同步回写本文档。


0. 开发约束

对本项目进行新增、修改、排障时,默认遵守以下原则:

  1. 分层隔离优先UI 只依赖 ViewModel / Service / Logic不直接依赖具体设备驱动。
  2. 接口先行SSPC、电源、负载、DAQ 一律经 SSPCTester.Devices.Interfaces 暴露,真假驱动由配置决定。
  3. 按设备粒度切换 Mock/Real:当前不再是“一个全局 MockMode 管全部设备”,而是每类设备都有自己的 UseMock
  4. 配置分层加载:程序先读内置默认值,再读 appsettings.json,最后读 %LOCALAPPDATA%\SSPCTester\settings.json
  5. 测试态独占:进入测试后只展示当前项目,禁止切换其他项目,设备连接由测试态独占。
  6. 文档随代码更新:涉及接口、项目结构、运行方式、持久化格式变化时,要同步更新本文档。

1. 项目背景

1.1 被测对象

固态功率控制器SSPC用于智能配电场景。本项目按 24 路 输出通道建模,通过软件控制每路导通/关断,并测量:

  • 基础通断状态
  • 开启/关断曲线与时间参数
  • 功率损耗与效率
  • 保护功能演示结果

1.2 当前测试台硬件

部件 型号 作用 当前代码状态
工控机 Windows x64 运行 WPF 主程序 已支持
被测件 SSPC 24 路 控制 24 路导通/关断 已有 SspcModbus
程控电源 UDP5080-100 输入端电压/电流读取 已有真实驱动,控制命令保留接口
可编程负载 IT8733P / IT8702P 输出端电压/电流/功率读取 已有真实驱动
高速采集卡 PCIe8586 曲线波形采集 已有 Pcie8586Daq
示波器 Tektronix MDO3024 线下校准基准 不纳入软件控制

1.3 当前实现事实

  • SSPC 24 路通过 3 个 Modbus 模块 × 每模块 8 路 映射。
  • 采集卡实现已经统一为 PCIe8586,不再使用旧文档中的 PCIe9318 命名。
  • 真假设备切换已经演进为 每类设备独立 UseMock
  • 主程序启动后会按配置自动连接 SSPC、电源、负载、DAQ。
  • 根目录脚本 run.ps1 / publish.ps1 已是当前标准运行入口。

2. 当前功能范围

主流程如下:

新建/打开项目
-> 填写项目信息 / 勾选测试项
-> 进入测试态
-> 执行基础测试 / 曲线测试 / 功率损耗 / 保护功能
-> 生成 PDF / Word 报告

2.1 四大模块

模块 当前实现 状态
基础测试 24 路逐路开/关、读电压电流、判定稳态关断 已实现
开启与关断曲线 支持开通/关断波形采集、指标计算、独立曲线视窗、波形落盘 已实现
功率损耗 使用 UDP5080 读输入端IT87xx 读输出端功率/电压/电流 已实现
保护功能 UI、数据结构和演示结果生成已完成真实联动未接 框架完成

2.2 指标口径

当前计算与判定主要围绕以下指标:

  • 1.1 开启时间:到达输入电压 90% 的时间
  • 1.2 关闭时间:下降到输入电压 10% 的时间
  • 1.5 上升/下降时间10%~90% 或 90%~10% 时间
  • 1.9 电压降:Vin - Vout
  • 1.10 / 1.13 功率损耗、效率
  • 1.14+ 保护功能相关故障时间与演示状态

阈值定义和最终判断以 Project.CurveThresholds 与各页结果模型为准。


3. 技术栈

用途 当前选型 说明
UI WPF + .NET 8 net8.0-windowsx64
MVVM CommunityToolkit.Mvvm ObservableObject / RelayCommand
配置 Microsoft.Extensions.Configuration JSON + 用户设置覆盖
DI / Host Microsoft.Extensions.Hosting 启动时装配所有服务
Modbus NModbus SSPC 串口控制
串口 System.IO.Ports SSPC/部分设备底层通信
波形绘制 ScottPlot / ScottPlot.WPF 曲线页与报告插图
报告 QuestPDF + DocumentFormat.OpenXml PDF 与 Word 双实现
Web 预览 Microsoft.Web.WebView2 报告页 PDF 预览
日志 Serilog Debug + 文件输出

4. 解决方案结构

4.1 分层

UI (WPF / XAML / ViewModel)
  -> Logic (测试流程 / 计算 / 报告 / 存储)
    -> Devices.Interfaces (统一设备接口)
      -> Devices.Drivers.Mock / Real (具体驱动)

依赖方向始终是 上层只依赖下层抽象
例如 UI 只拿到 ISspc,不直接感知背后是 MockSspc 还是 SspcModbus

4.2 当前解决方案

SSPCTester.sln
├── SSPCTester.UI/                 # WPF 主程序(启动项)
│   ├── Views/                     # 页面与窗口
│   ├── ViewModels/                # MVVM 视图模型
│   ├── Controls/                  # 自定义控件(含曲线控件)
│   ├── Resources/                 # Tokens / Controls / Icons
│   ├── Converters/                # 状态与颜色转换
│   └── Services/                  # 用户设置、应用配置等
├── SSPCTester.Logic/              # 业务层
│   ├── Testing/                   # 测试模块与运行器
│   ├── Calculation/               # 曲线/功率计算纯函数
│   ├── Report/                    # PDF/Word 报告实现
│   ├── Storage/                   # 项目与波形持久化
│   └── Models/                    # 项目、结果、阈值、枚举
├── SSPCTester.Devices/            # 设备抽象与驱动
│   ├── Interfaces/                # ISspc / IPowerSupply / ILoad / IDaq
│   ├── Drivers/Mock/              # Mock 驱动
│   ├── Drivers/Real/              # 真设备驱动
│   ├── Drivers/ConfigurableDevices.cs  # 按设备切换 Mock/Real
│   ├── Protocol/                  # 协议辅助
│   └── Config/                    # 设备配置模型
├── SSPCTester.Tests/              # xUnit 测试
├── SSPCTester.Seed/               # 示例项目/种子数据生成
└── Docs/PCIe8586驱动接入资料/src/Pcie8586.Driver/
    # 采集卡独立驱动类库,被 Devices/Tests 引用

4.3 关键脚本

  • run.ps1:发布 UI、可选执行单测、可选灌入种子数据、最后启动发布产物
  • publish.ps1:单独发布 WPF 程序
  • SSPCTester.Seed/WriteQualifiedProjects.ps1:生成演示项目

5. 配置与驱动切换

5.1 配置加载顺序

程序启动时配置来源按优先级叠加:

  1. 内置默认配置
  2. SSPCTester.UI/appsettings.json
  3. %LOCALAPPDATA%\SSPCTester\settings.json

用户在设置页修改的路径、报告格式等,最终写到用户目录,不回写仓库里的 appsettings.json

5.2 当前切换策略

当前采用 每类设备独立切换

  • Devices:Sspc:UseMock
  • Devices:PowerSupply:UseMock
  • Devices:Load:UseMock
  • Devices:Daq:UseMock

Devices:MockMode 仅保留兼容旧配置用途,不应再作为新逻辑入口。

5.3 当前 appsettings.json 示例

{
  "Devices": {
    "MockMode": false,
    "Sspc": {
      "UseMock": false,
      "AutoConnect": true,
      "PortName": "COM1",
      "BaudRate": 9600,
      "ModuleAddresses": [1, 2, 3]
    },
    "PowerSupply": {
      "UseMock": false,
      "AutoConnect": true,
      "Host": "192.168.6.5",
      "Port": 5025
    },
    "Load": {
      "UseMock": false,
      "AutoConnect": true,
      "Host": "192.168.200.100",
      "Port": 30000
    },
    "Daq": {
      "UseMock": false,
      "AutoConnect": true,
      "LogicalDeviceId": 0,
      "ChannelCount": 4,
      "PreTriggerMs": 10,
      "PostTriggerMs": 40
    }
  },
  "Storage": {
    "ProjectsRoot": "%LOCALAPPDATA%\\SSPCTester\\Projects"
  },
  "Report": {
    "SavePath": "%LOCALAPPDATA%\\SSPCTester\\Reports",
    "Format": "Pdf"
  }
}

6. 设备接口

所有设备接口均为异步接口,默认支持 CancellationToken

6.1 公共连接接口

public interface IDeviceConnection
{
    bool IsConnected { get; }
    string DisplayName { get; }
    Task<bool> ConnectAsync(CancellationToken ct = default);
    Task DisconnectAsync();
    event EventHandler<bool>? ConnectionChanged;
}

6.2 SSPC

public interface ISspc : IDeviceConnection
{
    int ChannelCount { get; }
    Task TurnOnAsync(int physicalSlot, CancellationToken ct = default);
    Task TurnOffAsync(int physicalSlot, CancellationToken ct = default);
    Task FlashAsync(int physicalSlot, int milliseconds, CancellationToken ct = default);
    Task<bool> GetChannelStateAsync(int physicalSlot, CancellationToken ct = default);
    Task<ChannelMeasurement> ReadMeasurementAsync(int physicalSlot, CancellationToken ct = default);
    Task<IReadOnlyList<ChannelMeasurement>> ReadMeasurementsAsync(CancellationToken ct = default);
}

6.3 电源

public interface IPowerSupply : IDeviceConnection
{
    Task SetVoltageAsync(double volts, CancellationToken ct = default);
    Task SetCurrentLimitAsync(double amps, CancellationToken ct = default);
    Task OutputAsync(bool on, CancellationToken ct = default);
    Task<(double volts, double amps)> ReadAsync(CancellationToken ct = default);
    Task<string> QueryIdentityAsync(CancellationToken ct = default);
}

6.4 负载

public readonly record struct PowerReading(double Volts, double Amps, double Watts);

public interface ILoad : IDeviceConnection
{
    Task SetModeAsync(LoadMode mode, CancellationToken ct = default);
    Task SetValueAsync(double value, CancellationToken ct = default);
    Task InputAsync(bool on, CancellationToken ct = default);
    Task<(double volts, double amps)> ReadAsync(CancellationToken ct = default);
    Task<PowerReading> ReadPowerAsync(CancellationToken ct = default);
    Task<string> QueryIdentityAsync(CancellationToken ct = default);
}

6.5 DAQ

public interface IDaq : IDeviceConnection
{
    Task<IReadOnlyList<DaqDeviceDescriptor>> EnumerateDevicesAsync(CancellationToken ct = default);
    Task<CurveData> CaptureAsync(int[] channels, int sampleRateHz, double durationSec, CancellationToken ct = default);
    Task<double[]> ReadInstantAsync(int[] channels, CancellationToken ct = default);
    Task<CurveData> CaptureAroundActionAsync(
        DaqActionCaptureRequest request,
        Func<CancellationToken, Task> action,
        CancellationToken ct = default);
    event EventHandler<CurveSample>? SampleReceived;
}

CaptureAroundActionAsync() 是当前曲线测试的核心接口:
先进入预采集,再在触发点附近执行开关动作,以得到统一对齐的波形。


7. 核心业务逻辑

7.1 测试模块统一入口

Logic/Testing 中已经落地:

public interface ITestModule
{
    string Name { get; }
    Task RunAsync(TestContext ctx, IProgress<TestProgress> progress, CancellationToken ct);
}

TestContext 当前持有:

  • Project
  • ISspc
  • IPowerSupply
  • ILoad
  • IDaq

TestRunner 依据 Project.Selection 串行执行模块。

7.2 浏览态 / 测试态

当前程序已实现两种应用状态:

  • 浏览态:左侧树显示全部项目,可自由切换
  • 测试态
    • 只显示当前项目
    • 顶部展示“测试进行中”状态条
    • 可中止测试
    • 设备连接视为当前项目独占

这一逻辑由 MainViewModel.AppState 控制。

7.3 基础测试

当前基础测试实现采用 ISspc.ReadMeasurementAsync() 直接读取每路电压/电流:

TurnOnAsync(ch)
-> Delay
-> ReadMeasurementAsync(ch)
-> 记录 VoltageOn / CurrentOn
-> TurnOffAsync(ch)
-> WaitForStableOffAsync(ch)
-> 根据导通和关断稳态结果判定 Pass / Fail

说明:

  • 不是旧文档中的 Daq.ReadInstant() 方案
  • “关断是否稳定”通过 BasicTestCriteria.WaitForStableOffAsync() 判定

7.4 曲线测试

当前代码存在两套相关逻辑:

  1. Logic 模块批处理CurveTest.cs
    • 一次完成开通与关断两段采集
    • 适用于测试模块整体执行
  2. UI 曲线页交互CurveTestViewModel
    • 已拆成两个独立按钮:
      • 开启曲线测试
      • 关断曲线测试
    • 开/关曲线各自保存、各自绘图、各自维护视窗范围

当前页与弹窗的“起点 / 终点 / 默认”已经拆成两套独立状态:

  • RisingViewStartMs / RisingViewEndMs
  • FallingViewStartMs / FallingViewEndMs

这些值会写回 CurveResultRow 并持久化。

状态规则:

  • 两半都没做:Untested
  • 只完成一半:Measured
  • 两半都完成后:才根据 4 个指标判 Pass / Fail

7.5 功率损耗

当前正式实现采用:

  • UDP5080 读取输入端 Vin / Iin
  • IT87xx 读取输出端 Vout / Iout / Pout

这是当前在用方案。
仓库中仍保留旧的 PowerTestLegacyDAQ 思路),但未作为正式模块注册。

7.6 保护功能

当前保护功能页和逻辑层是演示框架

  • UI 已完成
  • 结果模型已完成
  • ProtectTest 目前生成演示数据
  • 未接真实故障触发与真实曲线采集链路

7.7 报告

当前报告支持:

  • PDF
  • Word
  • PDF + Word

报告特性:

  • 基于项目与勾选项动态生成
  • 曲线插图由 CurveImageRenderer 生成
  • 报告文件名不是固定 report.docx,而是动态解析后输出
  • 报告页通过 WebView2 预览 PDF

8. 数据存储

8.1 项目目录

每个项目一个目录,目录根路径由 Storage:ProjectsRoot 决定。
典型内容:

  • project.json
  • curves/
  • 生成出的 PDF / Word 报告

8.2 项目对象

Project 当前持久化内容包括:

  • DUT 信息
  • 测试站点信息
  • 测试项勾选
  • 报告配置
  • 基础测试、曲线测试、功率损耗、保护功能结果
  • 曲线阈值
  • 四页测试说明文本

8.3 波形存储格式

波形不是简单的 JSON而是

  • curves/*.binfloat32 二进制采样数据
  • curves/*.json:元数据

元数据包含:

  • 采样率
  • 触发点位置
  • 通道角色/名称/单位
  • 标定参数

8.4 旧数据兼容

CurveResultRow 中保留了旧字段:

  • ViewStartMs
  • ViewEndMs

新逻辑优先使用:

  • RisingViewStartMs / RisingViewEndMs
  • FallingViewStartMs / FallingViewEndMs

缺失时会回退到旧字段,兼容老项目。


9. 运行与发布

9.1 本地运行

推荐命令:

PowerShell -ExecutionPolicy Bypass -File .\run.ps1

该脚本默认行为:

  1. dotnet publish UI 到 publish\win-x64
  2. 可选执行测试
  3. 可选执行种子数据生成
  4. 直接启动 publish\win-x64\SSPCTester.UI.exe

9.2 常用参数

  • -Test:执行 SSPCTester.Tests
  • -Seed:执行 SSPCTester.Seed
  • -CleanSeed:清空项目目录后重新灌入种子数据
  • -NoLaunch:只发布不启动

9.3 发布

推荐命令:

PowerShell -ExecutionPolicy Bypass -File .\publish.ps1

当前默认发布参数是:

  • Release
  • win-x64
  • SelfContained = true
  • SingleFile = false

说明:

  • 当前脚本明确没有走 WPF 单文件发布默认方案
  • 发布时会检查 ACTS1000_64.dll 是否存在

9.4 运行环境

源码构建至少需要:

  • Windows x64
  • .NET 8 SDK x64
  • WebView2 Runtime

若只运行现成发布版,则至少需要满足发布产物依赖和本机驱动/DLL 条件。


10. 当前状态与后续工作

10.1 已完成

  • WPF 主程序骨架、主题资源、页面导航
  • 浏览态 / 测试态切换
  • 项目新建、加载、保存
  • 基础测试、曲线测试、功率损耗、保护功能页
  • PDF / Word 报告生成
  • 真/假设备可按设备粒度切换
  • 实际 SSPC / 电源 / 负载 / PCIe8586 驱动接入代码

10.2 待统一 / 待完善

  • 保护功能仍为演示逻辑,未接真实测试链路
  • 功率损耗旧版 PowerTestLegacy 仍在仓库,后续应明确去留
  • 曲线弹窗窗口已实现,但当前主页面尚未提供入口按钮
  • 报告生成对新旧曲线视窗字段的使用口径后续建议统一

11. 风险与注意事项

  1. DAQ 仍是最高风险点:厂商 DLL、设备 ID、采样参数、输入量程和触发时序都依赖现场。
  2. Modbus 地址和端口仍需现场核实:虽然当前实现已支持 3 模块映射,但设备地址/串口号应视现场配置为准。
  3. 电源与负载真实驱动已接入,但控制命令支持度需按实物验证
  4. 所有长流程应贯穿 CancellationToken,中止后优先保证设备回到安全状态。
  5. 示波器不纳入软件控制,仅作为线下校准基准。
  6. 任何涉及数据模型持久化格式的修改,都要考虑旧项目兼容

12. 维护建议

  1. 改接口前,先同步修改 Devices.Interfaces、实现类、DI 装配和本文档。
  2. 改项目结构前,先检查 run.ps1publish.ps1Seed、测试项目是否受影响。
  3. 改曲线页前,注意当前已经有“主页面 + 弹窗 + 报告图”的三处视窗相关逻辑。
  4. 改报告前,确认 ReportViewModelLogic/ReportWebView2 预览链路同时保持可用。
  5. 若发现文档内容再次与代码偏离,应优先更新本文档,而不是继续在过时约束上开发。