diff --git a/CapMachine.Wpf/CanDrive/ToomossCan.cs b/CapMachine.Wpf/CanDrive/ToomossCan.cs
index 9de3eee..3df7b1a 100644
--- a/CapMachine.Wpf/CanDrive/ToomossCan.cs
+++ b/CapMachine.Wpf/CanDrive/ToomossCan.cs
@@ -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
{
diff --git a/CapMachine.Wpf/PPCalculation/2025-10-18.xlsx b/CapMachine.Wpf/PPCalculation/2025-10-18.xlsx
new file mode 100644
index 0000000..7a5f696
Binary files /dev/null and b/CapMachine.Wpf/PPCalculation/2025-10-18.xlsx differ
diff --git a/CapMachine.Wpf/Services/PPCService.cs b/CapMachine.Wpf/Services/PPCService.cs
index 9a76ea2..5f73855 100644
--- a/CapMachine.Wpf/Services/PPCService.cs
+++ b/CapMachine.Wpf/Services/PPCService.cs
@@ -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
///
private bool RtCalcEnable { get; set; } = true;
+ ///
+ /// 触发日志
+ ///
+ private bool DebugLog { get; set; }=false;
///
/// 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();
+ 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();
- 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.EngValue(VRV 位于气管,单位已为 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;
}