写这篇东西的起因,是我去年做一套压缩空气系统改造时,客户反复追问一个问题:“这气体从压缩机出来之后,到底降到多少度才开始析出水?”接管道的师傅对着露点仪挠头,工艺工程师拿着查出来的露点表说“大概5摄氏度”,结果系统在15摄氏度就开始出现冷凝液。问题就出在只查了水的饱和露点,没算混合气在操作压力下的真实露点。所以我把用安托因方程从气相组成反推露点的完整方法写出来,包含原理推导、手算演示、Python和Excel的落地实现,以及那些现场最容易踩的坑。
1. 露点计算到底在解决什么问题
露点这个词在工程上其实有歧义。对纯组分来说,露点就是该温度下饱和蒸气压等于体系总压的那个点,比如常压下水在100摄氏度沸腾,对应水蒸气的露点也是100摄氏度。但我们在实际项目里碰到的几乎都是多组分气体:天然气、压缩机出口的含油含湿空气、精馏塔顶的混合蒸气、干燥器再生气,这些体系没有一个单一的“饱和蒸气压”。它们在某一个温度下,可能只是混合气中某个重组分刚好开始凝结,这个时候体系里同时存在气相和极少量的液相,那个温度才是这套工艺气体的露点。
搞清楚的第一个意义是选设备。水冷器、空冷器、气液分离罐的设计,全部依赖这个温度。冷却介质温度比露点低多少,决定了实际冷凝量有多少,也决定了分离罐的尺寸。第二个意义是防冻堵。天然气管线里如果同时存在水和重组分烃类,温度降到某个值后,水和烃会分别或同时凝结,形成水合物或者液烃积累。第三个意义是干燥工艺的考核指标。吸附式干燥器出口气的露点,直接说明干燥剂有没有失效,这靠仪器测量,但仪器校准的时候你想过没有,标准露点值用的是什么体系?通常就是纯水蒸气在惰性气体里的露点,这本质上还是一个二元体系的安托因计算问题。
有了这个背景你就明白,露点计算不是背一个公式就完了,它是一个相平衡计算。温度是未知量,气相组成是已知量,体系的约束条件是:当温度降到露点时,混合气刚好达到饱和,或者说,在这个温度下气相中各组分的逸度与一个“即将出现”的液相达到平衡。那道相平衡方程解出来的温度,才是真正的露点。接下来要做的,就是把这个约束条件用安托因方程具体表达出来,然后找迭代方法求解。思路清楚了,后面所有步骤都是数学。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 安托因方程:常数、单位与三个容易踩的边界
安托因方程的常见形式是:
[
\log_{10} P^{sat} = A - \frac{B}{C + T}
]
式中 (P^{sat}) 是纯组分的饱和蒸气压,(T) 是温度,A、B、C是组分特性常数。它本质上是对克拉佩龙-克劳修斯方程在有限温度区间内的拟合,所以它对温度和压力的适用区间是有边界的。工程上最常用的常数表里,有两种单位体系要特别警惕。第一种是以摄氏度配毫米汞柱(mmHg),波林《化学工程手册》里大量采用这种;第二种是以开尔文配巴或帕斯卡,多见于后来的化工模拟软件数据包。同样是苯,摄氏度体系下A=6.90565,B=1211.033,C=220.790,但换到开尔文配千帕的体系,这三个数字完全不同,如果你混用,算出来的饱和蒸气压能差出几个数量级。
我习惯的做法是,从一开始就在计算表或程序里写清楚“常数采用的温度单位和压力单位”,并且统一转换到同一套体系。举个例子,假如我打算用摄氏度加毫米汞柱的常数,那么体系总压也要换算成毫米汞柱。一个常见错误是:总压用了兆帕,而饱和蒸气压算出来是毫米汞柱,直接把两个数相除算K值。单位错了,后面再精细的迭代都是白搭。
第二个边界是温度适用范围。安托因常数表通常会在末尾标注温度范围,比如苯在8到103摄氏度、甲苯在8到111摄氏度、乙苯在30到165摄氏度。出了这个范围,方程的外推结果就开始明显偏离真实蒸气压。尤其要注意低温端,很多人在算低温露点时把常数强行外推到零下几十度,算出来的结果比实际值差出十几摄氏度都有可能。
第三个边界是压力上限。安托因方程背后是理想气体和理想液体的假设,压力越高,真实气体效应越明显,也就越不可靠。经验上,体系总压超过5到10个大气压之后,直接用安托因算出的露点就需要谨慎对待了;超过20个大气压,基本就该切换状态方程(Peng-Robinson或SRK)来做闪蒸计算。这一点到后面第六节再展开,但你先记住,安托因方法的正确使用场景是常压、低压和中等压力下的理想体系,比如常压精馏塔顶、低压气体管道、干燥器进出口。
| 组分 | A(log10,mmHg,℃) | B | C | 适用温度范围(℃) |
|---|---|---|---|---|
| 苯 | 6.90565 | 1211.033 | 220.790 | 8 ~ 103 |
| 甲苯 | 6.95464 | 1344.800 | 219.482 | 8 ~ 111 |
| 乙苯 | 6.95719 | 1424.255 | 213.206 | 30 ~ 165 |
| 水 | 8.07131 | 1730.630 | 233.426 | 1 ~ 100 |
| 正己烷 | 6.87601 | 1171.170 | 224.410 | -25 ~ 70 |
这里有件事要说明:不同版本的手册给出的同一组分常数值偶尔会有小幅差异,这是因为拟合时的温度区间和实验数据源不同。如果你同时混用两本手册的常数,最好先在同一温度下对比一下各个组分的饱和蒸气压是否协调,否则迭代收敛的温度很可能被常数之间的不一致带偏。这也是为什么我接手一个项目时,会先把所有组分的常数从同一张表里抄出来,绝不在中途换表。
3. 露点约束方程的推导:把相平衡写成一个可迭代的式子
纯组分气液平衡的条件是液相和气相的逸度相等。对于理想体系,可以把逸度简化为分压。假设液相是理想溶液,气相是理想气体,那么拉乌尔定律和道尔顿分压定律同时成立,于是有:
[
y_i P = x_i P_i^{sat}(T)
]
其中 (y_i) 是气相摩尔分数,(x_i) 是液相摩尔分数,(P) 是总压,(P_i^{sat}) 是纯组分在温度T下的饱和蒸气压。定义平衡常数:
[
K_i = \frac{y_i}{x_i} = \frac{P_i^{sat}(T)}{P}
]
现在我们设想一个场景:气体在某个温度下刚刚开始凝结,液相的摩尔分数趋近于零,但又确实存在。这个状态下,液相组成 (x_i) 是无法直接测量的,因为液体量无穷小。但我们可以抓住一个特征:液相全体组分的摩尔分数之和必然等于1,即:
[
\sum_i x_i = \sum_i \frac{y_i}{K_i} = 1
]
把 (K_i = P_i^{sat}/P) 代入:
[
\sum_i \frac{y_i P}{P_i^{sat}(T)} = 1
]
这就是露点方程。左端的值用 (F(T)) 表示,那么露点就是满足 (F(T)=1) 的温度。注意观察 (F(T)) 的单调性:温度升高时,所有组分的 (P_i^{sat}) 都增大,所以每一项 (y_i P / P_i^{sat}) 都在减小,因此 (F(T)) 随温度升高单调下降。这个性质非常重要,它意味着露点方程只有一个根,并且我们可以在一个温度区间里放心地用二分法或割线法来迭代,不用担心多解或者振荡发散的问题。
从这个推导过程也能看出,所谓“用安托因方程计算露点”,本质上是把安托因方程作为 (P_i^{sat}) 的温度函数代入露点方程,然后求解这个非线性方程。你不需要背任何现成的“露点公式”,现场临时换了一个组分,只要你有它的A、B、C常数,就能立刻重新推导出计算式。
再稍微延伸一下。如果你面对的是二元体系,比如空气-水体系,气相组成通常不直接用摩尔分数,而是用相对湿度或绝对含湿量。此时露点方程可以改写成更直观的形式:露点温度是使得水的饱和蒸气压等于水蒸气分压的那个温度。也就是说,先由相对湿度和总压求出水蒸气分压,再求安托因方程的反函数,解得温度:
[
T = \frac{B}{A - \log_{10} P_{H_2O}^{sat}} - C
]
这一形式在露点仪标定和压缩空气系统里非常常用。它没有迭代过程,一步到位。但要注意,它只适用于水蒸气分压之和等于总压的某一部分且其他组分不凝结的情况,一旦气相里还有高沸点有机物参与凝结,就必须回到多组分的迭代形式。
4. 手算一个完整案例:苯-甲苯-乙苯三元混合气的露点
理论讲完,我带你完整算一遍。假设有一股常压气体,摩尔组成为苯40%、甲苯35%、乙苯25%,总压760 mmHg,要计算它的露点。安托因常数采用上一节表格里的摄氏度和毫米汞柱体系。计算目标是找到一个温度 (T_d),使得:
[
F(T_d) = \frac{0.40 \times 760}{P_{苯}^{sat}} + \frac{0.35 \times 760}{P_{甲苯}^{sat}} + \frac{0.25 \times 760}{P_{乙苯}^{sat}} = 1
]
先做一个粗略估算。三种纯组分在常压下的沸点分别约为80.1摄氏度、110.6摄氏度、136.2摄氏度,所以这个混合气的露点一定会落在80到136摄氏度之间,而且会偏向重组分多一些,先猜测105到115摄氏度附近。
第一次试探,取 (T = 100^\circ C)。用安托因方程算饱和蒸气压。先算苯:
[
\log_{10} P_{苯}^{sat} = 6.90565 - \frac{1211.033}{220.790 + 100} = 6.90565 - 3.7753 = 3.1304
]
[
P_{苯}^{sat} = 10^{3.1304} \approx 1350 \ \text{mmHg}
]
同理甲苯:
[
\log_{10} P_{甲苯}^{sat} = 6.95464 - \frac{1344.800}{219.482 + 100} = 6.95464 - 4.2093 = 2.7453
]
[
P_{甲苯}^{sat} \approx 556 \ \text{mmHg}
]
乙苯:
[
\log_{10} P_{乙苯}^{sat} = 6.95719 - \frac{1424.255}{213.206 + 100} = 6.95719 - 4.5468 = 2.4104
]
[
P_{乙苯}^{sat} \approx 257 \ \text{mmHg}
]
代入露点方程:
[
F(100) = \frac{0.40 \times 760}{1350} + \frac{0.35 \times 760}{556} + \frac{0.25 \times 760}{257}
]
[
F(100) = 0.225 + 0.478 + 0.740 = 1.443
]
(F(100) > 1),说明在这个温度下气体还没有达到饱和,真正开始凝结的温度一定高于100摄氏度。继续试探,取 (T = 120^\circ C)。
苯的饱和蒸气压:
[
\log_{10} P_{苯}^{sat} = 6.90565 - \frac{1211.033}{340.790} = 6.90565 - 3.5537 = 3.3519
]
[
P_{苯}^{sat} \approx 2248 \ \text{mmHg}
]
甲苯:
[
\log_{10} P_{甲苯}^{sat} = 6.95464 - \frac{1344.800}{339.482} = 6.95464 - 3.9614 = 2.9932
]
[
P_{甲苯}^{sat} \approx 984 \ \text{mmHg}
]
乙苯:
[
\log_{10} P_{乙苯}^{sat} = 6.95719 - \frac{1424.255}{333.206} = 6.95719 - 4.2745 = 2.6827
]
[
P_{乙苯}^{sat} \approx 481 \ \text{mmHg}
]
代入露点方程:
[
F(120) = \frac{304}{2248} + \frac{266}{984} + \frac{190}{481} = 0.135 + 0.270 + 0.395 = 0.800
]
(F(120) < 1),说明120摄氏度时气体已经过饱和,露点在100到120摄氏度之间。用线性插值先逼近:
[
T_d \approx 100 + \frac{1.443 - 1}{1.443 - 0.800} \times 20 = 100 + 13.7 = 113.7^\circ C
]
拿113.7摄氏度做实算。为避免手工算太多次,我先用112摄氏度算一遍,再用114摄氏度算一遍,把结果卡在一个小区间内。
(T = 112^\circ C)时:
苯:
[
\log_{10} P_{苯}^{sat} = 6.90565 - \frac{1211.033}{332.790} = 6.90565 - 3.6391 = 3.2666
]
[
P_{苯}^{sat} \approx 1847 \ \text{mmHg}
]
甲苯:
[
\log_{10} P_{甲苯}^{sat} = 6.95464 - \frac{1344.800}{331.482} = 6.95464 - 4.0566 = 2.8980
]
[
P_{甲苯}^{sat} \approx 791 \ \text{mmHg}
]
乙苯:
[
\log_{10} P_{乙苯}^{sat} = 6.95719 - \frac{1424.255}{325.206} = 6.95719 - 4.3796 = 2.5776
]
[
P_{乙苯}^{sat} \approx 378 \ \text{mmHg}
]
[
F(112) = \frac{304}{1847} + \frac{266}{791} + \frac{190}{378} = 0.165 + 0.336 + 0.503 = 1.004
]
已经很接近了,略大于1,说明112摄氏度时离露点还差不到1摄氏度。
(T = 114^\circ C)时:
苯:
[
P_{苯}^{sat} \approx 1941 \ \text{mmHg}
]
甲苯:
[
P_{甲苯}^{sat} \approx 835 \ \text{mmHg}
]
乙苯:
[
P_{乙苯}^{sat} \approx 402 \ \text{mmHg}
]
[
F(114) = \frac{304}{1941} + \frac{266}{835} + \frac{190}{402} = 0.157 + 0.318 + 0.473 = 0.948
]
所以在112到114摄氏度之间,用线性插值:
[
T_d \approx 112 + \frac{1.004 - 1}{1.004 - 0.948} \times 2 = 112 + 0.14 = 112.1^\circ C
]
露点约112.1摄氏度。这个结果对应的是“有液滴出现”的一瞬间,体系内的液相量趋近于零。在真实装置里,由于壁面效应、过饱和和传质阻力,实际出现可见液滴的温度可能比这个理论值低零点几到一两摄氏度,但作为设计基准,112.1摄氏度完全够用。
算到这里你可以体会到,手算的价值不在于真的去迭代几十次,而在于建立数值直觉。你对苯、甲苯、乙苯的分压贡献一眼就能看出来:25%的乙苯贡献了接近一半的 (F) 值,所以露点被重组分强烈主导。这个直觉在调整工艺时很有用,比如你想把露点降下来,优先做的应该是脱除重组分,而不是改变冷却水的温度。
5. 用Python和Excel把露点计算固化下来
现场不会让你每次手算。我更推荐把露点方程写成一个脚本,把常数表维护好,以后换组分、换压力只需要改输入数据。下面是基于二分法的Python实现,直接对应上一章的公式。
python复制import math
# 常数体系: log10 P_sat = A - B/(C + T),P_sat单位mmHg,T单位℃
CONSTS = {
"benzene": (6.90565, 1211.033, 220.790),
"toluene": (6.95464, 1344.800, 219.482),
"ethylbenzene": (6.95719, 1424.255, 213.206),
"water": (8.07131, 1730.630, 233.426),
}
def psat_mmhg(temp_c, comp):
A, B, C = CONSTS[comp]
return 10.0 ** (A - B / (C + temp_c))
def dew_point_fraction(y, P_mmhg, comps, t_low=-50.0, t_high=300.0, tol=1e-8):
def F(T):
total = 0.0
for yi, comp in zip(y, comps):
total += yi * P_mmhg / psat_mmhg(T, comp)
return total - 1.0
f_low = F(t_low)
f_high = F(t_high)
# 露点方程单调递减,确保两端异号
for _ in range(200):
t_mid = 0.5 * (t_low + t_high)
f_mid = F(t_mid)
if abs(f_mid) < tol:
return t_mid
if f_low * f_mid < 0:
t_high = t_mid
f_high = f_mid
else:
t_low = t_mid
f_low = f_mid
return 0.5 * (t_low + t_high)
if __name__ == "__main__":
y = [0.40, 0.35, 0.25]
comps = ["benzene", "toluene", "ethylbenzene"]
P = 760.0
td = dew_point_fraction(y, P, comps)
print(f"Dew point: {td:.2f} °C")
运行结果是:
text复制Dew point: 112.14 °C
和我手算的112.1摄氏度完全一致。这段代码的关键点是二分法的上下界要保证 (F) 端值异号。假如 (F(t_{low})) 和 (F(t_{high})) 同号,说明露点不在预设区间内,程序会在200次迭代后返回区间中点,但那个值没有意义。所以我一般在调用前会先做一次符号检查,如果同号就报警。
Excel的做法更轻量。把组分、摩尔分数、A、B、C常数列在表格里,假设一个温度单元格(比如B8),用三列分别算每个组分的饱和蒸气压,再算分压比 (y_iP/P_i^{sat}),最后用SUM得到 (F) 值。创建单元格目标:
text复制目标单元格 = F - 1
然后打开“数据”->“模拟分析”->“单变量求解”,目标值设为0,可变单元格设为温度,几秒钟就能收敛到112.14摄氏度。
我在实际项目中通常两种都保留:Excel给现场工程师做快速核算,Python给需要批量计算不同压力、不同组成的工况做扫描。扫描时要特别注意,压力一变,露点跟着变,这不是线性关系。用刚才的例子,如果总压从760 mmHg翻倍到1520 mmHg,每一组分的分压都增大一倍,(F) 值在同样温度下大约翻倍,所以要让 (F) 回到1,温度必须上升。具体上升多少,得重新迭代,不能靠简单比例估算。
Excel里还有个小技巧:用名称管理器给常数区命名,比如把苯的A、B、C命名为Ben_A、Ben_B、Ben_C,公式可读性好很多,后续排查错误时也容易对上号。算多元混合气时,VLOOKUP可以根据组分名自动带出常数,避免手动录入错误。这些看起来琐碎,但在多人维护的计算表里,它们能省掉大量反复核对的时间。
6. 工程现场常用的扩展判断与容易翻车的细节
用安托因方程算露点,在常压、近理想体系里非常漂亮,但工程现场很少给你一个干干净净的理想体系。以下几个问题我建议你在每一个项目里都过一遍,它们比迭代算法本身更容易导致结论偏差。
6.1 水露点和烃露点要分清楚
如果气体里同时有水蒸气和烃类,你会听到“水露点”和“烃露点”两个词。它们是两个不同的相变点:水露点是气相中的水蒸气分压达到该温度下水的饱和蒸气压,析出的是液态水;烃露点是气相中的重烃组分达到饱和,析出的是液烃。在天然气处理工艺里,这两个露点可能相差几十摄氏度,管线防冻堵主要盯水露点,压缩机级间冷却器和低温分离器主要盯烃露点。安托因方程本身并不区分你是水还是烃,它只是算纯组分的饱和蒸气压。但你必须先确定自己在算哪一个露点:如果算水露点,露点方程里只关心水这一项,其他组分当作不凝气背景即可;如果算烃露点,要考虑所有烃组分的总和。混在一起算一个“混合露点”在理论上只能说是一个近似,因为液相组成并非是全部凝结组分的简单加和,还要考虑互溶度。遇到这种情况,我会直接在报告中写清楚“本计算给出的是水露点”或“本计算给出的是烃露点”,不给后续工艺人员留模糊空间。
6.2 安托因常数的外推永远是风险
前面提过常数的温度适用范围,这里举一个真实例子。某次我需要估算一套冷箱在-30摄氏度下的露点,组分里有正己烷。查到的正己烷安托因常数适用温度下限是-25摄氏度,刚好不够,差5摄氏度。我一开始偷懒直接外推,算出来的露点比后面对照状态方程的结果低了快7摄氏度。原因是在低温区,饱和蒸气压对数与温度的线性关系会逐渐偏离安托因形式,修正项 (C+T) 已经无法完全描述曲率变化。所以当操作温度落在常数适用范围之外,优先做两件事:一是换用更宽范围的多项式蒸气压方程,比如Riedel方程或Wagner方程;二是找一组在目标温度附近实测的蒸气压数据点,做一次局部回归。不要迷信软件默认常数,很多模拟软件在超出范围时也会悄悄外推,只是不告诉你。
6.3 压力升高到一定程度,及时切换状态方程
安托因方程建立在理想气体和理想溶液假设上。压力升高后,气相逸度偏离分压,液相活度系数偏离1,K值不再是 (P_i^{sat}/P) 这么简单。工程上我给自己定了一条参考线:体系总压低于5 bar时,安托因方法配合适当修正可以接受;5到20 bar之间,看体系是否含有强极性组分(水、醇、酸),如果有,最好用状态方程;超过20 bar,直接用Peng-Robinson或SRK做泡点露点闪蒸计算。实际判断标准不能完全看压力,还要看温度是否接近临界区。比如二氧化碳在高压下对烃类的溶解能力很强,安托因方法完全失效,只能靠状态方程带上二元交互系数来处理。
6.4 多液相或水烃两相共存时,露点方程要升级
天然气减温后可能出现水相和烃相两股液体同时析出,也就是所谓的“三相露点”。这时候单一露点方程只保证“有液相出现”,但液相可能不止一相,相平衡条件变成气相同时与两个液相达到平衡。计算复杂度立刻上升,需要解闪蒸方程,并引入气液液三相的平衡常数。遇到这种情况,安托因就只是其中一个小小的蒸气压计算模块,不能承担整个体系的计算逻辑。我在做这类项目时,习惯先用安托因算出各路组成的近似露点,判断哪股组分最先析出,再用专业物性包做严格验证。这样做的好处是,给领导汇报时你能用简单的框架把结论讲清楚,最后拿出严格计算的数值作为设计依据,两边都不耽误。
6.5 露点仪测量值和计算值对不上的排查顺序
最后分享一个排查经验。现场露点仪读数和计算结果相差较大时,不要急着怀疑计算模型,先从这几个方向查。第一,取样点位置是否合理,如果取样点离注入点太近,组分还没混合均匀。第二,气体含液时,取样系统里可能发生闪蒸或提前凝结,露点仪测到的已经不是真实气相露点。第三,仪表本身是否需要校准,电容式露点仪在低露点区间老化后漂移很常见。第四,压力换算有没有做,露点仪测的是常压露点还是在线压力下的露点,两者不能直接对比。我曾经遇到过一个项目,计算结果和仪表读数差了8摄氏度,查了半天发现是取样管线没有伴热,气体在进仪表之前已经结露,仪表测到的是“管壁温度”而不是气体露点。这类问题在现场出现的概率,比公式推导错误高得多。
把安托因方程用到这个程度,已经能覆盖大部分常压低压工艺气体的露点计算需求。我个人的建议是:把它当作一个舒适区里的标准工具,熟练掌握手算逻辑和脚本实现,但心里始终清楚它的边界在哪里。真遇到高压甚至近临界体系,别硬撑,切换到状态方程工具,把安托因计算当作初步估算和现场校验的快速手段,这样才能在项目讨论时既能秒算一个参考值,又能判断严格计算软件的结果是不是合理。
