ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

冷热电三联供容量配置:基于多目标粒子群算法的Pareto优化实践

冷热电三联供容量配置:基于多目标粒子群算法的Pareto优化实践 做综合能源系统规划的朋友大概率都遇到过这么一个问题冷热电三联供CCHP系统的设备容量到底怎么定才能让运行费用、一次能耗和碳排放同时都说得过去。前阵子我接了一个园区三联供的容量配置优化需求最后在MATLAB里用多目标粒子群算法把整套模型跑通了。这篇就把从能量流建模到粒子编码、从目标函数到Pareto前沿选型的完整思路和踩坑记录写下来适合正在做综合能源容量优化、或者想把粒子群优化算法真正落到工程场景而不是只在测试函数上跑的人参考。整个项目里最花时间的其实不是算法本身而是怎么把冷、热、电三条能量流和三个优化目标揉进同一个评价函数里以及怎么让粒子群在容量变量和运行策略变量混合的高维搜索空间里不早熟、不塌缩。下面直接从问题本质开始讲。1. 三联供优化到底在优化什么先看懂能量流1.1 系统拓扑燃气轮机排烟的两次利用冷热电三联供最常见的构型是燃气轮机先发电排出的高温烟气通过余热回收装置一部分送去烟气热水型溴化锂吸收式制冷机做制冷一部分经过换热器供热。园区电负荷不够的部分向电网买电有余电也可以反向售电冷热负荷缺口分别由电制冷机和燃气锅炉补上。这个拓扑决定了三个能源品类是深度耦合的燃气轮机出力一变排热量跟着变制冷和供热可用的余热量也变。所以做容量优化时不能把设备一个个孤立地选型必须放在统一运行策略下做全年模拟看它们配合起来的效果。设备清单通常是五件套燃气轮机GT、吸收式制冷机AC、燃气锅炉GB、电制冷机EC、换热器HE。对于每个设备我们真正要定的是它的额定容量单位都是kW只是有的是电功率有的是制冷/制热功率。1.2 三个目标函数的量化口径这个项目里我用的三个目标和大多数综合能源多目标优化的文献口径一致年总费用设备投资的等年值 天然气燃料费 外购电费 运维费 - 售电收益。投资等年值要把初投资乘上资金回收系数把一次性投入摊到每年。一次能耗天然气消耗量按低位热值折算外购电按电网平均发电效率折算成一次能源。这个指标能反映系统是不是真的省了能源而不只是省了钱。碳排放天然气燃烧排放因子加上外购电对应的电网排放因子冷热电三联供的优势一般就是碳排放显著低于分供系统。三个目标量纲完全不同数值量级也差很远。费用一年是几百万元能耗是几百万kWh碳排放是几百吨CO2。这种差异是后面选择多目标算法而不是线性加权的重要原因之一。1.3 加权法为什么会在三联供上翻车很多人第一反应是把三个目标线性加权成一个综合指标再用单目标粒子群去优化。我最早也试过这条路但发现有三个很现实的问题加权系数没有客观依据。费用、能耗、碳排放谁是第一位的不同园区、不同业主的偏好完全不一样。你拍脑袋定了权重最终方案就是拍脑袋方案评审会上根本没法解释为什么取0.4和0.3。量纲归一化本身就很麻烦。把三个目标各自除以分供系统的基准值再加权确实是一种处理方式但归一化基准变了最优解位置也变了方案对基准极其敏感。最关键的是加权法在非凸Pareto前沿上会漏解。只要费用和碳排放之间存在非凸的权衡关系加权法就只能找到前沿的两个端点和中间个别点拿不到完整曲线。而三联供系统里因为设备投资存在规模效益恰好很容易出现非凸前沿。所以结论很直接直接上多目标粒子群MOPSO一次跑出一整套Pareto前沿让决策端去挑而不是在优化前就替决策端把权重拍了。2. 决策变量怎么编码进粒子容量加运行策略的组合设计2.1 容量类变量装机不是一个数决策变量设计是整个建模环节里最影响算法效果的一步。我的做法是五台设备容量全部作为决策变量归一化后再让粒子群搜索% 原始决策变量单位kW % x_raw [GT容量, AC容量, GB容量, EC容量, HE容量] % 归一化后 x ∈ [0,1]边界按负荷峰值的一定倍数设定 ub [peak_elec*1.2, peak_cool*1.2, peak_heat*1.5, peak_cool*1.2, peak_heat*1.2]; x x_raw ./ ub;这样处理的好处是避免粒子在初始化时因为不同变量量级差异太大而出现搜索偏好。GT容量上限按电负荷峰值的1.2倍制冷设备按冷负荷峰值的1.2倍锅炉按热负荷峰值的1.5倍——给一点冗余让算法有机会去探索大机组联合运行这类激进方案。2.2 运行策略变量以电定热还是以热定电容量定了同一个装机配置在不同运行策略下的年成本可能相差30%以上。所以优化问题不能只做容量选型还得同时决定运行方式否则你得到的最优容量是在一个固定运行策略下推出的局部最优。三联供系统里最经典的运行策略有两种以电定热FEL和以热定电FTL。前者让燃气轮机跟着电负荷走余热不够再补燃后者让机组跟着热负荷走多发的电卖给电网。我没有直接让算法在FEL和FTL之间做离散选择而是引入一个连续比例系数α表示每个时刻燃气轮机出力占电负荷的比例α∈[0,1]。α1就是以电定热α偏小就接近以热定电。这样处理有三个明显好处连续变量和PSO的更新机制天然匹配不需要处理离散变量的映射允许算法找到介于两种策略之间的混合运行方式很多文献已经证明混合策略优于单一策略把这个α设为全年典型日共享决策变量维度只增加一维不会把搜索空间撑爆炸。2.3 能量平衡用构造法保证不靠惩罚函数这是整个模型设计里我认为最重要的一个取舍。三联供优化里有一组硬约束每个时刻电、冷、热都必须平衡。如果用惩罚函数把这些等式约束加进目标函数里粒子群很容易陷入为了满足约束而牺牲目标的局部区域而且惩罚系数调起来非常痛苦。我的做法是让模拟逻辑天然保证平衡燃气轮机发多少电由α决定缺电就买电网电多了就卖余热不够供热就开燃气锅炉冷量不够就开电制冷机所有的能量差额都由外部设备兜底。这样目标函数计算时不存在等式约束违例的问题PSO只需要处理容量变量上下界这类简单约束。这个用仿真结构消解约束的思路在做工程类的优化问题时非常推荐。先别急着写惩罚函数想想能不能改一改模拟流程让约束在定义上就不可能被打破。3. MATLAB里设备模型和负荷数据怎么耦合3.1 典型日负荷怎么构造全年8760小时的逐时负荷曲线当然最精确但放进粒子群作为每一代都要算的评价函数就太贵了。实践里我用夏季、冬季、过渡季三个典型日每个典型日取24小时的电、冷、热负荷曲线再用天数加权代表整个年% 负荷数据结构示例 loads.summer.elec [950 900 850 820 800 780 900 1250 1450 1500 ... 1580 1550 1480 1450 1500 1420 1350 1280 1380 1500 ... 1350 1150 1050 980]; % 1x24单位kW loads.summer.cool [820 760 700 680 660 720 950 1400 1750 1950 ... 2050 2100 1980 1860 1920 1980 1900 1700 1520 1380 ... 1150 980 900 850]; loads.summer.day 90; % 夏季权重天数三条负荷曲线之间的相关性很重要。三联供园区一般是办公、商业综合体为主冷负荷峰值和电负荷峰值往往同时出现因为电制冷机在夏天也是大户。选取典型日的时候要保证峰值时刻对齐不能把电负荷峰值和冷负荷峰值错开半天否则优化出来的容量会严重偏小。如果项目数据充足更好的是做聚类用K-means把全年逐时数据聚成三类典型日比凭经验挑月份更客观。3.2 设备模型效率和余热回收的简化方式设备模型不需要太精细但要抓住主要矛盾。燃气轮机部分给定一个额定发电效率η_el燃料输入功率折算成一次能源发电后的排烟余热按热回收效率η_hr回收function [obj] simulate_year(x, sys, loads) % 解码决策变量 cap_gt x(1) * sys.ub(1); alpha x(6); % 运行策略系数 for s {summer,winter,trans} for t 1:24 p_gt(t) min(alpha * demand.elec(s,t), cap_gt); q_gt(t) p_gt(t) / sys.gt_eff * (1 - sys.gt_eff) * sys.hr_eff; % 余热先供冷再供热不足由锅炉和电制冷机补 q_hot(t) q_gt(t) - q_chill(t); ... end end end这段逻辑里有两个关键细节。一是燃气轮机出力做了额定容量截断α算出来的期望出力超过容量时只能按最大容量发剩下的电负荷从电网买——这种截断会让目标函数的惩罚自然体现出来容量太小就得多买电费用和碳排放都上去了。二是余热分配顺序先满足吸收式制冷机的热输入需求再给换热器供热。这个顺序排对了冬夏季节的模拟结果才有意义。3.3 目标函数子函数的接口设计粒子群每迭代一次要调用上百次目标函数评价每次评价要跑三个典型日共72小时的能量平衡。所以评价函数必须设计成一次调用返回三个目标值矩阵的结构function [cost_all, pec_all, co2_all] eval_design(x, sys, loads) % 一次算出全部典型日、全部时段的三个目标 % cost_all/pec_all/co2_all 均为年化累计值 % 不做全年逐时循环用矩阵运算加速 end同时把设备参数、电价、气价、排放因子全部放进sys结构体不要在目标函数里写死数字。后续调参数只用改一处不用到处翻代码。这个接口设计听着简单但在真实项目里很值得重视——我见过太多人把仿真代码和PSO代码纠缠在一起最后想换一套负荷数据都费半天劲。设备参数和成本系数我用的典型取值可以给大家参考参数取值说明燃气轮机发电效率0.35中小型燃机常见区间余热回收效率0.80含余热锅炉换热损失吸收式制冷机COP1.2烟气热水型溴化锂机组电制冷机COP4.5离心式机组天然气价格0.35元/kWh按低位热值折算电网购电电价0.8元/kWh峰谷分时后取综合值上网售电电价0.4元/kWh实际项目按当地政策电网排放因子0.86 kg CO2/kWh全国电网平均这些参数直接影响最优解位置但不会影响算法结构和分析思路。真做项目时务必替换成园区所在地的真实电价和排放因子数据。4. MOPSO主循环里那些容易写错的细节4.1 Pareto支配判断浮点数相等的坑多目标粒子群的核心就是Pareto支配关系。这个判断函数看上去简单但在MATLAB里写的时候有个很隐蔽的坑三个目标函数数值量级不同而且在多年化费用累积计算中会产生浮点误差直接比较相等性会出现大量两个解互相不支配的假象。我用的支配判断带了一个自适应容差function dom dominates(f1, f2, tol) % f1支配f2的条件f1各分量都不劣于f2且至少一个严格优于 dom all(f1 f2 tol) any(f1 f2 - tol); end % 调用时按目标函数量级取相对容差 tol 1e-4 * max(1, max(objectives, [], all));这个容差的含义是两个目标差值小于相对精度万分之一的视为不可区分。加上这个处理后档案更新稳定了很多不会出现每代都有一堆只有浮点差异的重复解这种问题。4.2 外部档案维护和网格分箱多目标粒子群的经典做法是维护一个外部档案Archive存放当前种群中所有非支配解。档案有两个操作容易写错一是新解进入时要淘汰被它支配的旧解二是档案空间满时要按拥挤程度删除多余的解。我的实现里档案上限设为100拥挤程度用网格法估计。把目标空间每个维度分成10段统计每个解落在哪个超立方体里密度最高的网格先删% 档案更新后若超出容量则按网格密度删除 grid_idx floor((archive_cost - minC) ./ (maxC - minC) * 9) 1; % 统计每个网格的计数选密度最高网格中的解淘汰网格分箱要注意两个细节一是目标空间上下界要随着档案的扩展动态更新否则前期解还在收敛过程中网格分布就不均匀二是每个维度分段数不宜太多9到12段足够太多会让每个网格里解的密度统计失真。4.3 领导粒子选择从稀疏区域挑gbest单目标PSO里gbest是全局唯一的多目标版本里档案中所有非支配解都有资格当领导者。如果每次都挑同一个解当gbest种群会快速向那个点靠拢把Pareto前沿探索成一条窄带。我的做法是先计算每个网格的解数量然后从解数量最少的网格里随机选一个解作为领导粒子。这个机制保证了算法会优先向前沿中解稀疏的区域探索最终得到分布均匀的完整前沿。% 网格密度统计后稀疏网格优先 [~, sparse_grid] min(grid_count); candidates find(grid_idx sparse_grid); leader archive(candidates(randi(length(candidates))));pbest的更新规则也值得一提如果当前位置支配历史pbest就更新如果相互不支配以0.5的概率随机更新。这样能让粒子同时往多个方向探索而不是死守一个局部最优。4.4 变异算子和减速收敛策略粒子群后期精度不足是众所周知的问题在多目标版本里更严重因为leader的选择已经引入了额外随机性。我给算法加了一个简单但有效的操作迭代后期以小概率对决策变量做高斯扰动幅度随迭代次数衰减if rand 0.1 * (1 - iter/maxiter) x(randi(dim)) x(randi(dim)) normrnd(0, 0.05 * (1 - iter/maxiter)); x max(0, min(1, x)); % 确保仍在归一化区间内 end这个算子是我对比了好几篇MOPSO改进文献后沉淀下来的方案实际效果远好过花哨的自适应变异策略。后期小概率扰动既能避免种群完全停滞又不会破坏已收敛区域。5. 实跑过程中的坑与调参记录5.1 计算速度瓶颈在目标函数而非PSO本身第一次跑通时我用了100个粒子、300次迭代结果每代仿真是全年的逐时循环总耗时超过两个小时。后来把内部循环全部向量化之后单次目标函数评价从0.5秒降到了0.02秒整个优化压到一分钟以内。给做类似项目的朋友一个优化建议优先把典型日24小时的循环向量化不要嵌套for循环去遍历每一个小时。MATLAB的矩阵运算在这种规模下的加速比非常可观代价只是代码可读性稍微下降一点。5.2 惯性权重的线性递减不是银弹经典PSO参数是w从0.9线性降到0.4c1c22。多目标场景下我试过好几组发现这个默认配置在前期探索还行后期经常出现档案完全不再更新的停滞。后来我改成自适应策略如果连续10代档案都没有增加新解就把w回弹到0.7打乱一下速度场如果档案更新活跃就按线性递减继续。单纯改固定参数很难兼顾早期探索和后期收敛两头。5.3 初始化均匀性的影响被低估了容量优化的决策变量数量不算大但上界从几百到几千kW跨度很大。如果初始化用均匀随机数粒子很容易全部堆在低容量区因为随机生成的五个容量变量同时落在高位区间的概率很低。我把初始化改成拉丁超立方采样每个变量维度都分成popsize个分层区间保证采样值均匀覆盖整个搜索空间。只是这个改动就明显减少了跑多次实验的结果方差Pareto前沿的极端端点也更完整。5.4 结果校验能量守恒是最好的调试工具算法跑完之后强烈建议大家做一次全年能量守恒校验天然气输入一次能源 电网购电一次能源应该等于电负荷 冷负荷折算 热负荷折算 设备损耗 上网售电。如果校验误差超过2%说明模拟逻辑里有bug或者截断处理有问题。我用这个方法抓到了一个真实的逻辑错误某台设备在部分负荷工况下的效率我用了线性外推但低负荷段效率掉得特别快导致余热回收量远小于实际Pareto前沿的能耗轴整体偏大。后来改成分段效率曲线结果才可信。6. 从Pareto前沿走向可落地的装机方案6.1 用TOPSIS从几十个非支配解里选一个MOPSO跑完你得到的是一整条前沿每个点都对应一组设备容量方案和年化费用/能耗/碳排放。但工程落地时最终要拍板一套方案。这个时候我一般给决策端做TOPSIS排序% front: N行3列每行一个方案的三个目标值 norm_f front ./ sqrt(sum(front.^2, 1)); ideal min(norm_f); negideal max(norm_f); d_pos sqrt(sum((norm_f - ideal).^2, 2)); d_neg sqrt(sum((norm_f - negideal).^2, 2)); score d_neg ./ (d_pos d_neg); % 贴近度越大越好如果决策端有明确偏好比如碳排放限值不能超过X吨就先做约束筛选再对剩余方案排序。这个先约束后偏好的顺序可以避免权重讨论纠缠太久实际项目里推进效率高很多。6.2 用单目标优化验证两头端点我习惯在MOPSO之外另跑三个单目标粒子群优化分别只优化费用、能耗、碳排放然后把单目标最优解拿来跟前沿端点对比。如果前沿的端点不比单目标差太多说明多目标实现没有bug如果差异大就得回头检查是不是粒子数不够或者档案维护逻辑有误。这个交叉验证成本很低但特别能暴露问题。我遇到过唯一一次前端点和单目标结果差10%的情况最后定位到是档案上限太小把真正的好解淘汰掉了。6.3 做项目时最实用的扩展方向如果后续想把这套东西做到更贴近工程有几个方向可以自然扩展加入蓄冷蓄热装置让运行策略多一个削峰填谷的维度Pareto前沿会出现更多有意思的权衡点分时电价精细化把购电价按峰平谷分段运行策略的α就会自动演化出储电、蓄冷的行为碳交易成本把碳配额价格算进费用目标三个目标之间会多一层耦合前沿形态变化会很剧烈容量选型完成后再固定容量做全年8760小时逐时运行优化验证方案在极端天气下的可行性。每一步扩展都只需要改评估函数和数据输入MOPSO主循环基本不用动——这就是把算法和仿真解耦设计带来的红利。最后说点个人体会。这套代码从搭框架到跑通真正难的不是粒子群本身而是把三联供系统的物理逻辑讲清楚、把约束设计得让算法好搜。如果最开始就冲着算法细节去调参很容易在错误模型上调出一个精美但没有意义的Pareto前沿。反过来模型结构对了哪怕用最朴素的多目标粒子群框架跑出来的结果也能直接支撑一次容量选型汇报。
返回列表