电力市场两级出清与消纳责任权重建模:Matlab+Cplex实现

电力市场两级出清与消纳责任权重建模:Matlab+Cplex实现 1. 模型定位两级市场与消纳责任权重怎么走到一起的电力市场方向的项目做到清洁能源消纳这一块迟早会跟消纳责任权重这个词打照面。它本质上就是给每个市场主体到底要消纳多少绿电定一个硬性比例不够就通过绿证或罚款来补。这个机制一旦进入市场出清模型就不只是加个约束那么简单了它会把全局的资源优化配置和每家售电公司自己的购电策略绑在一起稍不留神就变成一个挺复杂的双层问题。我最近用Matlab把这一整套流程完整搭了出来求解器用的Cplex从建模、编码到调试踩坑今天一次性讲透。这套代码适合谁来参考想复现电力市场出清、新能源配额制、绿证交易相关算例的同学毕业论文需要可运行Benchmark的或者工作中要给区域消纳权重算账做机制分析的朋友都可以直接对着抄。模型规模不大但框架完整顺序出清版本一百多行Matlab就能跑通进阶版KKT双层也能在这个基础上平滑升级。1.1 两级市场的设计动机全局配置与本地执行要分开为什么非要做两级不能拉平成一个市场核心原因是电力系统的资源优化配置是全局性的但交易执行和责任考核是本地性的。风电、光伏大基地通常离负荷中心很远一个交易中心想把所有细节全包进来不仅模型复杂度爆炸很多本地规则、个体偏好也没法在一个集中模型里表达清楚。参考全球能源互联网理念来看这里面最核心的思想是清洁能源全球配置、各类电源互补互济。落到电力市场运行上实际操作就是先有一个全局出清层负责把成本最低的电源组合算出来同时确定全网的可再生能源消纳总量然后再有一个本地执行层让市场成员在自己头上的约束下做实际的购电和绿证交易。两级之间有清晰的价格信号和配额信号传递所有市场成员的行动逻辑都能对上账这比一个大一统模型更容易解释、更容易落地也更容易编代码调试。现实中很多市场也是类似的两级结构比如省间-省内两级市场省间层做资源大范围优化省内层做交割和考核。这里顺便说一句两级结构不是说上层高级、下层低级而是分工不同。上层负责把全社会成本压到最低下层负责把责任和利益分到每个主体头上。所以建模时两层的目标函数和约束长得完全不一样理解这一点对后面写代码很重要。1.2 消纳责任权重到底是什么消纳责任权重通俗讲就是给用电方定一个绿色用电的下限比例。假设一个售电公司年用电量1000万度被分配的消纳责任权重是20%那它就要保证这1000万度电里有200万度来自可再生能源。这里可以用一个生活类比来帮助理解有点像企业安排残疾人就业的规定——用人规模到一定数量就必须按比例录用特定人员比例不达标要么补齐、要么交钱。绿证就是这个交钱的通道。在建模的时候权重不会直接罚钱而是通过两类机制成本化。第一类是绿电交易形成溢价绿电比常规电贵买了绿电等于付出了额外成本第二类是绿证交易和惩罚机制指标不够就要买绿证绿证价格就成了一个影响决策的关键变量。这两类信号最终都会落到售电公司的购电成本函数里所以模型里权重是用约束写的但效果是靠成本体现的。模型里权重通常要写两类约束全网层面的整体消纳约束和每个售电公司个体的责任约束。整体约束保证系统总体完成消纳目标个体约束保证目标不是被少数主体背走而是公平分摊到每个市场成员。两级市场里整体约束放在第一级个体约束放下层或结算阶段这个分工千万别搞反否则容易出现全网达标但某个售电公司严重不达标的怪结果。1.3 两级怎么交互先出清、后分配、再结算我实际跑通的基础版本是顺序出清框架。第一级由交易中心做全系统优化出清决策各火电出力和可再生能源出力约束包括机组上下限、可再生预测上限和整体消纳权重。出清完成后会得到一个系统边际电价也就是功率平衡约束对应的拉格朗日乘子这个价格是下层结算的基准也是整个代码里最容易写错的地方。第二级是每个售电公司拿到自己的负荷需求和在总可再生出力中的份额之后分别核算常规购电费用、绿电费用和绿证缺口成本。看起来像账务处理但因为可再生能源出力总额本身是上层决策的结果所以下层受上层的配额影响非常大。如果某个售电公司分到的可再生电量少于自己应承担的责任它就必须去买绿证如果绿证价格很高它也可以选择多买一点高溢价的绿电来替代绿证这就形成真正的购电结构优化。如果想让两级真正打起来也就是让下层的购电结构反过来影响上层出清那就要用KKT条件把下层优化问题转成上层的一个约束形成MPEC模型。这个我放在后面的进阶部分讲基础版本先把顺序框架跑明白已经能把很多配额机制的公平性、效率性问题看得清清楚楚。2. 数学模型两层各自优化什么、怎么耦合2.1 第一级出清目标函数与约束第一级模型写成标准优化问题很清晰。决策变量有两类火电机组的出力P_i以及每个可再生能源电站风电场、光伏电站的出力Pw_r。目标函数是最小化系统总运行成本火电用二次成本函数拟合可再生能源发电成本设成低价或者固定成本min Σ_i (a_i * P_i^2 b_i * P_i c_i) Σ_r (w_r * Pw_r)约束条件包括功率平衡 Σ_i P_i Σ_r Pw_r D_total [λ] 火电出力上下限 P_i_min ≤ P_i ≤ P_i_max 可再生预测上限 0 ≤ Pw_r ≤ FW_r 整体消纳约束 Σ_r Pw_r ≥ α_total * D_total这里面要解释两个细节。第一为什么可再生成本写得很低在现货市场出清逻辑里成本越低越优先可再生故意设低价能保证它尽量多消纳相当于模拟优先发电政策。但真正让可再生达到目标的不是这个低价而是那条整体消纳约束。就算可再生成本不是全场最低权重约束也会强制出力升到某个下限这和现实中保量保价的机制是呼应的。第二功率平衡约束旁边的[λ]就是系统边际电价的来源它是这个等式约束对偶乘子。如果可再生出力上升导致火电被替换λ会下降而下层结算全都要根据λ来走所以这一步算得准不准直接影响整个模型结果。如果火电成本用二次函数整个上层就是一个二次约束二次规划Cplex可以直接解。但有些版本里为了跟混合整数机组组合配合会把成本曲线分段线性化用binvar做分段选择那问题就变成MILP。两种我都试过算小算例差别不大但如果后面要加机组启停建议一开始就用分段线性化省得组合规模大了Cplex算不动。2.2 可再生能源出力怎么分给每个售电公司上层出清得到可再生能源出力总额后怎么分配给各个售电公司是整个模型里面机制设计味道最浓的一步。基础版我用的是按负荷占比分配y_m (D_m / D_total) * Σ_r Pw_r好处是无歧视、公平、好实现代码里就是一行矩阵运算。缺点也很明显没有考虑不同售电公司之间消纳责任权重的高低差异。比如甲和乙两家售电公司负荷一样分到的绿电也一样多但甲权重15%、乙权重30%那么乙很轻松、甲还差一大截而乙可能是超额完成超额部分又不能直接转让给甲这就造成配额资源浪费。进阶版可以改成按责任缺口比例分配先初步分一轮然后看哪些售电公司分到的量超过了自己的责任把超额部分收回来按缺口大小补给还差得多的主体。这样做能显著降低整个系统的绿证采购总量也更贴近实际市场中绿电溢价和绿证价格互相博弈的结果。再进一步就是干脆把分配也当成决策变量让每个售电公司自己申报、自己优化底层通过价格信号达到均衡——这是后面KKT双层要干的事。2.3 第二级售电公司购电与绿证缺口核算每个售电公司m的购电结构由三部分构成常规电量、可再生能源电量、绿证。如果按基础版固定分配量y_m来算目标函数就变成min λ * x_m p_ren * y_m p_cert * cert_m约束条件x_m y_m D_m cert_m ≥ α_m * D_m - y_m cert_m ≥ 0如果y_m是固定的那这一层本质上只是核算没有真正的优化空间。想让第二级有优化味道就把y_m从固定值改成决策变量系统出清只给出可再生可用量上限Y_max_m售电公司在常规电价λ、绿电价格p_ren、绿证价格p_cert三者相对关系下决定买多少绿电、买多少绿证。这里有一个非常实际的逻辑当p_ren比p_cert便宜的时候售电公司肯定倾向于多买绿电来完成任务哪怕绿电超过自己责任权重也不会觉得亏因为省下了绿证钱反过来如果绿证很便宜那大家可能就都去买绿证顶格完成任务后就不再买绿电。这种博弈行为在第一级出清完全看不到只有把第二级也做成优化问题才能体现出来。所以我的建议是基础版可以用固定分配但代码结构要留出变量化的余地后面升级MPEC就不用推翻重来。2.4 如果做成真正双层KKT和MPEC思路严格的双层模型长这样上层决定发电计划下层每个售电公司在给定价格下决定购电组合。下层要写成优化问题上层在决策时要把下层的反应函数考虑进来。把下层LP用KKT条件替换整个问题就等价转成一个带互补约束的单层问题也就是MPEC。KKT条件包括四块稳定性条件拉格朗日函数对变量求导等于0、原始可行性、对偶可行性、互补松弛。前三个都是线性约束麻烦的是互补松弛形式上长这样0 ≤ cert_m ⊥ (p_cert - μ_m) ≥ 0互补松弛Cplex不能直接处理需要引入一个大M整数变量把它线性化。对每对互补约束加一个0-1变量z约束变成λ ≥ 0, g(x) ≥ 0 λ ≤ M * z g(x) ≤ M * (1 - z)这样MPEC就变成混合整数线性规划Cplex可解。不过这个大M取值最坑取太大导致数值病态、解出来全是噪声取太小又把可行域削掉优化直接无解。我的经验是先解一个不加互补约束的松弛版看看对偶乘子的量级大概在多少再把M设成比这个量级大一两个数量级。比如对偶乘子大概在几十M取1000比较稳妥而不是随手写个1e6。3. Matlab Cplex代码实现从环境到核心代码段3.1 环境配置YALMIP和Cplex怎么装、怎么验证这套模型用到了MATLAB加YALMIP加Cplex三个部分安装顺序建议是先装MATLAB再装IBM ILOG CPLEX Optimization Studio最后把YALMIP下载好并加进MATLAB路径。CPLEX装完后要确认它的版本和MATLAB版本兼容比如CPLEX 12.10只支持到R2019a至R2021b的某些版本装好之后如果yalmiptest里CPLEX显示Not found大部分情况是版本不匹配少数情况是没把CPLEX的MATLAB接口路径加对。YALMIP其实只是一个建模层它不负责真正求解而是把模型翻译给Cplex。下载YALMIP之后直接用addpath(genpath(D:\tools\yalmip)); % 改成你的YALMIP目录 savepath;然后在Matlab命令窗口跑一下yalmiptest会列出可用的求解器。这里有一个细节yalmiptest会跑一大堆测试如果只关心Cplex可以用yalmiptest(cplex)。运行的时候建议把Cplex的许可也确认一下社区版有变量和约束规模限制模型大了容易报错如果项目比较大用教育版或者商业版会省心很多。还有一个小坑MATLAB自带的linprog、quadprog会被YALMIP默认识别如果没装CplexYALMIP也会自动退回到内点法求解结果可能也能出来但速度慢不少而且很多MILP问题直接没法解。所以写代码时最好在sdpsettings里面明确指定solver,cplex万一Cplex掉线至少能立刻发现而不是默默用别的求解器算出个不太好使的结果。3.2 算例数据准备一组能直接跑通的小系统为了让下面代码不悬空我准备了一个小算例4台火电机组、2个风电场加1个光伏电站、3家售电公司总负荷600MW。这个规模Cplex社区版肯定跑得动而且结果能手工验算。火电机组参数如下机组Pmin(MW)Pmax(MW)a(元/MW^2)b(元/MW)c(元)G1501500.02020100G2401200.0152580G