干度的恢复,干度的计算恢复到4f452b5这个干度计算方法上
封装了干度的执行方法
This commit is contained in:
599
CapMachine.Wpf/PPCalculation/EnthalpyDrynessCalculator.cs
Normal file
599
CapMachine.Wpf/PPCalculation/EnthalpyDrynessCalculator.cs
Normal file
@@ -0,0 +1,599 @@
|
||||
using System;
|
||||
|
||||
namespace CapMachine.Wpf.PPCalculation
|
||||
{
|
||||
/// <summary>
|
||||
/// 干度计算(基于焓法)的独立封装:
|
||||
/// - 先分别计算气路/液路阀前的单相质量比焓(TPRHO + THERM)
|
||||
/// - 再计算吸气压力对应的饱和液/饱和气质量比焓(SATP + THERM)
|
||||
/// - 最终按既定流程计算混合焓与干度,并限幅到 [0,1]
|
||||
///
|
||||
/// 注意:该类仅做封装以便维护,不应改变既有干度计算过程与逻辑。
|
||||
/// 调用方需确保 REFPROP 已完成 SETPATH/SETUP 初始化(与现有 PPCService 保持一致)。
|
||||
/// </summary>
|
||||
public sealed class EnthalpyDrynessCalculator
|
||||
{
|
||||
private readonly object _refpropLock;
|
||||
|
||||
/// <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)
|
||||
{
|
||||
// 气体流量 kg/h = 冷媒流量 kg/h - 液冷媒流量 kg/h
|
||||
double gasFlowKgPerH = input.VRVFlowKgPerH - input.LiqRefFlowKgPerH;
|
||||
|
||||
// 定义气相质量焓 kJ/kg(注意:保持既有逻辑,默认 0,仅在成功计算时赋值)
|
||||
double gas_hVap_kJkg = 0.0;
|
||||
|
||||
// 步骤1: 计算气路阀前气相焓 h_vap (单相气相)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 定义液相质量焓 kJ/kg(保持既有逻辑,默认 0,仅在成功计算时赋值)
|
||||
double liquid_hLiq_kJkg = 0.0;
|
||||
|
||||
// 步骤2: 计算液路阀前液相焓 h_liq (单相液相)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 定义饱和液/饱和气质量焓 kJ/kg(保持既有逻辑,默认 0,仅在同时成功时赋值)
|
||||
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;
|
||||
}
|
||||
|
||||
// 干度1:mg=气体流量;ml=液体流量
|
||||
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);
|
||||
|
||||
// 干度2:mg=气体流量+润滑油流量;ml=液体流量(保持既有策略)
|
||||
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,
|
||||
gas_hVap_kJkg,
|
||||
liquid_hLiq_kJkg,
|
||||
hSatL_kJkg,
|
||||
hSatV_kJkg,
|
||||
ok1,
|
||||
dryness1,
|
||||
hMix1,
|
||||
err1,
|
||||
ok2,
|
||||
dryness2,
|
||||
hMix2,
|
||||
err2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定组分的摩尔质量(kg/mol)。
|
||||
/// </summary>
|
||||
/// <param name="componentId">组分ID(icomp)。</param>
|
||||
/// <param name="molarMassKgPerMol">摩尔质量(kg/mol)。</param>
|
||||
/// <param name="error">错误信息。</param>
|
||||
/// <returns>是否成功。</returns>
|
||||
private bool TryGetMolarMassKgPerMol(long componentId, out double molarMassKgPerMol, out string error)
|
||||
{
|
||||
molarMassKgPerMol = double.NaN;
|
||||
error = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
double wmm = 0, Trp = 0, Tnbpt = 0, Tc = 0, Pc = 0, Dc = 0, Zc = 0, acf = 0, dip = 0, Rgas = 0;
|
||||
lock (_refpropLock)
|
||||
{
|
||||
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 (double.IsNaN(molarMassKgPerMol) || double.IsInfinity(molarMassKgPerMol) || molarMassKgPerMol <= 0)
|
||||
{
|
||||
error = "无效的摩尔质量";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = $"获取组分{componentId}的摩尔质量时出错: {ex.Message}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TPRHOdll 封装:按 T(℃)、P(MPa) 计算“气相”摩尔密度 D [mol/L](kph=2)。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// THERMdll 封装:按 T(℃) 与 D[mol/L] 计算气相质量焓 h_vap [kJ/kg]。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TPRHOdll 封装:按 T(℃)、P(MPa) 计算“液相”摩尔密度 D [mol/L](kph=1)。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// THERMdll 封装:按 T(℃) 与 D[mol/L] 计算液相质量焓 h_liq [kJ/kg]。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SATPdll:由压力 P(MPa) 求饱和温度 Tsat[K]、饱和液/气摩尔密度 Dl/Dv [mol/L]。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// THERMdll:由 T[K] 与 D[mol/L] 计算质量比焓 h[kJ/kg]。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 便捷:由压力 P(MPa) 直接得到“饱和液”质量比焓 h_liq[kJ/kg]。
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 便捷:由压力 P(MPa) 直接得到“饱和气”质量比焓 h_vap[kJ/kg]。
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按图片的最终流程计算干度:
|
||||
/// 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
|
||||
/// </summary>
|
||||
private 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按图片的最终流程计算干度2:
|
||||
/// 计算逻辑同干度1,但气体流量 mg = 气体流量 + 润滑油流量。
|
||||
/// </summary>
|
||||
private 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using Prism.Events;
|
||||
using Prism.Mvvm;
|
||||
using Prism.Services.Dialogs;
|
||||
using SixLabors.ImageSharp.ColorSpaces;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
@@ -35,6 +36,7 @@ namespace CapMachine.Wpf.Services
|
||||
public MachineRtDataService MachineRtDataService { get; }
|
||||
public IDialogService DialogService { get; }
|
||||
private readonly IDrynessCalculator _drynessCalculator;
|
||||
private readonly EnthalpyDrynessCalculator _enthalpyDrynessCalculator;
|
||||
|
||||
/// <summary>
|
||||
/// 标签中心
|
||||
@@ -58,6 +60,7 @@ namespace CapMachine.Wpf.Services
|
||||
MachineRtDataService = machineRtDataService;
|
||||
DialogService = dialogService;
|
||||
_drynessCalculator = drynessCalculator;
|
||||
_enthalpyDrynessCalculator = new EnthalpyDrynessCalculator(_refpropLock);
|
||||
TagManager = MachineRtDataService.TagManger;
|
||||
|
||||
if (TagManager.TryGetShortTagByName("转速[rpm]", out ShortValueTag? speedShortTag))
|
||||
@@ -95,8 +98,7 @@ namespace CapMachine.Wpf.Services
|
||||
//TxvFrTempTag = TagManager.DicTags.GetValueOrDefault("膨胀阀前温度[℃]")!;
|
||||
//TxvFrPressTag = TagManager.DicTags.GetValueOrDefault("膨胀阀前压力[BarA]")!;
|
||||
|
||||
if (TagManager.TryGetShortTagByName("膨胀阀前温度[℃]", out ShortValueTag? TxvFrTempShortTag) ||
|
||||
TagManager.TryGetShortTagByName("SUBCOOL出口温度[℃]", out TxvFrTempShortTag))
|
||||
if (TagManager.TryGetShortTagByName("SUBCOOL出口温度[℃]", out ShortValueTag? TxvFrTempShortTag))
|
||||
{
|
||||
TxvFrTempTag = TxvFrTempShortTag!;
|
||||
}
|
||||
@@ -326,6 +328,70 @@ namespace CapMachine.Wpf.Services
|
||||
/// </summary>
|
||||
private bool DebugLog { get; set; } = false;
|
||||
|
||||
private DateTime _lastDrynessSnapshotUtc = DateTime.MinValue;
|
||||
private static readonly TimeSpan _drynessSnapshotInterval = TimeSpan.FromSeconds(5);
|
||||
|
||||
/// <summary>
|
||||
/// 干度计算过程值输出(限频),用于现场快速定位干度为何为0/为何被限幅。
|
||||
/// </summary>
|
||||
private void LogDrynessSnapshotIfNeeded(
|
||||
string stage,
|
||||
string error,
|
||||
double dryness01,
|
||||
double hMix_kJkg,
|
||||
double gasInput_kJkg,
|
||||
double liquidInput_kJkg,
|
||||
double hSatL_kJkg,
|
||||
double hSatV_kJkg,
|
||||
double mGas_kg_h,
|
||||
double mLube_kg_h,
|
||||
double mLiq_kg_h)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
if (now - _lastDrynessSnapshotUtc < _drynessSnapshotInterval)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastDrynessSnapshotUtc = now;
|
||||
|
||||
double denom = hSatV_kJkg - hSatL_kJkg;
|
||||
double xRaw = double.NaN;
|
||||
if (!double.IsNaN(hMix_kJkg) && !double.IsNaN(hSatL_kJkg) && !double.IsNaN(denom) && Math.Abs(denom) > 1e-9)
|
||||
{
|
||||
xRaw = (hMix_kJkg - hSatL_kJkg) / denom;
|
||||
}
|
||||
|
||||
double vrv = VRVTag?.PVModel?.EngValue ?? double.NaN;
|
||||
double liqRef = LiqRefFlowTag?.PVModel?.EngValue ?? double.NaN;
|
||||
double lube = LubeFlowTag?.PVModel?.EngValue ?? double.NaN;
|
||||
double gasFlow = vrv - liqRef;
|
||||
|
||||
double mg = Math.Max(0.0, mGas_kg_h) + Math.Max(0.0, mLube_kg_h);
|
||||
double ml = Math.Max(0.0, mLiq_kg_h);
|
||||
double mSum = mg + ml;
|
||||
|
||||
var msg =
|
||||
$"[DrynessSnap] Stage={stage}; Err={error}; x={dryness01:F6} ({dryness01 * 100.0:F3}%); xRaw={xRaw}; " +
|
||||
$"hMix={hMix_kJkg}; hSatL={hSatL_kJkg}; hSatV={hSatV_kJkg}; denom={denom}; " +
|
||||
$"GasInput={gasInput_kJkg}; LiquidInput={liquidInput_kJkg}; " +
|
||||
$"mGas={mGas_kg_h}kg/h, mLube={mLube_kg_h}kg/h, mLiq={mLiq_kg_h}kg/h => mg={mg}kg/h, ml={ml}kg/h, mSum={mSum}kg/h; " +
|
||||
$"VRV={vrv}kg/h(Addr={VRVTag?.PVModel?.Address}), LiqRef={liqRef}kg/h(Addr={LiqRefFlowTag?.PVModel?.Address}), Lube={lube}kg/h(Addr={LubeFlowTag?.PVModel?.Address}), GasFlow(VRV-LiqRef)={gasFlow}kg/h; " +
|
||||
$"InhP={InhPressTag?.PVModel?.EngValue}BarA(Addr={InhPressTag?.PVModel?.Address}), InhT={InhTempTag?.PVModel?.EngValue}C(Addr={InhTempTag?.PVModel?.Address}), " +
|
||||
$"TxvP={TxvFrPressTag?.PVModel?.EngValue}BarA(Addr={TxvFrPressTag?.PVModel?.Address}), TxvT={TxvFrTempTag?.PVModel?.EngValue}C(Addr={TxvFrTempTag?.PVModel?.Address}), " +
|
||||
$"GasPreValveP={GasPreValvePressTag?.PVModel?.EngValue}BarA(Addr={GasPreValvePressTag?.PVModel?.Address}), GasPreValveT={GasPreValveTempTag?.PVModel?.EngValue}C(Addr={GasPreValveTempTag?.PVModel?.Address})";
|
||||
|
||||
Debug.WriteLine(msg);
|
||||
try
|
||||
{
|
||||
Console.WriteLine(msg);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PLC扫描线程
|
||||
/// </summary>
|
||||
@@ -393,99 +459,87 @@ namespace CapMachine.Wpf.Services
|
||||
|
||||
//干度技术
|
||||
|
||||
//气体流量kg/h=冷媒流量kg/h-液冷媒流量kg/h
|
||||
var GasFlowKgPerH = VRVTag.PVModel.EngValue - LiqRefFlowTag.PVModel.EngValue;//气体流量kg/h
|
||||
var drynessResult = _enthalpyDrynessCalculator.Calculate(
|
||||
new EnthalpyDrynessCalculator.Input(
|
||||
GasPreValvePressTag.PVModel.EngValue,
|
||||
GasPreValveTempTag.PVModel.EngValue,
|
||||
TxvFrPressTag.PVModel.EngValue,
|
||||
TxvFrTempTag.PVModel.EngValue,
|
||||
InhPressTag.PVModel.EngValue,
|
||||
VRVTag.PVModel.EngValue,
|
||||
LiqRefFlowTag.PVModel.EngValue,
|
||||
LubeFlowTag.PVModel.EngValue));
|
||||
|
||||
//摩尔质量(kg/mol)
|
||||
var molarMassKgPerMol = GetMolarMass();
|
||||
|
||||
//定义气相质量焓 kJ/(kg·K)
|
||||
var Gas_kJkgK = 0.0;
|
||||
|
||||
//步骤1:计算气路阀前气相焓h vap(单相气相)
|
||||
if (TryTPRHO_VaporDensity_ByTP_MPa_C(GasPreValvePressTag.PVModel.EngValue * 0.1, GasPreValveTempTag.PVModel.EngValue, out var D_molL, out var D_molLErr1))
|
||||
if (drynessResult.IsDryness1Success)
|
||||
{
|
||||
if (TryTHERM_VaporEntropy_ByTD(GasPreValveTempTag.PVModel.EngValue, D_molL, out var s_kJkgK, out var D_molLErr2))
|
||||
{
|
||||
// s_kJkgK 即为图片中的“气相质量熵 kJ/(kg·K)”
|
||||
Gas_kJkgK = s_kJkgK;
|
||||
}
|
||||
}
|
||||
DrynessTag2Value = drynessResult.Dryness1_01 * 100.0;
|
||||
|
||||
//定义液相质量焓 kJ/(kg·K)
|
||||
var Liquid_kJkg = 0.0;
|
||||
|
||||
//步骤2:计算液路阀前气相焓hlig(单相液相) TxvFrTempTag 液体阀前温度 TxvFrPressTag 液体阀前压力
|
||||
// 1) 先求 D_liq
|
||||
if (TryTPRHO_LiquidDensity_ByTP_MPa_C(TxvFrPressTag.PVModel.EngValue * 0.1, TxvFrTempTag.PVModel.EngValue, out var D_liq_molL, out var D_liqErr1))
|
||||
{
|
||||
// 2) 再用 THERM 求 h_liq
|
||||
if (TryTHERM_LiquidEnthalpy_ByTD(TxvFrTempTag.PVModel.EngValue, D_liq_molL, out var h_liq_kJkg, out var D_liqErr2))
|
||||
{
|
||||
// h_liq_kJkg 即为图片中的“液相质量焓 h_liq kJ/kg”
|
||||
Liquid_kJkg = h_liq_kJkg;
|
||||
//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
|
||||
{
|
||||
// 处理 err2
|
||||
//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;
|
||||
|
||||
//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
|
||||
{
|
||||
// 处理 err1
|
||||
}
|
||||
|
||||
//定义饱和液质量焓hl kJ/kg
|
||||
var Liquid_h_liq = 0.0;
|
||||
//定义饱和气质量焓hl k)/kg
|
||||
var Gas_h_vap = 0.0;
|
||||
|
||||
if (TryGetSaturationLiquidEnthalpy_ByP_MPa(InhPressTag.PVModel.EngValue * 0.1, out var h_liq, out var h_liqErr1) &&
|
||||
TryGetSaturationVaporEnthalpy_ByP_MPa(InhPressTag.PVModel.EngValue * 0.1, out var h_vap, out var h_vapErr2))
|
||||
{
|
||||
// h_liq / h_vap 即为图片右侧的两个“饱和液/饱和气 质量焓 kJ/kg”
|
||||
Liquid_h_liq = h_liq;
|
||||
Gas_h_vap = h_vap;
|
||||
}
|
||||
|
||||
// 气相焓 h_vap_kJkg(由 TPRHO 气相 + THERM)
|
||||
// 液相焓 h_liq_kJkg(由 TPRHO 液相 + THERM)
|
||||
// 饱和液 / 气焓 h_l / h_v(由 SATP +THERM)
|
||||
//气/液质量流量 mg/ml
|
||||
if (TryComputeDrynessByEnthalpy(
|
||||
Gas_kJkgK, Liquid_kJkg,//气相质量焓 h vap [k/kg] 液相质量焓 h liq [kJ/kg]
|
||||
GasFlowKgPerH, LiqRefFlowTag.PVModel.EngValue,//气体质量流量 mg [kg/h] 液体质量流量 ml [kg/h]
|
||||
Liquid_h_liq, Gas_h_vap, //饱和液质量焓 h liq [kJ/kg] 饱和气质量焓 h vap [kJ/kg]
|
||||
out var GasValue, out var hMix, out var err))
|
||||
{
|
||||
DrynessTag2Value = GasValue * 100.0;
|
||||
// x 为最终干度 [0..1],hMix 为混合后比焓
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// 处理 err
|
||||
}
|
||||
|
||||
//计算干度2
|
||||
// 气相焓 h_vap_kJkg(由 TPRHO 气相 + THERM)
|
||||
// 液相焓 h_liq_kJkg(由 TPRHO 液相 + THERM)
|
||||
// 饱和液 / 气焓 h_l / h_v(由 SATP +THERM)
|
||||
//气/液质量流量 mg/ml
|
||||
//***************** 经过验证,当前方法是正确 *****************
|
||||
if (TryComputeDrynessByEnthalpy2(
|
||||
Gas_kJkgK, Liquid_kJkg,//气相质量焓 h vap [k/kg] 液相质量焓 h liq [kJ/kg]
|
||||
GasFlowKgPerH, LubeFlowTag.PVModel.EngValue, //气体质量流量 mg [kg/h] 润滑油流量
|
||||
LiqRefFlowTag.PVModel.EngValue,// 液体质量流量 ml [kg/h]
|
||||
Liquid_h_liq, Gas_h_vap, //饱和液质量焓 h liq [kJ/kg] 饱和气质量焓 h vap [kJ/kg]
|
||||
out var GasValue2, out var hMix2, out var err2))
|
||||
{
|
||||
// x 为最终干度 [0..1],hMix 为混合后比焓
|
||||
DrynessTag.PVModel.EngValue = GasValue2 * 100.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 处理 err2
|
||||
//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 (TryUpdateThermodynamicSixResults(out var thermoErr))
|
||||
@@ -714,6 +768,40 @@ namespace CapMachine.Wpf.Services
|
||||
}
|
||||
|
||||
|
||||
public 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; // K
|
||||
double D = densityMolPerL; // mol/L
|
||||
|
||||
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;
|
||||
|
||||
double molarMassKgPerMol = GetMolarMass();
|
||||
if (molarMassKgPerMol <= 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 计算液路阀前液相密度D_liq(单相液相) 液相密度D_liq mol/L
|
||||
@@ -952,170 +1040,6 @@ namespace CapMachine.Wpf.Services
|
||||
return TryTHERM_Enthalpy_kJkg_ByT_K_D(tSatK, Dv, out h_vap_kJkg, out error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按图片的最终流程计算干度:
|
||||
/// 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;
|
||||
|
||||
// 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))
|
||||
{
|
||||
error = "输入质量流量存在 NaN";
|
||||
return false;
|
||||
}
|
||||
// 负值处理:小于 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;
|
||||
}
|
||||
|
||||
// 2) 质量流量加权混合焓(严格按图片:上、下两路相加后除以总流量)
|
||||
hMix_kJkg = (hVap_kJkg * mg + hLiq_kJkg * ml) / mSum;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
/// <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;
|
||||
hMix_kJkg = double.NaN;
|
||||
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))
|
||||
{
|
||||
error = "输入质量流量存在 NaN";
|
||||
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) 质量流量加权混合焓(严格按图片:上、下两路相加后除以总流量)
|
||||
hMix_kJkg = (hVap_kJkg * mg + hLiq_kJkg * ml) / mSum;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user