SSPC-Tester/SSPCTester.Logic/Testing/PowerTest.cs

104 lines
4.7 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.Extensions.Options;
using SSPCTester.Devices.Config;
using SSPCTester.Devices.Interfaces;
using SSPCTester.Logic.Models;
namespace SSPCTester.Logic.Testing;
/// <summary>功率损耗:采集输入/输出两端数据并计算损耗与效率。</summary>
public sealed class PowerTestLegacy : ITestModule
{
private readonly IDaq _daq;
private readonly DaqOptions _daqOptions;
public PowerTestLegacy(IDaq daq, IOptions<DeviceOptions> options)
{
_daq = daq;
_daqOptions = options.Value.Daq;
}
public string Name => "功率损耗";
/// <summary>每路采集次数。</summary>
public int SamplesPerChannel { get; set; } = 5;
/// <summary>采样间隔ms。</summary>
public int IntervalMs { get; set; } = 100;
public async Task RunAsync(TestContext ctx, IProgress<TestProgress> 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}%" });
}
}
/// <summary>解析用于输入端电压的高速采集卡通道(取已标定的电压通道,优先 OutputVoltage。</summary>
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<DaqChannelRole>(role, true, out var parsed)
&& parsed is DaqChannelRole.OutputVoltage or DaqChannelRole.InputVoltage;
}