ARTICLE DETAIL

资讯详情

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

独立储能参与现货与调频市场的协调出清机制及Matlab实现

独立储能参与现货与调频市场的协调出清机制及Matlab实现 1. 项目概述与核心需求解析1.1 独立储能同时参与两类市场的现实动机这两年国内电力现货市场试点铺开的速度比我预想中快得多。山西、山东、广东这几个省接连把独立储能推到了真正的市场环境下运行独立储能电站不再只是签个容量租赁合同吃固定收益而是被允许以独立市场主体身份参与现货电能量交易和调频辅助服务交易。这里面有一个绕不开的问题储能电站的功率和能量都是有限的你拿去现货市场低买高卖就不能同时把同一部分容量留在调频市场上赚调频里程补偿反过来你把容量都留给调频现货市场的峰谷价差收益又吃不到。两笔钱都想要但容量只有一个这就是独立储能参与市场时最内核的资源配置问题。我在做这个方向之前看过不少项目采用“先跑完现货出清再把剩余容量报给调频”的两段式做法。这种思路最大的问题在于现货市场出清时完全不知道调频市场的容量需求储能如果全部参与现货套利到了实时运行阶段AGC下发调节指令系统却发现储能根本没有预留上调空间只能眼睁睁看着机会成本变成考核费用。反过来如果储能提前留出一大块调频容量现货市场里该赚的峰谷价差又浪费了。所以我在Matlab里实现的这套协调出清机制本质上是把现货电能量市场出清和调频辅助服务市场出清放进了同一个优化问题里把储能容量同时作为两种商品的“生产能力”来分配用一组统一约束把两个市场的结果同时算出来。这样算出来的结果才是储能可执行、系统也愿意接受的均衡出清方案。这个项目适合谁参考一种是正在做储能电站运营策略研究的工程师或研究生另一种是做现货市场出清算法开发的技术人员。前者能从中理解市场机制是怎么和储能物理特性耦合的后者能直接借鉴我把电力市场出清模型落到MatlabYALMIP的完整套路。1.2 现货电能量市场与调频辅助服务市场的耦合逻辑要理解协调机制先要把这两个市场的“耦合点”看清楚。现货电能量市场解决的核心问题是未来15分钟或1小时系统需要哪些机组发多少电储能应该充电还是放电最终形成分时节点电价。调频辅助服务市场解决的核心问题是系统频率出现小扰动时谁能在几秒内响应AGC指令向上或向下调整出力恢复频率稳定。两个市场服务的时间尺度不同但用到的“资源”是同一条储能PCS的功率通道和电池里的电量。从物理约束看储能任意时刻的充电功率、放电功率和调频功率之间必须满足总功率约束。举例来说一个10MW/20MWh的储能电站PCS额定功率10MW如果你在某个时段安排8MW放电参与现货那最多只能剩2MW的调频上调能力。这还只是功率层面的耦合。能量层面的耦合更隐蔽——调频服务里你中标了多少上调容量就意味着如果AGC指令真的发出你得有能力在15分钟内多放出这么多功率对应的电量必须从SOC中扣除。反过来下调频容量意味着你得有空间把多余电量充进电池。这些都不是简单把两个市场结果叠加就能解决的。另一个耦合点是市场出清价格形成机制的联动。现货市场出清时如果储能的大规模充电抬高了某个低谷时段负荷这个时段电价可能被推高如果储能在高峰时段集体放电高峰电价可能被压低。调频市场出清时如果参与调频的储能越多调频价格可能被压到很低的水平。这意味着一个市场的出清结果会影响另一个市场的价格出清如果不放在同一个模型里迭代或联合求解容易得到互相矛盾的“事后不合理”结果。2. 协调出清机制的设计思路与数学建模2.1 为什么不能简单“先现货后调频”顺序出清顺序出清的做法在实际工程里很常见因为实现简单先解现货电能量出清问题得到储能充放电曲线和各节点电价再把剩余容量信息传递给调频市场解调频出清问题得到调频中标量和价格。这种两阶段方法用在火电机组上问题不大因为火电机组的调频容量一般只占额定出力的一小部分而且能量市场和调频市场的耦合相对弱。但储能不一样。储能是“单机容量小、调节速度快、爬坡能力几乎无限”的特殊资源它参与调频的容量占比常常可以到50%以上。一个10MW储能如果完全只做调频效果顶得上好几台火电机组的AGC响应。正是因为这个“强耦合”特性顺序出清常常导致两种极端结果第一种现货市场出清时储能被配置了满功率放电或充电留给调频的容量几乎为零。这种出清方案在系统频率超调时完全没有储能可以调用只能调度其他慢速机组系统调频性能大打折扣。第二种储能为了拿到高频次调频中标报一个很低的调频里程价格结果现货市场里该充的不充该放的不放损失了可能比调频收入更高的峰谷套利空间。我在实际调试模型时还发现一个更现实的坑顺序出清如果先解调频后解现货那现货市场出清时的储能SOC初始条件完全依赖调频中标结果中的“预调用能量”这个量依赖于系统实时频率偏差的预测根本不准算出来的现货结果基本没法落地执行。所以把两个市场的决策变量放进同一个优化问题里联合求解才是解决储能“多市场容量分身术”的正确路径。2.2 目标函数构建从社会福利到分段报价成本联合出清的目标函数我采用的是最小化系统总购电成本。这个目标在电力市场出清中是比较通用且容易实现的它能直接兼容节点边际电价LMP的出清框架。具体来说目标函数包括三部分第一现货电能量市场的购电成本。系统中所有发电机组按照分段报价曲线出清成本是各段报价乘以对应的中标电量之和。储能充电时视作负荷不产生能量购电成本但储能充电会贡献负荷导致其他机组多发电这部分成本会间接反映在总成本里。储能放电时视作发电资源按报价结算。第二调频辅助服务市场的容量成本和里程成本。储能在调频市场里的报价可以拆成两部分一是容量补偿单位是元/MW对应你承诺提供多少调频容量二是里程补偿单位是元/MW对应AGC反复调节过程中你实际完成的调节里程。火电机组报价往往容量成本高、里程成本低而储能正好反过来容量成本可以报很低里程成本才是真正的利润来源。这个报价结构差异正是协调出清中储能优先被选中参与调频的关键。第三为了鼓励储能合理分配容量我在目标函数中加入了储能在现货市场中的机会成本约束项。这个不是财务成本而是在优化过程中通过调频容量约束和SOC约束间接体现的。用数学形式表达目标函数就是min Σ_t Σ_g [ C_g(P_g,t) ] Σ_t [ C_reg_vol(R_reg,t) C_reg_mile(M_reg,t) ]其中C_g是一般机组的分段线性报价函数C_reg_vol是调频容量报价函数C_reg_mile是调频里程报价函数。P_g,t是机组出力R_reg,t是调频容量中标量M_reg,t是调频里程预测量。储能作为特殊参与者在目标函数里没有额外增加项它的报价体现在各时段充放电报价和调频报价里同样参与目标函数最小化。2.3 约束条件能量平衡、储能运行与调频容量联动我把约束条件拆成三大类每一类都是我在实际建模中反复踩坑后总结出来的必要项。第一类系统运行约束。最重要的是功率平衡约束在每个时段t系统总发电加储能放电功率等于系统总负荷加储能充电功率加网络损耗简单算例里可以忽略损耗。网络约束如果做单节点模型可以不加但如果要研究节点电价差异需要加入直流潮流方程和线路容量约束。这里提醒一下加了网络约束之后模型的求解规模会指数级增长我建议第一版先跑单节点模型把协调机制逻辑验证通了再加网络。第二类储能运行约束。SOC递推方程是最核心的SOC_t1 SOC_t η_c * P_ch,t * Δt - P_dis,t * Δt / η_d。这个方程看似简单但在调频场景里要拆成“计划充放电”和“调频响应充放电”两个分量。我的做法是把调频中标容量的一部分比例比如20%作为预期的能量扰动项加入SOC递推这样能避免中标调频容量后实际执行时SOC越界。功率约束方面充放电功率要分别与充电状态和放电状态绑定不能同时充电又放电。调频上调容量和放电功率之和不超过额定功率调频下调容量和充电功率之和也不超过额定功率。这一组约束是协调机制的灵魂所在。第三类调频容量耦合约束。调频上调容量R_up_t和调频下调容量R_down_t在时段t内要满足备用约束同时这两个参数直接决定了储能可用功率的上下边界。我用的方式是0 ≤ P_dis_t R_up_t ≤ P_max 0 ≤ P_ch_t R_down_t ≤ P_max这组约束数学上非常简单但它把现货出清功率和调频容量分配紧紧绑在一起是我整个协调机制的核心。第三类中还需要一个“能量可用性”约束保证即使发生最坏情况AGC连续向上指令储能也有足够的电量响应。这个可以通过约束SOC下限和R_up的联合关系实现。通常做法是加入一个不低于5%SOC的动态安全边界。3. Matlab代码实现全流程解析3.1 算例基础数据与参数设定我建议第一版算例选择一个小规模系统比如IEEE 6节点系统或自己搭一个3机2负荷系统时间尺度取24个时段每时段1小时。储能用10MW/20MWh配置充放电效率都是95%初始SOC设为50%。系统负荷数据可以用实际历史数据也可以自己构造一个有“早晚双峰”特征的负荷曲线。发电机组参数包括最大最小出力、爬坡速率、报价分段数和各段价格。我这里用一个简化机组数据表参数G1G2G3最大出力(MW)200150100最小出力(MW)503020爬坡速率(MW/h)604030第1段容量(MW)806040第1段价格(元/MWh)200300420第2段容量(MW)705035第2段价格(元/MWh)280360480第3段容量(MW)504025第3段价格(元/MWh)360420540调频需求曲线可以设为每时段系统需要不少于10MW的调频容量调频容量出清价由市场决定。储能调频报价设为容量报价50元/MW里程报价300元/MW预计调频里程转化系数为5即每MW调频容量对应5MW里程预期。以上参数写在一个Excel表格里或者直接以Matlab结构体写在脚本里都行。我习惯用结构体因为后续做灵敏度分析时改参数最方便。3.2 基于YALMIP的优化建模与求解Matlab里做这种线性规划或混合整数线性规划问题我推荐用YALMIP工具箱加Gurobi或Cplex求解器。YALMIP的好处是建模语法和数学公式几乎一一对应调试起来非常直观不必手动拼标准LP矩阵。这里给出核心建模代码。% 定义决策变量 P_g sdpvar(n_g, T, full); % 各机组出力 P_ch sdpvar(1, T, full); % 储能充电功率 P_dis sdpvar(1, T, full); % 储能放电功率 R_up sdpvar(1, T, full); % 调频上调容量 R_down sdpvar(1, T, full); % 调频下调容量 SOC sdpvar(1, T1, full); % 储能荷电状态 on_g binvar(n_g, T, full); % 机组启停状态 % 定义约束集合 Constraints []; % 功率平衡约束 for t 1:T Constraints [Constraints, sum(P_g(:,t)) P_dis(t) Load(t) P_ch(t)]; end % 机组出力上下限和分段报价成本简化版 Cost 0; for g 1:n_g for t 1:T Constraints [Constraints, ... P_min(g) * on_g(g,t) P_g(g,t) P_max(g) * on_g(g,t)]; Constraints [Constraints, ... -Ramp_down(g) P_g(g,t1) - P_g(g,t) Ramp_up(g)]; Cost Cost alpha(g,1) * P_g(g,t) alpha(g,2); end end % 储能运行约束 P_max_sto 10; eta 0.95; for t 1:T % 充放电互斥和功率上下限 Constraints [Constraints, 0 P_ch(t) P_max_sto]; Constraints [Constraints, 0 P_dis(t) P_max_sto]; Constraints [Constraints, P_ch(t) P_dis(t) P_max_sto]; % 调频容量与充放电功率联合约束 Constraints [Constraints, P_dis(t) R_up(t) P_max_sto]; Constraints [Constraints, P_ch(t) R_down(t) P_max_sto]; Constraints [Constraints, 0 R_up(t) P_max_sto]; Constraints [Constraints, 0 R_down(t) P_max_sto]; % SOC递推 Constraints [Constraints, SOC(t1) SOC(t) ... (eta * P_ch(t) - P_dis(t) / eta) * delta_t]; Constraints [Constraints, 0.1 SOC(t1) 0.9]; end Constraints [Constraints, SOC(1) 0.5]; Constraints [Constraints, SOC(T1) 0.5]; % 日循环约束 % 调频需求约束 for t 1:T Constraints [Constraints, R_up(t) R_g(t) Reg_demand(t)]; end这段代码是一个简化的骨架实际运行还需要补充分段报价的线性化处理。分段报价成本函数我建议用YALMIP内置的value函数结合辅助变量做分段线性化或者直接用implies工具处理。注意如果机组启停状态参与建模这个问题是MILP必须用Gurobi/Cplex这类商业求解器才能高效求解如果只做经济调度不涉及启停可以全部变量连续化LP求解就够速度会快很多。3.3 指标提取、结果整理与可视化求完解之后最容易被忽略的一步是指标的提取和口径统一。我用几个核心指标来评估协调出清效果收益端储能的总收益等于现货放电收益减充电成本加上调频容量收益和调频里程收益。其中调频里程收益的计算要特别注意里程补偿是“实际调节了多少MW”来结算的和容量是两个概念。在出清模型里我用预计里程转化系数来估算但在结果分析时应该单独列出“容量收益”和“里程收益”两项方便对比储能到底是靠现货套利赚得多还是靠调频赚得多。系统侧指标我关注机组总发电成本、节点电价曲线、调频出清价格曲线。节点电价可以直接用YALMIP求解器的对偶变量提取dual(Constraints(1,t))就是功率平衡约束的影子价格等价于节点电价。可视化方面我通常画三张图第一张是储能充放电功率、调频容量中标量和SOC的24小时时序曲线三者在同一张图里最直观第二张是系统各机组出力和负荷曲线验证功率平衡约束是否满足第三张是电价对比图把现货电价和调频容量价格放到同一坐标系下看联动关系。画图代码就是常规的plot和stairs不详细展开了。4. 典型算例仿真与结果分析4.1 算例场景设计与参数配置为了验证协调机制到底“协调”在哪儿我设计了三组对比场景场景一纯现货模式。储能只参与现货电能量市场调频需求完全由常规机组提供。这个场景作为基准用来测算储能在纯套利模式下的盈利能力。场景二纯调频模式。储能不参与现货充放电全部容量用于调频辅助服务标定储能只做调频的收益上限。场景三协调出清模式。储能同时参与两个市场出清模型里加入我上面写的那组功率联合约束和SOC安全边界让求解器自行决定每个时段储能怎么分配容量。三组场景都用同一组负荷数据、同一组机组报价、同一组调频需求数据。这样做对比才是干净的单因素对照否则计算结果没法解释差异来源。负荷曲线我构造的是典型夏季工作日曲线早高峰9:00-12:00晚高峰18:00-21:00凌晨低谷0:00-5:00。峰值负荷350MW谷值负荷200MW。这个负荷形状决定了峰谷价差空间也决定储能现货套利的机会窗口。4.2 协调出清与独立出清的结果对比跑完三组场景差异非常明显。纯现货模式下储能凌晨充满上午高峰放一部分下午再充满晚高峰放完日内循环次数1.5次左右。这种方式下储能收益全部来自峰谷价差在单时段价差超过0.4元/kWh的市场里能做到日收益8千到1万元10MW/20MWh算例。纯调频模式下储能全天候保持SOC在50%附近充放电双向调频不参与能量套利。收益主要来自调频里程日收益大约1.2万到1.5万元收益水平比纯现货高但前提是系统调频需求稳定。这个对比说明了一个很现实的问题储能做调频的单价远高于现货套利但调频市场的容量空间有限大容量储能全部压到调频上是不现实的。协调模式下求解器的行为很有意思。在晚高峰时段现货市场价格高储能把大部分容量用于放电套利调频中标容量压到了最小在凌晨低谷时段储能一边以低电价充电一边预留一部分下调容量做调频因为这时的机会成本很低——即使被AGC调用在低谷时段充电电价也低不亏在早高峰刚结束的过渡时段储能会以一个渐进的方式从放电状态切到调频状态避免出现“刚放完电SOC过低导致调频容量不足”的尴尬局面。最终日收益比纯现货高约35%比纯调频低但是总收益最大而且系统调频容量富余度始终满足要求。这个结果说明协调出清并不是简单在两种模式之间取平均而是根据实时价格信号动态调整两个市场的容量占比实现了比固定分配方式更高的综合收益。4.3 储能容量分配比的灵敏度变化我还做了一组灵敏度测试把储能额定功率从5MW逐步提高到20MW观察收益结构的变化。核心发现有两个第一随功率规模增大调频容量收益占比先升后降。小规模时储能容量较少系统调频需求有限储能优先把容量留给调频赚高价规模增大后调频市场饱和储能开始更多参与现货套利。这个曲线说明协调出清机制本身具备容量配置的自适应性。第二当储能规模超过系统调频需求的两倍以上储能报价策略对收益的影响开始超过协调机制本身的影响。这个时候需要重新考虑储能是否需要分段报价或设置最小运行时长约束防止求解器把储能当成了“既能无限充电又能无限放电”的虚拟理想电池。灵敏度分析曲线用Matlab画很简单就是把储能额定功率作为循环变量每次重新求解模型记录收益指标最后统一绘制。调参时建议每次只改一个参数改完先看SOC曲线和调频容量曲线能不能解释再看收益数字不要一上来就追求好看的收益先保证物理上的合理性。5. 常见问题与实操避坑指南5.1 模型无解与约束冲突排查这个模型的约束数量虽然在优化问题里不算多但因为同时包含充放电互斥、调频容量联合约束、SOC日循环约束很容易出现无解。我调试过程中被坑过好几种情况第一种是SOC初始值与日循环约束冲突。设了初始SOC为0.9又要日末SOC回到0.9但调频容量要求SOC下限不低于0.1如果储能模型允许在任意时段把SOC干到0.1以下还不够模型直接报infeasible。解决办法是先跑一次不带日循环约束的版本看储能SOC自然演化轨迹再决定要不要加严格的日循环约束还是改成SOC终点不低于初始值的松约束。第二种是调频需求设置过低或过高。调频需求如果低于储能的最低调频容量投标门槛联合出清里优化器为了追求整体经济性可能选择完全不使用储能调频这时候调频容量完全由火电承担储能全部精力做现货结果看起来像“协调失灵”实际上是需求信号的问题。第三种是功率联合约束“过紧”。我早期版本写过P_dis R_up P_ch R_down P_max这种把所有加在一起的约束看起来好像更严格更安全但实际上限制了储能同时充电和提供上调容量的能力导致模型过于保守出清结果中储能调频容量几乎为0。正确做法应该是充电与下调频绑定、放电与上调频绑定分开约束这个在我上面的代码里已经体现。排查无解问题时我的标准操作是先逐个注释约束组定位是哪个约束导致不可行然后再把硬约束改成带惩罚项的软约束对比结果差异。YALMIP还提供了一个sol.problem变量等于1或2代表不可行或无界配合sol.info可以看到更详细的报错原因。5.2 求解器选型与求解效率同样是线性出清问题求解器差异巨大。纯LP模型Matlab自带的linprog对三机24时段的小规模问题能跑但比较慢对大算例几乎不可用。我强烈建议从项目一开始就接入Gurobi或Cplex学术用途可以向官方申请免费license工程用途也值得采购性能差距不是一点半点。MILP场景下比如我考虑机组启停优化时Gurobi和Cplex的branch-and-cut算法能处理几百个整数变量的规模而纯intlinprog经常在可接受时间内跑不出来。另外YALMIP的语法里可以指定求解器options sdpsettings(solver,gurobi)这一行代码能避免很多默认求解器兼容性问题。求解效率优化的一个实用技巧把分段报价函数预先线性化而不是在优化问题里用implies让求解器自动处理。手动线性化会增加变量数但大大缩短单次求解时间尤其是要做几十组灵敏度分析的时候这点差异非常明显。5.3 数据处理与单位统一的细节电力市场出清模型最容易出错的地方不在算法而在单位。我遇到过最典型的问题是把容量单位MW和能量单位MWh混用。在SOC递推方程里充电功率P_ch单位是MW乘以时间尺度delta_t小时才是能量增量MWh和SOC单位是MWh或%运算时一定要先统一。我在代码里SOC直接用MWh存储0.1到0.9的上下限就写成0.1E_max到0.9E_max而不是写成0.1到0.9的百分比数。这样在调频里程约束里需要反算可用时间时单位才不会出问题。另一个细节是报价曲线的价格单位。国内现货市场价格用的元/MWh调频市场里容量价格经常用元/MW里程价格用元/MW。这三个价格单位不一样报价数据录入Excel的时候要给每列注明单位读取之后统一转换成目标函数里同一个数量纲否则优化结果在数学上是错的但表面上看着还挺合理特别迷惑人。我自己的做法是在脚本开头写一个unit conversion小节把元/MWh, 元/MW, 元/MW里程全部换算到“元”这个统一的货币单位然后在每个决策变量的定义注释里标注单位这样不管是谁接手代码都不会搞混。6. 扩展方向与个人实操体会这个协调出清模型后续值得扩展的方向我实际想了想至少有三个比较有价值。第一个是把单时段确定性出清扩展成多场景随机优化因为现货价格和调频需求都有很强的不确定性储能决策必须考虑预测误差否则出清结果在实时运行层面偏差很大。第二个是把SOC安全边界从固定值改成动态计算可以根据后续时段的边际电价预测动态调整安全边界的高宽深挖储能“跨时段转移”的价值空间。第三个是加入储能的寿命衰减模型把电池循环次数、DoD深度作为成本项写入目标函数避免优化结果为了追求短期收益把电池循环寿命提前耗尽。我在实际测试这个模型时跟团队讨论最多的一个问题就是“调频容量需求到底应该怎么预测”。很多研究直接用固定值或者用历史均值但实际调频需求是随负荷水平和新能源出力波动的尤其光伏渗透率高的地区晴朗天气和阴雨天气的调频需求能差好几倍。后来我们改成用滚动更新的方式每个时段根据最新预测刷新后续所有时段的调频需求曲线再重新求解出清模型效果比固定需求好很多。这个思路你也可以直接在Matlab里用循环实现每次间隔30分钟或1小时重新调用一次求解器。最后再分享一个我调试时的小技巧第一次跑通模型后不要急着做结果分析和写报告。先画一张储能SOC曲线看它是否平滑、是否存在“莫名跳变”。如果SOC在某个时段出现不合理跳变几乎可以断定是约束条件写漏了或单位转换错了。SOC曲线是验证储能模型物理合理性的第一道门槛这一步检查通过之前任何收益指标都没有意义。
返回列表