using CapMachine.Core; using CapMachine.Wpf.Models.PPCalc; using CapMachine.Wpf.Models.Tag; using CapMachine.Wpf.PPCalculation; using Prism.Mvvm; using System; using System.Globalization; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace CapMachine.Wpf.Services { /// /// 物性计算的服务 /// public class PPCService : BindableBase { /// /// 计算扫描 Task /// private static Task CalcTask { get; set; } = Task.CompletedTask; public ConfigService ConfigService { get; } public ILogService Logger { get; } public MachineRtDataService MachineRtDataService { get; } private readonly EnthalpyDrynessCalculator _enthalpyDrynessCalculator; private readonly ThermodynamicSixResultsCalculator _thermodynamicSixResultsCalculator; private readonly SuperheatSubcoolCalculator _superheatSubcoolCalculator; /// /// 标签中心 /// public TagManager TagManager { get; set; } /// /// 实例化 /// public PPCService(ConfigService configService, ILogService logService, MachineRtDataService machineRtDataService) { ConfigService = configService; Logger = logService; MachineRtDataService = machineRtDataService; _enthalpyDrynessCalculator = new EnthalpyDrynessCalculator(_refpropLock); _thermodynamicSixResultsCalculator = new ThermodynamicSixResultsCalculator(_refpropLock); _superheatSubcoolCalculator = new SuperheatSubcoolCalculator(_refpropLock); TagManager = MachineRtDataService.TagManger; if (TagManager.TryGetShortTagByName("转速[rpm]", out ShortValueTag? speedShortTag)) { SpeedTag = speedShortTag!; } if (TagManager.TryGetShortTagByName("排气压力[BarA]", out ShortValueTag? exPressShortTag)) { ExPressTag = exPressShortTag!; } if (TagManager.TryGetShortTagByName("排气温度[℃]", out ShortValueTag? exTempShortTag)) { ExTempTag = exTempShortTag!; } if (TagManager.TryGetShortTagByName("HV[W]", out ShortValueTag? hvPwShortTag)) { HVPwTag = hvPwShortTag!; } if (TagManager.TryGetShortTagByName("吸气压力[BarA]", out ShortValueTag? InhPressShortControlTag)) { InhPressTag = InhPressShortControlTag!; } if (TagManager.TryGetShortTagByName("吸气温度[℃]", out ShortValueTag? InhTempShortControlTag)) { InhTempTag = InhTempShortControlTag!; } //InhTempTag = TagManager.DicTags.GetValueOrDefault("吸气温度[℃]")!; //ComCapBusVolTag = TagManager.DicTags.GetValueOrDefault("通讯母线电压[V]"); //ComCapBusCurTag = TagManager.DicTags.GetValueOrDefault("通讯母线电流[A]"); //ComCapPwTag = TagManager.DicTags.GetValueOrDefault("通讯功率[W]"); //OS2TempTag = TagManager.DicTags.GetValueOrDefault("吸气混合器温度[℃]"); //TxvFrTempTag = TagManager.DicTags.GetValueOrDefault("膨胀阀前温度[℃]")!; //TxvFrPressTag = TagManager.DicTags.GetValueOrDefault("膨胀阀前压力[BarA]")!; if (TagManager.TryGetShortTagByName("SUBCOOL出口温度[℃]", out ShortValueTag? TxvFrTempShortTag)) { TxvFrTempTag = TxvFrTempShortTag!; } if (TagManager.TryGetShortTagByName("膨胀阀前压力[BarA]", out ShortValueTag? TxvFrPressShortTag)) { TxvFrPressTag = TxvFrPressShortTag!; } if (TagManager.TryGetShortTagByName("液冷媒流量[kg/h]", out ShortValueTag? LiqRefFlowShortTag)) { LiqRefFlowTag = LiqRefFlowShortTag!; } //kg/h if (TagManager.TryGetShortTagByName("冷媒流量[kg/h]", out ShortValueTag? VRVShortTag)) { VRVTag = VRVShortTag!; } //润滑油流量 if (TagManager.TryGetShortTagByName("润滑油流量[kg/h]", out ShortValueTag? LubeFlowShortTag)) { LubeFlowTag = LubeFlowShortTag!; } // 气路阀前 P/T(用于质量流量加权混合焓的计算,LabVIEW 流程) if (TagManager.TryGetShortTagByName("气路阀前压力[BarA]", out ShortValueTag? gasPreP)) { GasPreValvePressTag = gasPreP!; } if (TagManager.TryGetShortTagByName("气路阀前温度[℃]", out ShortValueTag? gasPreT)) { GasPreValveTempTag = gasPreT!; } //Cond1TempTag = TagManager.DicTags.GetValueOrDefault("冷凝器出口水温[℃]"); //CondInTempTag = TagManager.DicTags.GetValueOrDefault("冷凝器进口温度[℃]"); //Superheat = TagManager.DicTags.GetValueOrDefault("过热度[K]"); //Subcool = TagManager.DicTags.GetValueOrDefault("过冷度[K]"); if (TagManager.TryGetShortTagByName("过热度[K]", out ShortValueTag? SuperheatShortTag)) { Superheat = SuperheatShortTag!; } if (TagManager.TryGetShortTagByName("过冷度[K]", out ShortValueTag? SubcoolShortTag)) { Subcool = SubcoolShortTag!; } // 干度标签(如不存在则仅跳过写入,不抛异常)。优先使用“干度[%]”,其次“干度[-]”。 if (TagManager.TryGetShortTagByName("干度[-]", out ShortValueTag? drynessPct)) { DrynessTag = drynessPct!; } if (TagManager.TryGetShortTagByName("制热量Qh[W]", out ShortValueTag? heatingCapacityTag)) { HeatingCapacityTag = heatingCapacityTag!; } if (TagManager.TryGetShortTagByName("压缩机性能系数(制热COP)", out ShortValueTag? copHeatTag)) { COPHeatTag = copHeatTag!; } if (TagManager.TryGetShortTagByName("等熵效率ns[%]", out ShortValueTag? isentrpEffTag)) { IsentrpEffTag = isentrpEffTag!; } if (TagManager.TryGetShortTagByName("制冷量Qc[W]", out ShortValueTag? coolCapacityTag)) { CoolCapacityTag = coolCapacityTag!; } if (TagManager.TryGetShortTagByName("压缩机性能系数(制冷COP)", out ShortValueTag? copCoolTag)) { COPCoolTag = copCoolTag!; } if (TagManager.TryGetShortTagByName("容积效率nv[%]", out ShortValueTag? voltricEffTag)) { VoltricEffTag = voltricEffTag!; } SuperHeatCoolConfig.FluidsPath = ConfigHelper.GetValue("FluidsPath"); SuperHeatCoolConfig.Cryogen = ConfigHelper.GetValue("Cryogen"); ReloadTherdyH3TempOffset(); // 订阅 ConfigService.CurExpInfo 属性变化,实验切换时自动刷新排量缓存 ConfigService.PropertyChanged += (sender, e) => { if (e.PropertyName == nameof(ConfigService.CurExpInfo)) { RefreshDisplacementCache(); } }; // 首次初始化排量缓存(在订阅事件前初始化,避免首次触发不必要的刷新) RefreshDisplacementCache(); RtScanDeviceStart(); } /// /// 当前的配置 /// public SuperHeatCoolConfigModel SuperHeatCoolConfig { get; set; } = new SuperHeatCoolConfigModel(); private const string TherdyH3TempOffsetConfigKey = "Therdy_H3TempOffset_C"; private double _therdyH3TempOffset_C = -10.0; public double TherdyH3TempOffset_C { get { return _therdyH3TempOffset_C; } private set { _therdyH3TempOffset_C = value; RaisePropertyChanged(); } } /// /// 保存配置信息 /// public void SaveSuperHeatCoolConfig() { ConfigHelper.SetValue("FluidsPath", SuperHeatCoolConfig.FluidsPath ?? string.Empty); ConfigHelper.SetValue("Cryogen", SuperHeatCoolConfig.Cryogen ?? string.Empty); } public void ReloadTherdyH3TempOffset() { double offsetC = -10.0; try { string raw = ConfigHelper.GetValue(TherdyH3TempOffsetConfigKey); if (!string.IsNullOrWhiteSpace(raw) && double.TryParse(raw, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsed)) { offsetC = parsed; } } catch { } TherdyH3TempOffset_C = offsetC; _thermodynamicSixResultsCalculator.SetH3TempOffset_C(offsetC); } /// /// 吸气压力 /// public ShortValueTag InhPressTag { get; set; } = null!; /// /// 转速标签 /// public ShortValueTag? SpeedTag { get; set; } /// /// 排气压力 /// public ShortValueTag? ExPressTag { get; set; } /// /// 排气温度 /// public ShortValueTag? ExTempTag { get; set; } /// /// 压缩机功率(HV 电源) /// public ShortValueTag? HVPwTag { get; set; } /// /// 吸气温度 /// public ShortValueTag InhTempTag { get; set; } = null!; /// /// 液体阀前温度 /// public ShortValueTag TxvFrTempTag { get; set; } = null!; /// /// 液体阀前压力 /// public ShortValueTag TxvFrPressTag { get; set; } = null!; /// /// 过热度 /// public ShortValueTag Superheat { get; set; } = null!; /// /// 过冷度 /// public ShortValueTag Subcool { get; set; } = null!; /// /// 干度(无量纲 [-]) /// public ShortValueTag DrynessTag { get; set; } = null!; public ShortValueTag? HeatingCapacityTag { get; set; } public ShortValueTag? COPHeatTag { get; set; } public ShortValueTag? IsentrpEffTag { get; set; } public ShortValueTag? CoolCapacityTag { get; set; } public ShortValueTag? COPCoolTag { get; set; } public ShortValueTag? VoltricEffTag { get; set; } private double _DrynessTag2Value; /// /// 干度2(无量纲 [-]) /// public double DrynessTag2Value { get { return _DrynessTag2Value; } set { _DrynessTag2Value = value; RaisePropertyChanged(); } } /// /// 气路阀前压力(BarA) /// public ShortValueTag GasPreValvePressTag { get; set; } = null!; /// /// 气路阀前温度(℃) /// public ShortValueTag GasPreValveTempTag { get; set; } = null!; /// /// 冷媒流量kg/h /// 气体流量+液体流量=冷媒流量 /// public ShortValueTag VRVTag { get; set; } = null!; /// /// 液体流量(kg/h) /// 液冷媒流量kg/h=液体流量kg/h /// public ShortValueTag LiqRefFlowTag { get; set; } = null!; /// /// 润滑油流量(kg/h) /// public ShortValueTag LubeFlowTag { get; set; } = null!; /// /// 启用计算 /// private bool RtCalcEnable { get; set; } = true; /// /// PLC扫描线程 /// private void RtScanDeviceStart() { CalcTask = Task.Run(async () => { while (RtCalcEnable) { await Task.Delay(100); try { double[] x = new double[20]; double wm = 0.0; // 幂等初始化:仅首次或工质/路径变化时执行 SETPATH/SETUP,提高每秒循环效率 if (!EnsureRefpropInitialized(out var initErr)) { // 初始化失败,跳过本周期 Logger?.Error($"REFPROP 初始化失败: {initErr}"); continue; } // WMOL 仅在需要时调用;若调用,需设置 x[0]=1.0(纯工质) x[0] = 1.0; IRefProp64.WMOLdll(x, ref wm); UpdateSuperheatAndSubcool_BySatp(); //这里写死干度的输入数据 double gasPreValvePressBarA = GasPreValvePressTag.PVModel.EngValue; double gasPreValveTempC = GasPreValveTempTag.PVModel.EngValue; double txvFrPressBarA = TxvFrPressTag.PVModel.EngValue; double txvFrTempC = TxvFrTempTag.PVModel.EngValue; double inhPressBarA = InhPressTag.PVModel.EngValue; double vrvFlowKgPerH = VRVTag.PVModel.EngValue; double liqRefFlowKgPerH = LiqRefFlowTag.PVModel.EngValue; double lubeFlowKgPerH = 0.0; //干度技术 var drynessResult = _enthalpyDrynessCalculator.Calculate( new EnthalpyDrynessCalculator.Input( gasPreValvePressBarA, gasPreValveTempC, txvFrPressBarA, txvFrTempC, inhPressBarA, vrvFlowKgPerH, liqRefFlowKgPerH, lubeFlowKgPerH)); //以前会受 LubeFlowTag 影响,现在由于固定为 0,会与 Dryness1 更接近/一致(只要两者公式差异仅在油这一项) if (drynessResult.IsDryness1Success) { if (DrynessTag != null) { //DrynessTag.PVModel.EngValue = drynessResult.Dryness1_01 * 100.0; DrynessTag.PVModel.EngValue = Math.Round(drynessResult.Dryness1_01, 4); } //DrynessTag2Value = drynessResult.Dryness1_01 * 100.0; //if (drynessResult.Dryness1_01 <= 0) //{ // LogDrynessSnapshotIfNeeded( // "TryComputeDrynessByEnthalpy(SuccessButZero)", // string.Empty, // drynessResult.Dryness1_01, // drynessResult.HMix1_kJkg, // drynessResult.GasEnthalpy_kJkg, // drynessResult.LiquidEnthalpy_kJkg, // drynessResult.SatLiquidEnthalpy_kJkg, // drynessResult.SatVaporEnthalpy_kJkg, // drynessResult.GasFlowKgPerH, // 0, // LiqRefFlowTag.PVModel.EngValue); //} } else { //LogDrynessSnapshotIfNeeded( // "TryComputeDrynessByEnthalpy(Fail)", // drynessResult.Error1, // double.NaN, // double.NaN, // drynessResult.GasEnthalpy_kJkg, // drynessResult.LiquidEnthalpy_kJkg, // drynessResult.SatLiquidEnthalpy_kJkg, // drynessResult.SatVaporEnthalpy_kJkg, // drynessResult.GasFlowKgPerH, // 0, // LiqRefFlowTag.PVModel.EngValue); } if (drynessResult.IsDryness2Success) { //DrynessTag.PVModel.EngValue = drynessResult.Dryness2_01 * 100.0; DrynessTag2Value = Math.Round(drynessResult.Dryness2_01,4) ; //if (drynessResult.Dryness2_01 <= 0) //{ // LogDrynessSnapshotIfNeeded( // "TryComputeDrynessByEnthalpy2(SuccessButZero)", // string.Empty, // drynessResult.Dryness2_01, // drynessResult.HMix2_kJkg, // drynessResult.GasEnthalpy_kJkg, // drynessResult.LiquidEnthalpy_kJkg, // drynessResult.SatLiquidEnthalpy_kJkg, // drynessResult.SatVaporEnthalpy_kJkg, // drynessResult.GasFlowKgPerH, // LubeFlowTag.PVModel.EngValue, // LiqRefFlowTag.PVModel.EngValue); //} } else { //LogDrynessSnapshotIfNeeded( // "TryComputeDrynessByEnthalpy2(Fail)", // drynessResult.Error2, // double.NaN, // double.NaN, // drynessResult.GasEnthalpy_kJkg, // drynessResult.LiquidEnthalpy_kJkg, // drynessResult.SatLiquidEnthalpy_kJkg, // drynessResult.SatVaporEnthalpy_kJkg, // drynessResult.GasFlowKgPerH, // LubeFlowTag.PVModel.EngValue, // LiqRefFlowTag.PVModel.EngValue); } #if DEBUG //DebugRunThermoValidationCase_UsingCalculator_FromScreenshot_20260423(); //DebugRunDrynessValidationCase_FromScreenshot_20260425(); //DebugRunThermoValidationCase_UsingCalculator_FromScreenshot_20260428(); #endif if (TryUpdateThermodynamicSixResults(out var thermoErr)) { if (!string.IsNullOrWhiteSpace(thermoErr)) { //Logger?.Warn($"六个物性结果计算警告: {thermoErr}"); } } else { if (!string.IsNullOrWhiteSpace(thermoErr)) { //Logger?.Error($"六个物性结果计算失败: {thermoErr}"); } } } catch (Exception ex) { Logger.Error(String.Format("ErrSource : {0} ErrMsg : {1}", ex.StackTrace ?? string.Empty, ex.Message)); } } }); } private void UpdateSuperheatAndSubcool_BySatp() { _superheatSubcoolCalculator.Calculate( inhPressBarA: InhPressTag.PVModel.EngValue, inhTempC: InhTempTag.PVModel.EngValue, txvFrPressBarA: TxvFrPressTag.PVModel.EngValue, txvFrTempC: TxvFrTempTag.PVModel.EngValue, out var superheatK, out var subcoolK); Superheat.PVModel.EngValue = superheatK; Subcool.PVModel.EngValue = subcoolK; } // 若类中尚未定义,请添加全局互斥锁,串行化所有 REFPROP 调用 private static readonly object _refpropLock = new object(); // REFPROP 初始化状态(全局、幂等) private static volatile bool _rpInitialized = false; /// /// 幂等初始化:设置流体路径/工质/参考态;确保全局只初始化一次。 /// 注意:所有 REFPROP 原生调用都需在 _refpropLock 下串行化,包括初始化调用。 /// private bool EnsureRefpropInitialized(out string error) { error = string.Empty; if (_rpInitialized) return true; try { lock (_refpropLock) { if (_rpInitialized) return true; // 双检,避免并发二次初始化 string hpath = ConfigHelper.GetValue("FluidsPath"); if (string.IsNullOrWhiteSpace(hpath)) hpath = @".\PPCalculation\REFPROP\FLUIDS"; string configuredCryogen = ConfigHelper.GetValue("Cryogen"); if (string.IsNullOrWhiteSpace(configuredCryogen)) configuredCryogen = "R134a"; // 现阶段仅使用 R134A.FLD;如需扩展,可根据 configuredCryogen 选择不同文件 string hfldCore = configuredCryogen.Equals("R134a", StringComparison.OrdinalIgnoreCase) ? "R134A.FLD" : "R134A.FLD"; long size = hpath.Length; string hpathPadded = hpath + new string(' ', Math.Max(0, 255 - (int)size)); IRefProp64.SETPATHdll(hpathPadded, ref size); long numComps = 1; string hfld = hfldCore; size = hfld.Length; string hfldPadded = hfld + new string(' ', Math.Max(0, 10000 - (int)size)); string hfmix = "hmx.bnc" + new string(' ', 255); string hrf = "DEF"; string herr = new string(' ', 255); long ierr = 0; long hfldLen = hfldPadded.Length, hfmixLen = hfmix.Length, hrfLen = hrf.Length, herrLen = herr.Length; IRefProp64.SETUPdll(ref numComps, ref hfldPadded, ref hfmix, ref hrf, ref ierr, ref herr, ref hfldLen, ref hfmixLen, ref hrfLen, ref herrLen); if (ierr != 0) { error = $"REFPROP 初始化失败: {herr.Trim()} (ierr={ierr})"; _rpInitialized = false; return false; } _rpInitialized = true; return true; } } catch (Exception ex) { error = $"REFPROP 初始化异常: {ex.Message}"; Logger.Error(error); _rpInitialized = false; return false; } } ///制热量、压缩机性能系数COP(制热)、等熵效率、制冷量、压缩机性能系数COP(制冷)、容积效率 计算 #region /// /// 缓存的压缩机排量值(cc),在实验切换时自动刷新 /// private double _cachedDisplacement_cc = double.NaN; /// /// 缓存数据来源标识(用于调试):ExpInfo=实验信息, Config=配置文件, Default=默认值 /// private string _cachedSource = string.Empty; private int _CurDisplacementCc; /// /// 当前的排量信息(供 UI 展示) /// public int CurDisplacementCc { get { return _CurDisplacementCc; } set { _CurDisplacementCc = value; RaisePropertyChanged(); } } private double _HeatingCapacityQh_kW; /// /// 制热量 Qh [kW] /// public double HeatingCapacityQh_kW { get { return _HeatingCapacityQh_kW; } set { _HeatingCapacityQh_kW = value; RaisePropertyChanged(); } } private double _COPHeating; /// /// 压缩机性能系数 COP(制热)[-] /// public double COPHeating { get { return _COPHeating; } set { _COPHeating = value; RaisePropertyChanged(); } } private double _IsentropicEfficiencyPct; /// /// 等熵效率 ηs [%] /// public double IsentropicEfficiencyPct { get { return _IsentropicEfficiencyPct; } set { _IsentropicEfficiencyPct = value; RaisePropertyChanged(); } } private double _CoolingCapacityQc_kW; /// /// 制冷量 Qc [kW] /// public double CoolingCapacityQc_kW { get { return _CoolingCapacityQc_kW; } set { _CoolingCapacityQc_kW = value; RaisePropertyChanged(); } } private double _COPCooling; /// /// 压缩机性能系数 COP(制冷)[-] /// public double COPCooling { get { return _COPCooling; } set { _COPCooling = value; RaisePropertyChanged(); } } private double _VolumetricEfficiencyPct; /// /// 容积效率 ηv [%] /// public double VolumetricEfficiencyPct { get { return _VolumetricEfficiencyPct; } set { _VolumetricEfficiencyPct = value; RaisePropertyChanged(); } } /// /// 按流程图更新:制热量、COP(制热)、等熵效率、制冷量、COP(制冷)、容积效率。 /// /// /// 错误/警告信息输出。 /// - 当方法返回 时, 为失败原因,调用方应视为本周期计算无效。 /// - 当方法返回 非空时,表示仅部分结果无法计算(例如缺少排量导致容积效率为 NaN)。 /// /// /// 是否成功完成本周期的结果更新。 /// - :至少已成功更新 Qh/Qc/COP/ηs 等主要结果;容积效率可能因缺失排量而为 NaN。 /// - :关键输入或 REFPROP 计算失败,本周期结果不更新。 /// private bool TryUpdateThermodynamicSixResults(out string error) { error = string.Empty; if (InhPressTag == null || InhTempTag == null) { error = "缺少吸气压力/吸气温度标签"; return false; } if (TxvFrPressTag == null || TxvFrTempTag == null) { error = "缺少膨胀阀前压力/膨胀阀前温度标签"; return false; } if (ExPressTag == null || ExTempTag == null) { error = "缺少排气压力/排气温度标签"; return false; } if (HVPwTag == null) { error = "缺少 HV[W] 功率标签"; return false; } if (VRVTag == null) { error = "缺少总流量(冷媒流量)标签"; return false; } double suctionPress_BarA = InhPressTag.PVModel.EngValue; double suctionTemp_C = InhTempTag.PVModel.EngValue; double dischargePress_BarA = ExPressTag.PVModel.EngValue; double dischargeTemp_C = ExTempTag.PVModel.EngValue; double txvFrPress_BarA = TxvFrPressTag.PVModel.EngValue; double txvFrTemp_C = TxvFrTempTag.PVModel.EngValue; double totalFlow_kg_h = VRVTag.PVModel.EngValue; double w_W = HVPwTag.PVModel.EngValue; double speed_rpm = SpeedTag?.PVModel.EngValue ?? double.NaN; if (!TryGetCompressorDisplacement_cc(out var disp_cc, out var dispErr)) { error = dispErr; return false; } //这里把输入数据写死计算出结果。 //#if DEBUG // // 附件截图输入(单位换算:MPa -> BarA,kW -> W) // suctionPress_BarA = 0.3 * 10.0; // suctionTemp_C = 10.8; // dischargePress_BarA = 1.502 * 10.0; // dischargeTemp_C = 88.4; // txvFrPress_BarA = 1.494 * 10.0; // txvFrTemp_C = 45.0; // totalFlow_kg_h = 100.1; // w_W = 1.289 * 1000.0; // speed_rpm = 3004; // disp_cc = 35; //#endif if (!double.IsNaN(w_W) && !double.IsInfinity(w_W) && w_W == 0) { HeatingCapacityQh_kW = 0; CoolingCapacityQc_kW = 0; COPHeating = 0; COPCooling = 0; IsentropicEfficiencyPct = 0; VolumetricEfficiencyPct = 0; if (HeatingCapacityTag != null) { HeatingCapacityTag.PVModel.EngValue = 0; } if (COPHeatTag != null) { COPHeatTag.PVModel.EngValue = 0; } if (IsentrpEffTag != null) { IsentrpEffTag.PVModel.EngValue = 0; } if (CoolCapacityTag != null) { CoolCapacityTag.PVModel.EngValue = 0; } if (COPCoolTag != null) { COPCoolTag.PVModel.EngValue = 0; } if (VoltricEffTag != null) { VoltricEffTag.PVModel.EngValue = 0; } return true; } var calcInput = new ThermodynamicSixResultsCalculator.Input( suctionPress_BarA: suctionPress_BarA, suctionTemp_C: suctionTemp_C, dischargePress_BarA: dischargePress_BarA, dischargeTemp_C: dischargeTemp_C, txvFrPress_BarA: txvFrPress_BarA, txvFrTemp_C: txvFrTemp_C, hvPower_W: w_W, totalFlow_kg_h: totalFlow_kg_h, speed_rpm: speed_rpm, displacement_cc: disp_cc); if (!_thermodynamicSixResultsCalculator.TryCalculate(calcInput, out var r, out var calcErr)) { error = calcErr; return false; } HeatingCapacityQh_kW = r.HeatingCapacityQh_kW; CoolingCapacityQc_kW = r.CoolingCapacityQc_kW; COPHeating = r.COPHeating; COPCooling = r.COPCooling; IsentropicEfficiencyPct = r.IsentropicEfficiencyPct; if (HeatingCapacityTag != null) { HeatingCapacityTag.PVModel.EngValue = HeatingCapacityQh_kW * 1000.0; } if (COPHeatTag != null) { COPHeatTag.PVModel.EngValue = COPHeating; } if (IsentrpEffTag != null) { IsentrpEffTag.PVModel.EngValue = IsentropicEfficiencyPct; } if (CoolCapacityTag != null) { CoolCapacityTag.PVModel.EngValue = CoolingCapacityQc_kW * 1000.0; } if (COPCoolTag != null) { COPCoolTag.PVModel.EngValue = COPCooling; } if (double.IsNaN(r.VolumetricEfficiencyPct) || double.IsInfinity(r.VolumetricEfficiencyPct)) { VolumetricEfficiencyPct = double.NaN; error = calcErr; return true; } VolumetricEfficiencyPct = r.VolumetricEfficiencyPct; if (VoltricEffTag != null) { VoltricEffTag.PVModel.EngValue = VolumetricEfficiencyPct; } error = calcErr; return true; } /// /// 获取压缩机排量(使用缓存机制,避免每次计算周期实时读取) /// /// 排量输出,单位 cc(cm³/rev)。 /// 失败原因(仅在缓存异常时返回)。 /// 始终返回 true(因为默认回退 35cc 保证缓存始终有效)。 private bool TryGetCompressorDisplacement_cc(out double displacement_cc, out string error) { displacement_cc = _cachedDisplacement_cc; error = string.Empty; return true; } /// /// 刷新压缩机排量缓存,按优先级读取:实验信息 → 配置文件 → 默认值 /// 在实验切换时自动调用,保证缓存与当前实验信息一致 /// private void RefreshDisplacementCache() { const double defaultDisplacementCc = 35d; double displacementCc = defaultDisplacementCc; string source = "Default"; // 优先级1:从当前实验信息读取 if (ConfigService?.CurExpInfo != null && TryParseCompressorDisplacementTextToCc(ConfigService.CurExpInfo.CapDisplacement, out var expCc) && expCc > 0) { displacementCc = expCc; source = "ExpInfo"; } // 优先级2:从 App.config 配置读取 else if (ConfigHelper.IsExist("CompressorDisplacementCc") && TryParseCompressorDisplacementTextToCc(ConfigHelper.GetValue("CompressorDisplacementCc"), out var cfgCc) && cfgCc > 0) { displacementCc = cfgCc; source = "Config"; } // 优先级3:使用默认值 else { displacementCc = defaultDisplacementCc; source = "Default"; } // 更新缓存字段 _cachedDisplacement_cc = displacementCc; _cachedSource = source; // 同步更新 UI 展示属性 CurDisplacementCc = (int)displacementCc; // 记录日志(便于调试) Logger?.Info($"压缩机排量缓存已刷新: {displacementCc}cc (来源: {source})"); } /// /// 强制刷新压缩机排量缓存(供外部主动调用,用于调试或特殊情况如 App.config 配置修改后) /// public void ForceRefreshDisplacementCache() { RefreshDisplacementCache(); } private static bool TryParseCompressorDisplacementTextToCc(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; } #endregion } }