6个物性参数和干度的公式的更改
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
<add key="PLCIP" value="127.0.0.1"/>
|
<add key="PLCIP" value="127.0.0.1"/>
|
||||||
<add key="FluidsPath" value="D:\fluids"/>
|
<add key="FluidsPath" value="D:\fluids"/>
|
||||||
<add key="Cryogen" value="R134a"/>
|
<add key="Cryogen" value="R134a"/>
|
||||||
|
<add key="Therdy_H3TempOffset_C" value="-10"/>
|
||||||
<add key="LocalDBPath" value="D:\MSDB\LocalDb\CapMachineDb"/>
|
<add key="LocalDBPath" value="D:\MSDB\LocalDb\CapMachineDb"/>
|
||||||
</appSettings>
|
</appSettings>
|
||||||
</configuration>
|
</configuration>
|
||||||
640
CapMachine.Wpf/PPCalculation/EnthalpyDrynessCalculator.cs
Normal file
640
CapMachine.Wpf/PPCalculation/EnthalpyDrynessCalculator.cs
Normal file
@@ -0,0 +1,640 @@
|
|||||||
|
using CapMachine.Core;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace CapMachine.Wpf.PPCalculation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 干度(品质)计算器:按“焓加权混合 + 饱和焓归一化”的流程计算 Dryness1/Dryness2。
|
||||||
|
/// </summary>
|
||||||
|
public sealed class EnthalpyDrynessCalculator
|
||||||
|
{
|
||||||
|
private readonly object _refpropLock;
|
||||||
|
|
||||||
|
private static volatile bool _rpInitialized;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="refpropLock">REFPROP 全局互斥锁对象(必须与系统其它 REFPROP 调用共用,以避免并发竞态)。</param>
|
||||||
|
public EnthalpyDrynessCalculator(object refpropLock)
|
||||||
|
{
|
||||||
|
_refpropLock = refpropLock ?? throw new ArgumentNullException(nameof(refpropLock));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 干度计算输入模型(以 Tag 读数为准)。
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct Input
|
||||||
|
{
|
||||||
|
public Input(
|
||||||
|
double gasPreValvePressBarA,
|
||||||
|
double gasPreValveTempC,
|
||||||
|
double txvFrPressBarA,
|
||||||
|
double txvFrTempC,
|
||||||
|
double inhPressBarA,
|
||||||
|
double vrvFlowKgPerH,
|
||||||
|
double liqRefFlowKgPerH,
|
||||||
|
double lubeFlowKgPerH)
|
||||||
|
{
|
||||||
|
GasPreValvePressBarA = gasPreValvePressBarA;
|
||||||
|
GasPreValveTempC = gasPreValveTempC;
|
||||||
|
TxvFrPressBarA = txvFrPressBarA;
|
||||||
|
TxvFrTempC = txvFrTempC;
|
||||||
|
InhPressBarA = inhPressBarA;
|
||||||
|
VRVFlowKgPerH = vrvFlowKgPerH;
|
||||||
|
LiqRefFlowKgPerH = liqRefFlowKgPerH;
|
||||||
|
LubeFlowKgPerH = lubeFlowKgPerH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double GasPreValvePressBarA { get; }
|
||||||
|
public double GasPreValveTempC { get; }
|
||||||
|
public double TxvFrPressBarA { get; }
|
||||||
|
public double TxvFrTempC { get; }
|
||||||
|
public double InhPressBarA { get; }
|
||||||
|
|
||||||
|
public double VRVFlowKgPerH { get; }
|
||||||
|
public double LiqRefFlowKgPerH { get; }
|
||||||
|
public double LubeFlowKgPerH { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 干度计算输出模型。
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct Result
|
||||||
|
{
|
||||||
|
public Result(
|
||||||
|
double gasFlowKgPerH,
|
||||||
|
double gasEnthalpy_kJkg,
|
||||||
|
double liquidEnthalpy_kJkg,
|
||||||
|
double satLiquidEnthalpy_kJkg,
|
||||||
|
double satVaporEnthalpy_kJkg,
|
||||||
|
bool isDryness1Success,
|
||||||
|
double dryness1_01,
|
||||||
|
double hMix1_kJkg,
|
||||||
|
string error1,
|
||||||
|
bool isDryness2Success,
|
||||||
|
double dryness2_01,
|
||||||
|
double hMix2_kJkg,
|
||||||
|
string error2)
|
||||||
|
{
|
||||||
|
GasFlowKgPerH = gasFlowKgPerH;
|
||||||
|
GasEnthalpy_kJkg = gasEnthalpy_kJkg;
|
||||||
|
LiquidEnthalpy_kJkg = liquidEnthalpy_kJkg;
|
||||||
|
SatLiquidEnthalpy_kJkg = satLiquidEnthalpy_kJkg;
|
||||||
|
SatVaporEnthalpy_kJkg = satVaporEnthalpy_kJkg;
|
||||||
|
|
||||||
|
IsDryness1Success = isDryness1Success;
|
||||||
|
Dryness1_01 = dryness1_01;
|
||||||
|
HMix1_kJkg = hMix1_kJkg;
|
||||||
|
Error1 = error1 ?? string.Empty;
|
||||||
|
|
||||||
|
IsDryness2Success = isDryness2Success;
|
||||||
|
Dryness2_01 = dryness2_01;
|
||||||
|
HMix2_kJkg = hMix2_kJkg;
|
||||||
|
Error2 = error2 ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double GasFlowKgPerH { get; }
|
||||||
|
public double GasEnthalpy_kJkg { get; }
|
||||||
|
public double LiquidEnthalpy_kJkg { get; }
|
||||||
|
public double SatLiquidEnthalpy_kJkg { get; }
|
||||||
|
public double SatVaporEnthalpy_kJkg { get; }
|
||||||
|
|
||||||
|
public bool IsDryness1Success { get; }
|
||||||
|
public double Dryness1_01 { get; }
|
||||||
|
public double HMix1_kJkg { get; }
|
||||||
|
public string Error1 { get; }
|
||||||
|
|
||||||
|
public bool IsDryness2Success { get; }
|
||||||
|
public double Dryness2_01 { get; }
|
||||||
|
public double HMix2_kJkg { get; }
|
||||||
|
public string Error2 { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算干度 1/2。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">输入数据。</param>
|
||||||
|
/// <returns>计算结果(包含两路干度及中间量)。</returns>
|
||||||
|
public Result Calculate(Input input)
|
||||||
|
{
|
||||||
|
if (!EnsureRefpropInitialized(out _))
|
||||||
|
{
|
||||||
|
return new Result(
|
||||||
|
gasFlowKgPerH: double.NaN,
|
||||||
|
gasEnthalpy_kJkg: double.NaN,
|
||||||
|
liquidEnthalpy_kJkg: double.NaN,
|
||||||
|
satLiquidEnthalpy_kJkg: double.NaN,
|
||||||
|
satVaporEnthalpy_kJkg: double.NaN,
|
||||||
|
isDryness1Success: false,
|
||||||
|
dryness1_01: double.NaN,
|
||||||
|
hMix1_kJkg: double.NaN,
|
||||||
|
error1: "REFPROP 未初始化",
|
||||||
|
isDryness2Success: false,
|
||||||
|
dryness2_01: double.NaN,
|
||||||
|
hMix2_kJkg: double.NaN,
|
||||||
|
error2: "REFPROP 未初始化");
|
||||||
|
}
|
||||||
|
|
||||||
|
double gasFlowKgPerH = input.VRVFlowKgPerH - input.LiqRefFlowKgPerH;
|
||||||
|
|
||||||
|
double gas_hVap_kJkg = 0.0;
|
||||||
|
if (TryTPRHO_VaporDensity_ByTP_MPa_C(input.GasPreValvePressBarA * 0.1, input.GasPreValveTempC, out var dVap_molL, out _))
|
||||||
|
{
|
||||||
|
if (TryTHERM_VaporEnthalpy_ByTD(input.GasPreValveTempC, dVap_molL, out var hVap_kJkg, out _))
|
||||||
|
{
|
||||||
|
gas_hVap_kJkg = hVap_kJkg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double liquid_hLiq_kJkg = 0.0;
|
||||||
|
if (TryTPRHO_LiquidDensity_ByTP_MPa_C(input.TxvFrPressBarA * 0.1, input.TxvFrTempC, out var dLiq_molL, out _))
|
||||||
|
{
|
||||||
|
if (TryTHERM_LiquidEnthalpy_ByTD(input.TxvFrTempC, dLiq_molL, out var hLiq_kJkg, out _))
|
||||||
|
{
|
||||||
|
liquid_hLiq_kJkg = hLiq_kJkg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double hSatL_kJkg = 0.0;
|
||||||
|
double hSatV_kJkg = 0.0;
|
||||||
|
if (TryGetSaturationLiquidEnthalpy_ByP_MPa(input.InhPressBarA * 0.1, out var satL, out _) &&
|
||||||
|
TryGetSaturationVaporEnthalpy_ByP_MPa(input.InhPressBarA * 0.1, out var satV, out _))
|
||||||
|
{
|
||||||
|
hSatL_kJkg = satL;
|
||||||
|
hSatV_kJkg = satV;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok1 = TryComputeDrynessByEnthalpy(
|
||||||
|
gas_hVap_kJkg,
|
||||||
|
liquid_hLiq_kJkg,
|
||||||
|
gasFlowKgPerH,
|
||||||
|
input.LiqRefFlowKgPerH,
|
||||||
|
hSatL_kJkg,
|
||||||
|
hSatV_kJkg,
|
||||||
|
out var dryness1,
|
||||||
|
out var hMix1,
|
||||||
|
out var err1);
|
||||||
|
|
||||||
|
bool ok2 = TryComputeDrynessByEnthalpy2(
|
||||||
|
gas_hVap_kJkg,
|
||||||
|
liquid_hLiq_kJkg,
|
||||||
|
gasFlowKgPerH,
|
||||||
|
input.LubeFlowKgPerH,
|
||||||
|
input.LiqRefFlowKgPerH,
|
||||||
|
hSatL_kJkg,
|
||||||
|
hSatV_kJkg,
|
||||||
|
out var dryness2,
|
||||||
|
out var hMix2,
|
||||||
|
out var err2);
|
||||||
|
|
||||||
|
return new Result(
|
||||||
|
gasFlowKgPerH: gasFlowKgPerH,
|
||||||
|
gasEnthalpy_kJkg: gas_hVap_kJkg,
|
||||||
|
liquidEnthalpy_kJkg: liquid_hLiq_kJkg,
|
||||||
|
satLiquidEnthalpy_kJkg: hSatL_kJkg,
|
||||||
|
satVaporEnthalpy_kJkg: hSatV_kJkg,
|
||||||
|
isDryness1Success: ok1,
|
||||||
|
dryness1_01: dryness1,
|
||||||
|
hMix1_kJkg: hMix1,
|
||||||
|
error1: err1,
|
||||||
|
isDryness2Success: ok2,
|
||||||
|
dryness2_01: dryness2,
|
||||||
|
hMix2_kJkg: hMix2,
|
||||||
|
error2: err2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// REFPROP 初始化(幂等)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="error">失败原因。</param>
|
||||||
|
/// <returns>是否初始化成功。</returns>
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
long hfmixLen = hfmix.Length;
|
||||||
|
long hrfLen = hrf.Length;
|
||||||
|
long 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}";
|
||||||
|
_rpInitialized = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryTPRHO_VaporDensity_ByTP_MPa_C(double pressureMPa, double temperatureC, out double densityMolPerL, out string error)
|
||||||
|
{
|
||||||
|
densityMolPerL = double.NaN;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
double tK = temperatureC + 273.15;
|
||||||
|
double pKPa = pressureMPa * 1000.0;
|
||||||
|
|
||||||
|
double[] x = new double[20];
|
||||||
|
x[0] = 1.0;
|
||||||
|
|
||||||
|
long kph = 2;
|
||||||
|
long kguess = 0;
|
||||||
|
double D = 0.0;
|
||||||
|
long ierr = 0;
|
||||||
|
long herrLen = 255;
|
||||||
|
string herr = new string(' ', 255);
|
||||||
|
|
||||||
|
lock (_refpropLock)
|
||||||
|
{
|
||||||
|
IRefProp64.TPRHOdll(ref tK, ref pKPa, x, ref kph, ref kguess, ref D, ref ierr, ref herr, ref herrLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ierr != 0)
|
||||||
|
{
|
||||||
|
error = $"TPRHO 错误: {herr.Trim()} (ierr={ierr})";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
densityMolPerL = D;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryTPRHO_LiquidDensity_ByTP_MPa_C(double pressureMPa, double temperatureC, out double densityMolPerL, out string error)
|
||||||
|
{
|
||||||
|
densityMolPerL = double.NaN;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
double tK = temperatureC + 273.15;
|
||||||
|
double pKPa = pressureMPa * 1000.0;
|
||||||
|
|
||||||
|
double[] x = new double[20];
|
||||||
|
x[0] = 1.0;
|
||||||
|
|
||||||
|
long kph = 1;
|
||||||
|
long kguess = 0;
|
||||||
|
double D = 0.0;
|
||||||
|
long ierr = 0;
|
||||||
|
long herrLen = 255;
|
||||||
|
string herr = new string(' ', 255);
|
||||||
|
|
||||||
|
lock (_refpropLock)
|
||||||
|
{
|
||||||
|
IRefProp64.TPRHOdll(ref tK, ref pKPa, x, ref kph, ref kguess, ref D, ref ierr, ref herr, ref herrLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ierr != 0)
|
||||||
|
{
|
||||||
|
error = $"TPRHO(液相) 错误: {herr.Trim()} (ierr={ierr})";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
densityMolPerL = D;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryTHERM_VaporEnthalpy_ByTD(double temperatureC, double densityMolPerL, out double h_vap_kJ_per_kg, out string error)
|
||||||
|
{
|
||||||
|
h_vap_kJ_per_kg = double.NaN;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
double tK = temperatureC + 273.15;
|
||||||
|
double D = densityMolPerL;
|
||||||
|
|
||||||
|
double[] x = new double[20];
|
||||||
|
x[0] = 1.0;
|
||||||
|
|
||||||
|
double pOut = 0, e = 0, hJmol = 0, sJmolK = 0, cv = 0, cp = 0, w = 0, hjt = 0;
|
||||||
|
|
||||||
|
if (!TryGetMolarMassKgPerMol(1, out var molarMassKgPerMol, out error))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_refpropLock)
|
||||||
|
{
|
||||||
|
IRefProp64.THERMdll(ref tK, ref D, x, ref pOut, ref e, ref hJmol, ref sJmolK, ref cv, ref cp, ref w, ref hjt);
|
||||||
|
}
|
||||||
|
|
||||||
|
h_vap_kJ_per_kg = (hJmol / molarMassKgPerMol) * 0.001;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryTHERM_LiquidEnthalpy_ByTD(double temperatureC, double densityMolPerL, out double h_liq_kJ_per_kg, out string error)
|
||||||
|
{
|
||||||
|
h_liq_kJ_per_kg = double.NaN;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
double tK = temperatureC + 273.15;
|
||||||
|
double D = densityMolPerL;
|
||||||
|
|
||||||
|
double[] x = new double[20];
|
||||||
|
x[0] = 1.0;
|
||||||
|
|
||||||
|
double pOut = 0, e = 0, hJmol = 0, sJmolK = 0, cv = 0, cp = 0, w = 0, hjt = 0;
|
||||||
|
|
||||||
|
if (!TryGetMolarMassKgPerMol(1, out var molarMassKgPerMol, out error))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_refpropLock)
|
||||||
|
{
|
||||||
|
IRefProp64.THERMdll(ref tK, ref D, x, ref pOut, ref e, ref hJmol, ref sJmolK, ref cv, ref cp, ref w, ref hjt);
|
||||||
|
}
|
||||||
|
|
||||||
|
h_liq_kJ_per_kg = (hJmol / molarMassKgPerMol) * 0.001;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TrySATP_SaturationByP_MPa(double pressureMPa, out double tSatK, out double Dl_molL, out double Dv_molL, out string error)
|
||||||
|
{
|
||||||
|
tSatK = double.NaN;
|
||||||
|
Dl_molL = double.NaN;
|
||||||
|
Dv_molL = double.NaN;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
double pKPa = pressureMPa * 1000.0;
|
||||||
|
double[] x = new double[20];
|
||||||
|
x[0] = 1.0;
|
||||||
|
|
||||||
|
long kph = 1;
|
||||||
|
double Dl = 0, Dv = 0;
|
||||||
|
double[] xliq = new double[20];
|
||||||
|
double[] xvap = new double[20];
|
||||||
|
long ierr = 0, herrLen = 255;
|
||||||
|
string herr = new string(' ', 255);
|
||||||
|
|
||||||
|
lock (_refpropLock)
|
||||||
|
{
|
||||||
|
IRefProp64.SATPdll(ref pKPa, x, ref kph, ref tSatK, ref Dl, ref Dv, xliq, xvap, ref ierr, ref herr, ref herrLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ierr != 0)
|
||||||
|
{
|
||||||
|
error = $"SATP 错误: {herr.Trim()} (ierr={ierr})";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dl_molL = Dl;
|
||||||
|
Dv_molL = Dv;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryTHERM_Enthalpy_kJkg_ByT_K_D(double temperatureK, double densityMolPerL, out double h_kJ_per_kg, out string error)
|
||||||
|
{
|
||||||
|
h_kJ_per_kg = double.NaN;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
double tK = temperatureK;
|
||||||
|
double D = densityMolPerL;
|
||||||
|
|
||||||
|
double[] x = new double[20];
|
||||||
|
x[0] = 1.0;
|
||||||
|
|
||||||
|
double pOut = 0, e = 0, hJmol = 0, sJmolK = 0, cv = 0, cp = 0, w = 0, hjt = 0;
|
||||||
|
|
||||||
|
if (!TryGetMolarMassKgPerMol(1, out var molarMassKgPerMol, out error))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_refpropLock)
|
||||||
|
{
|
||||||
|
IRefProp64.THERMdll(ref tK, ref D, x, ref pOut, ref e, ref hJmol, ref sJmolK, ref cv, ref cp, ref w, ref hjt);
|
||||||
|
}
|
||||||
|
|
||||||
|
h_kJ_per_kg = (hJmol / molarMassKgPerMol) * 0.001;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryGetSaturationLiquidEnthalpy_ByP_MPa(double pressureMPa, out double h_liq_kJkg, out string error)
|
||||||
|
{
|
||||||
|
h_liq_kJkg = double.NaN;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
if (!TrySATP_SaturationByP_MPa(pressureMPa, out double tSatK, out double Dl, out _, out error))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TryTHERM_Enthalpy_kJkg_ByT_K_D(tSatK, Dl, out h_liq_kJkg, out error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryGetSaturationVaporEnthalpy_ByP_MPa(double pressureMPa, out double h_vap_kJkg, out string error)
|
||||||
|
{
|
||||||
|
h_vap_kJkg = double.NaN;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
if (!TrySATP_SaturationByP_MPa(pressureMPa, out double tSatK, out _, out double Dv, out error))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TryTHERM_Enthalpy_kJkg_ByT_K_D(tSatK, Dv, out h_vap_kJkg, out error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryComputeDrynessByEnthalpy(
|
||||||
|
double hVap_kJkg,
|
||||||
|
double hLiq_kJkg,
|
||||||
|
double mGas_kg_h,
|
||||||
|
double mLiq_kg_h,
|
||||||
|
double hSatL_kJkg,
|
||||||
|
double hSatV_kJkg,
|
||||||
|
out double dryness,
|
||||||
|
out double hMix_kJkg,
|
||||||
|
out string error)
|
||||||
|
{
|
||||||
|
dryness = double.NaN;
|
||||||
|
hMix_kJkg = double.NaN;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
if (double.IsNaN(hVap_kJkg) || double.IsNaN(hLiq_kJkg) || double.IsNaN(hSatL_kJkg) || double.IsNaN(hSatV_kJkg))
|
||||||
|
{
|
||||||
|
error = "输入焓值存在 NaN";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (double.IsNaN(mGas_kg_h) || double.IsNaN(mLiq_kg_h))
|
||||||
|
{
|
||||||
|
error = "输入质量流量存在 NaN";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double mg = Math.Max(0.0, mGas_kg_h);
|
||||||
|
double ml = Math.Max(0.0, mLiq_kg_h);
|
||||||
|
double mSum = mg + ml;
|
||||||
|
if (mSum <= 0)
|
||||||
|
{
|
||||||
|
error = "气液质量流量之和为 0,无法进行加权混合焓计算";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hMix_kJkg = (hVap_kJkg * mg + hLiq_kJkg * ml) / mSum;
|
||||||
|
|
||||||
|
double denom = (hSatV_kJkg - hSatL_kJkg);
|
||||||
|
const double eps = 1e-9;
|
||||||
|
if (Math.Abs(denom) < eps)
|
||||||
|
{
|
||||||
|
error = "饱和气/液焓差过小,无法计算干度(可能接近临界点或输入异常)";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double x = (hMix_kJkg - hSatL_kJkg) / denom;
|
||||||
|
|
||||||
|
if (double.IsNaN(x) || double.IsInfinity(x))
|
||||||
|
{
|
||||||
|
error = "干度计算结果异常(NaN/Inf)";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dryness = Math.Min(1.0, Math.Max(0.0, x));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryComputeDrynessByEnthalpy2(
|
||||||
|
double hVap_kJkg,
|
||||||
|
double hLiq_kJkg,
|
||||||
|
double mGas_kg_h,
|
||||||
|
double lubeFlow_kg_h,
|
||||||
|
double mLiq_kg_h,
|
||||||
|
double hSatL_kJkg,
|
||||||
|
double hSatV_kJkg,
|
||||||
|
out double dryness,
|
||||||
|
out double hMix_kJkg,
|
||||||
|
out string error)
|
||||||
|
{
|
||||||
|
dryness = double.NaN;
|
||||||
|
hMix_kJkg = double.NaN;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
if (double.IsNaN(hVap_kJkg) || double.IsNaN(hLiq_kJkg) || double.IsNaN(hSatL_kJkg) || double.IsNaN(hSatV_kJkg))
|
||||||
|
{
|
||||||
|
error = "输入焓值存在 NaN";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (double.IsNaN(mGas_kg_h) || double.IsNaN(mLiq_kg_h))
|
||||||
|
{
|
||||||
|
error = "输入质量流量存在 NaN";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double mg = Math.Max(0.0, mGas_kg_h) + Math.Max(0.0, lubeFlow_kg_h);
|
||||||
|
double ml = Math.Max(0.0, mLiq_kg_h);
|
||||||
|
double mSum = mg + ml;
|
||||||
|
if (mSum <= 0)
|
||||||
|
{
|
||||||
|
error = "气液质量流量之和为 0,无法进行加权混合焓计算";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hMix_kJkg = (hVap_kJkg * mg + hLiq_kJkg * ml) / mSum;
|
||||||
|
|
||||||
|
double denom = (hSatV_kJkg - hSatL_kJkg);
|
||||||
|
const double eps = 1e-9;
|
||||||
|
if (Math.Abs(denom) < eps)
|
||||||
|
{
|
||||||
|
error = "饱和气/液焓差过小,无法计算干度(可能接近临界点或输入异常)";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double x = (hMix_kJkg - hSatL_kJkg) / denom;
|
||||||
|
|
||||||
|
if (double.IsNaN(x) || double.IsInfinity(x))
|
||||||
|
{
|
||||||
|
error = "干度计算结果异常(NaN/Inf)";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dryness = Math.Min(1.0, Math.Max(0.0, x));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetMolarMassKgPerMol(long componentId, out double molarMassKgPerMol, out string error)
|
||||||
|
{
|
||||||
|
molarMassKgPerMol = double.NaN;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
double wmm = 0;
|
||||||
|
double Trp = 0;
|
||||||
|
double Tnbpt = 0;
|
||||||
|
double Tc = 0;
|
||||||
|
double Pc = 0;
|
||||||
|
double Dc = 0;
|
||||||
|
double Zc = 0;
|
||||||
|
double acf = 0;
|
||||||
|
double dip = 0;
|
||||||
|
double Rgas = 0;
|
||||||
|
IRefProp64.INFOdll(ref componentId, ref wmm, ref Trp, ref Tnbpt, ref Tc, ref Pc, ref Dc, ref Zc, ref acf, ref dip, ref Rgas);
|
||||||
|
molarMassKgPerMol = wmm * 0.001;
|
||||||
|
if (molarMassKgPerMol <= 0)
|
||||||
|
{
|
||||||
|
error = "无效的摩尔质量";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
error = $"读取摩尔质量异常: {ex.Message}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,9 +32,10 @@ namespace CapMachine.Wpf.Services
|
|||||||
public ILogService Logger { get; }
|
public ILogService Logger { get; }
|
||||||
public MachineRtDataService MachineRtDataService { get; }
|
public MachineRtDataService MachineRtDataService { get; }
|
||||||
public IDialogService DialogService { get; }
|
public IDialogService DialogService { get; }
|
||||||
|
private readonly object _refpropLock = new object();
|
||||||
private readonly PPCSuperheatSubcoolCalculator _superheatSubcoolCalculator;
|
private readonly PPCSuperheatSubcoolCalculator _superheatSubcoolCalculator;
|
||||||
private readonly PPCThermodynamicSixResultsCalculator _thermodynamicSixResultsCalculator;
|
private readonly PPCThermodynamicSixResultsCalculator _thermodynamicSixResultsCalculator;
|
||||||
|
private readonly EnthalpyDrynessCalculator _enthalpyDrynessCalculator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标签中心
|
/// 标签中心
|
||||||
@@ -71,39 +72,39 @@ namespace CapMachine.Wpf.Services
|
|||||||
|
|
||||||
InhTempTag = TagManager.DicTags.GetValueOrDefault("吸气温度[℃]");
|
InhTempTag = TagManager.DicTags.GetValueOrDefault("吸气温度[℃]");
|
||||||
|
|
||||||
//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]")!;
|
|
||||||
|
|
||||||
TxvFrTempTag = TagManager.DicTags.GetValueOrDefault("膨胀阀前温度[℃]");
|
TxvFrTempTag = TagManager.DicTags.GetValueOrDefault("膨胀阀前温度[℃]");
|
||||||
|
|
||||||
TxvFrPressTag = TagManager.DicTags.GetValueOrDefault("膨胀阀前压力[BarA]");
|
TxvFrPressTag = TagManager.DicTags.GetValueOrDefault("膨胀阀前压力[BarA]");
|
||||||
|
|
||||||
//LiqRefFlowTag = TagManager.DicTags.GetValueOrDefault("液冷媒流量[kg/h]");
|
GasPreValvePressTag = TagManager.DicTags.GetValueOrDefault("气路阀前压力[BarA]");
|
||||||
|
GasPreValveTempTag = TagManager.DicTags.GetValueOrDefault("气路阀前温度[℃]");
|
||||||
|
|
||||||
//kg/h
|
DrynessTag = TagManager.DicTags.GetValueOrDefault("干度[-]");
|
||||||
|
if (DrynessTag == null)
|
||||||
|
{
|
||||||
|
DrynessTag = TagManager.DicTags.GetValueOrDefault("干度");
|
||||||
|
}
|
||||||
|
|
||||||
|
VRVTag = TagManager.DicTags.GetValueOrDefault("冷媒流量[kg/h]");
|
||||||
|
if (VRVTag == null)
|
||||||
|
{
|
||||||
VRVTag = TagManager.DicTags.GetValueOrDefault("冷媒流量[L/min]");
|
VRVTag = TagManager.DicTags.GetValueOrDefault("冷媒流量[L/min]");
|
||||||
|
}
|
||||||
|
|
||||||
//润滑油流量
|
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("润滑油流量[L/min]");
|
LubeFlowTag = TagManager.DicTags.GetValueOrDefault("润滑油流量[L/min]");
|
||||||
|
}
|
||||||
|
|
||||||
//Cond1TempTag = TagManager.DicTags.GetValueOrDefault("冷凝器出口水温[℃]");
|
|
||||||
//CondInTempTag = TagManager.DicTags.GetValueOrDefault("冷凝器进口温度[℃]");
|
|
||||||
|
|
||||||
//Superheat = TagManager.DicTags.GetValueOrDefault("过热度[K]");
|
|
||||||
//Subcool = TagManager.DicTags.GetValueOrDefault("过冷度[K]");
|
|
||||||
|
|
||||||
Superheat = TagManager.DicTags.GetValueOrDefault("过热度[K]");
|
Superheat = TagManager.DicTags.GetValueOrDefault("过热度[K]");
|
||||||
|
|
||||||
|
|
||||||
Subcool = TagManager.DicTags.GetValueOrDefault("过冷度[K]");
|
Subcool = TagManager.DicTags.GetValueOrDefault("过冷度[K]");
|
||||||
|
|
||||||
HeatingCapacity = TagManager.DicTags.GetValueOrDefault("制热量Qh[KW]");
|
HeatingCapacity = TagManager.DicTags.GetValueOrDefault("制热量Qh[KW]");
|
||||||
@@ -113,15 +114,37 @@ namespace CapMachine.Wpf.Services
|
|||||||
COPCool = TagManager.DicTags.GetValueOrDefault("压缩机性能系数(制冷)[K]");
|
COPCool = TagManager.DicTags.GetValueOrDefault("压缩机性能系数(制冷)[K]");
|
||||||
VoltricEff = TagManager.DicTags.GetValueOrDefault("容积效率nv[%]");
|
VoltricEff = TagManager.DicTags.GetValueOrDefault("容积效率nv[%]");
|
||||||
|
|
||||||
|
|
||||||
SuperHeatCoolConfig.FluidsPath = ConfigHelper.GetValue("FluidsPath");
|
SuperHeatCoolConfig.FluidsPath = ConfigHelper.GetValue("FluidsPath");
|
||||||
SuperHeatCoolConfig.Cryogen = ConfigHelper.GetValue("Cryogen");
|
SuperHeatCoolConfig.Cryogen = ConfigHelper.GetValue("Cryogen");
|
||||||
_superheatSubcoolCalculator = new PPCSuperheatSubcoolCalculator();
|
_superheatSubcoolCalculator = new PPCSuperheatSubcoolCalculator();
|
||||||
_thermodynamicSixResultsCalculator = new PPCThermodynamicSixResultsCalculator();
|
_thermodynamicSixResultsCalculator = new PPCThermodynamicSixResultsCalculator(_refpropLock);
|
||||||
|
_enthalpyDrynessCalculator = new EnthalpyDrynessCalculator(_refpropLock);
|
||||||
|
ReloadTherdyH3TempOffset();
|
||||||
|
|
||||||
RtScanDeviceStart();
|
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>
|
||||||
/// 当前的配置
|
/// 当前的配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -227,7 +250,6 @@ namespace CapMachine.Wpf.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ITag LubeFlowTag { get; set; }
|
public ITag LubeFlowTag { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public ITag HeatingCapacity { get; set; }
|
public ITag HeatingCapacity { get; set; }
|
||||||
public ITag COPHeat { get; set; }
|
public ITag COPHeat { get; set; }
|
||||||
public ITag IsentrpEff { get; set; }
|
public ITag IsentrpEff { get; set; }
|
||||||
@@ -235,7 +257,6 @@ namespace CapMachine.Wpf.Services
|
|||||||
public ITag COPCool { get; set; }
|
public ITag COPCool { get; set; }
|
||||||
public ITag VoltricEff { get; set; }
|
public ITag VoltricEff { get; set; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 风量数据-乘以系数的后的最终结果
|
/// 风量数据-乘以系数的后的最终结果
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -261,6 +282,48 @@ namespace CapMachine.Wpf.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private bool DebugLog { get; set; } = false;
|
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>
|
/// <summary>
|
||||||
/// PLC扫描线程
|
/// PLC扫描线程
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -281,6 +344,21 @@ namespace CapMachine.Wpf.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 (TryUpdateThermodynamicSixResults(out var thermoErr))
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(thermoErr))
|
if (!string.IsNullOrWhiteSpace(thermoErr))
|
||||||
@@ -305,27 +383,12 @@ namespace CapMachine.Wpf.Services
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新过热度与过冷度结果。
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="error">
|
|
||||||
/// 错误汇总输出。
|
|
||||||
/// 当两个结果都失败时,返回拼接后的失败原因;
|
|
||||||
/// 当仅一个结果失败时,只返回该项失败原因;
|
|
||||||
/// 当至少有一项成功更新时,方法返回 <see langword="true"/>。
|
|
||||||
/// </param>
|
|
||||||
/// <returns>
|
|
||||||
/// 是否至少成功更新了一个结果。
|
|
||||||
/// 该方法保持原有行为:过热度和过冷度彼此独立,只要其中之一成功就返回 <see langword="true"/>。
|
|
||||||
/// </returns>
|
|
||||||
private bool TryUpdateSuperheatAndSubcool(out string error)
|
private bool TryUpdateSuperheatAndSubcool(out string error)
|
||||||
{
|
{
|
||||||
error = string.Empty;
|
error = string.Empty;
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
StringBuilder errorBuilder = new StringBuilder();
|
StringBuilder errorBuilder = new StringBuilder();
|
||||||
|
|
||||||
// 第一段:收集过热度所需标签,并把实时值直接交给独立计算类。
|
|
||||||
// PPCService 只负责“取值 + 回写”,具体热力学过程由 PPCSuperheatSubcoolCalculator 承担。
|
|
||||||
if (InhPressTag == null || InhTempTag == null || Superheat == null)
|
if (InhPressTag == null || InhTempTag == null || Superheat == null)
|
||||||
{
|
{
|
||||||
AppendCalculationError(errorBuilder, "缺少过热度计算标签");
|
AppendCalculationError(errorBuilder, "缺少过热度计算标签");
|
||||||
@@ -340,8 +403,6 @@ namespace CapMachine.Wpf.Services
|
|||||||
AppendCalculationError(errorBuilder, superheatErr);
|
AppendCalculationError(errorBuilder, superheatErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第二段:收集过冷度所需标签,并按同样方式委托给独立计算类。
|
|
||||||
// 两个结果互不阻塞,保持与旧实现一致的“部分成功也可回写”的策略。
|
|
||||||
if (TxvFrPressTag == null || TxvFrTempTag == null || Subcool == null)
|
if (TxvFrPressTag == null || TxvFrTempTag == null || Subcool == null)
|
||||||
{
|
{
|
||||||
AppendCalculationError(errorBuilder, "缺少过冷度计算标签");
|
AppendCalculationError(errorBuilder, "缺少过冷度计算标签");
|
||||||
@@ -375,234 +436,67 @@ namespace CapMachine.Wpf.Services
|
|||||||
errorBuilder.Append(error);
|
errorBuilder.Append(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private bool TryUpdateDryness(out string error)
|
||||||
/// 按图片的最终流程计算干度:
|
|
||||||
/// 1) 质量流量加权混合焓 h_mix = (h_vap*mg + h_liq*ml) / (mg + ml)
|
|
||||||
/// 2) 干度 x = (h_mix - h_l) / (h_v - h_l),并限幅到 [0,1]
|
|
||||||
///
|
|
||||||
/// 入参单位:
|
|
||||||
/// - hVap_kJkg, hLiq_kJkg, hSatL_kJkg, hSatV_kJkg 均为 kJ/kg
|
|
||||||
/// - mGas_kg_h, mLiq_kg_h 均为 kg/h
|
|
||||||
/// 返回:true 表示成功,输出 x∈[0,1] 与 h_mix;false 返回 error
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hVap_kJkg">气相质量焓 h_vap [kJ/kg]</param>
|
|
||||||
/// <param name="hLiq_kJkg">液相质量焓 h_liq [kJ/kg]</param>
|
|
||||||
/// <param name="mGas_kg_h">气体质量流量 mg [kg/h]</param>
|
|
||||||
/// <param name="mLiq_kg_h">液体质量流量 ml [kg/h]</param>
|
|
||||||
/// <param name="hSatL_kJkg">饱和液质量焓 h_l [kJ/kg]</param>
|
|
||||||
/// <param name="hSatV_kJkg">饱和气质量焓 h_v [kJ/kg]</param>
|
|
||||||
/// <param name="dryness">输出干度 x ∈ [0,1]</param>
|
|
||||||
/// <param name="hMix_kJkg">输出混合后总比焓 h_mix [kJ/kg]</param>
|
|
||||||
/// <param name="error">Err</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool TryComputeDrynessByEnthalpy(
|
|
||||||
double hVap_kJkg, // 气相质量焓 h_vap [kJ/kg]
|
|
||||||
double hLiq_kJkg, // 液相质量焓 h_liq [kJ/kg]
|
|
||||||
double mGas_kg_h, // 气体质量流量 mg [kg/h]
|
|
||||||
double mLiq_kg_h, // 液体质量流量 ml [kg/h]
|
|
||||||
double hSatL_kJkg, // 饱和液质量焓 h_l [kJ/kg]
|
|
||||||
double hSatV_kJkg, // 饱和气质量焓 h_v [kJ/kg]
|
|
||||||
out double dryness, // 输出干度 x ∈ [0,1]
|
|
||||||
out double hMix_kJkg, // 输出混合后总比焓 h_mix [kJ/kg]
|
|
||||||
out string error)
|
|
||||||
{
|
{
|
||||||
dryness = double.NaN;
|
|
||||||
hMix_kJkg = double.NaN;
|
|
||||||
error = string.Empty;
|
error = string.Empty;
|
||||||
|
bool updated = false;
|
||||||
|
StringBuilder errorBuilder = new StringBuilder();
|
||||||
|
|
||||||
// 1) 合法性校验
|
if (GasPreValvePressTag == null || GasPreValveTempTag == null || TxvFrPressTag == null || TxvFrTempTag == null || InhPressTag == null)
|
||||||
if (double.IsNaN(hVap_kJkg) || double.IsNaN(hLiq_kJkg) || double.IsNaN(hSatL_kJkg) || double.IsNaN(hSatV_kJkg))
|
|
||||||
{
|
{
|
||||||
error = "输入焓值存在 NaN";
|
AppendCalculationError(errorBuilder, "缺少干度计算压力/温度标签");
|
||||||
|
error = errorBuilder.ToString();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (double.IsNaN(mGas_kg_h) || double.IsNaN(mLiq_kg_h))
|
if (VRVTag == null || LiqRefFlowTag == null)
|
||||||
{
|
{
|
||||||
error = "输入质量流量存在 NaN";
|
AppendCalculationError(errorBuilder, "缺少干度计算流量标签");
|
||||||
return false;
|
error = errorBuilder.ToString();
|
||||||
}
|
|
||||||
// 负值处理:小于 0 视为 0(避免传感器噪声或符号错误影响)
|
|
||||||
double mg = Math.Max(0.0, mGas_kg_h);
|
|
||||||
double ml = Math.Max(0.0, mLiq_kg_h);
|
|
||||||
double mSum = mg + ml;
|
|
||||||
if (mSum <= 0)
|
|
||||||
{
|
|
||||||
error = "气液质量流量之和为 0,无法进行加权混合焓计算";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) 质量流量加权混合焓(严格按图片:上、下两路相加后除以总流量)
|
double lubeFlowKgPerH = 0.0;
|
||||||
hMix_kJkg = (hVap_kJkg * mg + hLiq_kJkg * ml) / mSum;
|
if (LubeFlowTag != null)
|
||||||
|
|
||||||
// 3) 干度计算:x = (h_mix - h_l) / (h_v - h_l)
|
|
||||||
double denom = (hSatV_kJkg - hSatL_kJkg);
|
|
||||||
const double eps = 1e-9;
|
|
||||||
if (Math.Abs(denom) < eps)
|
|
||||||
{
|
{
|
||||||
error = "饱和气/液焓差过小,无法计算干度(可能接近临界点或输入异常)";
|
lubeFlowKgPerH = LubeFlowTag.EngPvValue;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double x = (hMix_kJkg - hSatL_kJkg) / denom;
|
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));
|
||||||
|
|
||||||
// 4) 限幅到 [0,1]
|
if (drynessResult.IsDryness1Success)
|
||||||
if (double.IsNaN(x) || double.IsInfinity(x))
|
|
||||||
{
|
{
|
||||||
error = "干度计算结果异常(NaN/Inf)";
|
if (DrynessTag != null)
|
||||||
return false;
|
{
|
||||||
|
DrynessTag.EngPvValue = Math.Round(drynessResult.Dryness1_01, 4);
|
||||||
}
|
}
|
||||||
dryness = Math.Min(1.0, Math.Max(0.0, x));
|
updated = true;
|
||||||
return true;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AppendCalculationError(errorBuilder, drynessResult.Error1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (drynessResult.IsDryness2Success)
|
||||||
/// <summary>
|
|
||||||
/// 按图片的最终流程计算干度2:
|
|
||||||
/// 干度2的计算:临时用作为对比使用
|
|
||||||
/// 1) 质量流量加权混合焓 h_mix = (h_vap*mg + h_liq*ml) / (mg + ml)
|
|
||||||
/// 2) 干度 x = (h_mix - h_l) / (h_v - h_l),并限幅到 [0,1]
|
|
||||||
///
|
|
||||||
/// 入参单位:
|
|
||||||
/// - hVap_kJkg, hLiq_kJkg, hSatL_kJkg, hSatV_kJkg 均为 kJ/kg
|
|
||||||
/// - mGas_kg_h, mLiq_kg_h 均为 kg/h
|
|
||||||
/// 返回:true 表示成功,输出 x∈[0,1] 与 h_mix;false 返回 error
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hVap_kJkg">气相质量焓 h_vap [kJ/kg]</param>
|
|
||||||
/// <param name="hLiq_kJkg">液相质量焓 h_liq [kJ/kg]</param>
|
|
||||||
/// <param name="mGas_kg_h">气体质量流量 mg [kg/h]</param>
|
|
||||||
/// <param name="mLiq_kg_h">液体质量流量 ml [kg/h]</param>
|
|
||||||
/// <param name="hSatL_kJkg">饱和液质量焓 h_l [kJ/kg]</param>
|
|
||||||
/// <param name="hSatV_kJkg">饱和气质量焓 h_v [kJ/kg]</param>
|
|
||||||
/// <param name="dryness">输出干度 x ∈ [0,1]</param>
|
|
||||||
/// <param name="hMix_kJkg">输出混合后总比焓 h_mix [kJ/kg]</param>
|
|
||||||
/// <param name="error">Err</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool TryComputeDrynessByEnthalpy2(
|
|
||||||
double hVap_kJkg, // 气相质量焓 h_vap [kJ/kg]
|
|
||||||
double hLiq_kJkg, // 液相质量焓 h_liq [kJ/kg]
|
|
||||||
double mGas_kg_h, // 气体质量流量 mg [kg/h]
|
|
||||||
double lubeFlow_kg_h, // 润滑油流量 mg [kg/h]
|
|
||||||
double mLiq_kg_h, // 液体质量流量 ml [kg/h]
|
|
||||||
double hSatL_kJkg, // 饱和液质量焓 h_l [kJ/kg]
|
|
||||||
double hSatV_kJkg, // 饱和气质量焓 h_v [kJ/kg]
|
|
||||||
out double dryness, // 输出干度 x ∈ [0,1]
|
|
||||||
out double hMix_kJkg, // 输出混合后总比焓 h_mix [kJ/kg]
|
|
||||||
out string error)
|
|
||||||
{
|
{
|
||||||
dryness = double.NaN;
|
DrynessTag2Value = Math.Round(drynessResult.Dryness2_01, 4);
|
||||||
hMix_kJkg = double.NaN;
|
updated = true;
|
||||||
error = string.Empty;
|
|
||||||
|
|
||||||
// 1) 合法性校验
|
|
||||||
if (double.IsNaN(hVap_kJkg) || double.IsNaN(hLiq_kJkg) || double.IsNaN(hSatL_kJkg) || double.IsNaN(hSatV_kJkg))
|
|
||||||
{
|
|
||||||
error = "输入焓值存在 NaN";
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (double.IsNaN(mGas_kg_h) || double.IsNaN(mLiq_kg_h))
|
else
|
||||||
{
|
{
|
||||||
error = "输入质量流量存在 NaN";
|
AppendCalculationError(errorBuilder, drynessResult.Error2);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// 负值处理:小于 0 视为 0(避免传感器噪声或符号错误影响)
|
|
||||||
//double mg1 = Math.Max(0.0, mGas_kg_h);
|
|
||||||
double mg = Math.Max(0.0, mGas_kg_h) + Math.Max(0.0, lubeFlow_kg_h); // 这个是改动 气体流量再加上润滑油流量
|
|
||||||
double ml = Math.Max(0.0, mLiq_kg_h);
|
|
||||||
double mSum = mg + ml;
|
|
||||||
if (mSum <= 0)
|
|
||||||
{
|
|
||||||
error = "气液质量流量之和为 0,无法进行加权混合焓计算";
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) 质量流量加权混合焓(严格按图片:上、下两路相加后除以总流量)
|
error = errorBuilder.ToString();
|
||||||
hMix_kJkg = (hVap_kJkg * mg + hLiq_kJkg * ml) / mSum;
|
return updated;
|
||||||
|
|
||||||
// 3) 干度计算:x = (h_mix - h_l) / (h_v - h_l)
|
|
||||||
double denom = (hSatV_kJkg - hSatL_kJkg);
|
|
||||||
const double eps = 1e-9;
|
|
||||||
if (Math.Abs(denom) < eps)
|
|
||||||
{
|
|
||||||
error = "饱和气/液焓差过小,无法计算干度(可能接近临界点或输入异常)";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double x = (hMix_kJkg - hSatL_kJkg) / denom;
|
|
||||||
|
|
||||||
// 4) 限幅到 [0,1]
|
|
||||||
if (double.IsNaN(x) || double.IsInfinity(x))
|
|
||||||
{
|
|
||||||
error = "干度计算结果异常(NaN/Inf)";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
dryness = Math.Min(1.0, Math.Max(0.0, x));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///制热量、压缩机性能系数COP(制热)、等熵效率、制冷量、压缩机性能系数COP(制冷)、容积效率 计算
|
|
||||||
#region
|
|
||||||
|
|
||||||
private double _HeatingCapacityQh_kW;
|
|
||||||
/// <summary>
|
|
||||||
/// 制热量 Qh [kW]
|
|
||||||
/// </summary>
|
|
||||||
public double HeatingCapacityQh_kW
|
|
||||||
{
|
|
||||||
get { return _HeatingCapacityQh_kW; }
|
|
||||||
set { _HeatingCapacityQh_kW = value; RaisePropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private double _COPHeating;
|
|
||||||
/// <summary>
|
|
||||||
/// 压缩机性能系数 COP(制热)[-]
|
|
||||||
/// </summary>
|
|
||||||
public double COPHeating
|
|
||||||
{
|
|
||||||
get { return _COPHeating; }
|
|
||||||
set { _COPHeating = value; RaisePropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private double _IsentropicEfficiencyPct;
|
|
||||||
/// <summary>
|
|
||||||
/// 等熵效率 ηs [%]
|
|
||||||
/// </summary>
|
|
||||||
public double IsentropicEfficiencyPct
|
|
||||||
{
|
|
||||||
get { return _IsentropicEfficiencyPct; }
|
|
||||||
set { _IsentropicEfficiencyPct = value; RaisePropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private double _CoolingCapacityQc_kW;
|
|
||||||
/// <summary>
|
|
||||||
/// 制冷量 Qc [kW]
|
|
||||||
/// </summary>
|
|
||||||
public double CoolingCapacityQc_kW
|
|
||||||
{
|
|
||||||
get { return _CoolingCapacityQc_kW; }
|
|
||||||
set { _CoolingCapacityQc_kW = value; RaisePropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private double _COPCooling;
|
|
||||||
/// <summary>
|
|
||||||
/// 压缩机性能系数 COP(制冷)[-]
|
|
||||||
/// </summary>
|
|
||||||
public double COPCooling
|
|
||||||
{
|
|
||||||
get { return _COPCooling; }
|
|
||||||
set { _COPCooling = value; RaisePropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private double _VolumetricEfficiencyPct;
|
|
||||||
/// <summary>
|
|
||||||
/// 容积效率 ηv [%]
|
|
||||||
/// </summary>
|
|
||||||
public double VolumetricEfficiencyPct
|
|
||||||
{
|
|
||||||
get { return _VolumetricEfficiencyPct; }
|
|
||||||
set { _VolumetricEfficiencyPct = value; RaisePropertyChanged(); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -690,11 +584,6 @@ namespace CapMachine.Wpf.Services
|
|||||||
error = "缺少总流量(冷媒流量)标签";
|
error = "缺少总流量(冷媒流量)标签";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (LubeFlowTag == null)
|
|
||||||
{
|
|
||||||
error = "缺少油流量标签";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (InhPressTag == null || InhTempTag == null)
|
if (InhPressTag == null || InhTempTag == null)
|
||||||
{
|
{
|
||||||
error = "缺少吸气压力/吸气温度标签";
|
error = "缺少吸气压力/吸气温度标签";
|
||||||
@@ -715,10 +604,15 @@ namespace CapMachine.Wpf.Services
|
|||||||
error = "缺少转速标签";
|
error = "缺少转速标签";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!TryGetCompressorDisplacement_cc(out var displacementCc, out var displacementErr))
|
if (!TryGetCompressorDisplacement_cc(out var displacementCc, out _))
|
||||||
{
|
{
|
||||||
error = displacementErr;
|
displacementCc = double.NaN;
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
double oilFlowKgPerH = 0.0;
|
||||||
|
if (LubeFlowTag != null)
|
||||||
|
{
|
||||||
|
oilFlowKgPerH = LubeFlowTag.EngPvValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将实时标签值与配置值组装为独立计算类可直接消费的输入对象。
|
// 将实时标签值与配置值组装为独立计算类可直接消费的输入对象。
|
||||||
@@ -726,7 +620,7 @@ namespace CapMachine.Wpf.Services
|
|||||||
{
|
{
|
||||||
CompressorPowerW = HVPwTag.EngPvValue,
|
CompressorPowerW = HVPwTag.EngPvValue,
|
||||||
TotalMassFlowKgPerHour = VRVTag.EngPvValue,
|
TotalMassFlowKgPerHour = VRVTag.EngPvValue,
|
||||||
OilMassFlowKgPerHour = LubeFlowTag.EngPvValue,
|
OilMassFlowKgPerHour = oilFlowKgPerH,
|
||||||
SuctionPressureBarA = InhPressTag.EngPvValue,
|
SuctionPressureBarA = InhPressTag.EngPvValue,
|
||||||
SuctionTemperatureC = InhTempTag.EngPvValue,
|
SuctionTemperatureC = InhTempTag.EngPvValue,
|
||||||
DischargePressureBarA = ExPressTag.EngPvValue,
|
DischargePressureBarA = ExPressTag.EngPvValue,
|
||||||
@@ -776,7 +670,5 @@ namespace CapMachine.Wpf.Services
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,12 +151,19 @@ namespace CapMachine.Wpf.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly LocalCalculationSupport _support;
|
private readonly LocalCalculationSupport _support;
|
||||||
|
|
||||||
|
private double _h3TempOffset_C = -10.0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化六个热力结果值计算类。
|
/// 初始化六个热力结果值计算类。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PPCThermodynamicSixResultsCalculator()
|
public PPCThermodynamicSixResultsCalculator(object refpropLock)
|
||||||
{
|
{
|
||||||
_support = new LocalCalculationSupport();
|
_support = new LocalCalculationSupport(refpropLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetH3TempOffset_C(double offsetC)
|
||||||
|
{
|
||||||
|
_h3TempOffset_C = offsetC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -219,7 +226,18 @@ namespace CapMachine.Wpf.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 第 5 步:由液路压力/温度求液路比焓 h3。
|
// 第 5 步:由液路压力/温度求液路比焓 h3。
|
||||||
if (!TryGetLiquidPointEnthalpy_ByTP_BarA_C(input.LiquidPressureBarA, input.LiquidTemperatureC, out var h3_kJkg, out var p3Err))
|
double liquidTempForH3_C = input.LiquidTemperatureC;
|
||||||
|
if (_support.TrySATP_SaturationByP_MPa(input.DischargePressureBarA * 0.1, out var tSatK, out _, out _, out var satErr))
|
||||||
|
{
|
||||||
|
liquidTempForH3_C = (tSatK - 273.15) + _h3TempOffset_C;
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrWhiteSpace(satErr))
|
||||||
|
{
|
||||||
|
error = string.IsNullOrWhiteSpace(error)
|
||||||
|
? $"h3温度改用SATP(排气压力)计算Tsat失败,已回退使用LiquidTemperatureC。原因: {satErr}"
|
||||||
|
: $"{error}; h3温度改用SATP(排气压力)计算Tsat失败,已回退使用LiquidTemperatureC。原因: {satErr}";
|
||||||
|
}
|
||||||
|
if (!TryGetLiquidPointEnthalpy_ByTP_BarA_C(input.LiquidPressureBarA, liquidTempForH3_C, out var h3_kJkg, out var p3Err))
|
||||||
{
|
{
|
||||||
error = $"h3 计算失败: {p3Err}";
|
error = $"h3 计算失败: {p3Err}";
|
||||||
return false;
|
return false;
|
||||||
@@ -240,7 +258,7 @@ namespace CapMachine.Wpf.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 第 8 步:计算等熵效率。
|
// 第 8 步:计算等熵效率。
|
||||||
if (!TryComputeIsentropicEfficiencyPct(h1_kJkg, h2_kJkg, h2s_kJkg, out var etaS_pct, out var etaSErr))
|
if (!TryComputeIsentropicEfficiencyPct(mRef_kg_s, h1_kJkg, h2s_kJkg, w_kW, out var etaS_pct, out var etaSErr))
|
||||||
{
|
{
|
||||||
error = etaSErr;
|
error = etaSErr;
|
||||||
return false;
|
return false;
|
||||||
@@ -259,7 +277,7 @@ namespace CapMachine.Wpf.Services
|
|||||||
// 同时把失败原因放到 error 中,供调用方决定是否记录为警告。
|
// 同时把失败原因放到 error 中,供调用方决定是否记录为警告。
|
||||||
if (!TryComputeVolumetricEfficiencyPct(mRef_kg_s, v1_m3kg, input.CompressorSpeedRpm, input.CompressorDisplacementCc, out var etaV_pct, out var etaVErr))
|
if (!TryComputeVolumetricEfficiencyPct(mRef_kg_s, v1_m3kg, input.CompressorSpeedRpm, input.CompressorDisplacementCc, out var etaV_pct, out var etaVErr))
|
||||||
{
|
{
|
||||||
error = etaVErr;
|
error = string.IsNullOrWhiteSpace(error) ? etaVErr : $"{error}; {etaVErr}";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,9 +321,8 @@ namespace CapMachine.Wpf.Services
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// 当前流程保持与图片/旧代码一致:
|
/// 当前流程保持与图片/旧代码一致:
|
||||||
/// 1. 读取总流量 kg/h
|
/// 1. 读取总流量 kg/h
|
||||||
/// 2. 读取油流量 kg/h
|
/// 2. 冷媒流量 = 总流量
|
||||||
/// 3. 冷媒流量 = 总流量 - 油流量
|
/// 3. 再由 kg/h 换算为 kg/s
|
||||||
/// 4. 再由 kg/h 换算为 kg/s
|
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private bool TryGetRefrigerantMassFlow_kg_s(double totalMassFlowKgPerHour, double oilMassFlowKgPerHour, out double mRef_kg_s, out string error)
|
private bool TryGetRefrigerantMassFlow_kg_s(double totalMassFlowKgPerHour, double oilMassFlowKgPerHour, out double mRef_kg_s, out string error)
|
||||||
{
|
{
|
||||||
@@ -319,17 +336,10 @@ namespace CapMachine.Wpf.Services
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 再读取油流量。
|
double mRef_kg_h = mTotal_kg_h;
|
||||||
if (!TryGetOilMassFlow_kg_h(oilMassFlowKgPerHour, out var mOil_kg_h, out var oilErr))
|
if (mRef_kg_h <= 0)
|
||||||
{
|
{
|
||||||
error = oilErr;
|
error = $"冷媒质量流量<=0,总流量={mTotal_kg_h}kg/h";
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算真正参与循环的冷媒质量流量:mRef = mTotal - mOil。
|
|
||||||
if (!TryComputeRefrigerantMassFlow_kg_h(mTotal_kg_h, mOil_kg_h, out var mRef_kg_h, out var refErr))
|
|
||||||
{
|
|
||||||
error = refErr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,33 +824,45 @@ namespace CapMachine.Wpf.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 计算等熵效率,单位 %。
|
/// 计算等熵效率,单位 %。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="mRef_kg_s">冷媒质量流量,单位 kg/s。</param>
|
||||||
/// <param name="h1_kJkg">吸气比焓 h1,单位 kJ/kg。</param>
|
/// <param name="h1_kJkg">吸气比焓 h1,单位 kJ/kg。</param>
|
||||||
/// <param name="h2_kJkg">实际排气比焓 h2,单位 kJ/kg。</param>
|
|
||||||
/// <param name="h2s_kJkg">等熵出口比焓 h2s,单位 kJ/kg。</param>
|
/// <param name="h2s_kJkg">等熵出口比焓 h2s,单位 kJ/kg。</param>
|
||||||
|
/// <param name="w_kW">压缩机功率,单位 kW。</param>
|
||||||
/// <param name="etaS_pct">等熵效率输出,单位 %。</param>
|
/// <param name="etaS_pct">等熵效率输出,单位 %。</param>
|
||||||
/// <param name="error">失败原因。</param>
|
/// <param name="error">失败原因。</param>
|
||||||
/// <returns>是否计算成功。</returns>
|
/// <returns>是否计算成功。</returns>
|
||||||
private bool TryComputeIsentropicEfficiencyPct(double h1_kJkg, double h2_kJkg, double h2s_kJkg, out double etaS_pct, out string error)
|
private bool TryComputeIsentropicEfficiencyPct(double mRef_kg_s, double h1_kJkg, double h2s_kJkg, double w_kW, out double etaS_pct, out string error)
|
||||||
{
|
{
|
||||||
etaS_pct = double.NaN;
|
etaS_pct = double.NaN;
|
||||||
error = string.Empty;
|
error = string.Empty;
|
||||||
|
|
||||||
// 实际压缩焓升:(h2 - h1)。
|
if (double.IsNaN(mRef_kg_s) || double.IsInfinity(mRef_kg_s) || mRef_kg_s <= 0)
|
||||||
if (!TryComputeEnthalpyDifference_kJkg(h2_kJkg, h1_kJkg, "实际压缩焓升(h2-h1)", out var actualRise_kJkg, out var actualErr))
|
|
||||||
{
|
{
|
||||||
error = actualErr;
|
error = "无效冷媒质量流量";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (double.IsNaN(w_kW) || double.IsInfinity(w_kW) || w_kW <= 0)
|
||||||
|
{
|
||||||
|
error = "无效压缩机功率";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 等熵压缩焓升:(h2s - h1)。
|
|
||||||
if (!TryComputeEnthalpyDifference_kJkg(h2s_kJkg, h1_kJkg, "等熵压缩焓升(h2s-h1)", out var isentropicRise_kJkg, out var isoErr))
|
if (!TryComputeEnthalpyDifference_kJkg(h2s_kJkg, h1_kJkg, "等熵压缩焓升(h2s-h1)", out var isentropicRise_kJkg, out var isoErr))
|
||||||
{
|
{
|
||||||
error = isoErr;
|
error = isoErr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 等熵效率 = 等熵焓升 / 实际焓升 * 100%。
|
double eta = (mRef_kg_s * isentropicRise_kJkg) / w_kW;
|
||||||
return TryComputeEfficiencyPct(isentropicRise_kJkg, actualRise_kJkg, "等熵效率", out etaS_pct, out error);
|
if (double.IsNaN(eta) || double.IsInfinity(eta))
|
||||||
|
{
|
||||||
|
error = "等熵效率结果异常";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
etaS_pct = eta * 100.0;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1055,6 +1077,7 @@ namespace CapMachine.Wpf.Services
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 六个热力结果计算类私有的底层物性支持实现。
|
/// 六个热力结果计算类私有的底层物性支持实现。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1064,9 +1087,14 @@ namespace CapMachine.Wpf.Services
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
private sealed class LocalCalculationSupport : IPPCCalculationSupport
|
private sealed class LocalCalculationSupport : IPPCCalculationSupport
|
||||||
{
|
{
|
||||||
private static readonly object _refpropLock = new object();
|
private readonly object _refpropLock;
|
||||||
private static volatile bool _rpInitialized;
|
private static volatile bool _rpInitialized;
|
||||||
|
|
||||||
|
public LocalCalculationSupport(object refpropLock)
|
||||||
|
{
|
||||||
|
_refpropLock = refpropLock ?? throw new ArgumentNullException(nameof(refpropLock));
|
||||||
|
}
|
||||||
|
|
||||||
public bool EnsureRefpropInitialized(out string error)
|
public bool EnsureRefpropInitialized(out string error)
|
||||||
{
|
{
|
||||||
error = string.Empty;
|
error = string.Empty;
|
||||||
@@ -1139,7 +1167,47 @@ namespace CapMachine.Wpf.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TrySATP_SaturationByP_MPa(double pressureMPa, out double tSatK, out double Dl_molL, out double Dv_molL, out string error) => throw new NotSupportedException();
|
public bool TrySATP_SaturationByP_MPa(double pressureMPa, out double tSatK, out double Dl_molL, out double Dv_molL, out string error)
|
||||||
|
{
|
||||||
|
tSatK = double.NaN;
|
||||||
|
Dl_molL = double.NaN;
|
||||||
|
Dv_molL = double.NaN;
|
||||||
|
error = string.Empty;
|
||||||
|
|
||||||
|
if (!EnsureRefpropInitialized(out var initErr))
|
||||||
|
{
|
||||||
|
error = initErr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double pKPa = pressureMPa * 1000.0;
|
||||||
|
double[] x = new double[20];
|
||||||
|
x[0] = 1.0;
|
||||||
|
|
||||||
|
long kph = 1;
|
||||||
|
double Dl = 0.0;
|
||||||
|
double Dv = 0.0;
|
||||||
|
double[] xliq = new double[20];
|
||||||
|
double[] xvap = new double[20];
|
||||||
|
long ierr = 0;
|
||||||
|
long herrLen = 255;
|
||||||
|
string herr = new string(' ', 255);
|
||||||
|
|
||||||
|
lock (_refpropLock)
|
||||||
|
{
|
||||||
|
IRefProp64.SATPdll(ref pKPa, x, ref kph, ref tSatK, ref Dl, ref Dv, xliq, xvap, ref ierr, ref herr, ref herrLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ierr != 0)
|
||||||
|
{
|
||||||
|
error = $"SATP 错误: {herr.Trim()} (ierr={ierr})";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dl_molL = Dl;
|
||||||
|
Dv_molL = Dv;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryTPRHO_VaporDensity_ByTP_MPa_C(double pressureMPa, double temperatureC, out double densityMolPerL, out string error)
|
public bool TryTPRHO_VaporDensity_ByTP_MPa_C(double pressureMPa, double temperatureC, out double densityMolPerL, out string error)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user