更新20260605

This commit is contained in:
GukSang.Jin
2026-06-05 15:40:48 +08:00
parent 38eb461c36
commit 6763bc65c3
2 changed files with 146 additions and 8 deletions

View File

@@ -301,8 +301,8 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services
}
var pressureRaw = UshortToInt(data[0], data[1]);
var friction1Raw = UshortToInt(data[6], data[7]);
var friction2Raw = UshortToInt(data[2], data[3]);
var friction1Raw = UshortToInt(data[2], data[3]);
var friction2Raw = UshortToInt(data[6], data[7]);
var conversion = ConvertAdcReadings(pressureRaw, friction1Raw, friction2Raw);
LogAdcDiagnostic(pressureRaw, friction1Raw, friction2Raw, conversion);
@@ -525,10 +525,9 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services
var pressure = ConvertAdc(pressureRaw, pressureZero, pressureCoefficient);
// Keep the old instrument channel wiring: ADC 6/7 uses zero 1 with coefficient 2,
// and ADC 2/3 uses zero 2 with coefficient 1.
var friction1 = ConvertAdc(friction1Raw, frictionZero1, frictionCoefficient2);
var friction2 = ConvertAdc(friction2Raw, frictionZero2, frictionCoefficient1);
// Keep each settings row paired with the same ADC channel used by the legacy zero-capture button.
var friction1 = ConvertAdc(friction1Raw, frictionZero1, frictionCoefficient1);
var friction2 = ConvertAdc(friction2Raw, frictionZero2, frictionCoefficient2);
var friction = (friction1 + friction2) * -1.0;
return AdcConversionResult.Valid(pressure, friction1, friction2, friction);
}

View File

@@ -36,6 +36,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
private const string LegacyPlcPortName = "COM7";
private const string LegacyAdcPortName = "COM8";
private static readonly TimeSpan ResetButtonPendingTimeout = TimeSpan.FromMilliseconds(800);
private static readonly TimeSpan RealtimeCurveTraceInterval = TimeSpan.FromSeconds(1);
private readonly SlipResistanceDeviceService deviceService = new();
private readonly SlipExcelExportService excelExportService = new();
@@ -56,6 +57,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
private string activeAdcPortName = string.Empty;
private int activeBaudRate;
private List<SlipDataPoint> lastCompletedRun = [];
private DateTime lastRealtimeCurveTraceLoggedAt = DateTime.MinValue;
[ObservableProperty]
private string testNumber = $"SLIP-{DateTime.Now:yyyyMMdd-HHmm}";
@@ -672,6 +674,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
displacementPoints.Clear();
runStopwatch.Restart();
UploadProgress = 0;
lastRealtimeCurveTraceLoggedAt = DateTime.MinValue;
CurrentStatus = "测试运行:按标准采集垂直载荷、摩擦力、位移与摩擦系数";
Log.Information("测试开始TestNumber={TestNumber}, TargetLoad={TargetLoad}, TestSpeed={TestSpeed}", TestNumber, TargetLoadText, TestSpeedText);
}
@@ -699,11 +702,13 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
displacementPoints.Add(new ObservablePoint(time, point.DisplacementMm));
UploadProgress = Math.Min(99, currentRun.Count);
TraceRealtimeCurvePoint(point);
}
private void CompleteRun()
{
runStopwatch.Stop();
LogRealtimeCurveSummary("测试停止");
if (currentRun.Count < 3)
{
Log.Warning("测试停止但采样点不足TestNumber={TestNumber}, PointCount={PointCount}", TestNumber, currentRun.Count);
@@ -718,11 +723,18 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
.ToList();
if (dynamicWindow.Count < MinimumDynamicWindowPointCount)
{
var firstWindowPoint = dynamicWindow.FirstOrDefault();
var lastWindowPoint = dynamicWindow.LastOrDefault();
Log.Warning(
"测试停止但动摩擦窗口采样点不足TestNumber={TestNumber}, PointCount={PointCount}, DynamicWindowPointCount={DynamicWindowPointCount}",
"测试停止但动摩擦窗口采样点不足TestNumber={TestNumber}, PointCount={PointCount}, DynamicWindow=0.300-0.600s, DynamicWindowPointCount={DynamicWindowPointCount}, RequiredPointCount={RequiredPointCount}, ActualWindowStart={ActualWindowStart}, ActualWindowEnd={ActualWindowEnd}, FirstSampleTime={FirstSampleTime:F3}s, LastSampleTime={LastSampleTime:F3}s",
TestNumber,
currentRun.Count,
dynamicWindow.Count);
dynamicWindow.Count,
MinimumDynamicWindowPointCount,
FormatNullable(firstWindowPoint?.TimeSeconds),
FormatNullable(lastWindowPoint?.TimeSeconds),
currentRun[0].TimeSeconds,
currentRun[^1].TimeSeconds);
CurrentStatus = "测试已停止0.3 s~0.6 s 有效采样点不足,未生成结果";
return;
}
@@ -733,6 +745,28 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
var dynamicCoefficientValue = CalculateCoefficient(dynamicForce, dynamicLoad);
var verdict = NeedsRetest(staticCoefficientValue, dynamicCoefficientValue) ? "需重测" : "有效";
var nextIndex = Samples.Count == 0 ? 1 : Samples.Max(sample => sample.Index) + 1;
var peakIndex = currentRun.IndexOf(peak) + 1;
var dynamicStart = dynamicWindow[0].TimeSeconds;
var dynamicEnd = dynamicWindow[^1].TimeSeconds;
Log.Information(
"静/动摩擦计算明细TestNumber={TestNumber}, PointCount={PointCount}, StaticSearchWindow=0.000-{StaticSearchEnd:F3}s, StaticPointIndex={StaticPointIndex}, StaticTime={StaticTime:F3}s, StaticFriction={StaticFriction:F3}N, StaticLoad={StaticLoad:F3}N, StaticCoefficient={StaticCoefficient:F5}, DynamicWindow={DynamicWindowStart:F3}-{DynamicWindowEnd:F3}s, DynamicActualWindow={DynamicActualStart:F3}-{DynamicActualEnd:F3}s, DynamicPointCount={DynamicPointCount}, DynamicAvgFriction={DynamicAvgFriction:F3}N, DynamicAvgLoad={DynamicAvgLoad:F3}N, DynamicCoefficient={DynamicCoefficient:F5}",
TestNumber,
currentRun.Count,
DynamicWindowStartSeconds,
peakIndex,
peak.TimeSeconds,
peak.HorizontalFrictionN,
peak.VerticalLoadN,
staticCoefficientValue,
DynamicWindowStartSeconds,
DynamicWindowEndSeconds,
dynamicStart,
dynamicEnd,
dynamicWindow.Count,
dynamicForce,
dynamicLoad,
dynamicCoefficientValue);
Samples.Insert(0, new TestSample(
nextIndex,
@@ -834,6 +868,111 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
private static double CalculateCoefficient(double frictionForce, double verticalLoad) =>
Math.Abs(verticalLoad) > 0.0001 ? frictionForce / verticalLoad : 0;
private void LogRealtimeCurveSummary(string stage)
{
var expectedCount = currentRun.Count;
var countsMatch =
verticalLoadPoints.Count == expectedCount
&& horizontalFrictionPoints.Count == expectedCount
&& frictionCoefficientPoints.Count == expectedCount
&& displacementPoints.Count == expectedCount;
var lastPoint = currentRun.Count > 0 ? currentRun[^1] : null;
Log.Information(
"实时曲线同步汇总Stage={Stage}, TestNumber={TestNumber}, DataPointCount={DataPointCount}, ChartCounts=[Vertical:{VerticalCount}, Friction:{FrictionCount}, Coefficient:{CoefficientCount}, Displacement:{DisplacementCount}], CountsMatch={CountsMatch}, LastDataPoint={LastDataPoint}, ChartLast=[Vertical:{VerticalChart}, Friction:{FrictionChart}, Coefficient:{CoefficientChart}, Displacement:{DisplacementChart}]",
stage,
TestNumber,
expectedCount,
verticalLoadPoints.Count,
horizontalFrictionPoints.Count,
frictionCoefficientPoints.Count,
displacementPoints.Count,
countsMatch,
FormatDataPoint(lastPoint),
FormatChartPoint(verticalLoadPoints.Count > 0 ? verticalLoadPoints[^1] : null),
FormatChartPoint(horizontalFrictionPoints.Count > 0 ? horizontalFrictionPoints[^1] : null),
FormatChartPoint(frictionCoefficientPoints.Count > 0 ? frictionCoefficientPoints[^1] : null),
FormatChartPoint(displacementPoints.Count > 0 ? displacementPoints[^1] : null));
}
private void TraceRealtimeCurvePoint(SlipDataPoint point)
{
var expectedCount = currentRun.Count;
var countsMatch =
verticalLoadPoints.Count == expectedCount
&& horizontalFrictionPoints.Count == expectedCount
&& frictionCoefficientPoints.Count == expectedCount
&& displacementPoints.Count == expectedCount;
var valuesMatch =
countsMatch
&& ChartPointMatches(verticalLoadPoints[^1], point.TimeSeconds, point.VerticalLoadN)
&& ChartPointMatches(horizontalFrictionPoints[^1], point.TimeSeconds, point.HorizontalFrictionN)
&& ChartPointMatches(frictionCoefficientPoints[^1], point.TimeSeconds, point.FrictionCoefficient)
&& ChartPointMatches(displacementPoints[^1], point.TimeSeconds, point.DisplacementMm);
if (!countsMatch || !valuesMatch)
{
Log.Warning(
"实时曲线数据不同步TestNumber={TestNumber}, PointIndex={PointIndex}, ExpectedCount={ExpectedCount}, Counts=[Vertical:{VerticalCount}, Friction:{FrictionCount}, Coefficient:{CoefficientCount}, Displacement:{DisplacementCount}], ValuesMatch={ValuesMatch}, DataPoint=[Time:{Time:F3}s, Vertical:{Vertical:F3}N, Friction:{Friction:F3}N, Coefficient:{Coefficient:F5}, Displacement:{Displacement:F3}mm], ChartLast=[Vertical:{VerticalChart}, Friction:{FrictionChart}, Coefficient:{CoefficientChart}, Displacement:{DisplacementChart}]",
TestNumber,
expectedCount,
expectedCount,
verticalLoadPoints.Count,
horizontalFrictionPoints.Count,
frictionCoefficientPoints.Count,
displacementPoints.Count,
valuesMatch,
point.TimeSeconds,
point.VerticalLoadN,
point.HorizontalFrictionN,
point.FrictionCoefficient,
point.DisplacementMm,
FormatChartPoint(verticalLoadPoints.Count > 0 ? verticalLoadPoints[^1] : null),
FormatChartPoint(horizontalFrictionPoints.Count > 0 ? horizontalFrictionPoints[^1] : null),
FormatChartPoint(frictionCoefficientPoints.Count > 0 ? frictionCoefficientPoints[^1] : null),
FormatChartPoint(displacementPoints.Count > 0 ? displacementPoints[^1] : null));
return;
}
var now = DateTime.UtcNow;
if (expectedCount > 3 && now - lastRealtimeCurveTraceLoggedAt < RealtimeCurveTraceInterval)
{
return;
}
lastRealtimeCurveTraceLoggedAt = now;
Log.Debug(
"实时曲线点同步TestNumber={TestNumber}, PointIndex={PointIndex}, Time={Time:F3}s, Vertical={Vertical:F3}N, Friction={Friction:F3}N, Coefficient={Coefficient:F5}, Displacement={Displacement:F3}mm, InDynamicWindow={InDynamicWindow}, ChartCount={ChartCount}",
TestNumber,
expectedCount,
point.TimeSeconds,
point.VerticalLoadN,
point.HorizontalFrictionN,
point.FrictionCoefficient,
point.DisplacementMm,
point.TimeSeconds >= DynamicWindowStartSeconds && point.TimeSeconds <= DynamicWindowEndSeconds,
expectedCount);
}
private static bool ChartPointMatches(ObservablePoint chartPoint, double expectedX, double expectedY) =>
NearlyEquals(chartPoint.X, expectedX) && NearlyEquals(chartPoint.Y, expectedY);
private static bool NearlyEquals(double? actual, double expected) =>
actual.HasValue && Math.Abs(actual.Value - expected) < 0.000001;
private static string FormatChartPoint(ObservablePoint? point) =>
point is null
? "null"
: $"({FormatNullable(point.X)},{FormatNullable(point.Y)})";
private static string FormatNullable(double? value) =>
value.HasValue ? value.Value.ToString("F3", CultureInfo.InvariantCulture) : "null";
private static string FormatDataPoint(SlipDataPoint? point) =>
point is null
? "null"
: $"Time={point.TimeSeconds.ToString("F3", CultureInfo.InvariantCulture)}s, Vertical={point.VerticalLoadN.ToString("F3", CultureInfo.InvariantCulture)}N, Friction={point.HorizontalFrictionN.ToString("F3", CultureInfo.InvariantCulture)}N, Coefficient={point.FrictionCoefficient.ToString("F5", CultureInfo.InvariantCulture)}, Displacement={point.DisplacementMm.ToString("F3", CultureInfo.InvariantCulture)}mm";
private async Task RunDeviceCommand(Task command, string successMessage)
{
try