更新20260605
This commit is contained in:
@@ -301,8 +301,8 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pressureRaw = UshortToInt(data[0], data[1]);
|
var pressureRaw = UshortToInt(data[0], data[1]);
|
||||||
var friction1Raw = UshortToInt(data[6], data[7]);
|
var friction1Raw = UshortToInt(data[2], data[3]);
|
||||||
var friction2Raw = UshortToInt(data[2], data[3]);
|
var friction2Raw = UshortToInt(data[6], data[7]);
|
||||||
|
|
||||||
var conversion = ConvertAdcReadings(pressureRaw, friction1Raw, friction2Raw);
|
var conversion = ConvertAdcReadings(pressureRaw, friction1Raw, friction2Raw);
|
||||||
LogAdcDiagnostic(pressureRaw, friction1Raw, friction2Raw, conversion);
|
LogAdcDiagnostic(pressureRaw, friction1Raw, friction2Raw, conversion);
|
||||||
@@ -525,10 +525,9 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services
|
|||||||
|
|
||||||
var pressure = ConvertAdc(pressureRaw, pressureZero, pressureCoefficient);
|
var pressure = ConvertAdc(pressureRaw, pressureZero, pressureCoefficient);
|
||||||
|
|
||||||
// Keep the old instrument channel wiring: ADC 6/7 uses zero 1 with coefficient 2,
|
// Keep each settings row paired with the same ADC channel used by the legacy zero-capture button.
|
||||||
// and ADC 2/3 uses zero 2 with coefficient 1.
|
var friction1 = ConvertAdc(friction1Raw, frictionZero1, frictionCoefficient1);
|
||||||
var friction1 = ConvertAdc(friction1Raw, frictionZero1, frictionCoefficient2);
|
var friction2 = ConvertAdc(friction2Raw, frictionZero2, frictionCoefficient2);
|
||||||
var friction2 = ConvertAdc(friction2Raw, frictionZero2, frictionCoefficient1);
|
|
||||||
var friction = (friction1 + friction2) * -1.0;
|
var friction = (friction1 + friction2) * -1.0;
|
||||||
return AdcConversionResult.Valid(pressure, friction1, friction2, friction);
|
return AdcConversionResult.Valid(pressure, friction1, friction2, friction);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
|||||||
private const string LegacyPlcPortName = "COM7";
|
private const string LegacyPlcPortName = "COM7";
|
||||||
private const string LegacyAdcPortName = "COM8";
|
private const string LegacyAdcPortName = "COM8";
|
||||||
private static readonly TimeSpan ResetButtonPendingTimeout = TimeSpan.FromMilliseconds(800);
|
private static readonly TimeSpan ResetButtonPendingTimeout = TimeSpan.FromMilliseconds(800);
|
||||||
|
private static readonly TimeSpan RealtimeCurveTraceInterval = TimeSpan.FromSeconds(1);
|
||||||
|
|
||||||
private readonly SlipResistanceDeviceService deviceService = new();
|
private readonly SlipResistanceDeviceService deviceService = new();
|
||||||
private readonly SlipExcelExportService excelExportService = new();
|
private readonly SlipExcelExportService excelExportService = new();
|
||||||
@@ -56,6 +57,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
|||||||
private string activeAdcPortName = string.Empty;
|
private string activeAdcPortName = string.Empty;
|
||||||
private int activeBaudRate;
|
private int activeBaudRate;
|
||||||
private List<SlipDataPoint> lastCompletedRun = [];
|
private List<SlipDataPoint> lastCompletedRun = [];
|
||||||
|
private DateTime lastRealtimeCurveTraceLoggedAt = DateTime.MinValue;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string testNumber = $"SLIP-{DateTime.Now:yyyyMMdd-HHmm}";
|
private string testNumber = $"SLIP-{DateTime.Now:yyyyMMdd-HHmm}";
|
||||||
@@ -672,6 +674,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
|||||||
displacementPoints.Clear();
|
displacementPoints.Clear();
|
||||||
runStopwatch.Restart();
|
runStopwatch.Restart();
|
||||||
UploadProgress = 0;
|
UploadProgress = 0;
|
||||||
|
lastRealtimeCurveTraceLoggedAt = DateTime.MinValue;
|
||||||
CurrentStatus = "测试运行:按标准采集垂直载荷、摩擦力、位移与摩擦系数";
|
CurrentStatus = "测试运行:按标准采集垂直载荷、摩擦力、位移与摩擦系数";
|
||||||
Log.Information("测试开始:TestNumber={TestNumber}, TargetLoad={TargetLoad}, TestSpeed={TestSpeed}", TestNumber, TargetLoadText, TestSpeedText);
|
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));
|
displacementPoints.Add(new ObservablePoint(time, point.DisplacementMm));
|
||||||
|
|
||||||
UploadProgress = Math.Min(99, currentRun.Count);
|
UploadProgress = Math.Min(99, currentRun.Count);
|
||||||
|
TraceRealtimeCurvePoint(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompleteRun()
|
private void CompleteRun()
|
||||||
{
|
{
|
||||||
runStopwatch.Stop();
|
runStopwatch.Stop();
|
||||||
|
LogRealtimeCurveSummary("测试停止");
|
||||||
if (currentRun.Count < 3)
|
if (currentRun.Count < 3)
|
||||||
{
|
{
|
||||||
Log.Warning("测试停止但采样点不足:TestNumber={TestNumber}, PointCount={PointCount}", TestNumber, currentRun.Count);
|
Log.Warning("测试停止但采样点不足:TestNumber={TestNumber}, PointCount={PointCount}", TestNumber, currentRun.Count);
|
||||||
@@ -718,11 +723,18 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
|||||||
.ToList();
|
.ToList();
|
||||||
if (dynamicWindow.Count < MinimumDynamicWindowPointCount)
|
if (dynamicWindow.Count < MinimumDynamicWindowPointCount)
|
||||||
{
|
{
|
||||||
|
var firstWindowPoint = dynamicWindow.FirstOrDefault();
|
||||||
|
var lastWindowPoint = dynamicWindow.LastOrDefault();
|
||||||
Log.Warning(
|
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,
|
TestNumber,
|
||||||
currentRun.Count,
|
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 有效采样点不足,未生成结果";
|
CurrentStatus = "测试已停止,0.3 s~0.6 s 有效采样点不足,未生成结果";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -733,6 +745,28 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
|||||||
var dynamicCoefficientValue = CalculateCoefficient(dynamicForce, dynamicLoad);
|
var dynamicCoefficientValue = CalculateCoefficient(dynamicForce, dynamicLoad);
|
||||||
var verdict = NeedsRetest(staticCoefficientValue, dynamicCoefficientValue) ? "需重测" : "有效";
|
var verdict = NeedsRetest(staticCoefficientValue, dynamicCoefficientValue) ? "需重测" : "有效";
|
||||||
var nextIndex = Samples.Count == 0 ? 1 : Samples.Max(sample => sample.Index) + 1;
|
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(
|
Samples.Insert(0, new TestSample(
|
||||||
nextIndex,
|
nextIndex,
|
||||||
@@ -834,6 +868,111 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
|
|||||||
private static double CalculateCoefficient(double frictionForce, double verticalLoad) =>
|
private static double CalculateCoefficient(double frictionForce, double verticalLoad) =>
|
||||||
Math.Abs(verticalLoad) > 0.0001 ? frictionForce / verticalLoad : 0;
|
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)
|
private async Task RunDeviceCommand(Task command, string successMessage)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
Reference in New Issue
Block a user