From 808ef94b9103b6843b823ce5a5cb418e5e2be90c Mon Sep 17 00:00:00 2001 From: "GukSang.Jin" Date: Mon, 11 May 2026 10:37:14 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- COFTester/Services/ModbusProcessDataReader.cs | 8 +- COFTester/ViewModels/MainViewModel.cs | 94 ++++++++++--------- 2 files changed, 52 insertions(+), 50 deletions(-) diff --git a/COFTester/Services/ModbusProcessDataReader.cs b/COFTester/Services/ModbusProcessDataReader.cs index 1a90227..01a4eee 100644 --- a/COFTester/Services/ModbusProcessDataReader.cs +++ b/COFTester/Services/ModbusProcessDataReader.cs @@ -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, diff --git a/COFTester/ViewModels/MainViewModel.cs b/COFTester/ViewModels/MainViewModel.cs index 12b6ae9..c148a47 100644 --- a/COFTester/ViewModels/MainViewModel.cs +++ b/COFTester/ViewModels/MainViewModel.cs @@ -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));