干度251018

This commit is contained in:
2025-10-18 14:15:46 +08:00
parent 080d8e1ffa
commit c0e4c216a2
3 changed files with 138 additions and 126 deletions

View File

@@ -1,29 +1,14 @@
using CapMachine.Core;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.Models.Tag;
using CapMachine.Wpf.Models;
using CapMachine.Wpf.Services;
using HslCommunication;
using ImTools;
using NLog;
using NPOI.OpenXmlFormats.Wordprocessing;
using Prism.Ioc;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Interop;
using static CapMachine.Wpf.CanDrive.USB2CAN;
using CapMachine.Wpf.Models;
namespace CapMachine.Wpf.CanDrive
{

Binary file not shown.

View File

@@ -84,6 +84,7 @@ namespace CapMachine.Wpf.Services
{
LiqRefFlowTag = LiqRefFlowShortTag!;
}
//kg/h L/min
if (TagManager.TryGetShortTagByName("冷媒流量[L/min]", out ShortValueTag? VRVShortTag))
{
VRVTag = VRVShortTag!;
@@ -133,11 +134,16 @@ namespace CapMachine.Wpf.Services
DrynessTag = drynessPct!;
DrynessTagIsPercent = true;
}
else if (TagManager.TryGetShortTagByName("干度[-]", out ShortValueTag? drynessAbs))
{
DrynessTag = drynessAbs!;
DrynessTagIsPercent = false;
}
SuperHeatCoolConfig.FluidsPath = ConfigHelper.GetValue("FluidsPath");
SuperHeatCoolConfig.Cryogen = ConfigHelper.GetValue("Cryogen");
//RtScanDeviceStart();
RtScanDeviceStart();
}
@@ -265,6 +271,10 @@ namespace CapMachine.Wpf.Services
/// </summary>
private bool RtCalcEnable { get; set; } = true;
/// <summary>
/// 触发日志
/// </summary>
private bool DebugLog { get; set; }=false;
/// <summary>
/// PLC扫描线程
@@ -273,145 +283,117 @@ namespace CapMachine.Wpf.Services
{
CalcTask = Task.Run(async () =>
{
//Stopwatch stopwatch = new Stopwatch();
//物性的过热度和过冷度的相关物性计算
while (RtCalcEnable)
{
await Task.Delay(1000);
try
{
long iErr, kph = 1;
double te = 0.0, te1 = 0.0, p = 0.0, p1 = 0.0, d = 0.0, Dl = 0.0, Dv = 0.0, q = 0.0, h = 0.0, ee = 0.0, hh = 0.0, ss = 0.0, cp = 0.0, cv = 0.0, w = 0.0;
double[] x = new double[20], xliq = new double[20], xvap = new double[20];
double[] xlkg = new double[20], xvkg = new double[20];
double tk = 0.0, wm = 0.0, prevDeltaH = 0.0;
double tk = 0.0, wm = 0.0, prevDeltaH = 0.0;//prevDeltaH 未使用
// 统一初始化(仅必要时),避免循环内重复 SETUP/SETPATH
if (!EnsureRefpropInitialized(out string initErrLoop))
{
// 初始化失败:保护性置零并进入下一轮
Superheat.PVModel.EngValue = 0;
Subcool.PVModel.EngValue = 0;
// 可选:记录 initErrLoop
continue;
}
else
lock (_refpropLock)
{
// 在统一的锁内进行 REFPROP 计算,保证并发安全与状态一致性
lock (_refpropLock)
// 过热度
if (TryComputeSuperheatK_ByBarA(InhPressTag.PVModel.EngValue, InhTempTag.PVModel.EngValue, out double superheatK, out string shErr))
Superheat.PVModel.EngValue = superheatK;
else
{
// 建立纯工质组分(摩尔分数)
double[] xLoc = new double[20]; xLoc[0] = 1.0;
double[] xliqLoc = new double[20];
double[] xvapLoc = new double[20];
double DlLoc = 0, DvLoc = 0;
string herr2 = new string(' ', 255);
long herrLen2 = 255;
Superheat.PVModel.EngValue = 0;
if (DebugLog) Logger.Error($"过热度计算失败:{shErr}");
}
// 计算过热度/过冷度封装方法BarA→kPa
if (TryComputeSuperheatK_ByBarA(InhPressTag.PVModel.EngValue, InhTempTag.PVModel.EngValue, out double superheatK, out string shErr))
Superheat.PVModel.EngValue = superheatK;
// 过冷度
if (TryComputeSubcoolK_ByBarA(TxvFrPressTag.PVModel.EngValue, TxvFrTempTag.PVModel.EngValue, out double subcoolK, out string scErr))
Subcool.PVModel.EngValue = subcoolK;
else
{
Subcool.PVModel.EngValue = 0;
if (DebugLog) Logger.Error($"过冷度计算失败:{scErr}");
}
// 干度计算
var missing = new List<string>();
if (InhPressTag == null) missing.Add("吸气压力[BarA]");
if (GasPreValvePressTag == null) missing.Add("气路阀前压力[BarA]");
if (GasPreValveTempTag == null) missing.Add("气路阀前温度[℃]");
if (TxvFrPressTag == null) missing.Add("膨胀阀前压力[BarA]");
if (TxvFrTempTag == null) missing.Add("SUBCOOL出口温度[℃]");
if (VRVTag == null) missing.Add("气体质量流量[kg/h]");
if (LiqRefFlowTag == null) missing.Add("液冷媒流量[kg/h]");
if (missing.Count > 0)
{
if (DrynessTag != null) DrynessTag.PVModel.EngValue = 0;
if (DebugLog) Logger.Error($"质量流量加权干度必要测点缺失已将干度置0。缺失: {string.Join(", ", missing)}");
}
else
{
string dryErr;
//double ps = InhPressTag.PVModel.EngValue;
//double pg = GasPreValvePressTag.PVModel.EngValue;
//double tg = GasPreValveTempTag.PVModel.EngValue;
//double plv = TxvFrPressTag.PVModel.EngValue;
//double tlv = TxvFrTempTag.PVModel.EngValue;
double ps = InhPressTag.PVModel.EngValue;//吸气压力
//ps = 2.374421;//Mpa ->BarA
double pg = GasPreValvePressTag.PVModel.EngValue;//气路阀前压力
//pg = 19.77032;//Mpa ->BarA
double tg = GasPreValveTempTag.PVModel.EngValue;//气路阀前温度
//tg = 61.76869;
double plv = TxvFrPressTag.PVModel.EngValue;//膨胀阀前压力=液路阀前压力
//plv = 19.26757;//Mpa ->BarA
double tlv = TxvFrTempTag.PVModel.EngValue;//膨胀阀前温度 = SUBCOOL出口温度 =液路阀前温度
//tlv = 64.96428;
double LiquidMassFlowKgPerH = Math.Max(0.0, LiqRefFlowTag?.PVModel?.EngValue ?? 0.0);
//double LiquidMassFlowKgPerH = 214.3051;
//double GasMassFlowKgPerH = Math.Max(0.0, VRVTag?.PVModel?.EngValue ?? 0.0);
double GasMassFlowKgPerH = (double)(VRVTag?.PVModel?.EngValue - LiquidMassFlowKgPerH);
// 校验总质量流量
if ((GasMassFlowKgPerH + LiquidMassFlowKgPerH) <= 0)
{
if (DrynessTag != null) DrynessTag.PVModel.EngValue = 0;
if (DebugLog) Logger.Error("质量流量加权干度:气/液质量流量和<=0已将干度置0。");
}
else
{
Superheat.PVModel.EngValue = 0;
Logger.Error($"过热度计算失败:{shErr}");
}
double dryness = Step_ComputeDryness_LV_FlowWeighted(
GasMassFlowKgPerH,
LiquidMassFlowKgPerH,
ps, pg, tg, plv, tlv,
out dryErr
);
if (TryComputeSubcoolK_ByBarA(TxvFrPressTag.PVModel.EngValue, TxvFrTempTag.PVModel.EngValue, out double subcoolK, out string scErr))
Subcool.PVModel.EngValue = subcoolK;
else
{
Subcool.PVModel.EngValue = 0;
Logger.Error($"过冷度计算失败:{scErr}");
}
// 干度计算LabVIEW 严格流程,质量流量加权):
// A) 阀前两路相焓TPRHO→THERM
// B) 质量流量加权混合焓
// C) 吸气压力同压饱和焓SATP→THERM
// D) x = (h_mix - h_l)/(h_v - h_l)
try
{
// 输入校验:必要测点是否齐全
var missing = new List<string>();
if (InhPressTag == null) missing.Add("吸气压力[BarA]");
if (GasPreValvePressTag == null) missing.Add("气路阀前压力[BarA]");
if (GasPreValveTempTag == null) missing.Add("气路阀前温度[℃]");
if (TxvFrPressTag == null) missing.Add("膨胀阀前压力[BarA]");
if (TxvFrTempTag == null) missing.Add("SUBCOOL出口温度[℃]");
if (missing.Count > 0)
if (!double.IsNaN(dryness))
{
// 物理意义上干度应在 [0,1],写入 Tag 时进行夹紧保护
double drynessClamped = Math.Min(1.0, Math.Max(0.0, dryness));
if (DrynessTag != null)
{
DrynessTag.PVModel.EngValue = 0;
}
Logger.Error($"质量流量加权干度必要测点缺失已将干度置0。缺失: {string.Join(", ", missing)}");
DrynessTag.PVModel.EngValue = DrynessTagIsPercent ? drynessClamped * 100.0 : drynessClamped;
}
else
{
string dryErr;
double ps = InhPressTag.PVModel.EngValue;//吸气压力
//ps = 2.374421;//Mpa ->BarA
double pg = GasPreValvePressTag.PVModel.EngValue;//气路阀前压力
//pg = 19.77032;//Mpa ->BarA
double tg = GasPreValveTempTag.PVModel.EngValue;//气路阀前温度
//tg = 61.76869;
double plv = TxvFrPressTag.PVModel.EngValue;//膨胀阀前压力=液路阀前压力
//plv = 19.26757;//Mpa ->BarA
double tlv = TxvFrTempTag.PVModel.EngValue;//膨胀阀前温度 = SUBCOOL出口温度 =液路阀前温度
//tlv = 64.96428;
// 单位说明:
// - 液体质量流量 ml[kg/h] = LiqRefFlowTag.PVModel.EngValue
// - 气体质量流量 mg[kg/h] = VRVTag.PVModel.EngValueVRV 位于气管,单位已为 kg/h
double GasMassFlowKgPerH, LiquidMassFlowKgPerH;
LiquidMassFlowKgPerH = LiqRefFlowTag.PVModel.EngValue; // [kg/h]
//GasMassFlowKgPerH = Math.Max(0.0, VRVTag?.PVModel?.EngValue ?? 0.0); // [kg/h]
GasMassFlowKgPerH = (double)(VRVTag?.PVModel?.EngValue - LiquidMassFlowKgPerH);
//压力参数要求为BarA
double dryness = Step_ComputeDryness_LV_FlowWeighted(
GasMassFlowKgPerH,
LiquidMassFlowKgPerH,
ps, pg, tg, plv, tlv,
out dryErr
);
double val = (!double.IsNaN(dryness)) ? dryness : 0.0;
if (DrynessTag != null)
{
DrynessTag.PVModel.EngValue = DrynessTagIsPercent ? val * 100.0 : val;
}
if (double.IsNaN(dryness))
{
Logger.Error($"质量流量加权干度计算失败:{dryErr}已置0。输入: mg={GasMassFlowKgPerH:F3} kg/h, ml={LiquidMassFlowKgPerH:F3} kg/h, Ps={ps:F3} BarA, Pg={pg:F3} BarA, Tg={tg:F3} ℃, Pl={plv:F3} BarA, Tl={tlv:F3} ℃");
}
if (DebugLog) Logger.Warn($"质量流量加权干度计算失败:{dryErr};已跳过本次干度写入。输入: mg={GasMassFlowKgPerH:F3} kg/h, ml={LiquidMassFlowKgPerH:F3} kg/h, Ps={ps:F3} BarA, Pg={pg:F3} BarA, Tg={tg:F3} ℃, Pl={plv:F3} BarA, Tl={tlv:F3} ℃");
}
}
catch (Exception ex)
{
if (DrynessTag != null) DrynessTag.PVModel.EngValue = 0;
Logger.Error("质量流量加权干度计算异常已置0");
}
}
}
//p = Convert.ToDouble(textBox2.Text) * 100.0;//textBox2 Comp.吸气压力BarA→kPa
p = (InhPressTag.PVModel.EngValue) * 100.0;//textBox2 Comp.吸气压力BarA→kPa
kph = 1;
p1 = (TxvFrPressTag.PVModel.EngValue) * 100.0;//textBox3 Evap.膨胀阀前压力BarA→kPa
//p1 = Convert.ToDouble(textBox3.Text) * 100.0;//textBox3 Evap.膨胀阀前压力BarA→kPa
// 重复的 SATP 与干度计算已在上方 lock(_refpropLock) 中统一完成,此处移除重复调用
}
catch (Exception ex)
{
//logger.Error(String.Format("ErrSource : {0} ErrMsg : {1}", ex.StackTrace.ToString(), ex.Message.ToString()));
Logger.Error(String.Format("ErrSource : {0} ErrMsg : {1}", ex.StackTrace.ToString(), ex.Message.ToString()));
}
}
});
@@ -460,7 +442,7 @@ namespace CapMachine.Wpf.Services
}
if (ierr != 0) { error = $"SATP 失败: {herr.Trim()} (ierr={ierr})"; return false; }
double tSatC = tSatK - 273.15;
subcoolK = preValveTempC - tSatC;
subcoolK = tSatC - preValveTempC;
return true;
}
@@ -514,7 +496,7 @@ namespace CapMachine.Wpf.Services
herr = new string(' ', 255); herrLen = 255; iErr = 0;
IRefProp64.SATPdll(ref p1, x, ref kph, ref te1, ref Dl, ref Dv, xliq, xvap, ref iErr, ref herr, ref herrLen);
if (iErr == 0)
Subcool.PVModel.EngValue = TxvFrTempTag.PVModel.EngValue - (te1 - 273.15);
Subcool.PVModel.EngValue = (te1 - 273.15) - TxvFrTempTag.PVModel.EngValue;
else
Subcool.PVModel.EngValue = 0;
@@ -567,16 +549,60 @@ namespace CapMachine.Wpf.Services
{
h_kJkg = double.NaN; error = string.Empty;
if (!EnsureRefpropInitialized(out error)) return false;
// 统一输入与数组
double[] x = new double[20]; x[0] = 1.0;
double wmm = 0; // g/mol
double tK = temperatureC + 273.15;
double pKPa = pressureBarA * 100.0;
double D = 0; long kguess = 0; long ierr = 0; string herr = new string(' ', 255); long ln = 255;
double pOut = 0, el = 0, hl = 0, sl = 0, cvl = 0, cpl = 0, wl = 0, hjt = 0;
// 相态自适应:当期望液相(kph=1)但温度高于同压饱和或接近相边界时,改用 TPFLSH 或饱和液焓,避免跳变
const double EpsBandK = 0.4; // 饱和带宽K
lock (_refpropLock)
{
IRefProp64.WMOLdll(x, ref wmm);
if (!(wmm > 0)) { error = "WMOL 返回无效摩尔质量"; return false; }
// 计算当前压力下的饱和温度
double tSat = 0, DlSat = 0, DvSat = 0; long kphSat = 1; string herrSat = new string(' ', 255); long lnSat = 255; long ierrSat = 0;
double pForSat = pKPa;
IRefProp64.SATPdll(ref pForSat, x, ref kphSat, ref tSat, ref DlSat, ref DvSat, new double[20], new double[20], ref ierrSat, ref herrSat, ref lnSat);
double tSatC = (ierrSat == 0) ? (tSat - 273.15) : double.NaN;
// 当调用者要求液相,但温度在饱和带内或高于饱和温度时,优先使用 TPFLSH 获取真实相态焓
if (kphPhase == 1 && !double.IsNaN(tSatC))
{
double dT = temperatureC - tSatC;
if (dT >= EpsBandK)
{
// 已明显高于饱和按真实相态计算焓TPFLSH
string e2;
if (TryComputeHmassKJkgByTP_BarAC(pressureBarA, temperatureC, out double hMassTPF, out e2))
{ h_kJkg = hMassTPF; return true; }
// 若 TPFLSH 也失败,则退化为气相路径 TPRHO
long kphGas = 2; double tK2 = tK; double pKPa2 = pKPa; double DG = 0; long ierr2 = 0; string herr2 = new string(' ', 255); long ln2 = 255;
IRefProp64.TPRHOdll(ref tK2, ref pKPa2, x, ref kphGas, ref kguess, ref DG, ref ierr2, ref herr2, ref ln2);
if (ierr2 == 0)
{
double tLocal2 = tK2; double DLocal2 = DG;
IRefProp64.THERMdll(ref tLocal2, ref DLocal2, x, ref pOut, ref el, ref hl, ref sl, ref cvl, ref cpl, ref wl, ref hjt);
h_kJkg = hl / wmm; return true;
}
// 否则继续走默认液相路径(尽力返回)
}
else if (Math.Abs(dT) <= EpsBandK)
{
// 接近饱和:改用 TPFLSH(T,P) 真实相态焓,避免“直接切换为饱和液焓”导致阶跃
string e2b;
if (TryComputeHmassKJkgByTP_BarAC(pressureBarA, temperatureC, out double hMassTPF2, out e2b))
{ h_kJkg = hMassTPF2; return true; }
// 若失败,继续默认液相路径
}
}
// 默认:按给定 kphPhase 走 TPRHO→THERM与 LV 路径一致)
IRefProp64.TPRHOdll(ref tK, ref pKPa, x, ref kphPhase, ref kguess, ref D, ref ierr, ref herr, ref ln);
if (ierr != 0) { error = $"TPRHO 失败: {herr.Trim()} (ierr={ierr})"; return false; }
double tLocal = tK; double DLocal = D;
@@ -626,7 +652,8 @@ namespace CapMachine.Wpf.Services
if (Math.Abs(denom) < 1e-9) { error = "饱和焓差过小,可能临界附近"; return false; }
double val = (hMix_kJkg - hl_kJkg) / denom;
if (double.IsNaN(val) || double.IsInfinity(val)) { error = "干度数值异常"; return false; }
x = Math.Max(0.0, Math.Min(1.0, val));
// 不再夹紧到 [0,1],返回原始 x可能 <0 或 >1以避免跨界限时的阶跃
x = val;
return true;
}