using Microsoft.Extensions.Options; using SSPCTester.Devices.Config; using SSPCTester.Devices.Interfaces; using SSPCTester.Logic.Models; namespace SSPCTester.Logic.Testing; /// 功率损耗:采集输入/输出两端数据并计算损耗与效率。 public sealed class PowerTestLegacy : ITestModule { private readonly IDaq _daq; private readonly DaqOptions _daqOptions; public PowerTestLegacy(IDaq daq, IOptions options) { _daq = daq; _daqOptions = options.Value.Daq; } public string Name => "功率损耗"; /// 每路采集次数。 public int SamplesPerChannel { get; set; } = 5; /// 采样间隔(ms)。 public int IntervalMs { get; set; } = 100; public async Task RunAsync(TestContext ctx, IProgress progress, CancellationToken ct) { // 输入端电压由高速采集卡读取,输出端电压/电流由 Modbus 继电器端读取。 int daqVoltageChannel = ResolveDaqVoltageChannel(_daqOptions); if (!_daq.IsConnected) await _daq.ConnectAsync(ct).ConfigureAwait(false); if (!ctx.Sspc.IsConnected) await ctx.Sspc.ConnectAsync(ct).ConfigureAwait(false); int n = ctx.Sspc.ChannelCount; ctx.Project.PowerResults.Clear(); for (int ch = 1; ch <= n; ch++) { ct.ThrowIfCancellationRequested(); var row = new PowerLossRow { Channel = ch, Status = TestStatus.Running }; ctx.Project.PowerResults.Add(row); progress.Report(new TestProgress { ModuleName = Name, Step = ch - 1, TotalSteps = n, Message = $"采集 CH{ch} 输入/输出两端数据" }); try { double sumVin = 0, sumVout = 0, sumI = 0; for (int s = 0; s < SamplesPerChannel; s++) { // 输出端:Modbus 继电器端电压 + 通流电流(SSPC 为串联开关,Iin = Iout)。 var measurement = await ctx.Sspc.ReadMeasurementAsync(ch, ct).ConfigureAwait(false); // 输入端:高速采集卡电压。 var daqValues = await _daq.ReadInstantAsync(new[] { daqVoltageChannel }, ct).ConfigureAwait(false); double vin = daqValues.Length > 0 ? daqValues[0] : double.NaN; double vout = measurement.Voltage; double current = Math.Abs(measurement.Current); if (!double.IsFinite(vin) || !double.IsFinite(vout) || !double.IsFinite(current)) throw new InvalidOperationException("功率损耗采样无效:请检查采集卡电压通道标定与 Modbus 连接。"); sumVin += vin; sumVout += vout; sumI += current; await Task.Delay(IntervalMs, ct).ConfigureAwait(false); } row.Vin = sumVin / SamplesPerChannel; row.Vout = sumVout / SamplesPerChannel; row.Iin = sumI / SamplesPerChannel; row.Iout = sumI / SamplesPerChannel; row.Status = TestStatus.Measured; } catch { row.Status = TestStatus.Fail; throw; } progress.Report(new TestProgress { ModuleName = Name, Step = ch, TotalSteps = n, StepStatus = row.Status, Message = $"CH{ch} 损耗={row.PowerLossW:F3}W 效率={row.EfficiencyPct:F3}%" }); } } /// 解析用于输入端电压的高速采集卡通道(取已标定的电压通道,优先 OutputVoltage)。 internal static int ResolveDaqVoltageChannel(DaqOptions options) { if (options.Channels == null || options.Channels.Count == 0) throw new InvalidOperationException("未配置采集卡通道,无法执行功率损耗测试。"); var candidates = options.Channels .Where(x => x.PhysicalChannel >= 0 && x.PhysicalChannel < options.ChannelCount) .Where(x => x.IsCalibrated) .Where(x => IsVoltageRole(x.Role)) .ToArray(); var pick = candidates.FirstOrDefault(x => string.Equals(x.Role, nameof(DaqChannelRole.OutputVoltage), StringComparison.OrdinalIgnoreCase)) ?? candidates.FirstOrDefault(); if (pick == null) throw new InvalidOperationException("功率损耗测试需要一个已标定的采集卡电压通道(输入端电压),请在设置中配置并标定。"); return pick.PhysicalChannel; } private static bool IsVoltageRole(string? role) => Enum.TryParse(role, true, out var parsed) && parsed is DaqChannelRole.OutputVoltage or DaqChannelRole.InputVoltage; }