Files
CapMachine/CapMachine.Wpf/Services/PPCService.cs
Tyrone CT 47834ea4dc 物性更改2
一些已知的更改
2026-05-07 22:11:27 +08:00

780 lines
28 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using CapMachine.Core;
using CapMachine.Wpf.Models.PPCalc;
using CapMachine.Wpf.Models.Tag;
using CapMachine.Wpf.PPCalculation;
using ImTools;
using MaterialDesignThemes.Wpf;
using NLog;
using NPOI.XWPF.UserModel;
using Prism.Events;
using Prism.Mvvm;
using Prism.Services.Dialogs;
using SixLabors.ImageSharp.ColorSpaces;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
namespace CapMachine.Wpf.Services
{
/// <summary>
/// 物性计算的服务
/// </summary>
public class PPCService : BindableBase
{
/// <summary>
/// 计算扫描 Task
/// </summary>
private static Task CalcTask { get; set; }
public ConfigService ConfigService { get; }
private IEventAggregator _EventAggregator { get; set; }
public DataRecordService DataRecordService { get; }
public SysRunService SysRunServer { get; }
public ILogService Logger { get; }
public MachineRtDataService MachineRtDataService { get; }
public IDialogService DialogService { get; }
private readonly object _refpropLock = new object();
private readonly PPCSuperheatSubcoolCalculator _superheatSubcoolCalculator;
private readonly PPCThermodynamicSixResultsCalculator _thermodynamicSixResultsCalculator;
private readonly EnthalpyDrynessCalculator _enthalpyDrynessCalculator;
private DateTime _lastSuperheatSubcoolErrorLogAt = DateTime.MinValue;
private string _lastSuperheatSubcoolErrorText = string.Empty;
private int _hvZeroStreak;
/// <summary>
/// 标签中心
/// </summary>
public TagManager TagManager { get; set; }
/// <summary>
/// 实例化
/// </summary>
public PPCService(ConfigService configService, IEventAggregator eventAggregator,
DataRecordService dataRecordService, SysRunService sysRunService, ILogService logService,
MachineRtDataService machineRtDataService, IDialogService dialogService
)
{
ConfigService = configService;
//事件服务
_EventAggregator = eventAggregator;
DataRecordService = dataRecordService;
SysRunServer = sysRunService;
Logger = logService;
MachineRtDataService = machineRtDataService;
DialogService = dialogService;
TagManager = MachineRtDataService.TagManger;
SpeedTag = TagManager.DicTags.GetValueOrDefault("转速[rpm]");
ExPressTag = TagManager.DicTags.GetValueOrDefault("排气压力[BarA]");
ExTempTag = TagManager.DicTags.GetValueOrDefault("排气温度[℃]");
HVPwTag = TagManager.DicTags.GetValueOrDefault("HV[W]");
InhPressTag = TagManager.DicTags.GetValueOrDefault("吸气压力[BarA]");
InhTempTag = TagManager.DicTags.GetValueOrDefault("吸气温度[℃]");
TxvFrTempTag = TagManager.DicTags.GetValueOrDefault("膨胀阀前温度[℃]");
TxvFrPressTag = TagManager.DicTags.GetValueOrDefault("膨胀阀前压力[BarA]");
GasPreValvePressTag = TagManager.DicTags.GetValueOrDefault("气路阀前压力[BarA]");
GasPreValveTempTag = TagManager.DicTags.GetValueOrDefault("气路阀前温度[℃]");
DrynessTag = TagManager.DicTags.GetValueOrDefault("干度[-]");
if (DrynessTag == null)
{
DrynessTag = TagManager.DicTags.GetValueOrDefault("干度");
}
VRVTag = TagManager.DicTags.GetValueOrDefault("冷媒流量[kg/h]");
if (VRVTag == null)
{
VRVTag = TagManager.DicTags.GetValueOrDefault("冷媒流量[kg/h]");
}
LiqRefFlowTag = TagManager.DicTags.GetValueOrDefault("液冷媒流量[kg/h]");
if (LiqRefFlowTag == null)
{
LiqRefFlowTag = TagManager.DicTags.GetValueOrDefault("液体流量[kg/h]");
}
LubeFlowTag = TagManager.DicTags.GetValueOrDefault("润滑油流量[kg/h]");
if (LubeFlowTag == null)
{
LubeFlowTag = TagManager.DicTags.GetValueOrDefault("润滑油流量[kg/h]");
}
Superheat = TagManager.DicTags.GetValueOrDefault("过热度[K]");
Subcool = TagManager.DicTags.GetValueOrDefault("过冷度[K]");
HeatingCapacity = TagManager.DicTags.GetValueOrDefault("制热量Qh[KW]")
?? TagManager.DicTags.GetValueOrDefault("制热量Qh[W]");
COPHeat = TagManager.DicTags.GetValueOrDefault("压缩机性能系数(制热)[K]")
?? TagManager.DicTags.GetValueOrDefault("压缩机性能系数(制热COP)");
IsentrpEff = TagManager.DicTags.GetValueOrDefault("等熵效率ns[%]");
CoolCapacity = TagManager.DicTags.GetValueOrDefault("制冷量Qc[KW]")
?? TagManager.DicTags.GetValueOrDefault("制冷量Qc[W]");
COPCool = TagManager.DicTags.GetValueOrDefault("压缩机性能系数(制冷)[K]")
?? TagManager.DicTags.GetValueOrDefault("压缩机性能系数(制冷COP)");
VoltricEff = TagManager.DicTags.GetValueOrDefault("容积效率nv[%]");
SuperHeatCoolConfig.FluidsPath = ConfigHelper.GetValue("FluidsPath");
SuperHeatCoolConfig.Cryogen = ConfigHelper.GetValue("Cryogen");
_superheatSubcoolCalculator = new PPCSuperheatSubcoolCalculator(_refpropLock);
_thermodynamicSixResultsCalculator = new PPCThermodynamicSixResultsCalculator(_refpropLock);
_enthalpyDrynessCalculator = new EnthalpyDrynessCalculator(_refpropLock);
ReloadTherdyH3TempOffset();
RtScanDeviceStart();
}
private const string TherdyH3TempOffsetConfigKey = "Therdy_H3TempOffset_C";
public void ReloadTherdyH3TempOffset()
{
double offsetC = -10.0;
try
{
string raw = ConfigHelper.GetValue(TherdyH3TempOffsetConfigKey);
if (!string.IsNullOrWhiteSpace(raw) && double.TryParse(raw, out var parsed))
{
offsetC = parsed;
}
}
catch (Exception ex)
{
Logger?.Error($"读取 {TherdyH3TempOffsetConfigKey} 失败: {ex.Message}");
}
_thermodynamicSixResultsCalculator.SetH3TempOffset_C(offsetC);
}
/// <summary>
/// 当前的配置
/// </summary>
public SuperHeatCoolConfigModel SuperHeatCoolConfig { get; set; } = new SuperHeatCoolConfigModel();
/// <summary>
/// 保存配置信息
/// </summary>
public void SaveSuperHeatCoolConfig()
{
ConfigHelper.SetValue("FluidsPath", SuperHeatCoolConfig.FluidsPath);
ConfigHelper.SetValue("Cryogen", SuperHeatCoolConfig.Cryogen);
}
/// <summary>
/// 吸气压力
/// </summary>
public ITag InhPressTag { get; set; }
/// <summary>
/// 转速标签
/// </summary>
public ITag? SpeedTag { get; set; }
/// <summary>
/// 排气压力
/// </summary>
public ITag? ExPressTag { get; set; }
/// <summary>
/// 排气温度
/// </summary>
public ITag? ExTempTag { get; set; }
/// <summary>
/// 压缩机功率HV 电源)
/// </summary>
public ITag? HVPwTag { get; set; }
/// <summary>
/// 吸气温度
/// </summary>
public ITag InhTempTag { get; set; }
/// <summary>
/// 液体阀前温度
/// </summary>
public ITag TxvFrTempTag { get; set; }
/// <summary>
/// 液体阀前压力
/// </summary>
public ITag TxvFrPressTag { get; set; }
/// <summary>
/// 过热度
/// </summary>
public ITag Superheat { get; set; }
/// <summary>
/// 过冷度
/// </summary>
public ITag Subcool { get; set; }
/// <summary>
/// 干度(无量纲 [-]
/// </summary>
public ITag DrynessTag { get; set; }
private double _DrynessTag2Value;
/// <summary>
/// 干度2无量纲 [-]
/// </summary>
public double DrynessTag2Value
{
get { return _DrynessTag2Value; }
set { _DrynessTag2Value = value; RaisePropertyChanged(); }
}
/// <summary>
/// 气路阀前压力BarA
/// </summary>
public ITag GasPreValvePressTag { get; set; }
/// <summary>
/// 气路阀前温度(℃)
/// </summary>
public ITag GasPreValveTempTag { get; set; }
/// <summary>
/// 冷媒流量kg/h
/// </summary>
public ITag VRVTag { get; set; }
/// <summary>
/// 液体流量kg/h
/// 液冷媒流量kg/h=液体流量kg/h
/// </summary>
public ITag LiqRefFlowTag { get; set; }
/// <summary>
/// 润滑油流量kg/h
/// </summary>
public ITag LubeFlowTag { get; set; }
public ITag HeatingCapacity { get; set; }
public ITag COPHeat { get; set; }
public ITag IsentrpEff { get; set; }
public ITag CoolCapacity { get; set; }
public ITag COPCool { get; set; }
public ITag VoltricEff { get; set; }
/// <summary>
/// 风量数据-乘以系数的后的最终结果
/// </summary>
private double AirVolumeData { get; set; } = 0.0;
/// <summary>
/// 风量数据-公式计算的原始数据
/// </summary>
private double AirVolumeDataSource { get; set; } = 0;
/// <summary>
/// 风量喷嘴启用信息数据
/// </summary>
private string RozzleEnableInfo { get; set; } = "";
/// <summary>
/// 启用计算
/// </summary>
private bool RtCalcEnable { get; set; } = true;
/// <summary>
/// 触发日志
/// </summary>
private bool DebugLog { get; set; } = false;
private double _HeatingCapacityQh_kW;
public double HeatingCapacityQh_kW
{
get { return _HeatingCapacityQh_kW; }
set { _HeatingCapacityQh_kW = value; RaisePropertyChanged(); }
}
private double _COPHeating;
public double COPHeating
{
get { return _COPHeating; }
set { _COPHeating = value; RaisePropertyChanged(); }
}
private double _IsentropicEfficiencyPct;
public double IsentropicEfficiencyPct
{
get { return _IsentropicEfficiencyPct; }
set { _IsentropicEfficiencyPct = value; RaisePropertyChanged(); }
}
private double _CoolingCapacityQc_kW;
public double CoolingCapacityQc_kW
{
get { return _CoolingCapacityQc_kW; }
set { _CoolingCapacityQc_kW = value; RaisePropertyChanged(); }
}
private double _COPCooling;
public double COPCooling
{
get { return _COPCooling; }
set { _COPCooling = value; RaisePropertyChanged(); }
}
private double _VolumetricEfficiencyPct;
public double VolumetricEfficiencyPct
{
get { return _VolumetricEfficiencyPct; }
set { _VolumetricEfficiencyPct = value; RaisePropertyChanged(); }
}
/// <summary>
/// PLC扫描线程
/// </summary>
private void RtScanDeviceStart()
{
CalcTask = Task.Run(async () =>
{
while (RtCalcEnable)
{
await Task.Delay(300);
try
{
_ = TryUpdateSuperheatAndSubcool(out var superheatSubcoolErr);
if (!string.IsNullOrWhiteSpace(superheatSubcoolErr))
{
var now = DateTime.UtcNow;
if (!string.Equals(superheatSubcoolErr, _lastSuperheatSubcoolErrorText, StringComparison.Ordinal)
|| (now - _lastSuperheatSubcoolErrorLogAt) >= TimeSpan.FromSeconds(5))
{
Logger?.Error($"过热度/过冷度计算失败: {superheatSubcoolErr}");
_lastSuperheatSubcoolErrorLogAt = now;
_lastSuperheatSubcoolErrorText = superheatSubcoolErr;
}
}
//if (TryUpdateDryness(out var drynessErr))
//{
// if (!string.IsNullOrWhiteSpace(drynessErr))
// {
// Logger?.Error($"干度计算警告: {drynessErr}");
// }
//}
//else
//{
// if (!string.IsNullOrWhiteSpace(drynessErr))
// {
// Logger?.Error($"干度计算失败: {drynessErr}");
// }
//}
if (TryUpdateThermodynamicSixResults(out var thermoErr))
{
if (!string.IsNullOrWhiteSpace(thermoErr))
{
//Logger?.Error($"六个物性结果计算警告: {thermoErr}");
}
}
else
{
if (!string.IsNullOrWhiteSpace(thermoErr))
{
//Logger?.Error($"六个物性结果计算失败: {thermoErr}");
}
}
}
catch (Exception ex)
{
Logger.Error(String.Format("ErrSource : {0} ErrMsg : {1}", ex.StackTrace.ToString(), ex.Message.ToString()));
}
}
});
}
private bool TryUpdateSuperheatAndSubcool(out string error)
{
error = string.Empty;
bool updated = false;
StringBuilder errorBuilder = new StringBuilder();
if (InhPressTag == null || InhTempTag == null || Superheat == null)
{
AppendCalculationError(errorBuilder, "缺少过热度计算标签");
}
else if (_superheatSubcoolCalculator.TryCalculateSuperheatK(InhPressTag.EngPvValue, InhTempTag.EngPvValue, out var superheatValue, out var superheatErr))
{
Superheat.EngPvValue = Math.Abs(superheatValue);
updated = true;
}
else
{
AppendCalculationError(errorBuilder, superheatErr);
}
if (TxvFrPressTag == null || TxvFrTempTag == null || Subcool == null)
{
AppendCalculationError(errorBuilder, "缺少过冷度计算标签");
}
else if (_superheatSubcoolCalculator.TryCalculateSubcoolK(TxvFrPressTag.EngPvValue, TxvFrTempTag.EngPvValue, out var subcoolValue, out var subcoolErr))
{
Subcool.EngPvValue = Math.Abs(subcoolValue);
updated = true;
}
else
{
AppendCalculationError(errorBuilder, subcoolErr);
}
error = errorBuilder.ToString();
return updated;
}
private static void AppendCalculationError(StringBuilder errorBuilder, string error)
{
if (string.IsNullOrWhiteSpace(error))
{
return;
}
if (errorBuilder.Length > 0)
{
errorBuilder.Append("");
}
errorBuilder.Append(error);
}
private bool TryUpdateDryness(out string error)
{
error = string.Empty;
bool updated = false;
StringBuilder errorBuilder = new StringBuilder();
if (GasPreValvePressTag == null || GasPreValveTempTag == null || TxvFrPressTag == null || TxvFrTempTag == null || InhPressTag == null)
{
AppendCalculationError(errorBuilder, "缺少干度计算压力/温度标签");
error = errorBuilder.ToString();
return false;
}
if (VRVTag == null || LiqRefFlowTag == null)
{
AppendCalculationError(errorBuilder, "缺少干度计算流量标签");
error = errorBuilder.ToString();
return false;
}
double lubeFlowKgPerH = 0.0;
if (LubeFlowTag != null)
{
lubeFlowKgPerH = LubeFlowTag.EngPvValue;
}
var drynessResult = _enthalpyDrynessCalculator.Calculate(
new EnthalpyDrynessCalculator.Input(
gasPreValvePressBarA: GasPreValvePressTag.EngPvValue,
gasPreValveTempC: GasPreValveTempTag.EngPvValue,
txvFrPressBarA: TxvFrPressTag.EngPvValue,
txvFrTempC: TxvFrTempTag.EngPvValue,
inhPressBarA: InhPressTag.EngPvValue,
vrvFlowKgPerH: VRVTag.EngPvValue,
liqRefFlowKgPerH: LiqRefFlowTag.EngPvValue,
lubeFlowKgPerH: lubeFlowKgPerH));
if (drynessResult.IsDryness1Success)
{
if (DrynessTag != null)
{
DrynessTag.EngPvValue = Math.Round(drynessResult.Dryness1_01, 4);
}
updated = true;
}
else
{
AppendCalculationError(errorBuilder, drynessResult.Error1);
}
if (drynessResult.IsDryness2Success)
{
DrynessTag2Value = Math.Round(drynessResult.Dryness2_01, 4);
updated = true;
}
else
{
AppendCalculationError(errorBuilder, drynessResult.Error2);
}
error = errorBuilder.ToString();
return updated;
}
/// <summary>
/// 按流程图更新制热量、COP(制热)、等熵效率、制冷量、COP(制冷)、容积效率。
/// </summary>
/// <param name="error">
/// 错误/警告信息输出。
/// - 当方法返回 <see langword="false"/> 时,<paramref name="error"/> 为失败原因,调用方应视为本周期计算无效。
/// - 当方法返回 <see langword="true"/> 但 <paramref name="error"/> 非空时,表示仅部分结果无法计算(例如缺少排量导致容积效率为 NaN
/// </param>
/// <returns>
/// 是否成功完成本周期的结果更新。
/// - <see langword="true"/>:至少已成功更新 Qh/Qc/COP/ηs 等主要结果;容积效率可能因缺失排量而为 NaN。
/// - <see langword="false"/>:关键输入或 REFPROP 计算失败,本周期结果不更新。
/// </returns>
private bool TryUpdateThermodynamicSixResults(out string error)
{
error = string.Empty;
double w_W = HVPwTag?.EngPvValue ?? double.NaN;
if (!double.IsNaN(w_W) && !double.IsInfinity(w_W) && w_W == 0)
{
_hvZeroStreak = Math.Min(_hvZeroStreak + 1, 1000);
if (_hvZeroStreak < 3)
{
return false;
}
HeatingCapacityQh_kW = 0;
CoolingCapacityQc_kW = 0;
COPHeating = 0;
COPCooling = 0;
IsentropicEfficiencyPct = 0;
VolumetricEfficiencyPct = 0;
if (HeatingCapacity != null)
{
HeatingCapacity.EngPvValue = 0;
}
if (COPHeat != null)
{
COPHeat.EngPvValue = 0;
}
if (IsentrpEff != null)
{
IsentrpEff.EngPvValue = 0;
}
if (CoolCapacity != null)
{
CoolCapacity.EngPvValue = 0;
}
if (COPCool != null)
{
COPCool.EngPvValue = 0;
}
if (VoltricEff != null)
{
VoltricEff.EngPvValue = 0;
}
return true;
}
_hvZeroStreak = 0;
// 先把本周期所需的标签值组装为输入模型。
// PPCService 在这里负责完成“标签 -> 领域输入对象”的映射,
// 从而把计算类和 UI/标签层解耦。
if (!TryCreateThermodynamicSixResultsInput(out var input, out var inputErr))
{
error = inputErr;
return false;
}
// 把输入模型交给独立计算类统一完成 6 个结果的热力计算。
// 此处不再在 PPCService 中展开公式,只保留流程调度职责。
if (!_thermodynamicSixResultsCalculator.TryCalculate(input, out var result, out error))
{
return false;
}
// 先把结果同步到服务属性,供界面绑定或其他业务读取。
HeatingCapacityQh_kW = result.HeatingCapacityQh_kW;
CoolingCapacityQc_kW = result.CoolingCapacityQc_kW;
COPHeating = result.COPHeating;
COPCooling = result.COPCooling;
IsentropicEfficiencyPct = result.IsentropicEfficiencyPct;
// 再把结果回写到对应工程量标签。
if (HeatingCapacity != null)
{
HeatingCapacity.EngPvValue = string.Equals(HeatingCapacity.Unit, "W", StringComparison.OrdinalIgnoreCase)
? HeatingCapacityQh_kW * 1000.0
: HeatingCapacityQh_kW;
}
if (COPHeat != null)
{
COPHeat.EngPvValue = COPHeating;
}
if (IsentrpEff != null)
{
IsentrpEff.EngPvValue = IsentropicEfficiencyPct;
}
if (CoolCapacity != null)
{
CoolCapacity.EngPvValue = string.Equals(CoolCapacity.Unit, "W", StringComparison.OrdinalIgnoreCase)
? CoolingCapacityQc_kW * 1000.0
: CoolingCapacityQc_kW;
}
if (COPCool != null)
{
COPCool.EngPvValue = COPCooling;
}
// 容积效率在旧逻辑中允许单独失败;
// 因此只有拿到有效数值时才回写,避免覆盖已有结果为 NaN/Inf。
if (!double.IsNaN(result.VolumetricEfficiencyPct) && !double.IsInfinity(result.VolumetricEfficiencyPct))
{
VolumetricEfficiencyPct = result.VolumetricEfficiencyPct;
if (VoltricEff != null)
{
VoltricEff.EngPvValue = VolumetricEfficiencyPct;
}
}
return true;
}
/// <summary>
/// 创建六个热力结果值计算所需的输入模型。
/// </summary>
/// <param name="input">
/// 输出输入模型。
/// 该对象是 <see cref="PPCThermodynamicSixResultsCalculator"/> 与 <see cref="PPCService"/> 之间的数据边界:
/// 由服务层负责从标签提取实时值,由计算层只消费该对象而不直接依赖标签。
/// </param>
/// <param name="error">失败原因,通常为缺少标签、缺少排量配置或关键输入不可用。</param>
/// <returns>是否创建成功。</returns>
private bool TryCreateThermodynamicSixResultsInput(out PPCThermodynamicSixResultsCalculationInput input, out string error)
{
input = new PPCThermodynamicSixResultsCalculationInput();
error = string.Empty;
// 依次校验本周期计算所需的全部标签。
// 这里不做公式计算,只保证独立计算类拿到的是一套完整输入。
if (HVPwTag == null)
{
error = "缺少 HV[W] 功率标签";
return false;
}
if (VRVTag == null)
{
error = "缺少总流量(冷媒流量)标签";
return false;
}
if (InhPressTag == null || InhTempTag == null)
{
error = "缺少吸气压力/吸气温度标签";
return false;
}
if (ExPressTag == null || ExTempTag == null)
{
error = "缺少排气压力/排气温度标签";
return false;
}
if (TxvFrPressTag == null || TxvFrTempTag == null)
{
error = "缺少膨胀阀前压力/膨胀阀前温度标签";
return false;
}
if (SpeedTag == null)
{
error = "缺少转速标签";
return false;
}
if (!TryGetCompressorDisplacement_cc(out var displacementCc, out _))
{
displacementCc = double.NaN;
}
double oilFlowKgPerH = 0.0;
if (LubeFlowTag != null)
{
oilFlowKgPerH = LubeFlowTag.EngPvValue;
}
// 将实时标签值与配置值组装为独立计算类可直接消费的输入对象。
input = new PPCThermodynamicSixResultsCalculationInput
{
CompressorPowerW = HVPwTag.EngPvValue,
TotalMassFlowKgPerHour = VRVTag.EngPvValue,
OilMassFlowKgPerHour = oilFlowKgPerH,
SuctionPressureBarA = InhPressTag.EngPvValue,
SuctionTemperatureC = InhTempTag.EngPvValue,
DischargePressureBarA = ExPressTag.EngPvValue,
DischargeTemperatureC = ExTempTag.EngPvValue,
LiquidPressureBarA = TxvFrPressTag.EngPvValue,
LiquidTemperatureC = TxvFrTempTag.EngPvValue,
CompressorSpeedRpm = SpeedTag.EngPvValue,
CompressorDisplacementCc = displacementCc
};
return true;
}
/// <summary>
/// 获取压缩机排量。
/// </summary>
/// <param name="displacement_cc">排量输出,单位 cccm³/rev。</param>
/// <param name="error">失败原因(未配置、解析失败、数值不合法)。</param>
/// <returns>是否获取成功。</returns>
private bool TryGetCompressorDisplacement_cc(out double displacement_cc, out string error)
{
displacement_cc = double.NaN;
error = string.Empty;
const double defaultDisplacementCc = 35d;
const string key = "CompressorDisplacementCc";
static bool TryParseDisplacementCc(string? text, out double displacementCc)
{
displacementCc = double.NaN;
if (string.IsNullOrWhiteSpace(text))
{
return false;
}
var normalized = text.Trim().ToLowerInvariant();
normalized = normalized.Replace(',', '.');
var match = Regex.Match(normalized, @"[-+]?\d+(\.\d+)?");
if (!match.Success)
{
return false;
}
if (!double.TryParse(match.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var v))
{
return false;
}
displacementCc = v;
return true;
}
try
{
string raw = ConfigHelper.GetValue(key);
if (TryParseDisplacementCc(raw, out var cfgCc) && cfgCc > 0)
{
displacement_cc = cfgCc;
return true;
}
}
catch
{
// 忽略配置读取异常,走默认回退值
}
displacement_cc = defaultDisplacementCc;
return true;
}
}
}