更新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);
// 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);
var namedFriction1 = ConvertAdc(friction1Raw, frictionZero1, frictionCoefficient1);
var namedFriction2 = ConvertAdc(friction2Raw, frictionZero2, frictionCoefficient2);
var namedFriction = (namedFriction1 + namedFriction2) * -1.0;
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(
@@ -606,14 +616,18 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services
if (conversion.IsValid)
{
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,
friction1Raw,
friction2Raw,
conversion.Pressure,
conversion.Friction1,
conversion.Friction2,
conversion.Friction,
conversion.LegacyFriction1,
conversion.LegacyFriction2,
conversion.NamedFriction1,
conversion.NamedFriction2,
conversion.NamedFriction,
conversion.Friction - conversion.NamedFriction,
settings.NormalPressureCoefficient,
settings.FrictionCoefficient1,
settings.FrictionCoefficient2,
@@ -734,16 +748,35 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services
private readonly record struct AdcConversionResult(
bool IsValid,
double Pressure,
double Friction1,
double Friction2,
double NamedFriction1,
double NamedFriction2,
double NamedFriction,
double LegacyFriction1,
double LegacyFriction2,
double Friction,
string Error)
{
public static AdcConversionResult Valid(double pressure, double friction1, double friction2, double friction) =>
new(true, pressure, friction1, friction2, friction, string.Empty);
public static AdcConversionResult Valid(
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) =>
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 PreTriggerWindowSeconds = 0.5;
// 滑动检测:载荷达标后,水平摩擦力较静置接触基线上升超过该值即判定已进入滑动
private const double SlidingFrictionTriggerRiseN = 5.0;
// 回溯滑动起点:从检测点向前回溯,直到摩擦力回到基线附近(该裕度内)即认定为 onsett=0
private const double SlidingOnsetFrictionMarginN = 2.0;
// 滑动检测:载荷达标后只接受明显陡升,避免低幅慢漂移提前把曲线 0 点定错
private const double SlidingFrictionTriggerRiseN = 35.0;
private const double SlidingFrictionTriggerLookbackSeconds = 0.12;
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 int StaticPeakDropConfirmationPointCount = 3;
@@ -900,26 +903,67 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
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;
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)
{
for (var index = preTriggerBuffer.Count - 1; index >= 0; index--)
{
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;
while (onsetIndex > 0
&& preTriggerBuffer[onsetIndex - 1].HorizontalFrictionN > slidingBaselineFrictionN + SlidingOnsetFrictionMarginN)
for (var index = preTriggerBuffer.Count - 1; index >= 0; index--)
{
onsetIndex--;
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];
slidingStartTimeSeconds = onset.TimeSeconds;
slidingStartDisplacementMm = onset.DisplacementMm;
@@ -940,12 +984,17 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel
CurrentStatus = "已检测到有效滑动开始:曲线从 0.000 s 开始记录";
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,
trigger,
onset.TimeSeconds,
triggerPoint.TimeSeconds,
slidingBaselineFrictionN,
onset.HorizontalFrictionN,
triggerPoint.HorizontalFrictionN,
triggerPoint.HorizontalFrictionN - onset.HorizontalFrictionN,
slidingStartDisplacementMm,
triggerPoint.DisplacementMm,
currentRun.Count);
}