☰
冷热电联供系统运行优化:MOPSO如何平衡成本与碳排放
2026/10/5 12:02:13 网站建设 项目流程

做冷热电联供型综合能源系统的运行优化,最容易栽在“看起来简单”的坑上。去年我接到一个园区能源站的项目,需求提得很直白:每天运行成本压下来,碳排放也要尽量少。听起来就两个目标,可真开始建模就会发现,它们在很多时段是打架的——多发电可以少买电、甚至上网卖钱,但机组负荷率一低,单位电量的燃气耗量和排放反而更难看;少从电网买电听起来低碳,可本地机组一旦顶着上限跑,多余的热和冷又没地方去,照样是浪费。

这套项目最后是用多目标粒子群算法(MOPSO)解决的:对24小时逐时出力寻优,目标函数里同时放进运行成本和CO₂排放,约束条件覆盖电、热、冷三种负荷平衡和各设备的运行区间。跑完多组典型日数据,得到的不是单个“最优解”,而是一整条帕累托前沿。成本和排放的真实折衷关系摆在桌面上,决策层终于可以按自己的偏好挑方案,而不是被一个权重值绑架。

这篇文章会把整个建模过程、算法实现细节、实测对比和踩坑经验完整写出来,希望给正在做综合能源调度、又不太清楚多目标优化怎么落地的朋友一些够直接、能上手的东西。

1. 冷热电联供系统的优化调度,先拆清楚要优化什么

CCHP系统说穿了就是一套设备同时出电、热、冷三种能量。常见的园区级配置里,燃气轮机或燃气内燃机先发电,燃烧产生的高温烟气进余热锅炉变成蒸汽或热水,一部分直接送采暖,一部分进吸收式制冷机制冷;发电不够就并网购电,电多了还能上网卖;冷负荷不够时,电制冷机顶上来。如果再配蓄热水箱、蓄冷罐,那灵活性还会再上一个台阶。

1.1 联供系统的能量流与设备关系

能量流具体是这样走的:

  • 天然气进入燃气轮机发电,发电后的乏气、缸套水余热进入余热回收装置。
  • 余热优先满足采暖热负荷和吸收式制冷机组的驱动力。
  • 吸收式制冷机组把热量转成冷水供冷,电制冷机组则直接耗电制冷冷水。
  • 电网侧负责兜底:本地发电不足就购电,本地发电富余就尝试上网售电。

这套系统里最关键的耦合点在“余热”和“温度品位”。燃气轮机一开机,电和热几乎是同时出来的,用户要的电越多,产生的余热也越多;但余热总量和热负荷需求并不能总是对上。供热需求低的时候,大量余热只能通过散热器白白放掉,这就造成“发电多反而浪费大”的怪圈。供热需求高的时候,余热不够还要补燃锅炉额外烧燃料,排放又上去了。所以运行优化的核心,其实是在这种刚性耦合里把每一时段的设备出力安排到最合理的位置。

1.2 调度问题的变量、目标与约束

把一天划成T个时段,常见是24点或者96点,再定义决策变量:

  • 燃气轮机/内燃机每个时段的电出力P_gt(t)。
  • 补燃锅炉的热出力Q_boiler(t)。
  • 吸收式制冷机的制冷量Q_ac(t),电制冷机的制冷量Q_ec(t)。
  • 从电网购电/售电的功率P_grid(t)。

目标函数是两个:

  • 运行成本最小:燃气费用加上购电费用,再减去售电收益。
  • CO₂排放最小:本地燃气燃烧直接排放,加上外购电折合的间接排放。

约束条件则是这套系统的“物理边界”:

  1. 电功率平衡:机组发电 + 购电 - 售电 = 电负荷 + 电制冷耗电 + 其他自用电。
  2. 热功率平衡:余热回收 + 补燃锅炉出力 = 热负荷 + 吸收式制冷机耗热。
  3. 冷功率平衡:吸收式制冷 + 电制冷 = 冷负荷。
  4. 设备出力的上下限和爬坡率约束。
  5. 机组最小启停时间,如果模型精度要求更高还要加上这个。

为什么要拆得这么细?因为只有把每个时段的能量平衡写成等式约束,才能把“调电就会连带着调热”这个本质耦合暴露出来。燃气轮机的热电比不是固定的,负荷率高的时候,单位发电量的烟气和余热更充足;负荷率低的时候,余热总量少,单位电量的热耗反而升高。如果在模型里把这个关联简化掉,优化结果交给运行人员基本没法用。

2. 为什么我在这个项目里放弃了单目标加权,改用MOPSO

最早我用的方法也是大多数论文里常见的那套:把成本和排放分别归一化,然后乘以权重变成一个目标函数,再丢给粒子群或者遗传算法去跑。跑了一段时间后发现,这条路在工程决策上根本走不通。

2.1 单目标加权法的两个致命问题

第一个问题是要权重怎么定。成本和排放两个量纲完全不同,不归一化直接加权没有意义;归一化之后,权重还是拍脑袋定的。决策者说“成本和排放各占一半”,听着很公平,但算出来的“最优解”其实什么都不代表。你只要把权重从0.5换成0.6,方案就可能从“多用电网电”跳变到“多用本地气电”,这种不连续非常让人头疼。

第二个问题是目标之间的矛盾被掩盖了。举个项目里遇到的实际例子:某个午间时段,电负荷60kW,热负荷只有30kW,燃气轮机刚好落在低效区间。单看成本,最优策略很可能是不开机,直接从电网买电;单看排放,如果外购电的排放因子很高,反而应该顶着低效运转开机。两个策略都有道理,但哪个“更优”取决于电价、气价、排放因子这些外部条件。加权法只能告诉你“按这个权重,A比B好”,却没法告诉决策层“你们每多减排一公斤CO₂,要额外付出多少钱”。这个“换汇率”信息,只能从帕累托前沿上读出来。

2.2 MOPSO相比NSGA-II等算法的选择理由

可能有人会问,为什么不直接用NSGA-II?NSGA-II在学术界应用非常广,多样性保持机制也成熟,但我这边最后选了MOPSO,主要原因是CCHP调度问题的决策变量绝大多数是连续功率值,粒子群在这种连续搜索空间上天然友好。

两者对比下来,差异大致是这样:

对比维度MOPSONSGA-II
实现复杂度较低,核心算子少中等,需要非支配排序和拥挤度计算
收敛速度在连续变量问题上通常更快相对慢一点,需要更多代数
多样性保持需要额外设计外部档案和网格策略自带拥挤度距离机制
对离散变量的处理需要通过取整或映射处理二进制编码时更自然
参数敏感性惯性权重和加速系数需要调交叉变异概率相对不敏感

我实测下来,500个粒子跑500代,MOPSO处理24时段的典型日调度只要几分钟,得到的帕累托前沿在分布均匀性上并不输给同运算量下的NSGA-II。做工程项目,迭代速度很关键,因为你可能要反复跟决策者讨论“这个解为什么是这样”,每次讨论都要重新跑模型。后面相关内容里,我会重点讲外部档案怎么维护、多样性怎么保持,这些都是MOPSO能不能用好的关键。

3. 建模与目标函数设计:把成本和排放算清楚再动手

很多算法文章喜欢一上来就写优化方程,但真正决定结果靠谱程度的,是设备模型。设备模型偏了,算法再好也是白搭。

3.1 设备特性与运行区间怎么建模

我当时项目里用的一套典型参数是这样:

  • 燃气轮机额定功率300kW,发电效率曲线近似为二次多项式:低负荷40%时效率大约0.24,满负荷时效率能到0.32。
  • 余热回收系统按燃气轮机烟气余热与发电出力的关系建立曲线,热电比大致在0.9到1.1之间波动。
  • 补燃锅炉效率取0.85,出力范围0到500kW。
  • 吸收式制冷机组COP取1.3,电制冷机COP取4.0。
  • 天然气低热值按9.7kWh/Nm³,单价3.2元/Nm³。
  • 电网分时电价:峰时1.0元/kWh,平时0.65元/kWh,谷时0.35元/kWh,上网电价固定0.4元/kWh。
  • 外购电排放因子按当地电网公开数据取0.85 kg CO₂/kWh。

这些数字看起来琐碎,其实每一个都直接影响优化结果。比如燃气轮机效率曲线,很多简化模型把它当常数,这会导致低负荷时段的调度方案严重失真。实际机组在低负荷下效率掉得很快,如果模型里不体现,算法就会倾向于让机组频繁在低出力运行,而真实运行里这会带来很高的单位发电燃料成本。

3.2 成本、排放两个目标如何量化

运行成本目标可以写成:

C = C_gas + C_buy - C_sell

燃气费用按每个时段的耗气量乘以天然气单价来计算;购电费用按购电量和分时电价相乘;售电收益则按上网电量乘以上网电价。

排放目标写成:

E = E_gas + E_grid

燃气燃烧排放按实际燃气消耗量乘以排放因子;电网间接排放按外购电量乘以电网排放因子。这里要注意,联供系统的燃气排放如何分摊到电和热上,在学术上有不同的方法:可以简单把总排放都算在发电头上,也可以用热焓分摊法,还有按收益分摊的。不同的分摊方法会改变帕累托前沿的形状,但不会改变优化框架。我项目里用的是“总排放直接汇总”的方式,因为决策者要的是整个能源站对外部环境的净影响。

3.3 为什么成本和排放总是“打架”

算一笔简单的账就明白了。按燃气轮机效率0.32算,每发1kWh电需要消耗约3.125kWh燃料,折合的天然气量大概是0.322Nm³,成本约1.03元/kWh,直接排放约0.625kg CO₂/kWh。如果这台机组的余热还能被利用,比如同时带出约1kWh热量,那这部分经济性和环保效益就不一样了。

这时候和电网购电对比一下:电网电价谷时只要0.35元,但排放因子是0.85。所以“成本最优”和“排放最优”经常给出相反的指令:

  • 电价低谷且热负荷低时,低成本方案会倾向停掉机组、直接买电;但低排放方案可能会因为本地气电排放更低而坚持开机。
  • 电价高峰且热负荷高时,两个目标罕见地达成一致——本地联供机组既便宜又低碳,这时候优化算法会毫不犹豫地让机组满负荷跑,同时把余热全部利用起来。

换句话说,成本与排放的冲突不是模型造出来的,而是外部电价、气价和电网排放因子之间关系造成的。这个认知非常重要,因为后面你观察帕累托前沿时,如果某个区域前沿特别稀疏,往往不是因为算法没搜索到,而是这个时段目标方向天然一致。

4. 多目标粒子群算法的实现细节

框架大家都懂,真正区分一个项目能不能落地的是实现细节。我把我最后采用的方案完整写出来,供参考。

4.1 粒子编码、初始化与约束处理

首先是编码。我的做法是只把真正需要寻优并且互相之间没有直接关联的变量放进粒子,剩下的变量由能量平衡方程反推。这样能大幅降低搜索维度,也避免大量不可行粒子。

粒子的每个维度由以下变量组成:

  • 每个时段燃气轮机电出力。
  • 每个时段吸收式制冷机制冷量。
  • 每个时段电制冷机制冷量。

至于电网购电功率,是由电平衡方程推出来的;补燃锅炉的热出力,是由热平衡方程推出来的。这种“变量消元”的办法,等于把等式约束自动满足掉了。比如先给定P_gt,电平衡里其余都是已知量或已决策量,那么P_grid就唯一确定,不需要再专门作为粒子维度去搜索。

不等式约束,比如设备出力上下限,我用的是最朴素的钳位处理:粒子越界就拉回边界。对热平衡里出现的“余热过剩”问题,我加一个松弛量代表散热损失,并且在目标函数里给这个松弛量一个很小的惩罚。这样物理上说得通,算法也不会被逼到死胡同。

初始化采用随机生成加局部校正:先随机生成燃气轮机的初始出力,如果超出技术出力范围,就钳位到范围边界;然后校验补燃锅炉反推是否越界,越界则重新随机。这块逻辑虽然不起眼,但非常影响粒子群前期的收敛速度。

4.2 外部档案维护与多样性保持

MOPSO和单目标粒子群最大的区别,就是需要一个外部档案保存历史上找到的所有非支配解。档案容量不可能无限大,所以多样性保持是核心。

我用的是网格法,实现很直接:

  1. 把两个目标值分别归一化到[0,1]。
  2. 在每个目标维度上划分20个等宽网格。
  3. 每个粒子根据目标值找到自己落在哪个网格。
  4. 档案里的解如果超过容量上限,就优先删除“人多”的网格里的解。
  5. 选择全局最优引导时,先按概率挑一个稀疏网格,再从网格里随机选一个解。

这个“稀疏网格优先”的策略非常关键。如果总是选目标值最小的解当全局最优,粒子群很快就收敛到帕累托前沿的某一段,另一区域的解永远不会被发现。用网格稀疏度来引导,等于逼着粒子往还没探索过的地方跑。

伪代码大概是这样:

# 多目标粒子群算法主循环伪代码 初始化粒子位置X、速度V 评估每个粒子的目标值和约束 把非支配解存入外部档案A for gen in range(MAXGEN): for i in range(N): # 从A的低拥挤度网格中随机选全局最优 gbest_i = select_low_density_member(A) # 速度更新 V[i] = w*V[i] + c1*r1*(pbest[i]-X[i]) + c2*r2*(gbest_i-X[i]) X[i] = X[i] + V[i] # 边界钳位 + 约束校验 X[i] = clamp(X[i]) # 评估 fitness_i = evaluate(X[i]) # 更新个体最优:支配则替换,互不支配则比较拥挤度 if dominates(fitness_i, pbest_fitness[i]): pbest[i] = X[i] elif not dominated_by(fitness_i, pbest_fitness[i]): pbest[i] = X[i] # 随机更新或按拥挤度 # 更新外部档案 A = update_archive(A, X[i], fitness_i) # 网格维护 A = prune_archive(A) # 惯性权重线性递减 w = w_max - (w_max - w_min) * gen / MAXGEN

惯性权重w从0.9线性降到0.4,加速系数c1、c2都是1.8。这个参数组合在多组测试里表现很稳。w取太高,粒子容易在边界附近震荡;取太低,前期搜索范围不够,后期又容易陷入局部。如果要做更精细的调节,可以考虑非线性递减或者自适应,但对CCHP调度这种规模的问题,线性递减已经够用。

4.3 帕累托解集的最终决策

算完一遍,外部档案里可能有几十上百个非支配解,运行人员不可能一个个看。怎么挑?我用的方法是模糊隶属度法,也叫“折衷解选择”。

对每个解k,分别计算它在每个目标上的隶属度:

μ_m(k) = (f_m_max - f_m(k)) / (f_m_max - f_m_min)

这里f_m_max和f_m_min是指帕累托前沿上第m个目标的最大值和最小值。然后对每个解求平均隶属度:

S(k) = (1/M) * Σμ_m(k)

S(k)越大,说明这个解在多个目标之间整体越均衡,我最后给决策者看的默认推荐方案就是S最大的那个解。

当然,如果决策者明确说“多花20%成本可以,排放必须压到最低”,那就直接看帕累托前沿靠排放端的解。整个项目的优势正在这里——不是替决策者做选择,而是把所有可选项摆出来,让他把自己的偏好量化进去。

5. 典型日仿真结果:帕累托前沿带来的选择空间

只讲算法不讲结果是耍流氓。我挑了冬季典型日来说,因为这个场景最能体现热电联供的耦合。

5.1 测试场景与参数设置

冬季典型日负荷大致有这些特点:早晚电采暖负荷高,白天略低;热负荷全天都很高,尤其是清晨;冷负荷接近零,吸收式制冷机可以不开,只靠余热供热。负荷数据按24时段给出,我就不贴整张表了,这里列几个有代表性的时段:

时段电负荷(kW)热负荷(kW)冷负荷(kW)
0:00452100
8:001602200
14:001201400
20:001752100

可以看到热负荷非常大,而且要命的是,有些时段电负荷并不高,机组如果只满足电需求,热就不够;如果为了追热让机组高负荷运行,电又会过剩,只能往电网上卖。

粒子数量取500,迭代500代,外部档案容量100,网格划分数目20。整个仿真在我们一台普通工作站上跑大约3分钟。

5.2 三组解的结果对比

我跑完后从帕累托前沿里挑了三组有代表性的解:

方案运行成本(元/天)CO₂排放(kg/天)机组平均负荷率购电比例
成本最优解421526500.6838%
排放最优解483018100.8612%
折衷解446821900.7922%

这组数据本身就是很好的决策材料。成本最优解在中午和夜间电价低谷时段大量购电,燃气轮机只在电价高峰时段跑,低负荷率导致单位发电效率下降,排放自然高。排放最优解则尽量让燃气轮机承担基荷,即使电价低谷也少从电网买电,机组平均负荷率上去了,单位电量排放降下来了,代价是燃气费明显增加。

折衷解相当于每多花约1.6元,就能比成本最优解少排约1公斤CO₂。决策者看到这个数,比看到一堆权重参数有用得多。

5.3 几个值得注意的运行规律

第一,目标方向一致时段和冲突时段强烈分化。电价高峰和热负荷高峰重合时,寻优结果几乎只有一个选择:燃气轮机满负荷运行,余热全部吸收,补燃锅炉尽量少开。帕累托前沿在这些时段几乎没有分支,说明目标不冲突,算法怎么跑都是同一个方向。真正让前沿发散开的,是电价低谷和热负荷偏低的时段。

第二,排放目标会显著改变电网交互行为。排放最优解在谷时段的购电比例只有12%,因为外购电的排放因子0.85高于本地气电在低负荷时的排放。这个结论依赖当地电网的清洁能源比例,如果未来电网排放因子降下来,帕累托前沿会整体往左下方移动,到时候可能连排放最优解都会变成“多用网电”。

第三,如果把蓄热装置加进去,成本还能进一步压降。蓄热水箱可以在机组高负荷放电时把多余的热存下来,等机组停机时再释放。加了蓄热后,成本折衷解从4468降到了约4100,降幅相当可观。代价是决策变量多了一个时段的蓄放热功率,搜索空间变大,MOPSO的收敛时间也略有增加,但仍在可接受范围内。

6. 实测中的坑与工程化改造建议

最后把实际项目里踩过的坑和改动思路整理出来,这些是最容易让“论文算法”变成“废纸算法”的地方。

6.1 等式约束的惩罚与修复策略

如果直接用惩罚函数处理平衡等式,会遇到一个很恶心的问题:惩罚系数小了,粒子可以靠着违反平衡来拉低目标值,档案里全是不可行解;惩罚系数大了,可行域之外的目标梯度非常陡,粒子搜起来像在爬悬崖。

我最后的做法是“变量消元为主,修复为辅”,前面已经提到过:让P_grid、Q_boiler由平衡方程直接算出来,等式约束理论上恒成立。但实际操作里还是会出现“补燃锅炉计算值为负”的情况,这时候我会做一个两步处理:

  1. 如果Q_boiler算出来是负的,就把所有多余余热标记为散热损失,并在这个时段的成本里加一笔散热惩罚,代表物理上要开散热器。
  2. 散热损失过大时,说明粒子给出的机组出力组合不合理,这个粒子大概率会在下一轮被支配解淘汰。

对不等式约束,动态惩罚系数也是好用的技巧:初始阶段惩罚系数取小值,让粒子大胆探索;后期逐步加大,逼着所有粒子收敛到可行域。这样既保证了多样性,又保证了最终档案里所有解都是工程可用的。

6.2 目标冲突最严重的时段怎么处理

实测里会发现,有些时段帕累托前沿非常薄甚至几乎没有。最容易出现这种情况的是平电价、中负荷时段:燃气轮机的成本和外购电价接近,排放又和电网排放因子接近,两个目标基本不冲突,所以无论怎么选都差不多。

不要试图靠调整算法来解决这种“瘦前沿”。更关键的是,要检查是不是模型里少了某些实际约束。比如,很多园区实际情况是:燃气轮机不能频繁启停,或者有最低日运行时间要求。如果没有把这些约束加进去,算法给出的解可能在每个时段看都合理,但连起来就是“白天开机、夜里停机、早上再开”这种运行人员完全无法接受的方案。加上最小启停时间约束后,帕累托前沿会自动变化,一些原来看似可能的调度组合会消失,留下来的才真正可执行。

6.3 从离线优化走向滚动时域调度

离线优化的结果再漂亮,也不能直接交给运行系统。真实负荷一直在波动,光伏如果并网了,出力也是随时变化的。我们的最终落地方式是在项目环境里做滚动时域优化:

  • 每15分钟触发一次重计算。
  • 用最新预测数据替换最近24小时的电、热、冷负荷序列。
  • 只执行第一个时段的调度指令,到下一个15分钟再重新优化。

滚动优化的好处是误差不会累积,因为每15分钟都会拿真实值重新校准。但代价是计算必须在几分钟内完成。MOPSO在这种场景下的优势很明显:500粒子×500代对24时段的算例,我用向量化处理基本能在3分钟以内跑完,留出足够的时间做预测和数据质量控制。

如果现场控制器算力有限,还可以先离线把典型场景的帕累托前沿全部算好,存成指令表,在线时按当前负荷和电价在表里做最近邻匹配。这个思路特别适合那些不能接受任何延迟的场合。


最后再分享一个排查收敛问题的小技巧。很多人看算法收敛只看帕累托前沿画出来的两条曲线是不是差不多,这个判断非常不靠谱,因为前沿形状往往看不出微小变化。我建议跟踪超体积指标(HV),也就是帕累托解集与参考点之间围成的目标空间体积。HV从第400代到第500代的变化小于0.5%,同时极值点不再明显移动,这时候基本可以认为收敛了。如果HV根本稳不下来,别急着加迭代代数,先回头检查惩罚系数和网格划分数,多半是多样性保持的参数出了问题。这也是MOPSO这套方案最后能够稳定落地,而不是停在仿真报告里的重要原因。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询