ARTICLE DETAIL

资讯详情

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

热电联产机组联合优化控制:基于储热罐与电锅炉的风电消纳策略

热电联产机组联合优化控制:基于储热罐与电锅炉的风电消纳策略 去年冬天帮一个做园区综合能源的朋友做供热期运行方案优化凌晨两点那段的运行日志我到现在都记得室外接近-15℃电负荷在低谷区间风场接近满发但两台热电联产机组依然维持着相当高的电出力——为了满足供热需求电出力根本压不下来调度最后只能下达弃风指令。这个画面是理解整个问题的钥匙。风电最大化消纳的热电联产机组联合优化控制核心要解决的就是这件事让热电机组别再因为“必须发热”而锁死电出力把原本属于风电的发电空间腾出来。所谓联合优化控制就是在满足供热需求的前提下把热电机组、储热罐、电锅炉这些设备放在一个模型里统一决策让它们互相配合把弃风压到最低。这篇文章适合刚接触电力系统优化调度、做毕业设计或者正在做综合能源项目的同学。我会把问题根源、数学模型、Matlab代码实现框架、算例结果和几个实战中容易踩的坑都过一遍。文章里的参数和代码结构都是可以直接拿去改参数就跑的。1. 供暖季弃风的根源不是电网不够强是“以热定电”绑死了调峰空间1.1 风电反调峰特性把“时间错配”变成了系统压力风电出力和用电负荷在时序上天然不同步这在北方供暖期体现得尤其明显。白天用电高峰时段风电出力往往一般般到了后半夜全社会用电负荷降下来了大风却经常在这个时段“可劲儿吹”。对电网调度来说这种“负荷低谷时风电反而多”的特性叫反调峰它直接带来一个问题系统需要上调峰能力。什么叫做上调峰能力就是其他电源能不能在风电多的时候主动降低出力给风电让路。火电机组有最小技术出力常规火电能压到额定出力的40%-50%左右就不错了热电联产机组在供热期更夸张最小技术出力会被“热”抬得很高。调峰空间就这么被压缩了风电多出来的电没有地方去只能弃掉。我举个具体的数例。假设后半夜电负荷是500 MW风电场可出力300 MW。如果系统里的电源能把自身出力压到200 MW那么300 MW风电全能消纳。但如果热电机组因为供热需求最小电出力抬到了280 MW那么风电最多只能消纳500-280220 MW剩下80 MW只能弃掉。这就是弃风问题的本质电源侧灵活调节能力不足风电即使有电也送不出去。1.2 背压与抽凝两种机组、两种“锁死”方式热电联产机组跟普通火电机组的最大区别在于它的电出力不是独立变量而是跟热出力耦合在一起的。要理解这个耦合得先分清两种主流机型。第一种是背压式机组。它的逻辑很简单进了汽轮机的蒸汽做完功之后不排入凝汽器而是直接去供热。这意味着什么发多少电就对应供给多少热电热比基本固定。你说我想多发电少发热做不到。想少发电多发热也不行。它就是个刚性绑定。我经常跟学生打比方背压机组就像一个固定齿比的自行车你蹬一圈轮子转固定的角度没有换挡的空间。在供热期这种机组只要有热负荷电出力就基本被定死了完全没有调节余地。第二种是抽凝式机组。它稍微灵活一点蒸汽在汽轮机里做功后一部分抽出去供热一部分继续进入凝汽器冷凝。通过调整抽汽量可以在一定范围内实现热电比的变化。但这里有个关键的物理约束——凝汽器必须保持一定的蒸汽流量否则真空度维持不住机组运行安全性会出问题。所以抽凝机组虽然能调但调节范围依然是受限的电出力下限会随着热出力的增大而抬升。用一句话总结背压机组是“完全锁死”抽凝机组是“半锁死”。在冬季供热期这两种机组叠加在一起系统的调峰能力就被压得死死的了。1.3 解耦思路储热罐和电锅炉分别做了什么既然问题的根源是“热把电绑住了”那解决思路就很清晰了把“当前时刻必须供热”这个刚性约束想办法松弛掉或者让热量来源多元化。储热罐的思路是“时移”。它就像一个热量蓄水池在风电富余、热负荷相对不高的时候让机组多烧点热存进去同时把电出力降下来等热负荷高峰来了再从罐里放热补上。这样一来机组的“当前热出力”和“当前电出力”就不再是绑死的了热需求可以通过储热罐在不同时段之间腾挪。电锅炉的思路是“替代”。风电多的时候与其弃掉不如让电锅炉直接用电来产热替代掉一部分热电机组的热出力。这样热电机组可以把热出力降下来电出力下限也跟着降风电消纳空间就出来了。而且电锅炉本身也是一个用电负荷相当于给风电多了一个消纳出口。实际工程中储热罐和电锅炉往往一起用。储热罐擅长“挪时间”电锅炉擅长“拓空间”两者配合效果显著。这也是题目里“联合优化控制”的含义所在。2. 控制模型的核心目标函数、机组可行域与储热耦合约束2.1 目标函数选择“弃风最小”还是“成本最优”在动手写Matlab代码之前第一件事是把目标函数定下来。这个问题里有两种常见的目标函数写法。最简单直接的写法就是最大化风电消纳量等价于最小化弃风量。目标函数可以写成min Σ ( w_avail(t) - w(t) )其中w_avail是风电预测可出力w是实际消纳量。这个写法很直观适合教学和方案对比因为它直接把弃风量放进了目标函数结果一目了然。但实际项目中我更喜欢用经济成本作为目标函数其中包含机组煤耗成本、弃风惩罚成本。弃风惩罚系数设得比运行成本高这样优化器会优先消纳风电同时也能兼顾机组运行的经济性min Σ ( C_chp(p, h) λ_wind × (w_avail(t) - w(t)) )其中C_chp是热电机组的煤耗成本λ_wind是弃风惩罚系数。基于我个人的使用经验建议初学者先用纯弃风最小做一遍再换成本目标函数做对比这样能更好地理解两者在优化结果上的差异。2.2 抽凝机组可行域的线性化表达整个模型里最关键的约束就是抽凝机组的可行域。这部分我建议直接用线性不等式来表达因为线性约束可以直接交给LP/MILP求解器计算效率高代码也简洁。以一台典型的抽凝式机组为例参数取以下数值参数数值含义H_min50 MW最小抽汽供热出力H_max300 MW最大抽汽供热出力P_minHH_min时100 MW最小电出力P_maxHH_min时400 MW最大电出力P_maxHH_max时300 MW受最大进汽量约束时的电出力上限P_minHH_max时180 MW受最小凝汽流量约束时的电出力下限把上面这几个点连起来可以得到一个四边形可行域对应的线性约束如下p ≤ 400 - 0.4 × (h - 50) p ≥ 100 0.32 × (h - 50) 50 ≤ h ≤ 300为什么是这个斜率上限斜率是(300-400)/(300-50) -0.4代表随着热出力增加最大电出力线性下降下限斜率是(180-100)/(300-50) 0.32代表随着热出力增加最小电出力线性上升。这两个斜率在代码里就是两个常数直接写进约束就行。背压式机组就更简单了电出力就是一个常数或者跟热出力成正比的线性关系p k × h我们算例里用的机组1就是背压式电出力100 MW对应热出力300 MW等于说电热比固定为1:3。2.3 储热罐与电锅炉的时序约束储热罐的建模要特别注意“时序”这个维度。所谓时序约束是指储热罐的当前储热量SOCState of Charge跟上一时刻的储热量以及本时刻储/放热功率直接相关soc(t1) soc(t) η_in × c_in(t) - c_out(t) / η_out其中c_in和c_out分别代表储热和放热功率η_in和η_out是储放热效率一般取0.9-0.98左右。除了递推方程还有几个次要约束储热量SOC不能超过容量上限储放热功率不能超过各自的最大值。另外同一个时刻最好不要同时储热和放热实际运行中没有意义还浪费效率。这个问题可以通过引入0-1变量解决让模型变成MILPc_in(t) ≤ C_in_max × bin(t) c_out(t) ≤ C_out_max × (1 - bin(t))电锅炉的约束就简单多了它就是一个“用电产热”的装置h_eb(t) η_eb × eb(t) 0 ≤ eb(t) ≤ EB_max其中η_eb取0.95-0.99。在热功率平衡方程里电锅炉的产热量和储热罐的放热量一起算作热源在电功率平衡方程里电锅炉的耗电量算作新增电负荷。这两条平衡方程是整个联合优化模型的主骨架电平衡P_chp1(t) P_chp2(t) w(t) Load_P(t) eb(t) 热平衡H_chp1(t) H_chp2(t) c_out(t) - c_in(t) η_eb × eb(t) Load_H(t)3. Matlab代码实现YALMIP建模到求解器调用的完整链路3.1 代码结构化设计与参数表写Matlab代码之前先把代码结构设计好。我习惯把代码分成五个模块参数初始化、数据输入、模型构建、求解调用、结果可视化。这样后期改参数、换场景都方便。参数初始化的核心是定义基础时间尺度和机组参数%% 参数初始化 T 24; % 日前调度1小时一个时段 dt 1; % 时段长度单位小时 % 机组1背压式 P1_const 100; % 电出力固定值 MW H1_const 300; % 热出力固定值 MW % 机组2抽凝式 H2_min 50; % 最小热出力 H2_max 300; % 最大热出力 P2_max_hmin 400; % HH_min时的最大电出力 P2_min_hmin 100; % HH_min时的最小电出力 P2_max_hmax 300; % HH_max时的最大电出力 P2_min_hmax 180; % HH_max时的最小电出力 slope_up (P2_max_hmax - P2_max_hmin) / (H2_max - H2_min); slope_low (P2_min_hmax - P2_min_hmin) / (H2_max - H2_min); % 储热罐参数 SOC_max 800; % 容量 MWh c_in_max 100; % 最大储热功率 MW c_out_max 100; % 最大放热功率 MW eta_in 0.95; % 储热效率 eta_out 0.95; % 放热效率 % 电锅炉参数 EB_max 100; % 最大电功率 MW eta_EB 0.98; % 电热转换效率数据输入部分把24小时的预测负荷和风电可出力曲线定义成数组。推荐把数据放到Excel或者mat文件里通过读取函数导入这样换数据不用改代码。3.2 YALMIP建模的关键写法YALMIP是Matlab环境下非常好用的优化建模工具。它的核心思想是先用sdpvar定义决策变量然后用运算符拼接约束和目标函数最后交给求解器计算。%% 定义优化变量 p2 sdpvar(1, T); % 机组2电出力 h2 sdpvar(1, T); % 机组2热出力 w sdpvar(1, T); % 风电实际消纳量 cin sdpvar(1, T); % 储热功率 cout sdpvar(1, T); % 放热功率 soc sdpvar(1, T1); % 储热罐SOC多了一个末端时刻 eb sdpvar(1, T); % 电锅炉耗电功率 bin_s binvar(1, T); % 储/放热互斥的0-1变量 %% 约束条件拼接 Constraints []; % 电功率平衡 Constraints [Constraints, P1_const p2 w load_P eb]; % 热功率平衡 Constraints [Constraints, H1_const h2 cout - cin eta_EB*eb load_H]; % 机组2可行域 Constraints [Constraints, p2 P2_max_hmin slope_up*(h2 - H2_min)]; Constraints [Constraints, p2 P2_min_hmin slope_low*(h2 - H2_min)]; Constraints [Constraints, H2_min h2 H2_max]; % 储热罐时序约束 Constraints [Constraints, soc(1) SOC_init]; Constraints [Constraints, soc(2:T1) soc(1:T) eta_in*cin - cout/eta_out]; Constraints [Constraints, 0 soc SOC_max]; Constraints [Constraints, 0 cin c_in_max * bin_s]; Constraints [Constraints, 0 cout c_out_max * (1 - bin_s)]; % 电锅炉约束 Constraints [Constraints, 0 eb EB_max]; % 风电消纳约束 Constraints [Constraints, 0 w wind_avail];关于SOC的时间对齐这里有一个细节想提醒大家。soc(1)是初始储热量soc(T1)是第24小时结束后的储热量。递推方程里用的是“本时段的储放热功率影响下一时刻的储热量”这个逻辑。这么写的好处是末端状态可以很自然地加约束。3.3 求解器配置与MILP策略因为这个模型里引入了储放热互斥的0-1变量问题变成了混合整数线性规划MILP。求解器方面有几种选择如果只是教学演示、变量规模不大用Matlab自带的intlinprog就可以不需要额外装任何东西如果数据规模大、求解时间敏感建议安装Gurobi或CPLEX配合YALMIP使用如果不考虑储放热互斥约束整个问题退化成纯LP直接用linprog都行YALMIP求解调用写法如下%% 目标函数 % 加权弃风量 煤耗成本煤耗用线性近似 lambda_wind 500; % 弃风惩罚系数远高于发电成本 Objective lambda_wind * sum(wind_avail - w) sum(cost_p1 * P1_const cost_p2 * p2); %% 求解 ops sdpsettings(solver, gurobi, verbose, 2); optimize(Constraints, Objective, ops); %% 结果提取 w_opt value(w); p2_opt value(p2); h2_opt value(h2); soc_opt value(soc);求解完成后的可视化我强烈建议至少画两张图一张是电出力曲线把机组电出力、风电消纳、电负荷画在一起另一张是储热罐SOC曲线。这两张图基本能看出整个优化策略的工作逻辑。如果还要发论文可以再画一张热出力曲线和分场景对比柱状图。4. 一个典型冬季日的算例储热和电锅炉到底能多消纳多少风电4.1 典型日数据与参数设定为了搞清楚联合优化的效果我给你一个可以完全复现的算例。假设一个风-热-电系统包含一台背压机组机组1、一台抽凝机组机组2、一个300 MW风电场、一个储热罐和一个电锅炉。负荷数据取一个典型冬季日电负荷夜间低谷400-500 MW白天高峰750-820 MW热负荷在供暖期相对平稳全天保持在600 MW上下。风电可出力曲线设定为凌晨0点到5点处于高发区间240-300 MW上午回落到120-180 MW傍晚又爬升到200-280 MW。这个曲线的形状很有代表性——典型的大风出现在夜间负荷低谷时段。储热罐容量设为800 MWh储放热功率上限各100 MW电锅炉额定功率100 MW电热转换效率0.98。初始SOC设为400 MWh半罐。4.2 三种方案的结果对比我跑了三组场景传统“以热定电”没有任何解耦手段、只加储热罐、储热罐电锅炉联合。结果如下表方案风电消纳量(MWh/日)弃风率热电机组日总电出力(MWh)传统以热定电341418.6%4758仅加储热罐38957.1%4277储热罐电锅炉41940%4118你可以看到光靠储热罐弃风率就从18.6%压到了7.1%再加上电锅炉当天风电预测总出力4194 MWh实现了全额消纳弃风率为0。在计算中我还发现加入电锅炉后热电机组的总电出力反而降低了640 MWh——因为电锅炉替代了一部分热负荷热电机组的热出力下限进一步下移。从时序曲线上看会更直观凌晨风电大发时段传统方案中机组2的电出力维持在250-280 MW让风电只能发220 MW左右加入储热罐后机组2可以在夜间降低热出力由储热罐放热补充电出力下限降到了150 MW上下再加上电锅炉分担热负荷机组2夜间电出力可以降到110-130 MW风电直接满发。4.3 容量敏感性边际效益递减的规律跑到这一步你可能会想既然储热罐和电锅炉有效果是不是配得越大越好我特意做了容量敏感性分析结果很有意思。储热罐容量从200 MWh增加到800 MWh时弃风率下降非常明显但超过800 MWh之后再增加容量弃风率的改善幅度就很小了。原因是800 MWh的储热容量已经把夜间风电大发时段的“热量腾挪需求”基本满足了再大的容量在一天内根本用不满。电锅炉的功率也有类似规律100 MW时效果显著但继续加大到150 MW后对弃风率的边际改善就很有限了。这个结果说明一个工程上很现实的问题设备配置不是越大越好而是要根据风电弃电量、热负荷特性、投资成本综合权衡。我在做园区项目的时候一般会把设备容量设计成一个可调参数跑一遍容量扫描画出“弃风率-设备容量”曲线再结合造价选拐点位置。5. 工程落地中我最想提醒的三个坑5.1 风电预测数据质量决定结果可信度这是我踩过最大的坑。最开始我把风电预测曲线当成完美数据来做日前计划结果调度当天实际风电跟预测偏差一大优化结果就完全失真了。后来我学乖了在Matlab代码里加上预测误差场景把风电可出力数据做成多场景集合或者采用鲁棒优化的思路。对初学者来说最实际的做法就是——不要只跑一组数据把风电曲线上下浮动20%各跑一遍看看结果的变化范围。如果变化太大说明系统对风电预测的依赖度高这时候要考虑增加备用容量或者引入实时调整机制。5.2 储热初始SOC与末端约束最容易失真的细节很多人建完模型跑出来一个很漂亮的结果弃风率近乎0但仔细检查发现储热罐是从满载开始、放空结束的——这相当于“白嫖”了一整个罐子的热量实际日内运行根本不可能复现。要避免这个问题必须加SOC循环约束让日初和日末的储热量相等Constraints [Constraints, soc(1) soc(T1)];加了这条约束后弃风率会有小幅上升但结果才是真实可执行的。如果是做连续多日的仿真这个约束更是必不可少的否则你每天都在消耗前一天“偷来”的热量。5.3 从日前到滚动不要把模型的一次求解当成控制最后一个提醒是关于控制层面的。标题里写的是“优化控制”但很多实现其实只做了“日前优化调度”。日前优化是开环的用的是预测数据真正落地的时候风电和负荷都在波动最优决策必须滚动更新。我在实际项目中用的框架是滚动时域优化每15分钟更新一次预测数据只执行第一个时段的决策然后到下一个时段重新求解。Matlab里这个逻辑不难实现只需要在主循环里不断更新负荷和风电数据调用同一个优化模型。如果你做的是毕业设计能把这个“日前计划滚动修正”的框架跑通在答辩里是很大的加分项因为它说明你理解从理论模型到工程应用的差距。从原理到代码再到算例这个联合优化控制模型的完整链条已经跑通了。最后再分享一个小经验拿到任何优化调度项目先别急着上复杂算法先把LP模型跑通、把物理约束理解透再往里面加整数变量、加不确定性。用我师傅当年的话说先把最简单的东西做对再谈花活。这套代码框架我后续也在不断往里面加东西——热网的动态时延特性、电价响应需求侧资源、多风电场时空相关性每一层都能让模型离实际更近一步也值得你在这个方向上继续折腾。
返回列表