更新202606222

This commit is contained in:
GukSang.Jin
2026-06-22 11:04:39 +08:00
parent 7241d043c0
commit 4e751755bc
2 changed files with 111 additions and 29 deletions

View File

@@ -533,11 +533,21 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services
var pressure = ConvertAdc(pressureRaw, pressureZero, pressureCoefficient); var pressure = ConvertAdc(pressureRaw, pressureZero, pressureCoefficient);
// Keep each settings row paired with the same ADC channel used by the legacy zero-capture button. var namedFriction1 = ConvertAdc(friction1Raw, frictionZero1, frictionCoefficient1);
var friction1 = ConvertAdc(friction1Raw, frictionZero1, frictionCoefficient1); var namedFriction2 = ConvertAdc(friction2Raw, frictionZero2, frictionCoefficient2);
var friction2 = ConvertAdc(friction2Raw, frictionZero2, frictionCoefficient2); var namedFriction = (namedFriction1 + namedFriction2) * -1.0;
var friction = (friction1 + friction2) * -1.0;
return AdcConversionResult.Valid(pressure, friction1, friction2, friction); var legacyFriction1 = ConvertAdc(friction2Raw, frictionZero1, frictionCoefficient2);
var legacyFriction2 = ConvertAdc(friction1Raw, frictionZero2, frictionCoefficient1);
var legacyFriction = (legacyFriction1 + legacyFriction2) * -1.0;
return AdcConversionResult.Valid(
pressure,
namedFriction1,
namedFriction2,
namedFriction,
legacyFriction1,
legacyFriction2,
legacyFriction);
} }
private bool ValidateAdcSettings( private bool ValidateAdcSettings(
@@ -606,14 +616,18 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services
if (conversion.IsValid) if (conversion.IsValid)
{ {
Log.Debug( Log.Debug(
"ADC 采样RawPressure={RawPressure}, RawFriction1={RawFriction1}, RawFriction2={RawFriction2}, Pressure={Pressure:F3} N, Friction1={Friction1:F3} N, Friction2={Friction2:F3} N, Friction={Friction:F3} N, Coefficients=[P:{PressureCoefficient}, F1:{FrictionCoefficient1}, F2:{FrictionCoefficient2}], Zeros=[P:{PressureZero}, F1:{FrictionZero1}, F2:{FrictionZero2}]", "ADC 采样RawPressure={RawPressure}, RawFriction1={RawFriction1}, RawFriction2={RawFriction2}, Pressure={Pressure:F3} N, FrictionMode=LegacyCross, FinalFriction={Friction:F3} N, LegacyFriction1={LegacyFriction1:F3} N, LegacyFriction2={LegacyFriction2:F3} N, NamedFriction1={NamedFriction1:F3} N, NamedFriction2={NamedFriction2:F3} N, NamedFriction={NamedFriction:F3} N, FrictionDelta={FrictionDelta:F3} N, Coefficients=[P:{PressureCoefficient}, F1:{FrictionCoefficient1}, F2:{FrictionCoefficient2}], Zeros=[P:{PressureZero}, F1:{FrictionZero1}, F2:{FrictionZero2}]",
pressureRaw, pressureRaw,
friction1Raw, friction1Raw,
friction2Raw, friction2Raw,
conversion.Pressure, conversion.Pressure,
conversion.Friction1,
conversion.Friction2,
conversion.Friction, conversion.Friction,
conversion.LegacyFriction1,
conversion.LegacyFriction2,
conversion.NamedFriction1,
conversion.NamedFriction2,
conversion.NamedFriction,
conversion.Friction - conversion.NamedFriction,
settings.NormalPressureCoefficient, settings.NormalPressureCoefficient,
settings.FrictionCoefficient1, settings.FrictionCoefficient1,
settings.FrictionCoefficient2, settings.FrictionCoefficient2,
@@ -734,16 +748,35 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services
private readonly record struct AdcConversionResult( private readonly record struct AdcConversionResult(
bool IsValid, bool IsValid,
double Pressure, double Pressure,
double Friction1, double NamedFriction1,
double Friction2, double NamedFriction2,
double NamedFriction,
double LegacyFriction1,
double LegacyFriction2,
double Friction, double Friction,
string Error) string Error)
{ {
public static AdcConversionResult Valid(double pressure, double friction1, double friction2, double friction) => public static AdcConversionResult Valid(
new(true, pressure, friction1, friction2, friction, string.Empty); double pressure,
double namedFriction1,
double namedFriction2,
double namedFriction,
double legacyFriction1,
double legacyFriction2,
double friction) =>
new(
true,
pressure,
namedFriction1,
namedFriction2,
namedFriction,
legacyFriction1,
legacyFriction2,
friction,
string.Empty);
public static AdcConversionResult Invalid(string error) => public static AdcConversionResult Invalid(string error) =>
new(false, 0, 0, 0, 0, error); new(false, 0, 0, 0, 0, 0, 0, 0, error);
} }
} }
} }

View File

@@ -36,10 +36,13 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
private const double MinimumAnalysisLoadRatio = 0.8; private const double MinimumAnalysisLoadRatio = 0.8;
// 预触发缓冲:滑动检测前持续缓存的力/位移历史长度,用于回溯真实滑动起点(保证第一个摩擦力峰值被采到)。 // 预触发缓冲:滑动检测前持续缓存的力/位移历史长度,用于回溯真实滑动起点(保证第一个摩擦力峰值被采到)。
private const double PreTriggerWindowSeconds = 0.5; private const double PreTriggerWindowSeconds = 0.5;
// 滑动检测:载荷达标后,水平摩擦力较静置接触基线上升超过该值即判定已进入滑动 // 滑动检测:载荷达标后只接受明显陡升,避免低幅慢漂移提前把曲线 0 点定错
private const double SlidingFrictionTriggerRiseN = 5.0; private const double SlidingFrictionTriggerRiseN = 35.0;
// 回溯滑动起点:从检测点向前回溯,直到摩擦力回到基线附近(该裕度内)即认定为 onsett=0 private const double SlidingFrictionTriggerLookbackSeconds = 0.12;
private const double SlidingOnsetFrictionMarginN = 2.0; private const double SlidingFrictionTriggerSlopeN = 25.0;
private const double SlidingDisplacementFrictionRiseN = 20.0;
// 回溯滑动起点:在触发前短窗口内找摩擦最低点,贴近标准曲线中首峰前的真实滑动起点。
private const double SlidingOnsetSearchBackSeconds = 0.12;
// 曲线/分析窗口:滑动开始后只保留该时长,剔除加载段与滑动后回程,对应标准曲线图的有效区间。 // 曲线/分析窗口:滑动开始后只保留该时长,剔除加载段与滑动后回程,对应标准曲线图的有效区间。
private const double CurveEndSeconds = 1.0; private const double CurveEndSeconds = 1.0;
private const int StaticPeakDropConfirmationPointCount = 3; private const int StaticPeakDropConfirmationPointCount = 3;
@@ -900,26 +903,67 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
return; return;
} }
var frictionRose = samplePoint.HorizontalFrictionN - slidingBaselineFrictionN >= SlidingFrictionTriggerRiseN; var frictionRiseFromBaseline = samplePoint.HorizontalFrictionN - slidingBaselineFrictionN;
var lookbackPoint = FindLookbackPoint(samplePoint.TimeSeconds - SlidingFrictionTriggerLookbackSeconds);
var frictionRiseFromLookback = lookbackPoint is null
? 0
: samplePoint.HorizontalFrictionN - lookbackPoint.HorizontalFrictionN;
var frictionRose = frictionRiseFromBaseline >= SlidingFrictionTriggerRiseN
&& frictionRiseFromLookback >= SlidingFrictionTriggerSlopeN;
var displacementMoved = Math.Abs(samplePoint.DisplacementMm - runStartDisplacementMm) >= SlidingStartDisplacementThresholdMm; var displacementMoved = Math.Abs(samplePoint.DisplacementMm - runStartDisplacementMm) >= SlidingStartDisplacementThresholdMm;
if (frictionRose || displacementMoved) var displacementWithFriction = displacementMoved
&& frictionRiseFromBaseline >= SlidingDisplacementFrictionRiseN;
if (frictionRose || displacementWithFriction)
{ {
MarkSlidingStartFromBuffer(frictionRose ? "FrictionRise" : "DisplacementMove"); MarkSlidingStartFromBuffer(frictionRose ? "FrictionSharpRise" : "DisplacementWithFrictionRise");
return;
}
if (displacementMoved)
{
Log.Debug(
"滑动起点候选未触发TestNumber={TestNumber}, Reason=DisplacementWithoutFrictionRise, DisplacementDelta={DisplacementDelta:F3}mm, FrictionRiseFromBaseline={FrictionRiseFromBaseline:F3}N, FrictionRiseFromLookback={FrictionRiseFromLookback:F3}N, BaselineFriction={BaselineFriction:F3}N, CurrentFriction={CurrentFriction:F3}N",
TestNumber,
Math.Abs(samplePoint.DisplacementMm - runStartDisplacementMm),
frictionRiseFromBaseline,
frictionRiseFromLookback,
slidingBaselineFrictionN,
samplePoint.HorizontalFrictionN);
} }
} }
// 回溯预触发缓冲到摩擦力刚离开基线的那一刻设为 t=0并把该时刻起的缓冲点补进曲线保证第一个峰值被采到。 private SlipDataPoint? FindLookbackPoint(double targetTime)
private void MarkSlidingStartFromBuffer(string trigger)
{ {
var onsetIndex = preTriggerBuffer.Count - 1; for (var index = preTriggerBuffer.Count - 1; index >= 0; index--)
while (onsetIndex > 0
&& preTriggerBuffer[onsetIndex - 1].HorizontalFrictionN > slidingBaselineFrictionN + SlidingOnsetFrictionMarginN)
{ {
onsetIndex--; if (preTriggerBuffer[index].TimeSeconds <= targetTime)
{
return preTriggerBuffer[index];
}
}
return preTriggerBuffer.Count > 0 ? preTriggerBuffer[0] : null;
}
// 回溯预触发缓冲到摩擦力陡升前的低点设为 t=0并把该时刻起的缓冲点补进曲线保证第一个峰值被采到。
private void MarkSlidingStartFromBuffer(string trigger)
{
var triggerPoint = preTriggerBuffer[^1];
var earliestOnsetTime = triggerPoint.TimeSeconds - SlidingOnsetSearchBackSeconds;
var onsetIndex = preTriggerBuffer.Count - 1;
for (var index = preTriggerBuffer.Count - 1; index >= 0; index--)
{
if (preTriggerBuffer[index].TimeSeconds < earliestOnsetTime)
{
break;
}
if (preTriggerBuffer[index].HorizontalFrictionN <= preTriggerBuffer[onsetIndex].HorizontalFrictionN)
{
onsetIndex = index;
}
} }
// 多回退一个点(≈基线水平)作为 t=0使曲线起点的摩擦力接近基线、随后升至首峰与标准曲线一致。
onsetIndex = Math.Max(0, onsetIndex - 1);
var onset = preTriggerBuffer[onsetIndex]; var onset = preTriggerBuffer[onsetIndex];
slidingStartTimeSeconds = onset.TimeSeconds; slidingStartTimeSeconds = onset.TimeSeconds;
slidingStartDisplacementMm = onset.DisplacementMm; slidingStartDisplacementMm = onset.DisplacementMm;
@@ -940,12 +984,17 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
CurrentStatus = "已检测到有效滑动开始:曲线从 0.000 s 开始记录"; CurrentStatus = "已检测到有效滑动开始:曲线从 0.000 s 开始记录";
Log.Information( Log.Information(
"检测到有效滑动开始并建立曲线零点TestNumber={TestNumber}, Trigger={Trigger}, SlidingStartTime={SlidingStartTime:F3}s, BaselineFriction={BaselineFriction:F3}N, OnsetDisplacement={OnsetDisplacement:F3}mm, FlushedPointCount={FlushedPointCount}", "检测到有效滑动开始并建立曲线零点TestNumber={TestNumber}, Trigger={Trigger}, SlidingStartTime={SlidingStartTime:F3}s, TriggerTime={TriggerTime:F3}s, BaselineFriction={BaselineFriction:F3}N, OnsetFriction={OnsetFriction:F3}N, TriggerFriction={TriggerFriction:F3}N, FrictionRise={FrictionRise:F3}N, OnsetDisplacement={OnsetDisplacement:F3}mm, TriggerDisplacement={TriggerDisplacement:F3}mm, FlushedPointCount={FlushedPointCount}",
TestNumber, TestNumber,
trigger, trigger,
onset.TimeSeconds, onset.TimeSeconds,
triggerPoint.TimeSeconds,
slidingBaselineFrictionN, slidingBaselineFrictionN,
onset.HorizontalFrictionN,
triggerPoint.HorizontalFrictionN,
triggerPoint.HorizontalFrictionN - onset.HorizontalFrictionN,
slidingStartDisplacementMm, slidingStartDisplacementMm,
triggerPoint.DisplacementMm,
currentRun.Count); currentRun.Count);
} }