更新
This commit is contained in:
@@ -21,8 +21,8 @@ public sealed class ModbusProcessDataReader
|
||||
private static readonly PlcTelemetryRegisterMap DefaultTelemetryRegisterMap = new(
|
||||
SlaveAddress: 1,
|
||||
ForceAddress: 1314,
|
||||
HorizontalSpeedAddress: 350,
|
||||
HorizontalDisplacementAddress: 360,
|
||||
HorizontalSpeedAddress: 370,
|
||||
HorizontalDisplacementAddress: 380,
|
||||
LiftSpeedAddress: 310,
|
||||
LiftDisplacementAddress: 320,
|
||||
LiftPositionAddress: 12,
|
||||
@@ -111,10 +111,10 @@ public sealed class ModbusProcessDataReader
|
||||
var liftDisplacement = ReadFloatAt(motionRegisters, motionStartAddress, _telemetryRegisterMap.LiftDisplacementAddress);
|
||||
var liftPosition = ReadFloatAt(positionRegisters, positionStartAddress, _telemetryRegisterMap.LiftPositionAddress);
|
||||
var horizontalPosition = ReadFloatAt(positionRegisters, positionStartAddress, _telemetryRegisterMap.HorizontalPositionAddress);
|
||||
var completed = horizontalDisplacement >= _recipe.TravelMm;
|
||||
var completed = false;
|
||||
|
||||
return new ProcessFrame(
|
||||
horizontalDisplacement,
|
||||
horizontalPosition,
|
||||
Math.Max(force, 0.001),
|
||||
horizontalSpeed,
|
||||
completed,
|
||||
|
||||
@@ -47,12 +47,13 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
private const ushort CoilReset = 90;
|
||||
private const ushort RegisterSledMassGrams = 400;
|
||||
private const ushort RegisterReplicateCount = 406;
|
||||
private const ushort RegisterHorizontalSpeed = 350;
|
||||
private const ushort RegisterHorizontalDisplacement = 360;
|
||||
private const ushort RegisterHorizontalSpeedSetpoint = 370;
|
||||
private const ushort RegisterHorizontalTravelSetpoint = 380;
|
||||
private const ushort RegisterLiftSpeed = 310;
|
||||
private const ushort RegisterLiftDisplacement = 320;
|
||||
private static readonly TimeSpan RealtimeChartRefreshInterval = TimeSpan.FromMilliseconds(250);
|
||||
private const double RealtimeChartDisplacementStepMm = 0.5;
|
||||
private const double RealtimeChartXAxisPaddingMm = 5;
|
||||
|
||||
private readonly DispatcherTimer _timer;
|
||||
private readonly DispatcherTimer _deviceReconnectTimer;
|
||||
@@ -132,6 +133,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
private int _kineticSampleCount;
|
||||
private double _runStartHorizontalPositionMm = double.NaN;
|
||||
private double _lastRealtimeChartDisplacementMm = double.NaN;
|
||||
private double _realtimeChartMaxDisplacementMm;
|
||||
private DateTime _lastRealtimeChartRefreshAt = DateTime.MinValue;
|
||||
private double _lastForceXAxisMaxLimit;
|
||||
private double _lastForceYAxisMaxLimit;
|
||||
@@ -943,7 +945,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
private void UpdateLiveProcessSnapshot(ProcessFrame frame)
|
||||
{
|
||||
CurrentForceN = Math.Max(frame.ForceN, 0.001);
|
||||
CurrentDisplacementMm = frame.HorizontalPosition;
|
||||
CurrentDisplacementMm = frame.DisplacementMm;
|
||||
CurrentSpeedMmPerMin = frame.SpeedMmPerMin;
|
||||
CurrentLiftSpeed = frame.LiftSpeed;
|
||||
CurrentLiftDisplacement = frame.LiftDisplacement;
|
||||
@@ -995,6 +997,8 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
|
||||
private void AddRealtimeChartSample(double displacementMm, double forceN)
|
||||
{
|
||||
TrackRealtimeChartBounds(displacementMm);
|
||||
|
||||
var sample = new ObservablePoint(displacementMm, forceN);
|
||||
if (_forceSamples.Count == 0 || !IsFinite(_lastRealtimeChartDisplacementMm))
|
||||
{
|
||||
@@ -1013,37 +1017,46 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
_forceSamples[^1] = sample;
|
||||
}
|
||||
|
||||
private void TrackRealtimeChartBounds(double displacementMm)
|
||||
{
|
||||
if (IsFinite(displacementMm))
|
||||
{
|
||||
_realtimeChartMaxDisplacementMm = Math.Max(_realtimeChartMaxDisplacementMm, displacementMm);
|
||||
}
|
||||
}
|
||||
|
||||
private bool AppendRunningSample(ProcessFrame frame, out bool isCompleted)
|
||||
{
|
||||
isCompleted = false;
|
||||
if (!TryResolveRunningPosition(frame, out var horizontalPositionMm, out var travelDeltaMm))
|
||||
if (!TryResolveRunningDisplacement(frame, out var displacementMm))
|
||||
{
|
||||
AddWarningEvent("实时采样包含无效水平位置,已跳过本次曲线点。");
|
||||
AddWarningEvent("实时采样包含无效水平位移,已跳过本次曲线点。");
|
||||
return false;
|
||||
}
|
||||
|
||||
var forceN = CurrentForceN;
|
||||
var forceN = Math.Max(frame.ForceN, 0.001);
|
||||
if (!IsFinite(forceN))
|
||||
{
|
||||
AddWarningEvent("实时采样包含无效力值,已跳过本次曲线点。");
|
||||
return false;
|
||||
}
|
||||
|
||||
CurrentDisplacementMm = horizontalPositionMm;
|
||||
CurrentDisplacementMm = displacementMm;
|
||||
CurrentForceN = forceN;
|
||||
var isFirstChartSample = _forceSamples.Count == 0;
|
||||
_currentRunSamples.Add(new RawSampleRecord
|
||||
{
|
||||
RunId = _activeRunId,
|
||||
SampleIndex = _currentRunSamples.Count + 1,
|
||||
CapturedAt = DateTime.Now,
|
||||
DisplacementMm = horizontalPositionMm,
|
||||
DisplacementMm = displacementMm,
|
||||
ForceN = forceN,
|
||||
SpeedMmPerMin = frame.SpeedMmPerMin
|
||||
});
|
||||
|
||||
AddRealtimeChartSample(horizontalPositionMm, forceN);
|
||||
UpdateCurrentPoint(horizontalPositionMm, forceN);
|
||||
UpdatePreviewResult(travelDeltaMm, forceN);
|
||||
AddRealtimeChartSample(displacementMm, forceN);
|
||||
UpdateCurrentPoint(displacementMm, forceN);
|
||||
UpdatePreviewResult(displacementMm, forceN);
|
||||
StaticCoefficient1 = frame.StaticCoefficient1;
|
||||
KineticCoefficient1 = frame.KineticCoefficient1;
|
||||
StandardDeviation1 = frame.StandardDeviation1;
|
||||
@@ -1053,8 +1066,8 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
var activeReplicateCount = GetActiveReplicateCount();
|
||||
CurrentStaticCoefficient = ResolveRepresentativeValue(activeReplicateCount, StaticCoefficient1, StaticCoefficient2);
|
||||
CurrentKineticCoefficient = ResolveRepresentativeValue(activeReplicateCount, KineticCoefficient1, KineticCoefficient2);
|
||||
TrialProgressPercent = Math.Min(100, travelDeltaMm / Math.Max(Recipe.TravelMm, 1) * 100);
|
||||
isCompleted = travelDeltaMm >= GetActiveTravelMm();
|
||||
TrialProgressPercent = Math.Min(100, displacementMm / Math.Max(GetActiveTravelMm(), 1) * 100);
|
||||
isCompleted = displacementMm >= GetActiveTravelMm();
|
||||
RefreshRealtimeChartPresentation(force: isFirstChartSample || isCompleted);
|
||||
if (isFirstChartSample)
|
||||
{
|
||||
@@ -1064,23 +1077,21 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryResolveRunningPosition(ProcessFrame frame, out double horizontalPositionMm, out double travelDeltaMm)
|
||||
private bool TryResolveRunningDisplacement(ProcessFrame frame, out double displacementMm)
|
||||
{
|
||||
horizontalPositionMm = 0;
|
||||
travelDeltaMm = 0;
|
||||
displacementMm = 0;
|
||||
if (!IsFinite(frame.HorizontalPosition))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
horizontalPositionMm = frame.HorizontalPosition;
|
||||
if (!IsFinite(_runStartHorizontalPositionMm))
|
||||
{
|
||||
_runStartHorizontalPositionMm = horizontalPositionMm;
|
||||
_runStartHorizontalPositionMm = frame.HorizontalPosition;
|
||||
}
|
||||
|
||||
travelDeltaMm = Math.Abs(horizontalPositionMm - _runStartHorizontalPositionMm);
|
||||
return IsFinite(horizontalPositionMm) && IsFinite(travelDeltaMm);
|
||||
displacementMm = Math.Abs(frame.HorizontalPosition - _runStartHorizontalPositionMm);
|
||||
return IsFinite(displacementMm);
|
||||
}
|
||||
|
||||
private void UpdatePreviewResult(double displacementMm, double forceN)
|
||||
@@ -1115,8 +1126,15 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
|
||||
private void UpdateCurrentPoint(double x, double y)
|
||||
{
|
||||
var sample = new ObservablePoint(x, y);
|
||||
if (_currentPointSample.Count == 1)
|
||||
{
|
||||
_currentPointSample[0] = sample;
|
||||
return;
|
||||
}
|
||||
|
||||
_currentPointSample.Clear();
|
||||
_currentPointSample.Add(new ObservablePoint(x, y));
|
||||
_currentPointSample.Add(sample);
|
||||
}
|
||||
|
||||
private void UpdateReferenceLines()
|
||||
@@ -1148,12 +1166,8 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
|
||||
private double CalculateRealtimeXAxisMaxLimit()
|
||||
{
|
||||
var sampleMax = _forceSamples.Count == 0
|
||||
? 0
|
||||
: _forceSamples.Max(sample => sample.X ?? 0);
|
||||
var currentMax = Math.Max(CurrentDisplacementMm, CurrentHorizontalPosition);
|
||||
var visibleMax = Math.Max(sampleMax, currentMax);
|
||||
return Math.Max(visibleMax + 5, 1);
|
||||
var visibleMax = Math.Max(_realtimeChartMaxDisplacementMm, CurrentDisplacementMm);
|
||||
return Math.Max(visibleMax + RealtimeChartXAxisPaddingMm, 1);
|
||||
}
|
||||
|
||||
private void UpdateAxisLimits(double xMax, double yMax)
|
||||
@@ -1203,21 +1217,8 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
private bool UpdateKineticBand(double yMax)
|
||||
{
|
||||
var travelMm = GetActiveTravelMm();
|
||||
double xi;
|
||||
double xj;
|
||||
if (IsFinite(_runStartHorizontalPositionMm))
|
||||
{
|
||||
var direction = CurrentHorizontalPosition >= _runStartHorizontalPositionMm ? 1 : -1;
|
||||
var kineticStart = _runStartHorizontalPositionMm + direction * travelMm * 0.35;
|
||||
var kineticEnd = _runStartHorizontalPositionMm + direction * travelMm;
|
||||
xi = Math.Min(kineticStart, kineticEnd);
|
||||
xj = Math.Max(kineticStart, kineticEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
xi = travelMm * 0.35;
|
||||
xj = travelMm;
|
||||
}
|
||||
var xi = travelMm * 0.35;
|
||||
var xj = travelMm;
|
||||
|
||||
var changed = HasMeaningfulChange(_kineticBand.Xi ?? double.NaN, xi)
|
||||
|| HasMeaningfulChange(_kineticBand.Xj ?? double.NaN, xj)
|
||||
@@ -1315,6 +1316,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
_kineticSampleCount = 0;
|
||||
_runStartHorizontalPositionMm = double.NaN;
|
||||
_lastRealtimeChartDisplacementMm = double.NaN;
|
||||
_realtimeChartMaxDisplacementMm = 0;
|
||||
_lastRealtimeChartRefreshAt = DateTime.MinValue;
|
||||
}
|
||||
|
||||
@@ -1813,8 +1815,8 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
var sledMassGrams = await ReadFloatHoldingRegisterAsync(master, RegisterSledMassGrams);
|
||||
var liftSpeedMmPerMin = await ReadFloatHoldingRegisterAsync(master, RegisterLiftSpeed);
|
||||
var liftDisplacementMm = await ReadFloatHoldingRegisterAsync(master, RegisterLiftDisplacement);
|
||||
var speedMmPerMin = await ReadFloatHoldingRegisterAsync(master, RegisterHorizontalSpeed);
|
||||
var travelMm = await ReadFloatHoldingRegisterAsync(master, RegisterHorizontalDisplacement);
|
||||
var speedMmPerMin = await ReadFloatHoldingRegisterAsync(master, RegisterHorizontalSpeedSetpoint);
|
||||
var travelMm = await ReadFloatHoldingRegisterAsync(master, RegisterHorizontalTravelSetpoint);
|
||||
var replicateCount = Math.Clamp((int)Math.Round(await ReadFloatHoldingRegisterAsync(master, RegisterReplicateCount)), 0, 1);
|
||||
|
||||
Recipe.SledMassGrams = sledMassGrams;
|
||||
@@ -1849,10 +1851,10 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||
await _deviceConnectionService.WriteFloatRegisterAsync(ModbusSlaveAddress, RegisterLiftDisplacement, Recipe.LiftDisplacementMm);
|
||||
break;
|
||||
case nameof(TestRecipe.SpeedMmPerMin):
|
||||
await _deviceConnectionService.WriteFloatRegisterAsync(ModbusSlaveAddress, RegisterHorizontalSpeed, Recipe.SpeedMmPerMin);
|
||||
await _deviceConnectionService.WriteFloatRegisterAsync(ModbusSlaveAddress, RegisterHorizontalSpeedSetpoint, Recipe.SpeedMmPerMin);
|
||||
break;
|
||||
case nameof(TestRecipe.TravelMm):
|
||||
await _deviceConnectionService.WriteFloatRegisterAsync(ModbusSlaveAddress, RegisterHorizontalDisplacement, Recipe.TravelMm);
|
||||
await _deviceConnectionService.WriteFloatRegisterAsync(ModbusSlaveAddress, RegisterHorizontalTravelSetpoint, Recipe.TravelMm);
|
||||
break;
|
||||
case nameof(TestRecipe.ReplicateCount):
|
||||
await _deviceConnectionService.WriteFloatRegisterAsync(ModbusSlaveAddress, RegisterReplicateCount, Math.Clamp(Recipe.ReplicateCount, 0, 1));
|
||||
|
||||
Reference in New Issue
Block a user