CSV 的报错的更改
This commit is contained in:
173
CapMachine.Wpf/PPCalculation/PPCalculation-物性计算说明.md
Normal file
173
CapMachine.Wpf/PPCalculation/PPCalculation-物性计算说明.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# PPCalculation 物性计算说明
|
||||
|
||||
本文档用于说明当前工程中 **PPC 物性计算** 的整体数据流、输入输出、单位约定、关键规则,以及 REFPROP 调用链路,便于后续维护与复用。
|
||||
|
||||
## 1. 代码入口与职责边界
|
||||
|
||||
- **入口服务**:`CapMachine.Wpf.Services.PPCService`
|
||||
- 负责:
|
||||
- 从 `TagManager` 读取实时数据(压力、温度、功率、流量、转速等)。
|
||||
- 调用物性计算器(Calculator)完成计算。
|
||||
- 将结果写回 Tag(干度、过热/过冷、Qh/Qc、COP、效率等)。
|
||||
- 负责 REFPROP 初始化(SETPATH/SETUP)与全局串行化锁。
|
||||
- 不负责:
|
||||
- 具体的热力性质求解细节(已下沉到 Calculator)。
|
||||
|
||||
- **干度计算器**:`CapMachine.Wpf.PPCalculation.EnthalpyDrynessCalculator`
|
||||
- 职责:基于“加权混合焓 + 吸气压力下饱和焓差”的方法,计算干度。
|
||||
|
||||
- **六参数计算器**:`CapMachine.Wpf.PPCalculation.ThermodynamicSixResultsCalculator`
|
||||
- 职责:计算六个核心性能/效率结果:
|
||||
- `Qc`、`Qh`、`COPc`、`COPh`、`ηs`、`ηv`
|
||||
- 内部封装 REFPROP 计算链路、单位换算、以及关键规则(如 h3 的 Tsat-10°C)。
|
||||
|
||||
## 2. 单位约定(非常重要)
|
||||
|
||||
### 2.1 Tag 输入单位(来自 PLC/界面)
|
||||
|
||||
- 压力:`BarA`
|
||||
- 温度:`℃`
|
||||
- 功率:`W`(HV[W])
|
||||
- 冷媒总流量:`kg/h`
|
||||
- 转速:`rpm`
|
||||
- 排量:`cc`(cm³/rev)
|
||||
|
||||
### 2.2 REFPROP 常用单位(在 Calculator 内部处理)
|
||||
|
||||
REFPROP 不同接口参数单位不完全一致,工程中统一由 Calculator 进行换算。
|
||||
|
||||
- 温度:`K`
|
||||
- 压力:常见为 `kPa`(例如 SATP/TPRHO 采用 kPa)
|
||||
- 摩尔密度:`mol/L`
|
||||
- 焓:`J/mol`(THERM 输出),最终换算为 `kJ/kg`
|
||||
- 熵:`J/(mol·K)`(THERM 输出),最终换算为 `kJ/(kg·K)`
|
||||
|
||||
典型换算:
|
||||
- `BarA -> MPa`:乘 `0.1`
|
||||
- `MPa -> kPa`:乘 `1000`
|
||||
- `℃ -> K`:加 `273.15`
|
||||
- `J/mol -> kJ/kg`:`(J/mol) / (kg/mol) * 0.001`
|
||||
|
||||
## 3. 运行周期与整体数据流
|
||||
|
||||
`PPCService.RtScanDeviceStart()` 周期性执行(约 100ms 一次),主要步骤:
|
||||
|
||||
1. **REFPROP 幂等初始化**(第一次进入或未初始化时)
|
||||
- 调用 `EnsureRefpropInitialized()`
|
||||
- 内部在 `_refpropLock` 下执行:
|
||||
- `SETPATHdll` 设置流体库路径
|
||||
- `SETUPdll` 载入工质(当前默认 `R134A.FLD`)
|
||||
|
||||
2. **过热度/过冷度计算(当前仍在服务内直接调用 SATP)**
|
||||
- 吸气侧:由吸气压力求 `Tsat`,与吸气温度做差得到过热度
|
||||
- 膨胀阀前侧:由膨胀阀前压力求 `Tsat`,与膨胀阀前温度做差得到过冷度
|
||||
|
||||
3. **干度计算**(调用 `EnthalpyDrynessCalculator`)
|
||||
- 读取:
|
||||
- 气路阀前压力/温度(GasPreValve P/T)
|
||||
- 膨胀阀前压力/温度(TxvFr P/T)
|
||||
- 吸气压力(InhP)
|
||||
- 冷媒总流量(VRV)
|
||||
- 液体流量(LiqRefFlow)
|
||||
- 当前实现中:润滑油流量 `lubeFlowKgPerH` 固定为 `0.0`(不参与干度计算)。
|
||||
- 输出:
|
||||
- `Dryness1` 写入 `干度[%]` Tag(*100)
|
||||
- `Dryness2` 写入 `PPCService.DrynessTag2Value`(*100,用于界面绑定)
|
||||
|
||||
4. **六参数计算**(调用 `ThermodynamicSixResultsCalculator.TryCalculate`)
|
||||
- 读取输入:
|
||||
- 吸气 P/T(BarA/℃)
|
||||
- 排气 P/T(BarA/℃)
|
||||
- 膨胀阀前 P/T(BarA/℃)
|
||||
- 冷媒总流量(kg/h)
|
||||
- HV 功率(W)
|
||||
- 转速(rpm)
|
||||
- 排量(cc)
|
||||
- 输出写回:
|
||||
- `制热量Qh[W]`(kW * 1000)
|
||||
- `制冷量Qc[W]`(kW * 1000)
|
||||
- `压缩机性能系数(制热)`(COPh)
|
||||
- `压缩机性能系数(制冷)`(COPc)
|
||||
- `等熵效率ns[%]`
|
||||
- `容积效率nv[%]`
|
||||
|
||||
## 4. 干度计算(EnthalpyDrynessCalculator)概要
|
||||
|
||||
### 4.1 输入
|
||||
|
||||
- `GasPreValvePressBarA`
|
||||
- `GasPreValveTempC`
|
||||
- `TxvFrPressBarA`
|
||||
- `TxvFrTempC`
|
||||
- `InhPressBarA`
|
||||
- `VrvFlowKgPerH`
|
||||
- `LiqRefFlowKgPerH`
|
||||
- `LubeFlowKgPerH`(当前传 0)
|
||||
|
||||
### 4.2 核心思路
|
||||
|
||||
1. 分别求取:
|
||||
- 气路阀前气相焓 `h_vap`
|
||||
- 膨胀阀前液相焓 `h_liq`
|
||||
2. 由总流量与液体流量推算气体流量,按质量流量计算混合焓 `h_mix`。
|
||||
3. 由吸气压力求饱和液/饱和气焓:`h_satL`、`h_satV`。
|
||||
4. 干度:
|
||||
|
||||
`x = (h_mix - h_satL) / (h_satV - h_satL)`
|
||||
|
||||
并进行必要的边界处理(除零、NaN、限幅等由 Calculator 内实现)。
|
||||
|
||||
## 5. 六参数计算(ThermodynamicSixResultsCalculator)概要
|
||||
|
||||
### 5.1 输出结果
|
||||
|
||||
- `Qc`:制冷量(kW)
|
||||
- `Qh`:制热量(kW)
|
||||
- `COPc`:制冷 COP
|
||||
- `COPh`:制热 COP
|
||||
- `ηs`:等熵效率(%)
|
||||
- `ηv`:容积效率(%)
|
||||
|
||||
### 5.2 h3(液路阀前/冷凝出口)关键规则:Tsat-10°C
|
||||
|
||||
该规则已封装在 `ThermodynamicSixResultsCalculator` 内部:
|
||||
|
||||
- 由**排气压力**计算饱和温度 `Tsat_discharge`
|
||||
- 取 `T_for_h3 = Tsat_discharge - 10°C`
|
||||
- 用 `TxvFrPress` 与 `T_for_h3` 求液体点焓 `h3`
|
||||
|
||||
注意:这是为了对齐现场 LabVIEW 流程/截图对比,属于业务约束。
|
||||
|
||||
### 5.3 典型计算链路(概念级)
|
||||
|
||||
- h1/s1:吸气点(由吸气 P/T 求物性)
|
||||
- h2:排气点(由排气 P/T 求物性)
|
||||
- h2s:等熵压缩出口点(由排气压力 + s1 求物性)
|
||||
- h3:液体点(由 TxvFrPress + (Tsat(DischargePress)-10°C) 求物性)
|
||||
|
||||
由焓差与质量流量计算 Qc/Qh,并结合功率得到 COP。
|
||||
|
||||
## 6. REFPROP 初始化与线程安全
|
||||
|
||||
- `PPCService` 内使用静态锁:`_refpropLock`
|
||||
- 原因:REFPROP Fortran DLL 内部通常存在全局状态/非线程安全调用。
|
||||
- 约束:
|
||||
- `EnsureRefpropInitialized()` 必须在锁内进行。
|
||||
- 所有直接 REFPROP 原生调用也必须串行化。
|
||||
|
||||
Calculator 内部同样通过外部传入的锁对象串行化 REFPROP 调用。
|
||||
|
||||
## 7. 结果写回约定
|
||||
|
||||
- `DrynessTag`:按百分比写回(`x * 100`)。
|
||||
- `DrynessTag2Value`:按百分比用于界面绑定(`x * 100`)。
|
||||
- `Qh/Qc`:Tag 单位为 `W`,Calculator 输出为 `kW`,写回时乘 `1000`。
|
||||
|
||||
## 8. 扩展/维护建议
|
||||
|
||||
- 如后续希望让 `PPCService` 更纯粹:
|
||||
- 可将过热度/过冷度计算也下沉到独立 Calculator(避免在 Service 里直接调用 SATP)。
|
||||
- 工质切换:
|
||||
- 当前 `EnsureRefpropInitialized()` 默认只加载 `R134A.FLD`。
|
||||
- 若要支持 `R1234yf` 等,需要根据配置选择对应 `.FLD` 文件。
|
||||
|
||||
87
CapMachine.Wpf/PPCalculation/SuperheatSubcoolCalculator.cs
Normal file
87
CapMachine.Wpf/PPCalculation/SuperheatSubcoolCalculator.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
|
||||
namespace CapMachine.Wpf.PPCalculation
|
||||
{
|
||||
/// <summary>
|
||||
/// 过热度/过冷度计算器。
|
||||
///
|
||||
/// 说明:该类仅负责封装 SATPdll 调用与计算公式,保持与历史流程一致。
|
||||
/// - 压力换算保持原逻辑:BarA * 100.0
|
||||
/// - 温度换算保持原逻辑:Tsat[K] - 273.15
|
||||
/// - 失败时返回 0(与原先在服务中直接写 Tag 的行为一致)
|
||||
/// </summary>
|
||||
public sealed class SuperheatSubcoolCalculator
|
||||
{
|
||||
private readonly object _refpropLock;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数。
|
||||
/// </summary>
|
||||
/// <param name="refpropLock">REFPROP 全局锁(REFPROP DLL 非线程安全,需串行化调用)。</param>
|
||||
public SuperheatSubcoolCalculator(object refpropLock)
|
||||
{
|
||||
_refpropLock = refpropLock ?? throw new ArgumentNullException(nameof(refpropLock));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按既有流程计算过热度/过冷度。
|
||||
/// </summary>
|
||||
/// <param name="inhPressBarA">吸气压力(BarA)。</param>
|
||||
/// <param name="inhTempC">吸气温度(℃)。</param>
|
||||
/// <param name="txvFrPressBarA">膨胀阀前压力(BarA)。</param>
|
||||
/// <param name="txvFrTempC">膨胀阀前温度(℃)。</param>
|
||||
/// <param name="superheatK">过热度(K)。失败时为 0。</param>
|
||||
/// <param name="subcoolK">过冷度(K)。失败时为 0。</param>
|
||||
public void Calculate(
|
||||
double inhPressBarA,
|
||||
double inhTempC,
|
||||
double txvFrPressBarA,
|
||||
double txvFrTempC,
|
||||
out double superheatK,
|
||||
out double subcoolK)
|
||||
{
|
||||
superheatK = 0.0;
|
||||
subcoolK = 0.0;
|
||||
|
||||
long iErr;
|
||||
long kph = 1;
|
||||
|
||||
double te = 0.0;
|
||||
double te1 = 0.0;
|
||||
double p = 0.0;
|
||||
double p1 = 0.0;
|
||||
double Dl = 0.0;
|
||||
double Dv = 0.0;
|
||||
|
||||
double[] x = new double[20], xliq = new double[20], xvap = new double[20];
|
||||
x[0] = 1.0;
|
||||
|
||||
//p = Convert.ToDouble(textBox2.Text) * 1000.0;//textBox2 Comp.吸气压力(kpa)
|
||||
p = inhPressBarA * 100.0;// 保持你原有流程:将 BarA 当作 MPa? 历史代码为 *1000.0,不改变你的算法
|
||||
|
||||
p1 = txvFrPressBarA * 100.0;// 保持你原有流程
|
||||
//p1 = Convert.ToDouble(textBox3.Text) * 1000.0;//textBox3 Evap.膨胀阀前压力(Mpa)
|
||||
// 统一放入同一把锁中,避免并发导致的 Fortran 读文件/状态竞态
|
||||
string herr = new string(' ', 255); long herrLen = 255; iErr = 0;
|
||||
lock (_refpropLock)
|
||||
{
|
||||
IRefProp64.SATPdll(ref p, x, ref kph, ref te, ref Dl, ref Dv, xliq, xvap, ref iErr, ref herr, ref herrLen);
|
||||
}
|
||||
|
||||
if (iErr == 0)
|
||||
superheatK = Math.Abs(inhTempC - (te - 273.15));
|
||||
else
|
||||
superheatK = 0;
|
||||
|
||||
herr = new string(' ', 255); herrLen = 255; iErr = 0;
|
||||
lock (_refpropLock)
|
||||
{
|
||||
IRefProp64.SATPdll(ref p1, x, ref kph, ref te1, ref Dl, ref Dv, xliq, xvap, ref iErr, ref herr, ref herrLen);
|
||||
}
|
||||
if (iErr == 0)
|
||||
subcoolK = Math.Abs(txvFrTempC - (te1 - 273.15));
|
||||
else
|
||||
subcoolK = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user