From b009fabfdbde7a8d044982ae1c8a7ddfbf4fc184 Mon Sep 17 00:00:00 2001 From: "GukSang.Jin" Date: Fri, 22 May 2026 15:33:31 +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 --- .../SmokeDensitySettingsViewModel.cs | 72 ++++++++++++++++--- 1 file changed, 64 insertions(+), 8 deletions(-) diff --git a/ConeCalorimeter/ViewModels/SmokeDensitySettingsViewModel.cs b/ConeCalorimeter/ViewModels/SmokeDensitySettingsViewModel.cs index 9be537a..767cc8e 100644 --- a/ConeCalorimeter/ViewModels/SmokeDensitySettingsViewModel.cs +++ b/ConeCalorimeter/ViewModels/SmokeDensitySettingsViewModel.cs @@ -13,12 +13,17 @@ public sealed class SmokeDensitySettingsViewModel : PageViewModel private const ushort AbsorbanceRegister = 120; private const double AbsorbanceMinimum = 0; private const double AbsorbanceMaximum = 100; + private const double AbsorbanceStableTolerance = 0.25; + private const int AbsorbanceStableReadCount = 2; private readonly Action _closeAction; private readonly ITcpDeviceConnectionService _tcpDeviceConnectionService; private readonly DispatcherTimer _refreshTimer; private readonly HashSet _loggedFloatDiagnostics = []; private readonly HashSet _loggedInvalidFloatDiagnostics = []; + private double? _stableAbsorbance; + private double? _pendingAbsorbance; + private int _pendingAbsorbanceReadCount; private string _absorbanceText = ""; private string _lastCalibration = "待校准"; @@ -90,34 +95,85 @@ public sealed class SmokeDensitySettingsViewModel : PageViewModel private void RefreshDeviceValues() { - AbsorbanceText = ReadRangedFloatText( + if (!TryReadRangedFloatValue( "Absorbance", AbsorbanceRegister, AbsorbanceMinimum, AbsorbanceMaximum, - "0.00"); + out var value)) + { + if (!_stableAbsorbance.HasValue) + { + AbsorbanceText = string.Empty; + } + + return; + } + + if (TryUpdateStableAbsorbance(value, out var stableValue)) + { + AbsorbanceText = stableValue.ToString("0.00", CultureInfo.InvariantCulture); + } } - private string ReadRangedFloatText( + private bool TryReadRangedFloatValue( string label, ushort registerAddress, double minimum, double maximum, - string format) + out double value) { + value = double.NaN; + if (!_tcpDeviceConnectionService.TryReadFloatValues(registerAddress, out var result)) { - return string.Empty; + return false; } - if (!ModbusFloatSelector.TrySelectRangedFloat(result, minimum, maximum, out var byteOrder, out var value, out var matchCount)) + if (!ModbusFloatSelector.TrySelectRangedFloat(result, minimum, maximum, out var byteOrder, out var selectedValue, out var matchCount)) { LogFloatDiagnostic(label, registerAddress, result, null, matchCount); - return string.Empty; + return false; } LogFloatDiagnostic(label, registerAddress, result, byteOrder, matchCount); - return NormalizeDisplayValue(value).ToString(format, CultureInfo.InvariantCulture); + value = NormalizeDisplayValue(selectedValue); + return true; + } + + private bool TryUpdateStableAbsorbance(double value, out double stableValue) + { + stableValue = _stableAbsorbance ?? value; + + if (_stableAbsorbance.HasValue + && Math.Abs(value - _stableAbsorbance.Value) <= AbsorbanceStableTolerance) + { + _pendingAbsorbance = null; + _pendingAbsorbanceReadCount = 0; + stableValue = _stableAbsorbance.Value; + return true; + } + + if (!_pendingAbsorbance.HasValue + || Math.Abs(value - _pendingAbsorbance.Value) > AbsorbanceStableTolerance) + { + _pendingAbsorbance = value; + _pendingAbsorbanceReadCount = 1; + return false; + } + + _pendingAbsorbanceReadCount++; + + if (_pendingAbsorbanceReadCount < AbsorbanceStableReadCount) + { + return false; + } + + _stableAbsorbance = value; + _pendingAbsorbance = null; + _pendingAbsorbanceReadCount = 0; + stableValue = value; + return true; } private void LogFloatDiagnostic(