更新4/28
This commit is contained in:
@@ -51,6 +51,8 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
private const ushort RegisterHorizontalDisplacement = 360;
|
private const ushort RegisterHorizontalDisplacement = 360;
|
||||||
private const ushort RegisterLiftSpeed = 310;
|
private const ushort RegisterLiftSpeed = 310;
|
||||||
private const ushort RegisterLiftDisplacement = 320;
|
private const ushort RegisterLiftDisplacement = 320;
|
||||||
|
private static readonly TimeSpan RealtimeChartRefreshInterval = TimeSpan.FromMilliseconds(250);
|
||||||
|
private const double RealtimeChartDisplacementStepMm = 0.5;
|
||||||
|
|
||||||
private readonly DispatcherTimer _timer;
|
private readonly DispatcherTimer _timer;
|
||||||
private readonly DispatcherTimer _deviceReconnectTimer;
|
private readonly DispatcherTimer _deviceReconnectTimer;
|
||||||
@@ -125,6 +127,11 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
private ushort? _pendingTableMotionStopCoil;
|
private ushort? _pendingTableMotionStopCoil;
|
||||||
private MachineRuntimeState _machineRuntimeState = MachineRuntimeState.Idle;
|
private MachineRuntimeState _machineRuntimeState = MachineRuntimeState.Idle;
|
||||||
private string _plcCommandSummary = "等待 PLC 控制指令。";
|
private string _plcCommandSummary = "等待 PLC 控制指令。";
|
||||||
|
private double _runningPeakForceN;
|
||||||
|
private double _kineticForceSum;
|
||||||
|
private int _kineticSampleCount;
|
||||||
|
private double _lastRealtimeChartDisplacementMm = double.NaN;
|
||||||
|
private DateTime _lastRealtimeChartRefreshAt = DateTime.MinValue;
|
||||||
|
|
||||||
public MainViewModel()
|
public MainViewModel()
|
||||||
{
|
{
|
||||||
@@ -758,6 +765,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
_peakLineSamples.Clear();
|
_peakLineSamples.Clear();
|
||||||
_averageLineSamples.Clear();
|
_averageLineSamples.Clear();
|
||||||
_currentPointSample.Clear();
|
_currentPointSample.Clear();
|
||||||
|
ResetRealtimeSamplingMetrics();
|
||||||
CurrentForceN = 0;
|
CurrentForceN = 0;
|
||||||
CurrentDisplacementMm = 0;
|
CurrentDisplacementMm = 0;
|
||||||
CurrentPeakForceN = 0;
|
CurrentPeakForceN = 0;
|
||||||
@@ -930,7 +938,6 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_forceSamples.Add(new ObservablePoint(frame.DisplacementMm, CurrentForceN));
|
|
||||||
_currentRunSamples.Add(new RawSampleRecord
|
_currentRunSamples.Add(new RawSampleRecord
|
||||||
{
|
{
|
||||||
RunId = _activeRunId,
|
RunId = _activeRunId,
|
||||||
@@ -940,8 +947,9 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
ForceN = CurrentForceN,
|
ForceN = CurrentForceN,
|
||||||
SpeedMmPerMin = frame.SpeedMmPerMin
|
SpeedMmPerMin = frame.SpeedMmPerMin
|
||||||
});
|
});
|
||||||
|
AddRealtimeChartSample(frame.DisplacementMm, CurrentForceN);
|
||||||
UpdateCurrentPoint(frame.DisplacementMm, CurrentForceN);
|
UpdateCurrentPoint(frame.DisplacementMm, CurrentForceN);
|
||||||
UpdatePreviewResult();
|
UpdatePreviewResult(frame.DisplacementMm, CurrentForceN);
|
||||||
StaticCoefficient1 = frame.StaticCoefficient1;
|
StaticCoefficient1 = frame.StaticCoefficient1;
|
||||||
KineticCoefficient1 = frame.KineticCoefficient1;
|
KineticCoefficient1 = frame.KineticCoefficient1;
|
||||||
StandardDeviation1 = frame.StandardDeviation1;
|
StandardDeviation1 = frame.StandardDeviation1;
|
||||||
@@ -952,19 +960,16 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
CurrentStaticCoefficient = ResolveRepresentativeValue(activeReplicateCount, StaticCoefficient1, StaticCoefficient2);
|
CurrentStaticCoefficient = ResolveRepresentativeValue(activeReplicateCount, StaticCoefficient1, StaticCoefficient2);
|
||||||
CurrentKineticCoefficient = ResolveRepresentativeValue(activeReplicateCount, KineticCoefficient1, KineticCoefficient2);
|
CurrentKineticCoefficient = ResolveRepresentativeValue(activeReplicateCount, KineticCoefficient1, KineticCoefficient2);
|
||||||
TrialProgressPercent = Math.Min(100, frame.DisplacementMm / Math.Max(Recipe.TravelMm, 1) * 100);
|
TrialProgressPercent = Math.Min(100, frame.DisplacementMm / Math.Max(Recipe.TravelMm, 1) * 100);
|
||||||
UpdateReferenceLines();
|
|
||||||
|
|
||||||
ForceXAxes[0].MaxLimit = Math.Max(Recipe.TravelMm, frame.DisplacementMm + 5);
|
|
||||||
ForceYAxes[0].MaxLimit = Math.Max(CurrentPeakForceN * 1.15, 0.5);
|
|
||||||
_kineticBand.Yj = Math.Max(CurrentPeakForceN * 1.15, 0.5);
|
|
||||||
OnPropertyChanged(nameof(ForceXAxes));
|
|
||||||
OnPropertyChanged(nameof(ForceYAxes));
|
|
||||||
OnPropertyChanged(nameof(ForceSections));
|
|
||||||
|
|
||||||
if (frame.IsCompleted)
|
if (frame.IsCompleted)
|
||||||
{
|
{
|
||||||
|
RefreshRealtimeChartPresentation(force: true);
|
||||||
FinalizeRun();
|
FinalizeRun();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RefreshRealtimeChartPresentation(force: false);
|
||||||
|
}
|
||||||
|
|
||||||
RaiseStatusProperties();
|
RaiseStatusProperties();
|
||||||
}
|
}
|
||||||
@@ -1038,15 +1043,43 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
RaiseStatusProperties();
|
RaiseStatusProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdatePreviewResult()
|
private void AddRealtimeChartSample(double displacementMm, double forceN)
|
||||||
{
|
{
|
||||||
CurrentPeakForceN = _forceSamples.Count == 0 ? 0 : _forceSamples.Max(sample => sample.Coordinate.SecondaryValue);
|
var sample = new ObservablePoint(displacementMm, forceN);
|
||||||
|
if (_forceSamples.Count == 0 || !IsFinite(_lastRealtimeChartDisplacementMm))
|
||||||
if (_forceSamples.Count > 5)
|
|
||||||
{
|
{
|
||||||
var kineticWindow = _forceSamples.Skip((int)(_forceSamples.Count * 0.35)).ToArray();
|
_forceSamples.Add(sample);
|
||||||
CurrentAverageForceN = kineticWindow.Average(sample => sample.Coordinate.SecondaryValue);
|
_lastRealtimeChartDisplacementMm = displacementMm;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Math.Abs(displacementMm - _lastRealtimeChartDisplacementMm) >= RealtimeChartDisplacementStepMm)
|
||||||
|
{
|
||||||
|
_forceSamples.Add(sample);
|
||||||
|
_lastRealtimeChartDisplacementMm = displacementMm;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_forceSamples[^1] = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePreviewResult(double displacementMm, double forceN)
|
||||||
|
{
|
||||||
|
_runningPeakForceN = Math.Max(_runningPeakForceN, forceN);
|
||||||
|
CurrentPeakForceN = _runningPeakForceN;
|
||||||
|
|
||||||
|
var kineticStartMm = GetActiveTravelMm() * 0.35;
|
||||||
|
if (displacementMm >= kineticStartMm)
|
||||||
|
{
|
||||||
|
_kineticForceSum += forceN;
|
||||||
|
_kineticSampleCount++;
|
||||||
|
CurrentAverageForceN = _kineticForceSum / _kineticSampleCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double GetActiveTravelMm()
|
||||||
|
{
|
||||||
|
return _activeRecipeSnapshot?.TravelMm ?? Recipe.TravelMm;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetActiveReplicateCount()
|
private int GetActiveReplicateCount()
|
||||||
@@ -1072,6 +1105,25 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
UpdateReferenceLine(_averageLineSamples, CurrentAverageForceN);
|
UpdateReferenceLine(_averageLineSamples, CurrentAverageForceN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RefreshRealtimeChartPresentation(bool force)
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
if (!force && now - _lastRealtimeChartRefreshAt < RealtimeChartRefreshInterval)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastRealtimeChartRefreshAt = now;
|
||||||
|
UpdateReferenceLines();
|
||||||
|
|
||||||
|
ForceXAxes[0].MaxLimit = Math.Max(GetActiveTravelMm(), CurrentDisplacementMm + 5);
|
||||||
|
ForceYAxes[0].MaxLimit = Math.Max(CurrentPeakForceN * 1.15, 0.5);
|
||||||
|
_kineticBand.Yj = Math.Max(CurrentPeakForceN * 1.15, 0.5);
|
||||||
|
OnPropertyChanged(nameof(ForceXAxes));
|
||||||
|
OnPropertyChanged(nameof(ForceYAxes));
|
||||||
|
OnPropertyChanged(nameof(ForceSections));
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateReferenceLine(ObservableCollection<ObservablePoint> target, double y)
|
private void UpdateReferenceLine(ObservableCollection<ObservablePoint> target, double y)
|
||||||
{
|
{
|
||||||
if (y <= 0)
|
if (y <= 0)
|
||||||
@@ -1080,12 +1132,28 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var xEnd = Math.Max(Recipe.TravelMm, CurrentDisplacementMm);
|
var xEnd = Math.Max(GetDisplayRecipeSnapshot().TravelMm, CurrentDisplacementMm);
|
||||||
|
if (target.Count == 2)
|
||||||
|
{
|
||||||
|
target[0] = new ObservablePoint(0, y);
|
||||||
|
target[1] = new ObservablePoint(xEnd, y);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
target.Clear();
|
target.Clear();
|
||||||
target.Add(new ObservablePoint(0, y));
|
target.Add(new ObservablePoint(0, y));
|
||||||
target.Add(new ObservablePoint(xEnd, y));
|
target.Add(new ObservablePoint(xEnd, y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ResetRealtimeSamplingMetrics()
|
||||||
|
{
|
||||||
|
_runningPeakForceN = 0;
|
||||||
|
_kineticForceSum = 0;
|
||||||
|
_kineticSampleCount = 0;
|
||||||
|
_lastRealtimeChartDisplacementMm = double.NaN;
|
||||||
|
_lastRealtimeChartRefreshAt = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
|
||||||
private TestRecipeSnapshot GetDisplayRecipeSnapshot()
|
private TestRecipeSnapshot GetDisplayRecipeSnapshot()
|
||||||
{
|
{
|
||||||
return _isShowingHistoricalRun && _displayedRecipeSnapshot is not null
|
return _isShowingHistoricalRun && _displayedRecipeSnapshot is not null
|
||||||
@@ -1435,6 +1503,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
_peakLineSamples.Clear();
|
_peakLineSamples.Clear();
|
||||||
_averageLineSamples.Clear();
|
_averageLineSamples.Clear();
|
||||||
_currentPointSample.Clear();
|
_currentPointSample.Clear();
|
||||||
|
ResetRealtimeSamplingMetrics();
|
||||||
|
|
||||||
CurrentForceN = 0;
|
CurrentForceN = 0;
|
||||||
CurrentDisplacementMm = 0;
|
CurrentDisplacementMm = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user