ARTICLE DETAIL

资讯详情

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

碳交易与需求响应耦合的综合能源系统优化运行建模与实践

碳交易与需求响应耦合的综合能源系统优化运行建模与实践 做了大半年综合能源系统优化我发现一个很有意思的现象很多仿真脚本把目标函数写成“运行成本最小”把碳排放当成事后统计的指标。算例跑完成本和排放往往是对着干的——省了钱就多了碳降了碳成本又上去。这不是模型有问题而是约束和机制没对齐。真正的工程场景里碳配额本身就是一种稀缺资源碳交易价格是会波动的用户侧负荷也不是刚性的。把这些机制放进同一个优化框架里才能做出既经济又低碳的调度方案。这篇内容是我把一个园区级综合能源系统作为对象把碳交易机制和需求响应同时嵌入优化运行模型的完整记录。模型涵盖电、气、热三类负荷包含光伏、燃气轮机、电锅炉、储能和蓄热罐目标函数是运行成本、碳交易成本和需求响应补偿成本之和最小。适合正在做综合能源系统调度、储能配置或碳排放约束项目的研究生和工程师参考也适合想把碳约束真正落地到优化问题里的同行少走弯路。1. 从“双碳”到优化模型这套框架到底在解决什么问题1.1 为什么碳交易机制要进优化目标而不是事后统计“双碳”目标落实到工程层面最直接的抓手就是碳配额。现在越来越多的园区和用能企业被纳入碳市场每年领到的免费配额不再是“够不够用”的问题而是直接影响生产成本。用超了要去市场买配额用少了可以把多余的配额卖出去这个价格信号会真实地改变调度决策。传统综合能源系统优化只考虑“设备出力怎么分配最省钱”也就是电费加气费最小。但如果碳配额收紧燃气轮机虽然发电成本低它的碳排放强度远高于从电网买电当然也要看电网的清洁能源比例单纯按成本排序就会让碳排放大增。碳交易机制引入后成本函数里多了一项“碳配额盈亏的结算项”系统会自动在“多用气多发电”和“多买网络电”之间重新权衡。这就是为什么碳交易不能当后置统计指标必须作为优化目标的一部分。我早期踩过一个坑直接把碳排放设成约束条件要求碳排放量不能超过某个上限。结果模型求解时间和成本都异常后来发现这是把机制问题做成了硬约束问题。现实中碳是可以买卖的超过部分花钱就能解决没必要硬砍。改成碳交易成本后模型就聪明多了——它会在“多花碳交易费”和“多花运行费”之间找平衡点。1.2 综合能源系统的优化运行核心是“耦合”两个字综合能源系统强调电、气、热之间的多能互补。电负荷可以由电网买电、燃气轮机发电和储能放电共同满足热负荷可以由燃气轮机余热、燃气锅炉和蓄热罐放热共同满足。这种耦合关系让调度有了腾挪空间比如电价高的时段用燃气轮机发电余热顺便供热电价低的时段先买电充储能燃气锅炉单独供热。优化运行模型做的就是在每个调度时段通常取1小时决定每一个设备出力多少让一天下来总成本最低。典型的园区综合能源系统设备层面的决策变量包括燃气轮机发电出力P_chp和供热出力H_chp燃气锅炉供热出力H_gb电锅炉供热出力H_eb储能充放电功率P_ch/P_dis和蓄热罐充放热功率从电网购电功率P_grid需求响应后的电、热负荷变化量这些变量之间靠能量平衡约束耦合起来。比如电功率平衡关系电网购电加上燃气轮机发电再加上储能放电和光伏出力必须等于基础电负荷减去需求响应削减量再加上储能充电和电锅炉消耗。热平衡也是类似的燃气轮机余热、燃气锅炉、电锅炉的产热必须满足热负荷需求减去需求响应削减量。优化模型本质上就是把这些耦合关系写清楚找一个让总成本最小的同时满足所有平衡关系的出力组合。1.3 需求响应把“用户侧灵活性”变成系统调节能力需求响应在优化模型里的价值最核心是削峰填谷。中午光伏大发时电价可能还是峰时价不一定但很多地区中午光照强时电价反而低而晚高峰电负荷上来后电价高、光伏又没了。如果不做需求响应只能靠储能顶峰或者燃气轮机满发。如果用户侧负荷能主动调整——比如把部分可转移负荷从晚高峰挪到中午不仅自己省钱系统整体也能用更清洁的光伏电替代燃气轮机出力碳排放自然下降。需求响应又分价格型和激励型两条线。价格型是通过分时电价引导用户自主调整用电习惯模型中用需求价格弹性矩阵描述负荷对电价的响应。激励型则是用户和运营商签协议由运营商在特定时段直接削减或转移负荷运营商给用户补偿。这有点像快递公司和你约时间取件你响应了具体时段的要求快递公司给你补偿或优惠。价格型是“你看价格决定怎么买”激励型是“我告诉你什么时候寄你配合我给你好处”。两者在模型里的数学表达完全不同后面我会详细拆解。2. 碳交易建模细节初始配额、碳价函数和阶梯价格处理2.1 初始碳配额的两种分配方式算例里怎么选碳交易机制建模的第一步是确定免费碳配额E_p。工程中常见的有两种算法我建议新手从历史强度法入手因为参数好定、实物物理含义清晰。历史强度法的公式是[ E_p \mu \times \eta \times \sum_{t1}^{T} (P_{grid}(t) P_{chp}(t) P_{gb}(t)) ]其中 (\mu) 是企业历史碳排放基准强度tCO₂/MWh根据设备类型确定(\eta) 是逐年递减系数用于反映配额收紧趋势。这里我踩过一个坑直接用了文献里的默认排放强度没考虑自己系统里燃气轮机的实际效率。后来用参与项目的历史运行数据反算发现电网购电的排放因子可以取近似平均值 0.997 tCO₂/MWh燃气轮机的排放强度按天然气热值估算为 0.202 tCO₂/MWh。这个差异直接影响配额松紧和最终碳交易费用建议务必根据实际设备参数核算。另一种基准线法相对复杂它按行业先进水平设定单位产品排放基准再乘以产品产量。这种方法的优点是有明确的行业对标缺点是数据要求高不太适合园区级示范项目的初期仿真。如果你只是做自己园区的优化运行历史强度法加上一个递减系数就是最实用的选择。2.2 碳交易成本函数不只是“超标买、余量卖”这么简单碳配额一旦确定系统一天的累计碳排放量和配额的差额就决定了碳交易成本。基础公式是[ E_{CO2} E_s - E_p ](E_s 0)超出配额需要购买成本增加(E_s 0)配额富余可以出售获得收益(E_s 0)恰好持平。最简单的线性碳价就是 (C_carbon p_c \times E_s)(p_c) 是碳价元/tCO₂。这种线性模型适合入门但工程实际中碳交易价格不是常数市场会波动而且超额越多成本压力越大。所以我推荐用阶梯碳价模型这是文献和实际项目中出现最多的做法[ C_{carbon} \begin{cases} \lambda \times E_s, 0 \le E_s \le d_1 \ \lambda d_1 \lambda\alpha(E_s - d_1), d_1 E_s \le d_2 \ \lambda d_1 \lambda\alpha(d_2 - d_1) \lambda\beta(E_s - d_2), E_s d_2 \end{cases} ]其中 (\lambda) 是基础碳价(\alpha)、(\beta) 是价格系数通常取1.2、1.8(d_1)、(d_2) 是阶梯分段阈值比如分别设为配额基准的10%和20%。这个函数的思路是碳排放差额越大每吨碳的边际成本越高模型就不会铤而走险地无节制排放。我用算例对比过阶梯碳价下系统换用电气设备替代气设备的比例明显提高比单一碳价更贴近真实碳市场的奖罚逻辑。2.3 阶梯碳价是分段函数怎么塞进线性优化模型阶梯碳价函数是分段线性的直接放进混合整数线性规划会制造非线性求解器会抱怨甚至直接不收敛。我用的处理办法是引入0-1整数变量和Big-M法辅助线性化。实质做法是把碳交易费用 (C_carbon) 拆成三个区间段每个区间段对应一个辅助变量 (E_{s,i})第i段的碳排放差额量并满足[ E_s E_{s,1} E_{s,2} E_{s,3} ]每一段引入 (s_i) 作为0-1整数变量表示该区间段是否被激活[ s_i \times d_{i-1} \le E_{s,i} \le s_{i-1} \times d_i ]注意第二段的“上界保证”要写成 (E_{s,2} \le (d_2 - d_1) \times s_1)否则模型会在一个区间内老老实实把第二段填满再用第三段逻辑会错。这就是很多新手线性化之后跑出负成本或者离奇结果的根源。Big-M法还要保证激活顺序(s_2 \le s_1)(s_3 \le s_2)让碳差额只能从第一段往第三段扩展不能跳段。我实际跑算例时用YALMIP配合Gurobi这个线性化过程大概多出十几个变量对求解速度影响极小完全值得。3. 需求响应建模的两个方向价格引导用户和激励约定补偿3.1 价格型需求响应怎么用弹性矩阵表达“用户会看价格”价格型需求响应Price-based DR的思路是用户根据电价信号自主调整用能在模型里用价格弹性矩阵来描述这种响应关系。弹性系数 (\varepsilon_{ij}) 的定义是[ \varepsilon_{ij} \frac{\Delta L_i / L_i^0}{\Delta \rho_j / \rho_j^0} ]其中 (i j) 时为自弹性反映同一时段荷载对自身价格的敏感度(i \neq j) 时为交叉弹性反映其他时段价格变化对本时段负荷的影响。自弹性典型值是 -0.1 到 -0.3交叉弹性一般是 0.01 到 0.1 的小正数。这个物理含义有点类似商品打折——自己降价销量上升负弹性别家涨价自己销量也上升交叉正弹性。实际建模我分三步走。先把全天24小时分成峰、平、谷三个时段给出分时电价然后确定弹性矩阵的组成自弹性放在对角线交叉弹性放在非对角最后按下式计算负荷变化量[ \Delta L(t) L_0(t) \times \sum_{j} \varepsilon(t,j) \times \frac{\Delta \rho_j}{\rho_j} ]这一步我踩过坑直接用弹性矩阵把所有时段的价格变化都耦合进来导致峰谷时段负荷变化互相牵扯出现“谷时电价降了负荷反而下降”的反常识结果。原因是交叉弹性正负取值没控制好模型里出现了数学振荡。后面我调整了策略交叉弹性只对相邻时段设置较小的正值远处时段直接忽略数据就稳定了。在优化模型里价格型DR执行后得到的新负荷曲线 (L_{new}(t)) 会重新参与能量平衡约束。价格弹性系数越大负荷对电价越敏感系统削峰填谷的效果越好但同时要小心过度响应导致用户舒适度下降。3.2 激励型需求响应可削减负荷和可转移负荷的两种数学表示激励型需求响应是通过签约方式让用户承诺在特定时段削减或转移负荷运营商按量补偿。工程上最常建模的两类是可削减负荷可切负荷在某个时段直接减少一部分用电比如空调温度上调2℃。数据上反映为 (0 \le \Delta L_{cur}(t) \le \Delta L_{cur}^{max}(t))实际削减量不能超过用户可承受上限。可转移负荷例如洗衣机、蓄热式热水器这些负荷可以挪到其他时段。反映为 (\sum_{t} \Delta L_{trans}(t) 0)也就是说削了的量必须在他时段补回来总和不变。两类负荷分开建模对应的补偿费用也不同。可削减负荷因为直接影响用户舒适度补偿单价通常更高可转移负荷只是换个时段补偿单价可以低一些。优化模型里补偿成本写成[ C_{dr} \sum_{t} \left( c_{cur} \times \Delta L_{cur}(t) c_{trans} \times \Delta L_{trans}^{up}(t) \right) ]这里有一个细节需要注意可转移负荷要区分“上调”从别处挪入和“下调”挪到别处补偿费用只对“实际调整”发生的一次使用权付费。我遇到过直接把 (|\Delta L_{trans}(t)|) 写进目标函数的情况结果目标函数带了绝对值不可导模型变形成非线性跑起来极慢。后来引入两个非负变量 (L_{trans}^{up}) 和 (L_{trans}^{dn}) 分别表示上调和下调约束 (L_{trans}(t) L_{trans}^{up}(t) - L_{trans}^{dn}(t))才正常收敛。3.3 需求响应的补偿价格多少合适才不浪费也不失真补偿价格设置是一个很实际的问题。报高了模型会拼命削减负荷来省钱但实际上用户可能根本不愿压那么多报低了用户没有动力响应DR形同虚设。我常用的方法是用“停电损失函数”或者“用户侧价值函数”估算。最简单的工程做法是参考当地峰谷电价差补偿单价设为峰谷差价的60%~80%。比如某地峰时电价1.0元/kWh、谷时电价0.3元/kWh、差价为0.7元/kWh那可削减负荷的补偿单价取0.45~0.55元/kWh就比较合理。可转移负荷因为用户损耗小打个6折取0.3~0.35元/kWh。同时还必须设置参与率上限。不是所有用户都愿意在通知时段立刻配合削减园区级案例里我一般把可削减负荷的总量上限设为基础负荷的10%~15%可转移负荷上限设为5%~8%。上限太大会错误夸大需求响应潜力导致调度方案在现实中根本执行不了上限太小则DR存在感太弱发挥不出调节作用。4. 完整实操建模工具、关键代码与算例结果分析4.1 工具链选型用MATLABYALMIPGurobi搭建模型我推荐用MATLAB加YALMIP建模求解器用Gurobi或CPLEX。理由很简单YALMIP对线性规划和混合整数线性规划的建模语法高度抽象省去手写约束矩阵的麻烦。尤其是涉及多个设备、多时段耦合、碳交易阶梯函数的线性化时YALMIP的变量索引和约束拼接比手写B矩阵高效太多。如果团队里有人不习惯MATLAB也可以尝试Python的pyomo或Gurobi原生接口。两种语言写出的模型结构几乎可以一一对应我自己更习惯MATLAB是因为旧项目代码积累多、调试快。核心标准是你自己和队友最容易上手、最容易验证正确性的工具就是好工具。完整模型文件一般分成四个文件参数定义脚本、模型构建函数、求解与输出脚本、结果绘图脚本。这样做的好处是修改参数不用动模型结构跑场景对比时尤其顺手。4.2 模型目标函数与关键约束的YALMIP写法下面给出一段简化后的YALMIP核心代码片段涵盖目标函数和几个核心约束。这里把24个时段的变量写成一维向量配合几个设备参数就能跑起来。% 假设T24个时段决策变量 P_chp sdpvar(1, T); % 燃气轮机发电出力 H_chp sdpvar(1, T); % 燃气轮机供热出力 P_gb sdpvar(1, T); % 燃气锅炉产热 P_eb sdpvar(1, T); % 电锅炉产热 P_dis sdpvar(1, T); % 储能放电 P_ch sdpvar(1, T); % 储能充电 P_grid sdpvar(1, T); % 电网购电 L_cur sdpvar(1, T); % 可削减负荷量 L_trans_up sdpvar(1, T); % 可转移负荷上调 L_trans_dn sdpvar(1, T); % 可转移负荷下调 % 碳排放差额变量 E_s sdpvar(1, 1); E_s1 sdpvar(1, 1); % 阶梯第1段 E_s2 sdpvar(1, 1); % 阶梯第2段 E_s3 sdpvar(1, 1); % 阶梯第3段 s1 binvar(1, 1); % 第1段激活标志 s2 binvar(1, 1); % 第2段激活标志 % 目标函数 C_e r_elec * P_grid; % 购电费用 C_g r_gas * sum(P_chp ./ eta_chp P_gb ./ eta_gb); % 购气费用 C_carbon lambda * (E_s1 alpha * E_s2 beta * E_s3); % 碳交易成本 C_dr r_cur * sum(L_cur) r_trans * sum(L_trans_up); % 需求响应补偿 C_reward c_aban * sum(P_pv - P_pv_used); % 弃光惩罚 optimize(constraints, C_e C_g C_carbon C_dr C_reward, sdpsettings(solver, gurobi));约束部分几个关键点要写清楚。一是电平衡约束电网购电加燃气轮机发电加储能放电加光伏消纳等于基础负荷减去削减负荷再减去转移负荷再加上储能充电和电锅炉消耗。二是燃气轮机的热电耦合约束供热出力与发电出力之间由热电比常数关联不能切换任意。三是可转移负荷的总和为零约束这是激励型DR不增耗电的本质保证。4.3 算例场景设计四组对照看出模型价值算例参数来自一个典型园区包含光伏装机2 MW燃气轮机1.4 MW电锅炉0.5 MW燃气锅炉0.6 MW储能0.8 MW/1.6 MWh蓄热罐1.5 MWh。我设计了四个场景对比场景A纯经济调度不考虑碳交易不考虑需求响应场景B只考虑碳交易不考虑需求响应场景C只考虑需求响应不考虑碳交易场景D碳交易需求响应同时考虑求解结果基于典型日数据场景总运行成本万元碳排放量吨峰时段购电量MW·hA12.54231.86.2B13.31192.45.8C11.86215.33.9D12.47179.63.3场景B碳排放比A降了约17%但成本升了6%。场景C成本最低因为DR把负荷移到了低价时段但碳排放没被约束还是偏高。场景D实现了碳排放最低成本与A接近比单纯碳交易便宜6%以上。这组结果说明碳交易单独引入会让运营成本上升需求响应单独引入主要实现削峰填谷只有两者协调才能在不大幅增加成本的前提下显著降碳——这就是需求响应对碳交易机制的系统性平滑作用。4.4 结果分析怎么看三个关键指标判断模型运行结果是不是合理我会依次看三个指标。一看费用构成比例购电费、购气费、碳交易费、DR补偿费占比是否符合物理直观。如果碳交易费用高到超过总成本30%可能是初始配额设得太紧或者碳排放强度算得过高。二看设备出力曲线燃气轮机在电价峰时段输出高谷时段压低光伏大发时电锅炉用多余电供热这套联动如果有冲突说明约束写错了。三看负荷平移幅度可转移负荷的平移量占总负荷比重如果超过预设上限比如我之前说的10%上限就要怀疑是不是补偿单价设高了。如果结果里出现“某时段电负荷为负”这类异常八成是平衡约束中正负号写反了。我调试时有个习惯先用简化小规模比如6个时段跑通模型确认每一类约束都按物理规律工作再扩展到24小时或96时段。这比直接跑大模型方便太多。5. 实操中反复踩过的坑六个典型问题与排查思路5.1 碳交易函数线性化之后跑出“负碳成本”有次我调整阶梯碳价参数后模型跑出来的碳交易成本为负数而且绝对值巨大。排查发现是线性化变量 (E_{s,1})、(E_{s,2})、(E_{s,3}) 没有被约束成非负模型为了“套利”把第二段设置成了负值空手套了一笔碳收益。解决办法很简单给每个分段变量加 (0 \le E_{s,i} \le M \times s_i) 约束M取一个大于碳差额合理上限的数即可。这个坑非常隐蔽因为分段变量在物理上不是真实变量没有非负约束时求解器会钻漏洞。5.2 需求响应的“削峰填谷”变成“谷削峰填”我在模型调试早期遇到了一个很尴尬的结果模型主动把谷时段负荷削减掉移到了峰时段。原因是我的可转移负荷补偿单价低于峰谷电价差的反向激励模型发现从谷时段往峰时段转移负荷虽然要多付补偿但峰时段生产价值更高如果目标函数里有产出的收益项所以“反向调峰”反而更省钱。解决方式有两种。一种是给可转移负荷的转移方向加约束例如规定夜谷时段只能接收转移、峰时段只能输出从制度上限制反向调度。另一种是把DR的目标设定为最小化峰谷差或负荷方差单独作为一项惩罚项进目标函数。两种我都用过第一种简单直接适合新手第二种更细腻适合深入研究。5.3 模型求解时间过长24时段怎么跑都跑不完混合整数线性规划在冷启动时求解速度慢很常见尤其是引入了碳交易的分段整数变量后。我最初直接跑24时段完整模型Gurobi要跑十几分钟还没收敛工作流完全没法用。我的优化组合拳是先跑整数变量松弛版本把binvar改成sdpvar用线性规划结果做初始解再将初始解作为MIP的起点YALMIP支持assign然后调用warm-start。同时把MIPGap容忍度设为1%sdpsettings(gurobi.MIPGap, 0.01)实际工程里1%的精度足够。这三招下来模型求解从十几分钟压缩到一分钟左右效果非常明显。5.4 光伏预测不准导致调度结果不可用园区级微网的光伏出力预测误差尤其在有云的天气可以达到20%~30%。如果优化模型用的是确定性预测曲线实际运行中电量平衡可能被打破配网购电指令就会失真。更稳妥的做法是用场景法生成典型晴、多云、阴天的三组预测曲线加上对应的概率权重让模型以期望成本最小为目标。或者更轻量一点用鲁棒优化的思路只约束最恶劣场景下的平衡关系。两个方案都能解决预测误差问题具体选哪个取决于你对成本保守程度的容忍度。我在示范项目中两种方法都试过场景法更容易解释给业主听也更容易通过评审。5.5 基线负荷定高了需求响应“白做了”需求响应的改造效果是相对基线计算出来的。如果基线负荷取的是历史同期最大值那天气变化、生产波动都会被误算成需求响应效果评价失真。比如我碰过一个项目把基线设为上周同期负荷但恰好那周有高温空调负荷上去了实际DR削减没那么多评估时却算了一大笔削减量。工程上我采用的做法是取“削减前同一时段前5个正常日的平均负荷”再乘一个天气修正系数。这个修正系数根据温度变化线性调整。别小看这个细节很多项目审计就是栽在基线认定上基线的科学性直接决定DR补偿结算有没有说服力。5.6 所有设备参数归一化一个简单的数学检查设备效率、排放因子、电价基准值这些参数来自不同数据源如果不统一量纲模型里很容易出现“数值风暴”——各个变量之间相差几个数量级求解器数值稳定性崩溃。我每次都做一次单位预检查功率统一用MW能量用MWh成本统一用万元或元碳配额用吨。如果某台设备效率写作0.35而另一台写作35%数值上就会差一百倍模型会给出荒谬的出力决策。养成先把所有数据填进一张参数表、逐一核对单位的习惯能省下大量调试时间。这个模型后续还可以怎么扩展如果你已经跑通了这个基础模型后续可以沿着三条线扩展一是引入绿证交易和CCER机制让碳减排量可以在不同市场上流转二是把需求响应从“日前调度”延伸到“实时市场”加入滚动优化和模型预测控制三是加入多园区协同让相邻园区共享储能或互济出力。我自己下一步的计划是把不确定性建模做扎实用分布鲁棒优化替代目前的场景法让模型在极端天气下依然有满意的经济性。最后分享一个小技巧建模早期一定要把需求响应的所有成本项分开累计不要混在运行成本里这样审计时每一笔支出都有据可查业主和验收方都会高看你一眼。
返回列表