更新一版20260525

This commit is contained in:
GukSang.Jin
2026-05-25 17:47:34 +08:00
parent 3aabe94d05
commit d4affddd6e
2 changed files with 91 additions and 19 deletions

View File

@@ -23,6 +23,7 @@ public sealed class CValueCalibrationViewModel : PageViewModel
private const double PressureDifferenceMaximum = 5000;
private const double CValueMinimum = 0;
private const double CValueMaximum = 1000;
private const double BaselineOxygenDisplayScale = 100;
private const ushort CirculatingWaterCoil = 49;
private const ushort SamplingPumpCoil = 50;
private const ushort IgniterCoil = 53;
@@ -32,6 +33,7 @@ public sealed class CValueCalibrationViewModel : PageViewModel
private const ushort BaselineEndCoil = 62;
private const ushort CalibrationStartCoil = 70;
private const ushort CalibrationEndCoil = 72;
private static readonly TimeSpan PairedActionPulseDuration = TimeSpan.FromMilliseconds(300);
private const string CirculatingWaterAction = "循环水";
private const string SamplingPumpAction = "取样泵";
private const string IgniterAction = "点火器";
@@ -86,6 +88,8 @@ public sealed class CValueCalibrationViewModel : PageViewModel
CreateAction(CalibrationStartAction, CalibrationStartAction, "标定结束"),
CreateAction(BaselineCollectionAction, BaselineCollectionAction, "基线结束")
];
_actionsByLabel[CalibrationStartAction].UpdateStatus(false);
_actionsByLabel[BaselineCollectionAction].UpdateStatus(false);
RefreshDeviceValues();
_refreshTimer = new DispatcherTimer
@@ -168,8 +172,9 @@ public sealed class CValueCalibrationViewModel : PageViewModel
"BaselineOxygen",
BaselineOxygenRegister,
OxygenMinimum,
OxygenMaximum,
"0.00");
OxygenMaximum / BaselineOxygenDisplayScale,
"0.00",
BaselineOxygenDisplayScale);
TemperatureText = ReadRangedFloatText(
"Temperature",
TemperatureRegister,
@@ -194,7 +199,7 @@ public sealed class CValueCalibrationViewModel : PageViewModel
CValueMinimum,
CValueMaximum,
"0.00");
RefreshActionStates();
RefreshHoldActionStates();
}
private string ReadRangedFloatText(
@@ -202,7 +207,8 @@ public sealed class CValueCalibrationViewModel : PageViewModel
ushort registerAddress,
double minimum,
double maximum,
string format)
string format,
double displayScale = 1)
{
if (!_tcpDeviceConnectionService.TryReadFloatValues(registerAddress, out var result))
{
@@ -216,7 +222,7 @@ public sealed class CValueCalibrationViewModel : PageViewModel
}
LogFloatDiagnostic(label, registerAddress, result, byteOrder, matchCount);
return NormalizeDisplayValue(value).ToString(format, CultureInfo.InvariantCulture);
return NormalizeDisplayValue(value * displayScale).ToString(format, CultureInfo.InvariantCulture);
}
private void LogFloatDiagnostic(
@@ -262,15 +268,13 @@ public sealed class CValueCalibrationViewModel : PageViewModel
return action;
}
private void RefreshActionStates()
private void RefreshHoldActionStates()
{
UpdateActionStatus(CirculatingWaterAction, CirculatingWaterCoil);
UpdateActionStatus(MethaneValveAction, MethaneValveCoil);
UpdateActionStatus(FanAction, FanCoil);
UpdateActionStatus(IgniterAction, IgniterCoil);
UpdateActionStatus(SamplingPumpAction, SamplingPumpCoil);
UpdateActionStatus(BaselineCollectionAction, BaselineCollectionCoil);
UpdateActionStatus(CalibrationStartAction, CalibrationStartCoil);
}
private bool UpdateActionStatus(string action, ushort coilAddress)
@@ -327,27 +331,23 @@ public sealed class CValueCalibrationViewModel : PageViewModel
return;
}
if (!_tcpDeviceConnectionService.TryReadCoil(startCoilAddress, out var isActive))
if (!_actionsByLabel.TryGetValue(action, out var actionViewModel))
{
LastAction = $"{action}状态读取失败";
Debug.WriteLine($"C value calibration action '{action}' state read failed.");
return;
}
var isActive = actionViewModel.IsActive;
var coilAddress = isActive ? endCoilAddress : startCoilAddress;
var actionText = isActive ? endActionText : action;
if (_tcpDeviceConnectionService.TryWriteCoil(coilAddress, true))
if (TryStartCoilPulse(coilAddress, actionText))
{
var completedBaselineCollection = action == BaselineCollectionAction && isActive;
var completedCalibration = action == CalibrationStartAction && isActive;
LastAction = completedBaselineCollection
? "基线采集完成"
: completedCalibration ? "标定完成" : actionText;
if (_actionsByLabel.TryGetValue(action, out var actionViewModel))
{
actionViewModel.UpdateStatus(!isActive);
}
actionViewModel.UpdateStatus(!isActive);
if (completedBaselineCollection)
{
@@ -366,6 +366,26 @@ public sealed class CValueCalibrationViewModel : PageViewModel
Debug.WriteLine($"C value calibration action '{actionText}' write failed.");
}
private bool TryStartCoilPulse(ushort coilAddress, string actionText)
{
if (!_tcpDeviceConnectionService.TryWriteCoil(coilAddress, true))
{
return false;
}
_ = ReleaseCoilAfterPulseAsync(coilAddress, actionText);
return true;
}
private async Task ReleaseCoilAfterPulseAsync(ushort coilAddress, string actionText)
{
await Task.Delay(PairedActionPulseDuration);
if (!_tcpDeviceConnectionService.TryWriteCoil(coilAddress, false))
{
Debug.WriteLine($"C value calibration action '{actionText}' pulse release failed.");
}
}
private static bool TryGetHoldActionCoil(string action, out ushort coilAddress)
{
switch (action)

View File

@@ -18,6 +18,8 @@ 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 int CurrentHeatFluxStableReadCount = 3;
private const double HeatTransferInputMinimum = 0;
private const double HeatTransferReadMinimum = 0.01;
private const double HeatTransferMaximum = 20000;
@@ -44,6 +46,9 @@ public sealed class ConeRadiationSettingsViewModel : PageViewModel
private bool _heatingActive;
private bool _isEditingConeParameters;
private double? _lastStableCurrentTemperature;
private double? _lastStableCurrentHeatFlux;
private double? _pendingCurrentHeatFlux;
private int _pendingCurrentHeatFluxReadCount;
private DateTime _parameterRefreshBlockedUntil = DateTime.MinValue;
public ConeRadiationSettingsViewModel(
@@ -191,10 +196,17 @@ public sealed class ConeRadiationSettingsViewModel : PageViewModel
CurrentHeatFluxMinimum,
CurrentHeatFluxMaximum,
"0.00",
out var currentHeatFluxText,
out _))
out _,
out var currentHeatFlux))
{
CurrentHeatFluxText = currentHeatFluxText;
if (TryUpdateStableCurrentHeatFlux(currentHeatFlux, out var stableCurrentHeatFlux))
{
CurrentHeatFluxText = stableCurrentHeatFlux.ToString("0.00", CultureInfo.InvariantCulture);
}
}
else if (!_lastStableCurrentHeatFlux.HasValue)
{
CurrentHeatFluxText = string.Empty;
}
if (CanRefreshConeParameters())
@@ -271,6 +283,46 @@ public sealed class ConeRadiationSettingsViewModel : PageViewModel
|| value >= _lastStableCurrentTemperature.Value - CurrentTemperatureMaximumDropPerRefresh;
}
private bool TryUpdateStableCurrentHeatFlux(double value, out double stableValue)
{
value = NormalizeDisplayValue(value);
stableValue = _lastStableCurrentHeatFlux ?? value;
if (_lastStableCurrentHeatFlux.HasValue
&& Math.Abs(value - _lastStableCurrentHeatFlux.Value) <= CurrentHeatFluxStableTolerance)
{
AcceptStableCurrentHeatFlux(value);
stableValue = value;
return true;
}
if (!_pendingCurrentHeatFlux.HasValue
|| Math.Abs(value - _pendingCurrentHeatFlux.Value) > CurrentHeatFluxStableTolerance)
{
_pendingCurrentHeatFlux = value;
_pendingCurrentHeatFluxReadCount = 1;
return false;
}
_pendingCurrentHeatFluxReadCount++;
if (_pendingCurrentHeatFluxReadCount < CurrentHeatFluxStableReadCount)
{
return false;
}
AcceptStableCurrentHeatFlux(value);
stableValue = value;
return true;
}
private void AcceptStableCurrentHeatFlux(double value)
{
_lastStableCurrentHeatFlux = value;
_pendingCurrentHeatFlux = null;
_pendingCurrentHeatFluxReadCount = 0;
}
private string ReadScaledInt16Text(ushort registerAddress, double scale, string format)
{
return _tcpDeviceConnectionService.TryReadInt16(registerAddress, out var rawValue)