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
}
}