综合能源系统优化调度:绿证交易与需求响应的MATLAB实现

发布时间:2026/10/8 9:32:19
综合能源系统优化调度:绿证交易与需求响应的MATLAB实现 这几年跑综合能源系统优化调度模型我最大的感受是模型本身不难难的是把政策机制绿证、碳、需求响应和物理设备约束同时塞进一个可求解的优化问题里。这篇文章要聊的就是一套围绕“绿证交易综合需求响应”的优化调度MATLAB代码。它解决的问题很具体园区或区域综合能源系统在同时考虑绿色电力证书交易和用户侧综合需求响应时如何制定未来一段时间的设备出力和购能计划让总成本最低、可再生能源消纳更高同时守住供能安全。这套模型的适用对象很明确做综合能源系统规划、电力市场、园区能量管理方向的研究生或者刚入行做能源系统优化的工程师。代码层面用MATLABYALMIP搭建求解器可以用Gurobi或CPLEX属于典型的混合整数线性规划MILP问题。我会把模型思路、数学表达、代码实现方式、算例结果和调试经验都拆开讲一遍尤其是那些文档里不会写、自己跑才会踩到的坑。1. 模型里塞了哪些东西绿证交易与综合需求响应的角色定位1.1 综合能源系统优化调度的基本盘综合能源系统的核心特点是“多能互补”光伏、风电、燃气轮机、电锅炉、燃气锅炉、储能电池、蓄热罐这些设备不再各干各的而是通过电、热、气三种能源网络的耦合形成一个可以统一调度的整体。优化调度的本质是一个“在一定约束下找最优决策”的问题。决策变量包括各设备的启停状态、出力大小、储能充放功率、从电网购买的电量、从气网购入的燃气量等。约束条件则包括电功率平衡、热功率平衡、设备出力上下限、爬坡速率、储能SOC荷电状态限制等等。目标函数一般是总运行成本最小有时候也会加入碳排放最小、可再生能源消纳量最大等目标。很多初学者上来就写代码结果变量一多、约束一多就乱套。我的建议是先明确系统的物理拓扑电母线、热母线、气母线分别连接哪些设备母线之间通过哪些耦合设备传递能量。只要拓扑清楚了约束建模就不会差太远。这套模型的母线结构大概是电母线接入光伏、风电、CHP热电联产机组、电锅炉、储能电池、外部电网热母线接入CHP余热、燃气锅炉、电锅炉、蓄热罐、热负荷气母线接入外购天然气供给CHP和燃气锅炉。1.2 绿证交易为什么会被放进调度模型绿色电力证书说白了就是可再生能源发电的“凭证”。每发一定量的绿色电力就可以获得相应的绿证绿证可以在市场里卖给那些有可再生能源消纳责任的主体比如火电企业或者售电公司。在优化调度模型里加入绿证交易主要影响两块一是收益项。系统内的风电、光伏出力可以获得绿证并在目标函数里产生绿证收益这会直接改变调度偏好让可再生能源的“优先级”更高。二是约束项。如果系统承担了消纳责任权重就必须持有或交易足够的绿证否则要缴纳罚金这一条会以约束或惩罚项的形式进入模型。说得直白一点没有绿证交易时光储系统可能为了减少弃风弃光而高成本运维有了绿证收益可再生能源多发出来的每一度电都不仅有卖电收益还有绿证收益经济性就能改善很多。算例里通常能看到绿证价格在合理区间内时系统会更主动地消纳风光弃风弃光率明显下降。1.3 综合需求响应不只是削峰填谷很多人对需求响应的理解停留在“电力负荷可平移、可削减”这一层但综合需求响应强调的是电、热、气多类负荷的协同柔性。比如工厂的某些生产环节可以把用电时段往后挪可转移电负荷楼宇空调可以在保证室温舒适度的情况下参与削减可削减电负荷采暖用户可以用蓄热方式把用热需求从高峰时段挪到低谷时段热负荷转移工业蒸汽用户甚至可以切换燃气和电锅炉来调节用气量气负荷替代。这些柔性负荷在模型里表现为“需求响应约束”可转移负荷的总能量不变但各时段功率可调整可削减负荷的削减量有上下限热负荷的温度上下限约束由室内热平衡方程体现。更常见的方式是给需求响应加一个单位补偿成本这样模型不会无限地“折腾”用户而是在削峰填谷效益和补偿成本之间做权衡。综合需求响应的加入会让原来刚性的负荷曲线变成一组“可活动的区间”。这个区间给调度提供了更多自由度尤其当系统同时包含储能和多能耦合设备时效果非常明显低谷时段储能充电、蓄热罐蓄热、电锅炉多产热高峰时段负荷被转移或削减储能放热放电。最终结果是系统运行成本下降电网侧的峰谷差也减小。2. 数学模型设计目标函数和约束是怎么一步步搭起来的2.1 目标函数钱从哪来花到哪去这套模型的目标函数一般写成最小化总成本但里面各项的取舍很讲究。我常用的表达式是从电网购电成本分时电价与购电功率的乘积累加购电价按峰平谷时段设置。购气成本CHP和燃气锅炉消耗的天然气量乘气价。设备运维成本各设备出力乘单位运维系数储能充放电一般也有折算成本。弃风弃光惩罚实际可用可再生能源出力与消纳量之差的惩罚项让模型尽量不弃能。绿证收益风电、光伏实际发电量换算成绿证数量后乘绿证价格作为负成本放进目标函数。需求响应补偿成本对可转移、可削减负荷的补偿总和单价一般远低于购电峰时电价否则不划算。碳交易成本可选如果系统纳入碳排放配额购买碳配额或出售多余配额的金额也可以加进去。目标函数写成数学形式时注意所有项的单位要统一。很多初学者容易把kW写成kWh、把小时数漏掉导致最终结果莫名其妙。我的习惯是所有能量变量都用“功率×时段时长”来表示比如购电量是购电功率乘每个时段的时长通常取1小时但如果采用15分钟建模就要除以4。2.2 设备约束储能、CHP和锅炉怎么建模设备模型是调度模型的“物理底座”简单写一下几个关键设备。储能电池的约束核心是SOC递推公式SOC(t1) SOC(t) (Pch(t) × ηch - Pdis(t) / ηdis) × Δt / Cap同时要加充放电功率上限、SOC上下限和“不能同时充放”的逻辑约束。不能同时充放这条如果不用0-1变量模型会出现既充电又放电来“洗钱”的漏洞所以要么引入二进制变量要么用充放互斥约束。在MILP框架下推荐用两个0-1变量加big-M方法。CHP热电联产机组的关键是热电耦合电出力和热出力不是独立的而是存在一个可行域。常见简化是用热电比联系比如Hchp(t) Rchp × Pchp(t)如果机组有抽汽调节功能可行域更复杂可以用多边形顶点组合近似。CHP还要有爬坡约束和启停时间约束这里不多展开。电锅炉和燃气锅炉相对简单就是出力上下限和爬坡约束注意电锅炉的输入功率和输出热功率之间要乘一个转换效率。蓄热罐与储能电池类似也有蓄热状态递推和蓄放热功率限制。光伏和风电的出力模型通常直接采用预测曲线作为可用上限调度变量是“实际消纳功率”它的范围在0到预测功率之间。这样模型才能通过绿证收益和弃能惩罚共同决定可再生能源是否全额消纳。2.3 绿证交易的约束表达绿证交易在数学上可以这样处理。设系统在t时段获得的可再生能源绿证数量为GC(t) (Ppv(t) Pwind(t)) × Δt / G_unit其中G_unit表示单个绿证对应的电量国内常见是1个绿证对应1000千瓦时也就是1MWh。如果模型电量单位是兆瓦时这个系数就是1。绿证持有量可以跨时段累积也可以当期出售。常见约束是每一时期结束时满足承担的消纳责任权重Σ_GC_hold(t) ≥ 消纳责任权重 × 总用电量如果是不要求强制持有只是考虑绿证交易收益则只需在目标函数中加入“绿证收益绿证价格×当期出售绿证数量”。更精细的模型会设“绿证持有上限”和“绿证交易费用”但一般入门模型不需要加得太重。算例中比较常用的是直接给一个绿证价格然后看系统愿意多消纳多少可再生能源。这里有个现象很有意思绿证价格达到某个阈值后弃风弃光率会突然下降这个阈值本质上等于“多用一度绿电的边际成本”包括储能损耗、可能的爬坡成本等。2.4 综合需求响应的约束建模先说可转移负荷。假设用户有一批用电任务总用电能量固定但开始时间可以调整比如洗衣机、消毒设备这类生产工序。建模时用一个汇总方式Σ_t Pshift(t) E_shift_total0 ≤ Pshift(t) ≤ Pshift_max还可以加“连续性约束”但简化时通常只约束总能量和每时段功率上限。可削减负荷更直接原有用电计划减去削减量就是实际负荷。削减量有一个最大比例Pcut(t) Pbase_cut(t) - Δcut(t)0 ≤ Δcut(t) ≤ α × Pbase_cut(t)同时要保证削减后的用电不低于用户最低需求。热负荷的柔性一般通过“热舒适度”来体现不是直接限制热功率而是限制室内温度在某个区间内。如果采用等效热参数模型就可以把热负荷约束变成一阶差分约束这与储能约束很类似T_in(t1) T_in(t) (H_supply(t) - K_loss × (T_in(t) - T_out(t))) / C_buildingT_min ≤ T_in(t) ≤ T_max这个式子其实理解成“把建筑当成一个蓄热罐”就行。这样模型可以在电价高的时段少供热利用建筑本身的热惯性维持舒适度等电价低了再补上。这就是需求响应里很典型的“建筑蓄热”逻辑。3. MATLAB实现从数学表达式到可跑的代码3.1 为什么推荐MATLABYALMIPGurobi/CPLEX综合能源优化调度模型基本都是线性或混合整数线性问题用MATLAB自己写单纯形法不太现实所以我要推荐组合方案MATLAB负责数据准备和结果展示YALMIP负责模型建模Gurobi或CPLEX负责求解。YALMIP的最大优势是语法非常接近数学表达式写约束和写论文公式几乎一一对应调试也方便。代码框架长这样% 定义变量 P_chp sdpvar(1, T, full); % CHP电出力 H_chp sdpvar(1, T, full); % CHP热出力 P_buy sdpvar(1, T, full); % 购电功率 P_pv sdpvar(1, T, full); % 光伏实际消纳 z_chp binvar(1, T); % CHP启停状态 % 约束 Constraints []; Constraints [Constraints, 0 P_chp 500]; Constraints [Constraints, H_chp 1.2 * P_chp]; % ... 其他约束 % 目标函数 Objective sum(price_buy .* P_buy) sum(price_gas .* gas_use) ... - gc_price * sum(P_pv P_wind) ... demand_response_cost; % 求解 optimize(Constraints, Objective, sdpsettings(solver, gurobi));YALMIP里sdpvar是连续变量binvar是0-1变量。注意和MATLAB自带变量区分不要对sdpvar直接数组赋值。我见过不少同学在循环里写P_chp(1,t) ...然后用这类式子拼约束结果约束被覆盖掉还找不到原因。正确做法是先用sdpvar定义整行变量再用变量名直接构建约束如果循环赋值一定要用assign不要用等于号。3.2 数据准备参数和典型日曲线怎么构造建模之前数据准备工作其实占一半工作量。核心数据分五类系统参数设备容量、效率、爬坡率、储能容量与初始SOC、温度上下限等。负荷数据典型日或典型周的电、热、气负荷预测曲线步长可以是1小时或15分钟。新能源数据光伏和风电的预测功率曲线最好按季节分典型场景。价格参数分时电价、天然气价格、绿证价格、需求响应补偿单价、运维成本系数。需求响应参数可转移负荷总量、可削减比例、补偿成本、室内温度要求等。初学者最容易忽略的是“单位一致性”。比如光伏预测功率给的是kW储能容量给的是kWh电价是元/kWh天然气热值是MJ/m³这几套单位混在一起非常容易错。我的习惯是全部统一成MW和MWh天然气按燃机发电效率反算成购气量再乘气价这样目标函数里不会出现数量级对不上的尴尬。3.3 核心约束的代码写法与调试技巧写约束时每个约束组最好单独注释最后输出维度检查。比如电功率平衡约束Constraints [Constraints, P_chp P_pv P_wind P_buy P_dis ... P_load_elec - P_shift P_cut P_eb];这里P_load_elec是原始电负荷P_shift是转移走的负荷P_cut是可削减负荷P_eb是电锅炉用电。注意方向别搞反需求响应是把负荷从高峰移走但可转移负荷的总量守恒所以原始负荷上要做区分。储能SOC递推的写法和约束一样直接写等式约束。但这里有一个小坑YALMIP里如果SOC(t1)和SOC(t)都是变量这个递推等式本身没毛病但连续性循环的约束数量会比较大调试时可以打印一下Constraints的长度确认没有意外叠加。另外为了数值稳定性建议把储能容量归一化成1让SOC保持在0到1之间初始SOC值设为0.2或0.3别取消负荷功率都已经超了还说模型不收敛。一个重要的调试技巧是写完模型先不求解直接把约束和变量维度打印出来。YALMIP有个命令size(Constraints) length(Objective)如果约束数量是0说明某个约束的维度不一致YALMIP已经报错但没有完全抛出。优先检查每个向量变量的长度是否都是T。另一个技巧是先用一个小规模测试比如把24小时改成4小时模型如果能在几秒内求解再扩展到24小时避免一开始就遇到大模型无解而不知道是数据问题还是建模问题。3.4 求解结果处理与可视化求解完成后用value()函数提取变量P_chp_opt value(P_chp); P_pv_opt value(P_pv); SOC_opt value(SOC);然后绘制出力曲线、负荷曲线、储能SOC变化图。建议至少画三张图一是各设备电力出力堆叠图二是热力平衡图三是SOC与负荷对比图。这些图不仅用于论文展示更重要的是用来检查物理合理性。比如看到CHP电出力在某个时段突然降为零就该查一下是不是启停状态约束导致看到SOC全程贴着上限走可能初始SOC设置不合理或者约束没加对。另一个值得检查的量是“影子价格”也就是约束的对偶乘子在YALMIP里可以用dual(Constraints)获取。电功率平衡等式的影子价格其实就是该时段的节点边际电价这个数值能反映系统在哪些时段最紧张用来验证需求响应效果很直观。4. 算例分析一个典型园区系统的三个场景对比4.1 场景设置与参数取值我测试时常设一个典型园区系统包含100 MW风电、50 MW光伏、50 MW燃气轮机CHP热电比1.2、30 MW燃气锅炉、40 MW电锅炉、30 MWh储能最大充放功率10 MW、50 MWh蓄热罐最大蓄放热功率10 MW电负荷峰值80 MW热负荷峰值60 MW。分时电价参考国内典型工商业峰谷电价峰时1.1元/kWh、平时0.68元/kWh、谷时0.35元/kWh。天然气价格取2.5元/m³按热值折算后单位供热成本需自己算清楚。绿证价格设为50元/张对应1 MWh绿电需求响应补偿单价取20元/MWh到30元/MWh不要比单位发电成本还高否则模型会“疯狂”削减负荷。对比三个场景场景1无绿证交易、无综合需求响应负荷全部刚性。场景2加入绿证交易收益与消纳责任约束负荷仍然刚性。场景3同时加入绿证交易与综合需求响应。4.2 调度结果怎么读首先看总运行成本。场景1里系统很可能在谷时多充电、峰时多用CHP顶着弃风弃光现象存在但不一定是“零”。加入绿证交易后风电和光伏的实际消纳量上升弃风弃光率可能从8%降到2%原因是绿证收益让每度绿电的“到手价格”变高了。加入需求响应后系统的成本进一步下降削峰效果很直观高峰时段净负荷降低谷时负荷略有上升负荷峰谷差缩小10%到15%。再看设备出力曲线。场景2中为了拿更多绿证收益系统可能在光伏出力充足的午间多发一点CHP给光伏配储不对CHP是火电不是为了绿证。这里要小心绿证收益只针对可再生能源所以模型会更倾向于多消纳光伏风电而不是多开CHP。一个更合理的表现是午间光伏大发时原本需要储能充电消纳的绿电现在因为绿证收益系统宁可让电锅炉多产热储存起来也不愿意弃掉光伏。于是蓄热罐的蓄热时段可能从夜间移到午间。到晚上光伏停了蓄热罐放热满足热负荷CHP可以少烧气。这就是绿证交易改变调度时序的典型现象。需求响应加入后负荷曲线明显平滑。电负荷高峰从傍晚高峰往后或往前平移热负荷也会选择在电价较低的时段预供热室内温度曲线在允许区间内波动。把三张场景的SOC曲线放一起能看出需求响应对储能调用次数的影响储能充放次数可能减少但每次充放的经济收益更高。4.3 敏感性分析绿证价格和需求响应潜力的影响这套模型很适合做双参数敏感性分析。固定其他参数让绿证价格从0元/张一直升到100元/张观察弃风弃光率、可再生能源消纳量和总成本的变化。通常结果会呈现一条“阶梯下降”的弃风弃光率曲线在某个价格区间内绿证的收益不足以覆盖额外消纳带来的运行成本变化一旦超过某个临界点弃风弃光率会大幅下降然后趋于平缓。需求响应潜力也很有看头。把可转移负荷占比从5%调到20%看总成本下降幅度。刚开始成本下降明显但比例超过一定值后边际效益递减因为需求响应补偿成本也在上升而且系统可能没有足够多的储能或灵活设备去“接住”转移来的负荷。这类敏感性分析不仅是为了画漂亮的曲线更重要的是帮你判断到底哪个政策参数对整个系统的价值最大如果绿证价格提升带来的收益远不如需求响应比例提升那就说明这个系统更缺的是用户侧灵活性而不是新能源补贴激励。5. 常见问题与调试经验跑这类模型最容易踩的坑5.1 常见报错与排查方法现象可能原因排查与解决YALMIP报“Dimension mismatch”某个向量变量长度不是T或约束里混入了标量打印所有size(变量)检查T是否一致求解报Infeasible约束过紧典型是电/热平衡等式与负荷不匹配先把所有需求响应和绿证约束注释掉确定基准可解再逐层加回储能SOC长期为0初始SOC或充放互斥约束有问题检查SOC初始值、充放效率符号打印SOC曲线结果里同时充电和放电缺少充放互斥约束或者使用了非线性乘积用binvarbig-M实现互斥求解时间特别长0-1变量太多或模型存在冗余约束减少启停变量或者把24小时换成96点时先检查是否能接受绿证收益导致目标函数“负得离谱”绿证价格设置过高或没有约束可再生消纳不超过预测可用功率给光伏风电的实际消纳变量加0到预测功率的上下限这里重点讲一下“Infeasible”的调试。我一般分三步第一步把目标函数设成一个常数0只求解可行解看是否有解第二步如果可行解都没有用“松弛法”找问题就是把各平衡等式改成允许偏差比如加一个松弛变量让约束变成等式左边加松弛项然后看哪些松弛变量不为零就说明是哪个平衡对应不上第三步把需求响应相关约束拆分出来单独debug。5.2 建模技巧线性化与big-M方法综合能源系统里常见的非线性来源有三个设备输入输出特性曲线的分段线性化、储能充放互斥、逻辑启停。解决手段基本都是引入0-1变量和big-M大数。举个例子储能充放互斥约束可以用两个0-1变量Uch和Udis然后Pch(t) ≤ Uch(t) × Pch_maxPdis(t) ≤ Udis(t) × Pdis_maxUch(t) Udis(t) ≤ 1这里的M就是最大充放电功率不需要取特别大的数取10000反而会让求解器数值不稳定。big-M的正确取值是“约束里该变量可能出现的最小上界”能小就小。比如Pch上限是10 MWM取10或12不要取1e6。数值稳定性在MILP求解里太重要了。启停约束也是一样CHP启动时有启动成本停机时有最低运行时间这些都需要二进制变量。如果你的模型只想做经济调度而非机组组合可以暂时忽略启停成本只把出力上下限和爬坡约束写上。这样模型规模小很多对初学者更友好。5.3 几条独家避坑经验第一所有参数先过一遍单位。我曾经因为把天然气的元/m³和MJ/m³弄混导致CHP一直不开机查了一个晚上才发现是气价贵得离谱。第二储能效率不要写成“充放都用同一个效率”。更合理的是充电效率0.95、放电效率0.92而且放电效率要放在SOC递推公式的分母位置。很多人写成“充放都乘0.95”看起来差不多但在长时间尺度下SOC会漂移优化结果也会出现莫名的能量偏差。第三需求响应补偿成本不要设太低。如果补偿成本是0元/ MWh模型会为了省钱把可转移负荷安排得极其极端虽然理论上可行但不符合用户真实行为。实际设定时至少让补偿成本略高于正常谷时段电价的10%到20%这样模型才会“理性地”使用需求响应而不是无限摆弄用户负荷。第四做结果合理性检查时不要把目光只放在成本数字上。先看每个时段能量平衡是否满足再看CHP电出力和热出力之间的耦合关系最后再看储能SOC终值是否落在合理区间。如果SOC终值和初始值差很多说明模型在“吃老本”或“攒能量”需要增加SOC首末相等约束或者让初始SOC可调。5.4 模型扩展方向碳交易、多园区协同与长时间尺度这套模型跑通以后扩展空间很大。最常加的是碳交易机制给碳排放配额超排需购买配额减排可以出售。碳成本的加入会让CHP和燃气锅炉的出力结构发生变化尤其当碳价高到一定程度电锅炉和蓄热罐的使用优先级甚至会超过CHP。另一个方向是多园区协同调度把三五个园区连接起来共享绿证配额和储能资源模型变成分布式优化可以用ADMM交替方向乘子法或列约束生成算法CCG求解。这个扩展尤其适合研究生毕业论文既能体现数学深度又能落地到具体场景。还有长时间尺度扩展从24小时日调度扩展到168小时周调度甚至按年做运行模拟。这时候需要处理新能源出力场景的聚类比如用K-means把全年风光数据聚成几个典型日再代入调度模型。运行模拟对“绿证年度消纳责任权重”这类约束会更有意义因为年度约束在单日调度里只能粗糙处理。我个人实际跑下来的体会是这类优化调度模型最怕的不是求解器不行而是建模时思路没理顺就动手写代码。先把系统拓扑画清楚再把目标函数每一项的物理意义想明白最后才碰MATLAB时序上反而最快。如果非要给一句建议写完约束后先看维度和能量平衡再谈结果优化。这套方法适用于几乎所有IES调度代码不管是绿证、碳交易还是需求响应本质都是给基础模型叠加市场化机制根基稳了什么都能往上加。