91 lines
4.0 KiB
C#
91 lines
4.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
|
|
namespace MultiWheelC.TrajectoryPlanning.PathSmoothing.Comparison;
|
|
|
|
/// <summary>一个方法的固定五次计时样本和确定性结论。</summary>
|
|
public sealed class SmoothingTimingSummary
|
|
{
|
|
/// <summary>创建一个只接受五个已测量样本的计时汇总。</summary>
|
|
public SmoothingTimingSummary(
|
|
IReadOnlyList<double> measuredElapsedMilliseconds,
|
|
bool isDeterministic,
|
|
string diagnostic)
|
|
{
|
|
if (measuredElapsedMilliseconds == null || measuredElapsedMilliseconds.Count != 5)
|
|
throw new ArgumentException("计时汇总必须包含五个已测量样本。", nameof(measuredElapsedMilliseconds));
|
|
|
|
var copy = new List<double>(measuredElapsedMilliseconds.Count);
|
|
for (int index = 0; index < measuredElapsedMilliseconds.Count; index++)
|
|
{
|
|
double value = measuredElapsedMilliseconds[index];
|
|
if (double.IsNaN(value) || double.IsInfinity(value) || value < 0d)
|
|
throw new ArgumentOutOfRangeException(nameof(measuredElapsedMilliseconds), "计时样本必须为有限非负数。");
|
|
copy.Add(value);
|
|
}
|
|
|
|
MeasuredElapsedMilliseconds = new ReadOnlyCollection<double>(copy);
|
|
MedianElapsedMilliseconds = Median(copy);
|
|
IsDeterministic = isDeterministic;
|
|
Diagnostic = diagnostic ?? string.Empty;
|
|
}
|
|
|
|
/// <summary>不含预热执行的五个实测耗时,单位 ms。</summary>
|
|
public IReadOnlyList<double> MeasuredElapsedMilliseconds { get; }
|
|
|
|
/// <summary>五个实测耗时的稳定中位数,单位 ms。</summary>
|
|
public double MedianElapsedMilliseconds { get; }
|
|
|
|
/// <summary>五次输出是否具有相同的状态和稳定几何摘要。</summary>
|
|
public bool IsDeterministic { get; }
|
|
|
|
/// <summary>非确定性或测量失败的稳定诊断说明。</summary>
|
|
public string Diagnostic { get; }
|
|
|
|
/// <summary>从五次测量结果中生成计时汇总,并拒绝状态或几何不稳定的输出。</summary>
|
|
public static SmoothingTimingSummary FromMeasurements(
|
|
IReadOnlyList<double> measuredElapsedMilliseconds,
|
|
IReadOnlyList<PathSmoothingResult> measuredResults)
|
|
{
|
|
if (measuredResults == null || measuredResults.Count != 5)
|
|
throw new ArgumentException("确定性检查必须包含五个测量结果。", nameof(measuredResults));
|
|
for (int index = 0; index < measuredResults.Count; index++)
|
|
{
|
|
if (measuredResults[index] == null)
|
|
throw new ArgumentException("确定性检查不能包含空测量结果。", nameof(measuredResults));
|
|
}
|
|
|
|
PathSmoothingResult canonical = measuredResults[0];
|
|
string canonicalDigest = StableGeometryDigest.Compute(canonical);
|
|
for (int index = 1; index < measuredResults.Count; index++)
|
|
{
|
|
PathSmoothingResult measured = measuredResults[index];
|
|
string digest = StableGeometryDigest.Compute(measured);
|
|
if (measured.Status != canonical.Status ||
|
|
measured.Path.Count != canonical.Path.Count ||
|
|
measured.Segments.Count != canonical.Segments.Count ||
|
|
!string.Equals(digest, canonicalDigest, StringComparison.Ordinal))
|
|
{
|
|
return new SmoothingTimingSummary(
|
|
measuredElapsedMilliseconds,
|
|
false,
|
|
"五次测量的状态、点数、分段数或稳定几何摘要不一致。");
|
|
}
|
|
}
|
|
|
|
return new SmoothingTimingSummary(measuredElapsedMilliseconds, true, string.Empty);
|
|
}
|
|
|
|
internal static double Median(IReadOnlyList<double> values)
|
|
{
|
|
var sorted = new double[values.Count];
|
|
for (int index = 0; index < values.Count; index++) sorted[index] = values[index];
|
|
Array.Sort(sorted);
|
|
int middle = sorted.Length / 2;
|
|
return sorted.Length % 2 == 1
|
|
? sorted[middle]
|
|
: (sorted[middle - 1] + sorted[middle]) / 2d;
|
|
}
|
|
}
|