1456 lines
57 KiB
C#
1456 lines
57 KiB
C#
using CapMachine.Core;
|
||
using CapMachine.Wpf.PPCalculation;
|
||
using System;
|
||
|
||
namespace CapMachine.Wpf.Services
|
||
{
|
||
/// <summary>
|
||
/// 六个热力结果值计算的输入数据。
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 该输入对象对应六个结果值计算过程中用到的全部外部测点/配置量。
|
||
/// 所有字段均采用当前系统中已经约定好的工程单位,不在本对象中做任何换算。
|
||
/// </remarks>
|
||
public sealed class PPCThermodynamicSixResultsCalculationInput
|
||
{
|
||
/// <summary>
|
||
/// 压缩机输入功率,单位 W。
|
||
/// 当前来源为 HV 功率标签。
|
||
/// </summary>
|
||
public double CompressorPowerW { get; set; }
|
||
|
||
/// <summary>
|
||
/// 总流量(冷媒流量标签当前语义),单位 kg/h。
|
||
/// 该值会与油流量做差,得到真正参与热力计算的冷媒质量流量。
|
||
/// </summary>
|
||
public double TotalMassFlowKgPerHour { get; set; }
|
||
|
||
/// <summary>
|
||
/// 润滑油流量,单位 kg/h。
|
||
/// </summary>
|
||
public double OilMassFlowKgPerHour { get; set; }
|
||
|
||
/// <summary>
|
||
/// 吸气压力,单位 BarA(绝压)。
|
||
/// </summary>
|
||
public double SuctionPressureBarA { get; set; }
|
||
|
||
/// <summary>
|
||
/// 吸气温度,单位 ℃。
|
||
/// </summary>
|
||
public double SuctionTemperatureC { get; set; }
|
||
|
||
/// <summary>
|
||
/// 排气压力,单位 BarA(绝压)。
|
||
/// </summary>
|
||
public double DischargePressureBarA { get; set; }
|
||
|
||
/// <summary>
|
||
/// 排气温度,单位 ℃。
|
||
/// </summary>
|
||
public double DischargeTemperatureC { get; set; }
|
||
|
||
/// <summary>
|
||
/// 膨胀阀前液路压力,单位 BarA(绝压)。
|
||
/// </summary>
|
||
public double LiquidPressureBarA { get; set; }
|
||
|
||
/// <summary>
|
||
/// 膨胀阀前液路温度,单位 ℃。
|
||
/// </summary>
|
||
public double LiquidTemperatureC { get; set; }
|
||
|
||
/// <summary>
|
||
/// 压缩机转速,单位 rpm。
|
||
/// 用于容积效率计算。
|
||
/// </summary>
|
||
public double CompressorSpeedRpm { get; set; }
|
||
|
||
/// <summary>
|
||
/// 压缩机单转排量,单位 cc。
|
||
/// 用于理论体积流量计算。
|
||
/// </summary>
|
||
public double CompressorDisplacementCc { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 六个热力结果值计算结果。
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 默认均初始化为 <see cref="double.NaN"/>,用于明确区分“未成功得到结果”和“得到有效数值”。
|
||
/// </remarks>
|
||
public sealed class PPCThermodynamicSixResultsCalculationResult
|
||
{
|
||
/// <summary>
|
||
/// 制热量 Qh,单位 kW。
|
||
/// 计算公式:<c>Qh = mRef * (h2 - h3)</c>。
|
||
/// </summary>
|
||
public double HeatingCapacityQh_kW { get; set; } = double.NaN;
|
||
|
||
/// <summary>
|
||
/// 制冷量 Qc,单位 kW。
|
||
/// 计算公式:<c>Qc = mRef * (h1 - h3)</c>。
|
||
/// </summary>
|
||
public double CoolingCapacityQc_kW { get; set; } = double.NaN;
|
||
|
||
/// <summary>
|
||
/// 制热 COP。
|
||
/// 计算公式:<c>COPHeating = Qh / W</c>。
|
||
/// </summary>
|
||
public double COPHeating { get; set; } = double.NaN;
|
||
|
||
/// <summary>
|
||
/// 制冷 COP。
|
||
/// 计算公式:<c>COPCooling = Qc / W</c>。
|
||
/// </summary>
|
||
public double COPCooling { get; set; } = double.NaN;
|
||
|
||
/// <summary>
|
||
/// 等熵效率,单位 %。
|
||
/// 计算公式:<c>(h2s - h1) / (h2 - h1) * 100</c>。
|
||
/// </summary>
|
||
public double IsentropicEfficiencyPct { get; set; } = double.NaN;
|
||
|
||
/// <summary>
|
||
/// 容积效率,单位 %。
|
||
/// 计算公式:<c>实际吸气体积流量 / 理论吸气体积流量 * 100</c>。
|
||
/// </summary>
|
||
public double VolumetricEfficiencyPct { get; set; } = double.NaN;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 六个热力结果值独立计算类。
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 本类负责以下六个结果的完整计算流程:
|
||
/// - 制热量
|
||
/// - COP(制热)
|
||
/// - 等熵效率
|
||
/// - 制冷量
|
||
/// - COP(制冷)
|
||
/// - 容积效率
|
||
///
|
||
/// 设计目标是把“结果计算逻辑”从 <c>PPCService</c> 中抽离出来,
|
||
/// 让服务层只负责取标签和写回,计算类只负责计算本身。
|
||
/// 为降低后续新增其他计算类时对已验算结果的影响范围,
|
||
/// 本类将自身所需的底层 REFPROP 支撑实现内聚在类内私有 support 中。
|
||
///
|
||
/// 当前实现严格保持既有流程不变:
|
||
/// 1. 由总流量和油流量得到冷媒质量流量
|
||
/// 2. 由吸气点得到 h1 / s1 / v1
|
||
/// 3. 由排气点得到 h2
|
||
/// 4. 由液路点得到 h3
|
||
/// 5. 由排气压力和吸气熵得到 h2s
|
||
/// 6. 计算 Qh / Qc / COP / 等熵效率 / 容积效率
|
||
/// </remarks>
|
||
public sealed class PPCThermodynamicSixResultsCalculator
|
||
{
|
||
/// <summary>
|
||
/// 底层物性计算支持对象。
|
||
/// 负责提供 REFPROP 初始化与 TPRHO / THERM / PSFLSH 等共用能力。
|
||
/// </summary>
|
||
private readonly LocalCalculationSupport _support;
|
||
|
||
/// <summary>
|
||
/// 初始化六个热力结果值计算类。
|
||
/// </summary>
|
||
public PPCThermodynamicSixResultsCalculator()
|
||
{
|
||
_support = new LocalCalculationSupport();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按既定流程一次性计算六个热力结果值。
|
||
/// </summary>
|
||
/// <param name="input">输入数据,包含功率、流量、吸排气状态点、液路状态点、转速与排量。</param>
|
||
/// <param name="result">输出结果对象。</param>
|
||
/// <param name="error">
|
||
/// 错误或警告信息。
|
||
/// 当前逻辑中,若“容积效率”计算失败但其他 5 个结果成功,会返回 <see langword="true"/>,
|
||
/// 同时通过此参数把容积效率失败原因返回给上层,保持原有行为不变。
|
||
/// </param>
|
||
/// <returns>
|
||
/// - <see langword="true"/>:主要结果计算完成;容积效率可能成功也可能失败
|
||
/// - <see langword="false"/>:关键输入或关键热力步骤失败
|
||
/// </returns>
|
||
public bool TryCalculate(PPCThermodynamicSixResultsCalculationInput input, out PPCThermodynamicSixResultsCalculationResult result, out string error)
|
||
{
|
||
// 创建输出对象,并将错误文本清空。
|
||
result = new PPCThermodynamicSixResultsCalculationResult();
|
||
error = string.Empty;
|
||
|
||
// 所有物性函数调用之前,先确保 REFPROP 已完成初始化。
|
||
if (!_support.EnsureRefpropInitialized(out var initErr))
|
||
{
|
||
error = initErr;
|
||
return false;
|
||
}
|
||
|
||
// 第 1 步:将压缩机输入功率由 W 换算为 kW。
|
||
if (!TryGetCompressorPower_kW(input.CompressorPowerW, out var w_kW, out var wErr))
|
||
{
|
||
error = wErr;
|
||
return false;
|
||
}
|
||
|
||
// 第 2 步:根据“总流量 - 油流量”,得到真正参与循环的冷媒质量流量,
|
||
// 并从 kg/h 换算到后续公式使用的 kg/s。
|
||
if (!TryGetRefrigerantMassFlow_kg_s(input.TotalMassFlowKgPerHour, input.OilMassFlowKgPerHour, out var mRef_kg_s, out var mRefErr))
|
||
{
|
||
error = mRefErr;
|
||
return false;
|
||
}
|
||
|
||
// 第 3 步:由吸气压力/温度求出吸气点状态:
|
||
// - h1:吸气比焓
|
||
// - s1:吸气比熵
|
||
// - v1:吸气比容
|
||
if (!TryGetVaporPointState_ByTP_BarA_C(input.SuctionPressureBarA, input.SuctionTemperatureC, out var h1_kJkg, out var s1_kJkgK, out var v1_m3kg, out var p1Err))
|
||
{
|
||
error = $"h1/s1/吸气比容计算失败: {p1Err}";
|
||
return false;
|
||
}
|
||
|
||
// 第 4 步:由排气压力/温度求排气比焓 h2。
|
||
if (!TryGetVaporPointEnthalpy_ByTP_BarA_C(input.DischargePressureBarA, input.DischargeTemperatureC, out var h2_kJkg, out var p2Err))
|
||
{
|
||
error = $"h2 计算失败: {p2Err}";
|
||
return false;
|
||
}
|
||
|
||
// 第 5 步:由液路压力/温度求液路比焓 h3。
|
||
if (!TryGetLiquidPointEnthalpy_ByTP_BarA_C(input.LiquidPressureBarA, input.LiquidTemperatureC, out var h3_kJkg, out var p3Err))
|
||
{
|
||
error = $"h3 计算失败: {p3Err}";
|
||
return false;
|
||
}
|
||
|
||
// 第 6 步:由排气压力 P2 和吸气熵 s1 求等熵出口焓 h2s。
|
||
if (!_support.TryGetIsentropicOutletEnthalpy_h2s_ByP2AndS1_BarA(input.DischargePressureBarA, s1_kJkgK, out var h2s_kJkg, out var h2sErr))
|
||
{
|
||
error = $"h2s 计算失败: {h2sErr}";
|
||
return false;
|
||
}
|
||
|
||
// 第 7 步:计算 Qh、Qc、COP(制热)、COP(制冷)。
|
||
if (!TryComputeCapacitiesAndCOP(mRef_kg_s, h1_kJkg, h2_kJkg, h3_kJkg, w_kW, out var qh_kW, out var qc_kW, out var copH, out var copC, out var capErr))
|
||
{
|
||
error = capErr;
|
||
return false;
|
||
}
|
||
|
||
// 第 8 步:计算等熵效率。
|
||
if (!TryComputeIsentropicEfficiencyPct(h1_kJkg, h2_kJkg, h2s_kJkg, out var etaS_pct, out var etaSErr))
|
||
{
|
||
error = etaSErr;
|
||
return false;
|
||
}
|
||
|
||
// 先写入 5 个关键结果。
|
||
result.HeatingCapacityQh_kW = qh_kW;
|
||
result.CoolingCapacityQc_kW = qc_kW;
|
||
result.COPHeating = copH;
|
||
result.COPCooling = copC;
|
||
result.IsentropicEfficiencyPct = etaS_pct;
|
||
|
||
// 最后再算容积效率。
|
||
// 当前逻辑特意保持与旧实现一致:
|
||
// 即使容积效率失败,只要前面 5 个主结果已经成功,就仍然返回 true,
|
||
// 同时把失败原因放到 error 中,供调用方决定是否记录为警告。
|
||
if (!TryComputeVolumetricEfficiencyPct(mRef_kg_s, v1_m3kg, input.CompressorSpeedRpm, input.CompressorDisplacementCc, out var etaV_pct, out var etaVErr))
|
||
{
|
||
error = etaVErr;
|
||
return true;
|
||
}
|
||
|
||
result.VolumetricEfficiencyPct = etaV_pct;
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取压缩机输入功率并换算为 kW。
|
||
/// </summary>
|
||
/// <param name="compressorPowerW">输入功率,单位 W。</param>
|
||
/// <param name="w_kW">输出功率,单位 kW。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否换算成功。</returns>
|
||
private bool TryGetCompressorPower_kW(double compressorPowerW, out double w_kW, out string error)
|
||
{
|
||
w_kW = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 读取输入功率,并做基础合法性校验。
|
||
double w_W = compressorPowerW;
|
||
if (double.IsNaN(w_W) || double.IsInfinity(w_W) || w_W <= 0)
|
||
{
|
||
error = $"无效压缩机功率 HV[W]={w_W}";
|
||
return false;
|
||
}
|
||
|
||
// 六个热力结果公式里统一使用 kW,因此这里做 W -> kW 的标准换算。
|
||
w_kW = w_W / 1000.0;
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取冷媒质量流量,输出单位 kg/s。
|
||
/// </summary>
|
||
/// <param name="totalMassFlowKgPerHour">总流量,单位 kg/h。</param>
|
||
/// <param name="oilMassFlowKgPerHour">油流量,单位 kg/h。</param>
|
||
/// <param name="mRef_kg_s">冷媒质量流量输出,单位 kg/s。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
/// <remarks>
|
||
/// 当前流程保持与图片/旧代码一致:
|
||
/// 1. 读取总流量 kg/h
|
||
/// 2. 读取油流量 kg/h
|
||
/// 3. 冷媒流量 = 总流量 - 油流量
|
||
/// 4. 再由 kg/h 换算为 kg/s
|
||
/// </remarks>
|
||
private bool TryGetRefrigerantMassFlow_kg_s(double totalMassFlowKgPerHour, double oilMassFlowKgPerHour, out double mRef_kg_s, out string error)
|
||
{
|
||
mRef_kg_s = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 先读取总流量。
|
||
if (!TryGetTotalMassFlow_kg_h(totalMassFlowKgPerHour, out var mTotal_kg_h, out var totalErr))
|
||
{
|
||
error = totalErr;
|
||
return false;
|
||
}
|
||
|
||
// 再读取油流量。
|
||
if (!TryGetOilMassFlow_kg_h(oilMassFlowKgPerHour, out var mOil_kg_h, out var oilErr))
|
||
{
|
||
error = oilErr;
|
||
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;
|
||
}
|
||
|
||
// 将 kg/h 换算成后续容量计算使用的 kg/s。
|
||
return TryConvertMassFlow_kg_h_To_kg_s(mRef_kg_h, out mRef_kg_s, out error);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取总流量,单位 kg/h。
|
||
/// </summary>
|
||
/// <param name="totalMassFlowKgPerHour">输入总流量。</param>
|
||
/// <param name="mTotal_kg_h">输出总流量。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否读取成功。</returns>
|
||
private bool TryGetTotalMassFlow_kg_h(double totalMassFlowKgPerHour, out double mTotal_kg_h, out string error)
|
||
{
|
||
mTotal_kg_h = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 当前方法只做数值读取和合法性校验,不做其他换算。
|
||
mTotal_kg_h = totalMassFlowKgPerHour;
|
||
if (double.IsNaN(mTotal_kg_h) || double.IsInfinity(mTotal_kg_h))
|
||
{
|
||
error = "总流量(冷媒流量)为 NaN/Inf";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取油流量,单位 kg/h。
|
||
/// </summary>
|
||
/// <param name="oilMassFlowKgPerHour">输入油流量。</param>
|
||
/// <param name="mOil_kg_h">输出油流量。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否读取成功。</returns>
|
||
private bool TryGetOilMassFlow_kg_h(double oilMassFlowKgPerHour, out double mOil_kg_h, out string error)
|
||
{
|
||
mOil_kg_h = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 当前方法只做数值读取和合法性校验,不做其他换算。
|
||
mOil_kg_h = oilMassFlowKgPerHour;
|
||
if (double.IsNaN(mOil_kg_h) || double.IsInfinity(mOil_kg_h))
|
||
{
|
||
error = "油流量为 NaN/Inf";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算冷媒质量流量,单位 kg/h。
|
||
/// </summary>
|
||
/// <param name="mTotal_kg_h">总流量,单位 kg/h。</param>
|
||
/// <param name="mOil_kg_h">油流量,单位 kg/h。</param>
|
||
/// <param name="mRef_kg_h">冷媒质量流量输出,单位 kg/h。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryComputeRefrigerantMassFlow_kg_h(double mTotal_kg_h, double mOil_kg_h, out double mRef_kg_h, out string error)
|
||
{
|
||
mRef_kg_h = double.NaN;
|
||
error = string.Empty;
|
||
|
||
if (double.IsNaN(mTotal_kg_h) || double.IsInfinity(mTotal_kg_h))
|
||
{
|
||
error = "总流量(冷媒流量)为 NaN/Inf";
|
||
return false;
|
||
}
|
||
|
||
if (double.IsNaN(mOil_kg_h) || double.IsInfinity(mOil_kg_h))
|
||
{
|
||
error = "油流量为 NaN/Inf";
|
||
return false;
|
||
}
|
||
|
||
// 与既有实现一致:冷媒质量流量 = 总流量 - 油流量。
|
||
mRef_kg_h = mTotal_kg_h - mOil_kg_h;
|
||
if (mRef_kg_h <= 0)
|
||
{
|
||
error = $"冷媒质量流量<=0,总流量={mTotal_kg_h}kg/h,油流量={mOil_kg_h}kg/h";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将质量流量从 kg/h 换算到 kg/s。
|
||
/// </summary>
|
||
/// <param name="massFlow_kg_h">输入质量流量,单位 kg/h。</param>
|
||
/// <param name="massFlow_kg_s">输出质量流量,单位 kg/s。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否换算成功。</returns>
|
||
private bool TryConvertMassFlow_kg_h_To_kg_s(double massFlow_kg_h, out double massFlow_kg_s, out string error)
|
||
{
|
||
massFlow_kg_s = double.NaN;
|
||
error = string.Empty;
|
||
|
||
if (double.IsNaN(massFlow_kg_h) || double.IsInfinity(massFlow_kg_h) || massFlow_kg_h <= 0)
|
||
{
|
||
error = $"无效质量流量={massFlow_kg_h}kg/h";
|
||
return false;
|
||
}
|
||
|
||
// 1 小时 = 3600 秒,因此 kg/h -> kg/s 需要除以 3600。
|
||
massFlow_kg_s = massFlow_kg_h / 3600.0;
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 由某一气相状态点的压力 / 温度求质量比焓。
|
||
/// </summary>
|
||
/// <param name="pressureBarA">输入压力,单位 BarA(绝压)。</param>
|
||
/// <param name="temperatureC">输入温度,单位 ℃。</param>
|
||
/// <param name="h_kJkg">输出质量比焓,单位 kJ/kg。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
/// <remarks>
|
||
/// 当前流程:
|
||
/// 1. BarA -> MPa
|
||
/// 2. 用气相 TPRHO 求摩尔密度 D
|
||
/// 3. 用 THERM 求焓
|
||
/// </remarks>
|
||
private bool TryGetVaporPointEnthalpy_ByTP_BarA_C(double pressureBarA, double temperatureC, out double h_kJkg, out string error)
|
||
{
|
||
h_kJkg = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 物性 helper 的压力输入单位是 MPa,因此先换算。
|
||
double pMPa = pressureBarA * 0.1;
|
||
|
||
// 先求气相摩尔密度 D。
|
||
if (!_support.TryTPRHO_VaporDensity_ByTP_MPa_C(pMPa, temperatureC, out var d_molL, out var dErr))
|
||
{
|
||
error = dErr;
|
||
return false;
|
||
}
|
||
|
||
// THERM helper 的温度输入为 K,因此把 ℃ 转成 K 后再求焓。
|
||
double tK = temperatureC + 273.15;
|
||
if (!_support.TryTHERM_Enthalpy_kJkg_ByT_K_D(tK, d_molL, out h_kJkg, out var hErr))
|
||
{
|
||
error = hErr;
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 由某一液相状态点的压力 / 温度求质量比焓。
|
||
/// </summary>
|
||
/// <param name="pressureBarA">输入压力,单位 BarA(绝压)。</param>
|
||
/// <param name="temperatureC">输入温度,单位 ℃。</param>
|
||
/// <param name="h_kJkg">输出质量比焓,单位 kJ/kg。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryGetLiquidPointEnthalpy_ByTP_BarA_C(double pressureBarA, double temperatureC, out double h_kJkg, out string error)
|
||
{
|
||
h_kJkg = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 物性 helper 的压力输入单位是 MPa,因此先换算。
|
||
double pMPa = pressureBarA * 0.1;
|
||
|
||
// 先按液相路径求摩尔密度 D。
|
||
if (!_support.TryTPRHO_LiquidDensity_ByTP_MPa_C(pMPa, temperatureC, out var d_molL, out var dErr))
|
||
{
|
||
error = dErr;
|
||
return false;
|
||
}
|
||
|
||
// 再按液相路径求质量比焓 h。
|
||
if (!_support.TryTHERM_LiquidEnthalpy_ByTD(temperatureC, d_molL, out h_kJkg, out var hErr))
|
||
{
|
||
error = hErr;
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 由某一气相状态点的压力 / 温度联合求取 h、s、v。
|
||
/// </summary>
|
||
/// <param name="pressureBarA">输入压力,单位 BarA(绝压)。</param>
|
||
/// <param name="temperatureC">输入温度,单位 ℃。</param>
|
||
/// <param name="h_kJkg">输出质量比焓,单位 kJ/kg。</param>
|
||
/// <param name="s_kJkgK">输出质量比熵,单位 kJ/(kg·K)。</param>
|
||
/// <param name="v_m3kg">输出比容,单位 m³/kg。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryGetVaporPointState_ByTP_BarA_C(double pressureBarA, double temperatureC, out double h_kJkg, out double s_kJkgK, out double v_m3kg, out string error)
|
||
{
|
||
h_kJkg = double.NaN;
|
||
s_kJkgK = double.NaN;
|
||
v_m3kg = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 第一步:BarA -> MPa。
|
||
double pMPa = pressureBarA * 0.1;
|
||
|
||
// 第二步:由气相 TPRHO 求摩尔密度 D。
|
||
if (!_support.TryTPRHO_VaporDensity_ByTP_MPa_C(pMPa, temperatureC, out var d_molL, out var dErr))
|
||
{
|
||
error = dErr;
|
||
return false;
|
||
}
|
||
|
||
// 第三步:用 THERM 求吸气点比焓 h1。
|
||
double tK = temperatureC + 273.15;
|
||
if (!_support.TryTHERM_Enthalpy_kJkg_ByT_K_D(tK, d_molL, out h_kJkg, out var hErr))
|
||
{
|
||
error = hErr;
|
||
return false;
|
||
}
|
||
|
||
// 第四步:用 THERM 求吸气点比熵 s1。
|
||
if (!_support.TryTHERM_VaporEntropy_ByTD(temperatureC, d_molL, out s_kJkgK, out var sErr))
|
||
{
|
||
error = sErr;
|
||
return false;
|
||
}
|
||
|
||
// 第五步:由摩尔密度换算为质量比容 v1。
|
||
if (!_support.TryConvertMolarDensityToSpecificVolume(d_molL, out v_m3kg, out var vErr))
|
||
{
|
||
error = vErr;
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 统一计算制热量、制冷量、制热 COP、制冷 COP。
|
||
/// </summary>
|
||
/// <param name="mRef_kg_s">冷媒质量流量,单位 kg/s。</param>
|
||
/// <param name="h1_kJkg">吸气比焓,单位 kJ/kg。</param>
|
||
/// <param name="h2_kJkg">排气比焓,单位 kJ/kg。</param>
|
||
/// <param name="h3_kJkg">液路比焓,单位 kJ/kg。</param>
|
||
/// <param name="w_kW">压缩机功率,单位 kW。</param>
|
||
/// <param name="qh_kW">制热量输出,单位 kW。</param>
|
||
/// <param name="qc_kW">制冷量输出,单位 kW。</param>
|
||
/// <param name="copHeating">制热 COP 输出。</param>
|
||
/// <param name="copCooling">制冷 COP 输出。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryComputeCapacitiesAndCOP(double mRef_kg_s, double h1_kJkg, double h2_kJkg, double h3_kJkg, double w_kW,
|
||
out double qh_kW, out double qc_kW, out double copHeating, out double copCooling, out string error)
|
||
{
|
||
qh_kW = double.NaN;
|
||
qc_kW = double.NaN;
|
||
copHeating = double.NaN;
|
||
copCooling = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 先算制热量:Qh = mRef * (h2 - h3)。
|
||
if (!TryComputeHeatingCapacityQh_kW(mRef_kg_s, h2_kJkg, h3_kJkg, out qh_kW, out var qhErr))
|
||
{
|
||
error = qhErr;
|
||
return false;
|
||
}
|
||
|
||
// 再算制冷量:Qc = mRef * (h1 - h3)。
|
||
if (!TryComputeCoolingCapacityQc_kW(mRef_kg_s, h1_kJkg, h3_kJkg, out qc_kW, out var qcErr))
|
||
{
|
||
error = qcErr;
|
||
return false;
|
||
}
|
||
|
||
// 制热 COP = Qh / W。
|
||
if (!TryComputeHeatingCOP(qh_kW, w_kW, out copHeating, out var copHErr))
|
||
{
|
||
error = copHErr;
|
||
return false;
|
||
}
|
||
|
||
// 制冷 COP = Qc / W。
|
||
if (!TryComputeCoolingCOP(qc_kW, w_kW, out copCooling, out var copCErr))
|
||
{
|
||
error = copCErr;
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算焓差,单位 kJ/kg。
|
||
/// </summary>
|
||
/// <param name="minuend_kJkg">被减数,单位 kJ/kg。</param>
|
||
/// <param name="subtrahend_kJkg">减数,单位 kJ/kg。</param>
|
||
/// <param name="quantityName">当前计算量名称,用于拼接错误信息。</param>
|
||
/// <param name="deltaH_kJkg">焓差输出,单位 kJ/kg。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryComputeEnthalpyDifference_kJkg(double minuend_kJkg, double subtrahend_kJkg, string quantityName, out double deltaH_kJkg, out string error)
|
||
{
|
||
deltaH_kJkg = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 先校验输入两端焓值是否有效。
|
||
if (double.IsNaN(minuend_kJkg) || double.IsInfinity(minuend_kJkg) || double.IsNaN(subtrahend_kJkg) || double.IsInfinity(subtrahend_kJkg))
|
||
{
|
||
error = $"{quantityName}输入存在 NaN/Inf";
|
||
return false;
|
||
}
|
||
|
||
// 焓差按“被减数 - 减数”计算。
|
||
deltaH_kJkg = minuend_kJkg - subtrahend_kJkg;
|
||
if (double.IsNaN(deltaH_kJkg) || double.IsInfinity(deltaH_kJkg))
|
||
{
|
||
error = $"{quantityName}结果异常";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据质量流量与焓差计算容量,单位 kW。
|
||
/// </summary>
|
||
/// <param name="mRef_kg_s">冷媒质量流量,单位 kg/s。</param>
|
||
/// <param name="deltaH_kJkg">焓差,单位 kJ/kg。</param>
|
||
/// <param name="quantityName">容量名称,用于错误信息。</param>
|
||
/// <param name="capacity_kW">容量输出,单位 kW。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
/// <remarks>
|
||
/// 公式:<c>Capacity = mRef * Δh</c>。
|
||
/// 因为 <c>kg/s * kJ/kg = kJ/s = kW</c>,所以结果天然就是 kW。
|
||
/// </remarks>
|
||
private bool TryComputeCapacity_kW(double mRef_kg_s, double deltaH_kJkg, string quantityName, out double capacity_kW, out string error)
|
||
{
|
||
capacity_kW = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 校验冷媒质量流量是否有效。
|
||
if (double.IsNaN(mRef_kg_s) || double.IsInfinity(mRef_kg_s) || mRef_kg_s <= 0)
|
||
{
|
||
error = "无效冷媒质量流量";
|
||
return false;
|
||
}
|
||
|
||
// 校验焓差是否有效。
|
||
if (double.IsNaN(deltaH_kJkg) || double.IsInfinity(deltaH_kJkg))
|
||
{
|
||
error = $"{quantityName}焓差异常";
|
||
return false;
|
||
}
|
||
|
||
// 按容量公式直接计算。
|
||
capacity_kW = mRef_kg_s * deltaH_kJkg;
|
||
if (double.IsNaN(capacity_kW) || double.IsInfinity(capacity_kW))
|
||
{
|
||
error = $"{quantityName}结果异常";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算制热量 Qh,单位 kW。
|
||
/// </summary>
|
||
/// <param name="mRef_kg_s">冷媒质量流量,单位 kg/s。</param>
|
||
/// <param name="h2_kJkg">排气比焓 h2,单位 kJ/kg。</param>
|
||
/// <param name="h3_kJkg">液路比焓 h3,单位 kJ/kg。</param>
|
||
/// <param name="qh_kW">制热量输出,单位 kW。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryComputeHeatingCapacityQh_kW(double mRef_kg_s, double h2_kJkg, double h3_kJkg, out double qh_kW, out string error)
|
||
{
|
||
qh_kW = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 先计算制热焓差:(h2 - h3)。
|
||
if (!TryComputeEnthalpyDifference_kJkg(h2_kJkg, h3_kJkg, "制热焓差(h2-h3)", out var deltaH_kJkg, out var deltaErr))
|
||
{
|
||
error = deltaErr;
|
||
return false;
|
||
}
|
||
|
||
// 再由质量流量与焓差得到制热量。
|
||
return TryComputeCapacity_kW(mRef_kg_s, deltaH_kJkg, "制热量Qh", out qh_kW, out error);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算制冷量 Qc,单位 kW。
|
||
/// </summary>
|
||
/// <param name="mRef_kg_s">冷媒质量流量,单位 kg/s。</param>
|
||
/// <param name="h1_kJkg">吸气比焓 h1,单位 kJ/kg。</param>
|
||
/// <param name="h3_kJkg">液路比焓 h3,单位 kJ/kg。</param>
|
||
/// <param name="qc_kW">制冷量输出,单位 kW。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryComputeCoolingCapacityQc_kW(double mRef_kg_s, double h1_kJkg, double h3_kJkg, out double qc_kW, out string error)
|
||
{
|
||
qc_kW = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 先计算制冷焓差:(h1 - h3)。
|
||
if (!TryComputeEnthalpyDifference_kJkg(h1_kJkg, h3_kJkg, "制冷焓差(h1-h3)", out var deltaH_kJkg, out var deltaErr))
|
||
{
|
||
error = deltaErr;
|
||
return false;
|
||
}
|
||
|
||
// 再由质量流量与焓差得到制冷量。
|
||
return TryComputeCapacity_kW(mRef_kg_s, deltaH_kJkg, "制冷量Qc", out qc_kW, out error);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算 COP。
|
||
/// </summary>
|
||
/// <param name="capacity_kW">容量,单位 kW。</param>
|
||
/// <param name="w_kW">压缩机输入功率,单位 kW。</param>
|
||
/// <param name="quantityName">当前 COP 名称,用于错误信息。</param>
|
||
/// <param name="cop">COP 输出。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryComputeCOP(double capacity_kW, double w_kW, string quantityName, out double cop, out string error)
|
||
{
|
||
cop = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 容量必须是有效数值。
|
||
if (double.IsNaN(capacity_kW) || double.IsInfinity(capacity_kW))
|
||
{
|
||
error = $"{quantityName}输入异常";
|
||
return false;
|
||
}
|
||
|
||
// 功率必须有效且大于 0,避免除零。
|
||
if (double.IsNaN(w_kW) || double.IsInfinity(w_kW) || w_kW <= 0)
|
||
{
|
||
error = "无效压缩机功率";
|
||
return false;
|
||
}
|
||
|
||
// COP = 容量 / 输入功率。
|
||
cop = capacity_kW / w_kW;
|
||
if (double.IsNaN(cop) || double.IsInfinity(cop))
|
||
{
|
||
error = $"{quantityName}结果异常";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算制热 COP。
|
||
/// </summary>
|
||
/// <param name="qh_kW">制热量,单位 kW。</param>
|
||
/// <param name="w_kW">压缩机输入功率,单位 kW。</param>
|
||
/// <param name="copHeating">制热 COP 输出。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryComputeHeatingCOP(double qh_kW, double w_kW, out double copHeating, out string error)
|
||
{
|
||
return TryComputeCOP(qh_kW, w_kW, "COP(制热)", out copHeating, out error);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算制冷 COP。
|
||
/// </summary>
|
||
/// <param name="qc_kW">制冷量,单位 kW。</param>
|
||
/// <param name="w_kW">压缩机输入功率,单位 kW。</param>
|
||
/// <param name="copCooling">制冷 COP 输出。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryComputeCoolingCOP(double qc_kW, double w_kW, out double copCooling, out string error)
|
||
{
|
||
return TryComputeCOP(qc_kW, w_kW, "COP(制冷)", out copCooling, out error);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算等熵效率,单位 %。
|
||
/// </summary>
|
||
/// <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="etaS_pct">等熵效率输出,单位 %。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryComputeIsentropicEfficiencyPct(double h1_kJkg, double h2_kJkg, double h2s_kJkg, out double etaS_pct, out string error)
|
||
{
|
||
etaS_pct = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 实际压缩焓升:(h2 - h1)。
|
||
if (!TryComputeEnthalpyDifference_kJkg(h2_kJkg, h1_kJkg, "实际压缩焓升(h2-h1)", out var actualRise_kJkg, out var actualErr))
|
||
{
|
||
error = actualErr;
|
||
return false;
|
||
}
|
||
|
||
// 等熵压缩焓升:(h2s - h1)。
|
||
if (!TryComputeEnthalpyDifference_kJkg(h2s_kJkg, h1_kJkg, "等熵压缩焓升(h2s-h1)", out var isentropicRise_kJkg, out var isoErr))
|
||
{
|
||
error = isoErr;
|
||
return false;
|
||
}
|
||
|
||
// 等熵效率 = 等熵焓升 / 实际焓升 * 100%。
|
||
return TryComputeEfficiencyPct(isentropicRise_kJkg, actualRise_kJkg, "等熵效率", out etaS_pct, out error);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算容积效率,单位 %。
|
||
/// </summary>
|
||
/// <param name="mRef_kg_s">冷媒质量流量,单位 kg/s。</param>
|
||
/// <param name="v1_m3kg">吸气比容 v1,单位 m³/kg。</param>
|
||
/// <param name="speed_rpm">压缩机转速,单位 rpm。</param>
|
||
/// <param name="disp_cc">压缩机排量,单位 cc。</param>
|
||
/// <param name="etaV_pct">容积效率输出,单位 %。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryComputeVolumetricEfficiencyPct(double mRef_kg_s, double v1_m3kg, double speed_rpm, double disp_cc, out double etaV_pct, out string error)
|
||
{
|
||
etaV_pct = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 先校验转速。
|
||
if (!TryGetCompressorSpeed_rpm(speed_rpm, out var validatedSpeed_rpm, out var speedErr))
|
||
{
|
||
error = speedErr;
|
||
return false;
|
||
}
|
||
|
||
// 再校验排量。
|
||
if (!TryGetCompressorDisplacement_cc(disp_cc, out var validatedDisp_cc, out var dispErr))
|
||
{
|
||
error = dispErr;
|
||
return false;
|
||
}
|
||
|
||
// 计算实际吸气体积流量。
|
||
if (!TryComputeSuctionVolumeFlow_m3_h(mRef_kg_s, v1_m3kg, out var suctionVolFlow_m3_h, out var suctionErr))
|
||
{
|
||
error = suctionErr;
|
||
return false;
|
||
}
|
||
|
||
// 计算理论吸气体积流量。
|
||
if (!TryComputeTheoreticalVolumeFlow_m3_h(validatedSpeed_rpm, validatedDisp_cc, out var theoVolFlow_m3_h, out var theoErr))
|
||
{
|
||
error = theoErr;
|
||
return false;
|
||
}
|
||
|
||
// 容积效率 = 实际吸气体积流量 / 理论吸气体积流量 * 100%。
|
||
return TryComputeEfficiencyPct(suctionVolFlow_m3_h, theoVolFlow_m3_h, "容积效率", out etaV_pct, out error);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算百分比效率。
|
||
/// </summary>
|
||
/// <param name="numerator">分子。</param>
|
||
/// <param name="denominator">分母。</param>
|
||
/// <param name="quantityName">当前效率名称,用于错误信息。</param>
|
||
/// <param name="efficiencyPct">效率输出,单位 %。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryComputeEfficiencyPct(double numerator, double denominator, string quantityName, out double efficiencyPct, out string error)
|
||
{
|
||
efficiencyPct = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 先校验分子。
|
||
if (double.IsNaN(numerator) || double.IsInfinity(numerator))
|
||
{
|
||
error = $"{quantityName}分子异常";
|
||
return false;
|
||
}
|
||
|
||
// 再校验分母,避免除零或极小数造成结果发散。
|
||
const double eps = 1e-9;
|
||
if (double.IsNaN(denominator) || double.IsInfinity(denominator) || Math.Abs(denominator) < eps)
|
||
{
|
||
error = $"{quantityName}分母过小或异常";
|
||
return false;
|
||
}
|
||
|
||
// 效率 = 分子 / 分母。
|
||
double efficiency = numerator / denominator;
|
||
if (double.IsNaN(efficiency) || double.IsInfinity(efficiency))
|
||
{
|
||
error = $"{quantityName}结果异常";
|
||
return false;
|
||
}
|
||
|
||
// 将无量纲效率换算为百分数。
|
||
efficiencyPct = efficiency * 100.0;
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取并校验压缩机转速,单位 rpm。
|
||
/// </summary>
|
||
/// <param name="compressorSpeedRpm">输入转速,单位 rpm。</param>
|
||
/// <param name="speed_rpm">输出转速,单位 rpm。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否获取成功。</returns>
|
||
private bool TryGetCompressorSpeed_rpm(double compressorSpeedRpm, out double speed_rpm, out string error)
|
||
{
|
||
speed_rpm = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 当前方法只做读取与合法性校验。
|
||
speed_rpm = compressorSpeedRpm;
|
||
if (double.IsNaN(speed_rpm) || double.IsInfinity(speed_rpm) || speed_rpm <= 0)
|
||
{
|
||
error = $"无效转速: {speed_rpm} rpm";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算实际吸气体积流量,单位 m³/h。
|
||
/// </summary>
|
||
/// <param name="mRef_kg_s">冷媒质量流量,单位 kg/s。</param>
|
||
/// <param name="v1_m3kg">吸气比容,单位 m³/kg。</param>
|
||
/// <param name="suctionVolFlow_m3_h">实际吸气体积流量输出,单位 m³/h。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
private bool TryComputeSuctionVolumeFlow_m3_h(double mRef_kg_s, double v1_m3kg, out double suctionVolFlow_m3_h, out string error)
|
||
{
|
||
suctionVolFlow_m3_h = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 校验质量流量。
|
||
if (double.IsNaN(mRef_kg_s) || double.IsInfinity(mRef_kg_s) || mRef_kg_s <= 0)
|
||
{
|
||
error = "无效冷媒质量流量";
|
||
return false;
|
||
}
|
||
|
||
// 校验吸气比容。
|
||
if (double.IsNaN(v1_m3kg) || double.IsInfinity(v1_m3kg) || v1_m3kg <= 0)
|
||
{
|
||
error = "无效吸气比容";
|
||
return false;
|
||
}
|
||
|
||
// 实际吸气体积流量 = (kg/s * 3600) * m³/kg = m³/h。
|
||
suctionVolFlow_m3_h = (mRef_kg_s * 3600.0) * v1_m3kg;
|
||
if (double.IsNaN(suctionVolFlow_m3_h) || double.IsInfinity(suctionVolFlow_m3_h))
|
||
{
|
||
error = "实际吸气体积流量结果异常";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算理论吸气体积流量,单位 m³/h。
|
||
/// </summary>
|
||
/// <param name="speed_rpm">压缩机转速,单位 rpm。</param>
|
||
/// <param name="disp_cc">压缩机排量,单位 cc。</param>
|
||
/// <param name="theoVolFlow_m3_h">理论吸气体积流量输出,单位 m³/h。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否计算成功。</returns>
|
||
/// <remarks>
|
||
/// 当前公式保持原实现不变:
|
||
/// <c>(speed_rpm / 60.0) * disp_cc * 0.0036</c>
|
||
/// </remarks>
|
||
private bool TryComputeTheoreticalVolumeFlow_m3_h(double speed_rpm, double disp_cc, out double theoVolFlow_m3_h, out string error)
|
||
{
|
||
theoVolFlow_m3_h = double.NaN;
|
||
error = string.Empty;
|
||
|
||
if (double.IsNaN(speed_rpm) || double.IsInfinity(speed_rpm) || speed_rpm <= 0)
|
||
{
|
||
error = $"无效转速: {speed_rpm} rpm";
|
||
return false;
|
||
}
|
||
|
||
if (double.IsNaN(disp_cc) || double.IsInfinity(disp_cc) || disp_cc <= 0)
|
||
{
|
||
error = $"无效压缩机排量: {disp_cc} cc";
|
||
return false;
|
||
}
|
||
|
||
// 理论体积流量公式保持原有写法不变。
|
||
theoVolFlow_m3_h = (speed_rpm / 60.0) * disp_cc * 0.0036;
|
||
if (double.IsNaN(theoVolFlow_m3_h) || double.IsInfinity(theoVolFlow_m3_h) || theoVolFlow_m3_h <= 0)
|
||
{
|
||
error = "理论吸气体积流量<=0";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取并校验压缩机排量,单位 cc。
|
||
/// </summary>
|
||
/// <param name="compressorDisplacementCc">输入排量,单位 cc。</param>
|
||
/// <param name="displacement_cc">输出排量,单位 cc。</param>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否获取成功。</returns>
|
||
private bool TryGetCompressorDisplacement_cc(double compressorDisplacementCc, out double displacement_cc, out string error)
|
||
{
|
||
displacement_cc = double.NaN;
|
||
error = string.Empty;
|
||
|
||
// 当前方法只做读取与合法性校验。
|
||
displacement_cc = compressorDisplacementCc;
|
||
if (double.IsNaN(displacement_cc) || double.IsInfinity(displacement_cc) || displacement_cc <= 0)
|
||
{
|
||
error = $"压缩机排量<=0: {displacement_cc}";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
/// <summary>
|
||
/// 六个热力结果计算类私有的底层物性支持实现。
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 该实现仅服务当前六结果计算类,不与其他结果类共享实现细节,
|
||
/// 这样即使后续为了新计算类调整别处的 support,也不会影响本类已验算通过的流程。
|
||
/// </remarks>
|
||
private sealed class LocalCalculationSupport : IPPCCalculationSupport
|
||
{
|
||
private static readonly object _refpropLock = RefpropGlobalSync.SyncRoot;
|
||
private static volatile bool _rpInitialized;
|
||
|
||
public 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;
|
||
}
|
||
}
|
||
|
||
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 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;
|
||
}
|
||
|
||
public bool TryTHERM_VaporEntropy_ByTD(double temperatureC, double densityMolPerL, out double entropy_kJ_per_kgK, out string error)
|
||
{
|
||
entropy_kJ_per_kgK = 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;
|
||
double e = 0;
|
||
double hJmol = 0;
|
||
double sJmolK = 0;
|
||
double cv = 0;
|
||
double cp = 0;
|
||
double w = 0;
|
||
double 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);
|
||
}
|
||
|
||
entropy_kJ_per_kgK = (sJmolK / molarMassKgPerMol) * 0.001;
|
||
return true;
|
||
}
|
||
|
||
public 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;
|
||
}
|
||
|
||
public 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;
|
||
double e = 0;
|
||
double hJmol = 0;
|
||
double sJmolK = 0;
|
||
double cv = 0;
|
||
double cp = 0;
|
||
double w = 0;
|
||
double 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_liq_kJ_per_kg = (hJmol / molarMassKgPerMol) * 0.001;
|
||
return true;
|
||
}
|
||
|
||
public 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;
|
||
double e = 0;
|
||
double hJmol = 0;
|
||
double sJmolK = 0;
|
||
double cv = 0;
|
||
double cp = 0;
|
||
double w = 0;
|
||
double 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_kJ_per_kg = (hJmol / molarMassKgPerMol) * 0.001;
|
||
return true;
|
||
}
|
||
|
||
public bool TryConvertMolarDensityToSpecificVolume(double d_molL, out double v_m3kg, out string error)
|
||
{
|
||
v_m3kg = double.NaN;
|
||
error = string.Empty;
|
||
|
||
if (double.IsNaN(d_molL) || double.IsInfinity(d_molL) || d_molL <= 0)
|
||
{
|
||
error = $"无效摩尔密度: {d_molL} mol/L";
|
||
return false;
|
||
}
|
||
|
||
double molarMassKgPerMol = GetMolarMass();
|
||
if (molarMassKgPerMol <= 0)
|
||
{
|
||
error = "无效的摩尔质量";
|
||
return false;
|
||
}
|
||
|
||
double rho_kg_m3 = d_molL * molarMassKgPerMol * 1000.0;
|
||
if (rho_kg_m3 <= 0)
|
||
{
|
||
error = $"无效密度: {rho_kg_m3} kg/m3";
|
||
return false;
|
||
}
|
||
|
||
v_m3kg = 1.0 / rho_kg_m3;
|
||
return true;
|
||
}
|
||
|
||
public bool TryGetIsentropicOutletEnthalpy_h2s_ByP2AndS1_BarA(double dischargePressureBarA, double suctionEntropy_kJkgK, out double h2s_kJkg, out string error)
|
||
{
|
||
h2s_kJkg = double.NaN;
|
||
error = string.Empty;
|
||
|
||
double pKPa = dischargePressureBarA * 100.0;
|
||
if (pKPa <= 0)
|
||
{
|
||
error = $"无效排气压力: {dischargePressureBarA} BarA";
|
||
return false;
|
||
}
|
||
|
||
if (double.IsNaN(suctionEntropy_kJkgK) || double.IsInfinity(suctionEntropy_kJkgK))
|
||
{
|
||
error = "无效吸气熵 s1";
|
||
return false;
|
||
}
|
||
|
||
if (!TryConvertS_kJkgK_To_JmolK(suctionEntropy_kJkgK, out var s_JmolK, out var convErr))
|
||
{
|
||
error = convErr;
|
||
return false;
|
||
}
|
||
|
||
double[] z = new double[20];
|
||
z[0] = 1.0;
|
||
|
||
double t = 0.0;
|
||
double d = 0.0;
|
||
double Dl = 0.0;
|
||
double Dv = 0.0;
|
||
double[] xliq = new double[20];
|
||
double[] xvap = new double[20];
|
||
double q = 0.0;
|
||
double ee = 0.0;
|
||
double h = 0.0;
|
||
double Cv = 0.0;
|
||
double Cp = 0.0;
|
||
double w = 0.0;
|
||
long ierr = 0;
|
||
long herrLen = 255;
|
||
string herr = new string(' ', 255);
|
||
|
||
lock (_refpropLock)
|
||
{
|
||
IRefProp64.PSFLSHdll(ref pKPa, ref s_JmolK, z, ref t, ref d, ref Dl, ref Dv, xliq, xvap, ref q, ref ee, ref h, ref Cv, ref Cp, ref w, ref ierr, ref herr, ref herrLen);
|
||
}
|
||
|
||
if (ierr != 0)
|
||
{
|
||
error = $"PSFLSH 错误: {herr.Trim()} (ierr={ierr})";
|
||
return false;
|
||
}
|
||
|
||
return TryConvertH_Jmol_To_kJkg(h, out h2s_kJkg, out error);
|
||
}
|
||
|
||
private static double GetMolarMass()
|
||
{
|
||
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;
|
||
long componentId = 1;
|
||
|
||
IRefProp64.INFOdll(ref componentId, ref wmm, ref Trp, ref Tnbpt, ref Tc, ref Pc, ref Dc, ref Zc, ref acf, ref dip, ref Rgas);
|
||
return wmm * 0.001;
|
||
}
|
||
|
||
private static bool TryConvertH_Jmol_To_kJkg(double h_Jmol, out double h_kJkg, out string error)
|
||
{
|
||
h_kJkg = double.NaN;
|
||
error = string.Empty;
|
||
|
||
double molarMassKgPerMol = GetMolarMass();
|
||
if (molarMassKgPerMol <= 0)
|
||
{
|
||
error = "无效的摩尔质量";
|
||
return false;
|
||
}
|
||
|
||
h_kJkg = (h_Jmol / molarMassKgPerMol) * 0.001;
|
||
return true;
|
||
}
|
||
|
||
private static bool TryConvertS_kJkgK_To_JmolK(double s_kJkgK, out double s_JmolK, out string error)
|
||
{
|
||
s_JmolK = double.NaN;
|
||
error = string.Empty;
|
||
|
||
double molarMassKgPerMol = GetMolarMass();
|
||
if (molarMassKgPerMol <= 0)
|
||
{
|
||
error = "无效的摩尔质量";
|
||
return false;
|
||
}
|
||
|
||
s_JmolK = s_kJkgK * 1000.0 * molarMassKgPerMol;
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
}
|