This commit is contained in:
GukSang.Jin
2026-05-26 20:12:08 +08:00
parent 0c4393bebc
commit 5477fdf210

View File

@@ -18,8 +18,12 @@ public sealed class ConeRadiationSettingsViewModel : PageViewModel
private const double CurrentTemperatureMaximumDropPerRefresh = 80;
private const double CurrentHeatFluxMinimum = 0;
private const double CurrentHeatFluxMaximum = 1000;
private const double CurrentHeatFluxStableTolerance = 5;
private const double CurrentHeatFluxZeroTolerance = 0.005;
private const double CurrentHeatFluxStableAbsoluteTolerance = 0.25;
private const double CurrentHeatFluxStableRelativeTolerance = 0.1;
private const double CurrentHeatFluxStableMaximumTolerance = 5;
private const int CurrentHeatFluxStableReadCount = 3;
private const int CurrentHeatFluxZeroStableReadCount = 10;
private const double HeatTransferInputMinimum = 0;
private const double HeatTransferReadMinimum = 0.01;
private const double HeatTransferMaximum = 20000;
@@ -36,6 +40,14 @@ public sealed class ConeRadiationSettingsViewModel : PageViewModel
private readonly DispatcherTimer _refreshTimer;
private readonly HashSet<ushort> _loggedFloatDiagnostics = [];
private readonly HashSet<ushort> _loggedInvalidFloatDiagnostics = [];
private static readonly ModbusFloatByteOrder[] CurrentHeatFluxByteOrders =
[
ModbusFloatByteOrder.Abcd,
ModbusFloatByteOrder.Cdab,
ModbusFloatByteOrder.Badc,
ModbusFloatByteOrder.Dcba
];
private string _currentTemperatureText = "";
private string _currentHeatFluxText = "";
private string _targetTemperatureText = "";
@@ -49,6 +61,8 @@ public sealed class ConeRadiationSettingsViewModel : PageViewModel
private double? _lastStableCurrentHeatFlux;
private double? _pendingCurrentHeatFlux;
private int _pendingCurrentHeatFluxReadCount;
private int _pendingCurrentHeatFluxZeroReadCount;
private ModbusFloatByteOrder? _currentHeatFluxByteOrder;
private DateTime _parameterRefreshBlockedUntil = DateTime.MinValue;
public ConeRadiationSettingsViewModel(
@@ -190,14 +204,7 @@ public sealed class ConeRadiationSettingsViewModel : PageViewModel
private void RefreshDeviceValues()
{
if (TryReadRangedFloatText(
"ConeCurrentHeatFlux",
CurrentHeatFluxRegister,
CurrentHeatFluxMinimum,
CurrentHeatFluxMaximum,
"0.00",
out _,
out var currentHeatFlux))
if (TryReadCurrentHeatFlux(out var currentHeatFlux))
{
if (TryUpdateStableCurrentHeatFlux(currentHeatFlux, out var stableCurrentHeatFlux))
{
@@ -243,6 +250,46 @@ public sealed class ConeRadiationSettingsViewModel : PageViewModel
}
}
private bool TryReadCurrentHeatFlux(out double value)
{
value = double.NaN;
if (!_tcpDeviceConnectionService.TryReadFloatValues(CurrentHeatFluxRegister, out var result))
{
return false;
}
var preferredByteOrder = _currentHeatFluxByteOrder;
if (!ModbusFloatSelector.TrySelectRangedFloat(
result,
CurrentHeatFluxMinimum,
CurrentHeatFluxMaximum,
out var byteOrder,
out var selectedValue,
out var matchCount,
preferredByteOrder))
{
if (!TrySelectSingleNonZeroCurrentHeatFluxCandidate(result, out byteOrder, out selectedValue))
{
LogFloatDiagnostic("ConeCurrentHeatFlux", CurrentHeatFluxRegister, result, null, matchCount);
return false;
}
}
if (!preferredByteOrder.HasValue
&& IsZeroLikeCurrentHeatFlux(selectedValue)
&& TrySelectSingleNonZeroCurrentHeatFluxCandidate(result, out var nonZeroByteOrder, out var nonZeroValue))
{
byteOrder = nonZeroByteOrder;
selectedValue = nonZeroValue;
}
LogFloatDiagnostic("ConeCurrentHeatFlux", CurrentHeatFluxRegister, result, byteOrder, matchCount);
RememberCurrentHeatFluxByteOrder(byteOrder, selectedValue);
value = NormalizeDisplayValue(selectedValue);
return true;
}
private bool TryReadRangedFloatText(
string label,
ushort registerAddress,
@@ -288,8 +335,26 @@ public sealed class ConeRadiationSettingsViewModel : PageViewModel
value = NormalizeDisplayValue(value);
stableValue = _lastStableCurrentHeatFlux ?? value;
if (IsZeroLikeCurrentHeatFlux(value))
{
_pendingCurrentHeatFlux = null;
_pendingCurrentHeatFluxReadCount = 0;
_pendingCurrentHeatFluxZeroReadCount++;
if (_pendingCurrentHeatFluxZeroReadCount < CurrentHeatFluxZeroStableReadCount)
{
return false;
}
AcceptStableCurrentHeatFlux(0);
stableValue = 0;
return true;
}
_pendingCurrentHeatFluxZeroReadCount = 0;
if (_lastStableCurrentHeatFlux.HasValue
&& Math.Abs(value - _lastStableCurrentHeatFlux.Value) <= CurrentHeatFluxStableTolerance)
&& IsWithinCurrentHeatFluxStableTolerance(value, _lastStableCurrentHeatFlux.Value))
{
AcceptStableCurrentHeatFlux(value);
stableValue = value;
@@ -297,7 +362,7 @@ public sealed class ConeRadiationSettingsViewModel : PageViewModel
}
if (!_pendingCurrentHeatFlux.HasValue
|| Math.Abs(value - _pendingCurrentHeatFlux.Value) > CurrentHeatFluxStableTolerance)
|| !IsWithinCurrentHeatFluxStableTolerance(value, _pendingCurrentHeatFlux.Value))
{
_pendingCurrentHeatFlux = value;
_pendingCurrentHeatFluxReadCount = 1;
@@ -321,6 +386,62 @@ public sealed class ConeRadiationSettingsViewModel : PageViewModel
_lastStableCurrentHeatFlux = value;
_pendingCurrentHeatFlux = null;
_pendingCurrentHeatFluxReadCount = 0;
_pendingCurrentHeatFluxZeroReadCount = 0;
}
private static bool TrySelectSingleNonZeroCurrentHeatFluxCandidate(
ModbusFloatReadResult result,
out ModbusFloatByteOrder byteOrder,
out double value)
{
var matches = CurrentHeatFluxByteOrders
.Select(candidate => new
{
ByteOrder = candidate,
Value = result.GetValue(candidate)
})
.Where(candidate => ModbusFloatSelector.IsInRange(
candidate.Value,
CurrentHeatFluxMinimum,
CurrentHeatFluxMaximum)
&& !IsZeroLikeCurrentHeatFlux(candidate.Value))
.ToArray();
if (matches.Length != 1)
{
byteOrder = default;
value = double.NaN;
return false;
}
byteOrder = matches[0].ByteOrder;
value = matches[0].Value;
return true;
}
private void RememberCurrentHeatFluxByteOrder(ModbusFloatByteOrder byteOrder, double value)
{
if (!IsZeroLikeCurrentHeatFlux(value))
{
_currentHeatFluxByteOrder = byteOrder;
}
}
private static bool IsWithinCurrentHeatFluxStableTolerance(double value, double referenceValue)
{
return Math.Abs(value - referenceValue) <= GetCurrentHeatFluxStableTolerance(referenceValue);
}
private static double GetCurrentHeatFluxStableTolerance(double referenceValue)
{
return Math.Min(
CurrentHeatFluxStableMaximumTolerance,
Math.Max(CurrentHeatFluxStableAbsoluteTolerance, Math.Abs(referenceValue) * CurrentHeatFluxStableRelativeTolerance));
}
private static bool IsZeroLikeCurrentHeatFlux(double value)
{
return double.IsFinite(value) && Math.Abs(value) < CurrentHeatFluxZeroTolerance;
}
private string ReadScaledInt16Text(ushort registerAddress, double scale, string format)