ARTICLE DETAIL

资讯详情

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

储能参与调峰配置建模与Matlab实现及经济性分析

储能参与调峰配置建模与Matlab实现及经济性分析 去年帮课题组复现一篇EI会议论文里的“储能参与调峰”配置模型前后折腾了差不多两周。中间踩了不少坑但也把整个问题的数学建模、Matlab实现路径和经济性分析口径理顺了。这篇博文就围绕这个主题展开——储能系统参与调峰的配置方案怎么建模、经济性指标怎么算、Matlab代码怎么落地给准备复现这类论文或者做实操项目的朋友一条能直接走通的路线。调峰问题听起来抽象其实落在具体场景里很好理解电网负荷有峰谷差峰时电不够用、谷时电过多。传统火电调节能力有限而且低谷时段硬压机组出力既不安全也不经济。储能的价值就在这——谷段充电、峰段放电把能量在时间轴上搬一搬从而减少系统对新建调峰机组的依赖。EI论文里最常见的写法就是在给定的负荷曲线上求解“装多大容量、配多大功率、怎么充放电”能使综合成本最小或收益最大然后在Matlab里用优化算法求出来。这篇文章不会只给一个能跑的代码片段我会把建模时每个公式背后的想法、求解时容易出错的细节、以及经济性分析里真正影响结论的参数口径都拆开讲毕竟复现论文最要命的从来不是写代码而是模型没吃透。1. 参与调峰的储能配置问题到底在算什么1.1 从“削峰填谷”到量化调峰需求先明确一个基本场景。电网侧或者用户侧的负荷曲线大致是早晚两个高峰、深夜一个低谷。储能系统参与调峰本质是对负荷曲线做时移低谷时段系统有富余电力储能以较低价格充电高峰时段系统供电紧张储能放电支撑。这样系统整体需要应对的“净峰谷差”就变小了对火电机组、对输电通道的压力都会下降。建模前必须把“调峰需求”这个词转化成可计算的指标。行业内常用的是峰谷差率公式为调峰深度 (最大负荷 - 最小负荷) / 最大负荷加入储能后希望这个值降到某个阈值以下或者直接以“最大化削峰量 最小化电池成本”为目标。很多论文里会直接写“以一天24小时负荷曲线为输入优化储能充放电功率”这句话看着简单实际做起来要处理几个前置条件使用哪类负荷曲线、峰谷时段怎么划分、负荷数据是单日还是全年8760小时。不同时间粒度得到的储能容量结论可能差出30%以上这一点后文会专门展开。1.2 配置方案的决策变量不只是“容量和功率”初次接触这类问题容易以为储能配置就是解两个数额定容量kWh和额定功率kW。但真正参与调峰光有这两个数是没法运行系统的。模型中实际要确定的包括额定功率储能能同时充电或放电的最大功率单位kW或MW额定容量储能能存储的电能总量单位kWh或MWh逐时充放电功率序列也就是调度策略每个时刻充多少、放多少、是否待机SOC荷电状态动态电池在每个时刻的剩余电量比例充放电状态标志严格说绝大多数电池不能同时充电和放电需要引入0-1变量控制。换句话说这是一个“配置变量 运行策略变量”同时求解的优化问题。论文里常说的“联合优化”指的就是这两层变量不是先定容量后算策略而是在同一个模型里一起解出来。1.3 为什么不能只做“容量优化”举个反例。如果只给储能定容量然后按一个固定规则“谷段满充、峰段满放”去估算收益遇到负荷曲线陡、峰谷时间不规则的场景结果会严重失真。比如某些地区午间有光伏出力负荷低谷出现在中午而不是凌晨固定充放策略会算出一堆“放了却没地方送”的冗余容量。所以更可靠的思路是把容量的取值用连续变量表达同时让每个时刻的充放电功率由优化算法根据负荷曲线、电价曲线和系统约束自动挑选。这就是一个标准的多时段优化调度问题容量变量相当于给整个调度问题套了一层“外衣”。在复现代码时最稳妥的建模方式是把它写成单层混合整数线性规划MILP或者用一个双层结构外层搜容量内层算调度。后文我会分别说明两条路的写法和适用场景。2. 优化建模目标函数、约束条件与线性化细节2.1 目标函数总成本最小还是收益最大这类文章的目标函数大致有两种写法复现时一定先看清论文用的是哪一种否则结果对不上。常见写法一以系统综合成本最小为目标。以一天为单位目标函数为min C C_inv_daily C_om C_purchase C_penalty其中C_inv_daily储能投资成本的等年值折算到每天的值与额定容量和额定功率成正比C_om日运行维护成本C_purchase系统从电网购电的成本低谷充电会抬高这个值高峰放电会降低这个值C_penalty系统未满足调峰要求时的惩罚项或者说是调峰不足的代价。常见写法二以储能投资方收益最大为目标max R R_peak_shaving R_price_arbitrage - C_om - C_inv_daily两种写法在数学结构上可以等价但当论文里只给了“净收益”而没给“总成本”时复现者很容易把符号弄反。我个人更偏好用成本最小作为主目标因为调峰的“硬约束”更方便加惩罚项且和火电调峰的表述习惯一致。2.2 核心约束条件SOC递推、功率限制、调峰率储能调度模型的约束条件归纳起来是这几类SOC递推方程能量平衡约束SOC(t1) SOC(t) (P_ch(t) * eta_ch - P_dis(t) / eta_dis) * dt / Q_rated其中P_ch为充电功率P_dis为放电功率eta_ch和eta_dis为充放电效率Q_rated为电池额定容量dt为时间步长。这个公式是所有储能模型的骨架漏一项就全错。功率上下限约束0 P_ch(t) P_rated * u_ch(t) 0 P_dis(t) P_rated * u_dis(t) u_ch(t) u_dis(t) 1u_ch和u_dis是0-1变量确保同一时刻电池只有一个工作状态。如果论文里说“允许同时充放电”那通常是为了简化某个外特性仿真工程上不常见。SOC幅值约束SOC_min SOC(t) SOC_max一般取SOC_min 0.1、SOC_max 0.9但有些论文会把下限设为0这会影响电池寿命模型。建议先按论文参数来再做一个“SOC下限敏感性分析”。调峰率约束调峰约束的定义必须仔细看。如果论文要求“配置储能后系统最大负荷不超过某个限值”那需要额外引入辅助变量M_max和M_min表示储能接入后的净负荷极值写成Load(t) - P_dis(t) P_ch(t) M_max Load(t) - P_dis(t) P_ch(t) M_min然后在目标函数里对M_max - M_min做惩罚或者约束其大小。这一步尤其容易出错很多代码只约束了逐时功率忘了约束净负荷的极值结果储能SOC曲线上来后系统峰谷差却几乎没有改善。2.3 非线性项怎么处理状态互斥、效率、极值储能模型里有几个非线性来源复现时要用线性化手段处理否则求解器不认。第一个是充放电互斥。上面已经用0-1变量处理了这是MILP的标准操作。如果用的是粒子群这类启发式算法可以不显式建模互斥但要在适应度函数里加惩罚否则会出现同充同放的自循环解。第二个是效率项。SOC递推式中P_ch * eta_ch和P_dis / eta_dis都是线性的没有问题。但如果论文用“充放电效率平方根”表达那其实是把电池内阻模型简化成了等效效率本质还是线性。真正麻烦的是某些论文把效率建模成SOC的分段函数这会引入额外的整数变量复现成本高。我建议先按常数效率复现如果结果对不上论文再考虑效率曲线。第三个是极大值极小值约束。前面提到的净负荷峰值、谷值在目标函数中会形成max(...) - min(...)形式。线性化方法就是引入辅助变量加一组不等式也就是2.2里的M_max和M_min然后用目标函数系数促使它取到真实极值。这一步非常关键很多复现代码跑到后面数值发散都是因为极值辅助变量没加“推逼”系数导致两个自由变量乱跳。3. Matlab代码实现路径从数据准备到求解器选择3.1 数据准备负荷曲线、分时电价、储能参数建模之前先把输入数据理顺。我一般用结构体统一存参数这样后面做敏感性分析不需要到处改代码param.dt 1; % 时间步长1小时 param.horizon 24; % 优化时段数 param.Load [800 760 710 ...]; % 24h负荷曲线单位kW param.price_peak 1.0; % 峰时电价元/kWh param.price_valley 0.3; % 谷时电价元/kWh param.Q_rated 600; % 额定容量kWh param.P_rated 150; % 额定功率kW param.eta_ch 0.95; % 充电效率 param.eta_dis 0.95; % 放电效率 param.SOC_min 0.1; param.SOC_max 0.9; param.SOC_init 0.2;注意SOC_init不要随便设很多复现结果初始目标值异常就是因为初值设了0.5但论文用的是0.2或者要求运行周期内始末SOC相等。提前看论文的边界条件说明比事后猜高效得多。3.2 基于YALMIP CPLEX/Gurobi的标准MILP写法Matlab里最顺手的建模工具是YALMIP配合CPLEX或Gurobi求解MILP。以一天24时段、单台储能的简化问题为例核心代码框架如下% 决策变量 P_ch sdpvar(param.horizon, 1); % 充电功率 P_dis sdpvar(param.horizon, 1); % 放电功率 SOC sdpvar(param.horizon, 1); % 荷电状态 u_ch binvar(param.horizon, 1); % 充电状态 u_dis binvar(param.horizon, 1); % 放电状态 Constraints []; % SOC递推 SOC(1) param.SOC_init (P_ch(1)*param.eta_ch - P_dis(1)/param.eta_dis) / param.Q_rated; for t 2:param.horizon Constraints [Constraints, ... SOC(t) SOC(t-1) (P_ch(t)*param.eta_ch - P_dis(t)/param.eta_dis) / param.Q_rated]; end % 功率上下限与互斥 Constraints [Constraints, ... 0 P_ch param.P_rated * u_ch, ... 0 P_dis param.P_rated * u_dis, ... u_ch u_dis 1]; % SOC幅值 Constraints [Constraints, ... param.SOC_min SOC param.SOC_max];目标函数先做一个最简单的套利版本objective sum(param.price_peak * P_dis*param.dt) - sum(param.price_valley * P_ch*param.dt); ops sdpsettings(solver, cplex, verbose, 0, showprogress, 0); optimize(Constraints, -objective, ops); % 最大化净收益即最小化负收益求解完取出变量P_ch_opt value(P_ch); P_dis_opt value(P_dis); SOC_opt value(SOC);如果你想看“接入储能后净负荷曲线”再算一个Load_net param.Load - P_dis_opt P_ch_opt;画一下Load_net对比原负荷曲线峰谷差有没有被压下来一眼就能判断模型对不对。3.3 没有商业求解器时粒子群算法的替代写法很多学生手里没有Gurobi授权CPLEX试用期也就半年。这时候可以用Matlab自带的优化工具箱配合粒子群算法PSO做替代。思路是把每个时刻的充放电功率作为粒子位置编码然后在适应度函数里手动写约束惩罚。一个简化的粒子群适应度函数结构大致是function obj storage_fitness(x, param) % x 是充电、放电功率序列拼接的向量 P_ch x(1:param.horizon); P_dis x(param.horizon1:2*param.horizon); % 计算SOC序列 SOC zeros(param.horizon1, 1); SOC(1) param.SOC_init; for t 1:param.horizon SOC(t1) SOC(t) (P_ch(t)*param.eta_ch - P_dis(t)/param.eta_dis) / param.Q_rated; end % 收益 revenue sum(param.price_peak * P_dis) - sum(param.price_valley * P_ch); % 惩罚项 penalty 0; if any(SOC param.SOC_min) || any(SOC param.SOC_max) penalty penalty 1e6 * (sum(max(SOC - param.SOC_max, 0)) sum(max(param.SOC_min - SOC, 0))); end if any(P_ch 0) || any(P_dis 0) penalty penalty 1e6; end obj -(revenue - penalty); end这个方案的优点是“什么都可以往里塞”缺点是解的质量没有保障。粒子群容易陷入局部最优尤其在变量维度高、约束强的情况下可能连续几次跑出来的容量都不一样。所以我的建议是先跑通MILP版本理解约束结构没求解器再用PSO做近似但不要直接拿PSO结果跟EI论文对。3.4 从单日到全年典型日法与8760小时连续仿真的取舍论文里经常出现“典型日负荷曲线”。这个词要仔细审。有的论文用夏季、冬季两个典型日代表全年有的直接用8760小时连续数据。两种做法的代码规模完全不同。典型日法的好处是计算快、便于绘制充放电曲线坏处是忽略负荷的连续性和SOC跨日衔接。如果模型要求“运行周期内始末SOC相等”那么单日模型必须加一个约束Constraints [Constraints, SOC(end) param.SOC_init];而8760小时模型引入的问题是求解时间暴涨、数据清理麻烦。实际复现时我通常先按典型日把模型调通再扩展到大时间尺度验证结论稳健性。这么做调试效率能提升不少。4. 经济性分析的计算口径与参数敏感性4.1 等年值法把一次性投资折算到每一年经济性分析不能只看“一年赚多少电费”因为储能是重资产第一年投入上千万收益是分年回收的。所以标准做法是把总投资折算成等年值成本再和年收益对比。假设储能系统投资成本由容量成本和功率成本两部分组成Cost_inv c_E * Q_rated c_P * P_rated其中c_E是单位容量成本元/kWhc_P是单位功率成本元/kW。这部分是一次性投入一般按储能寿命年限N年、贴现率r折算成每年A Cost_inv * r * (1r)^N / ((1r)^N - 1)这就是等年值系数。很多复现代码里直接拿总投资除以年限结果在贴现率较高时会低估年成本应该用上面的年金公式。参考参数方面以当前行业常见报价为例磷酸铁锂储能系统的单位容量成本在1000~1500元/kWh区间PCS、变压器、土建等按功率折算大约300~600元/kW。这个价格波动大复现时一定要以论文给定的表为准不要用自己查到的市场价格去硬套。下表是我常用的参数口径参考参数典型值说明单位容量成本1000~1500元/kWh含电池、BMS、集装箱等单位功率成本300~600元/kWPCS、变压器、并网设备储能寿命年限10年按电池日历寿命贴现率6%~8%与论文基准收益率一致年运维费率2%~3%按初始投资比例充放电效率90%~95%单程DC侧循环寿命4000~8000次影响是否考虑更换成本4.2 收益项峰谷套利、调峰补偿、备用价值储能参与调峰的收益不能只算峰谷价差。EI论文里常见的收益项有三类复现时逐项核对一是峰谷套利收益。计算逻辑是R_arbitrage sum(P_dis * dt * price_peak) - sum(P_ch * dt * price_valley)注意充电时按谷时电价购电放电时按峰时电价上网或自用。如果论文里电价有平段、尖峰段还要把时段划分清楚。这个收益最容易高估因为很多型号的储能实际充放次数受限不可能每个高峰都满功率放出。二是调峰辅助服务补偿。储能参与调峰之后电网或交易机构会按调峰电量或调峰容量给补偿。模型里可按两种方式处理按电量补偿即每放出1kWh给固定补偿单价或按容量补偿即储能提供调峰容量按额定功率乘以补偿标准。我建议优先按论文明确写的口径来论文没写就按电量补偿做因为好收敛、好解释。三是延缓电网投资或备用容量价值。这个收益在工程实际中很重要但论文里往往不量化。如果目标是复现论文结果不建议自己加收益项但如果做实际项目预可研这笔收益可能是决定项目能不能过审的关键。4.3 净现值、回收期与敏感性分析经济性指标的计算顺序建议是先算年收益R_total再算等年值成本A算年净收益R_net R_total - A算净现值NPV -Cost_inv sum(R_total - C_om) / (1r)^t静态回收期 Cost_inv / (R_total - C_om)。敏感性分析做哪几个参数最有用我的经验是峰谷价差、单位容量成本、年充放电循环次数、贴现率。这四个参数对最终经济性结论的影响最大。其中峰谷价差直接决定套利收益上限单位容量成本直接决定初始投资循环次数决定了储能是“两年一换”还是“十年一换”贴现率决定了长期投资值不值得。举例来说单一套利场景下谷电0.3元/kWh、峰电1.0元/kWh、单程效率95%那么放电1kWh对应的充电成本大约是0.3/0.95 ≈ 0.316元净套利空间约0.684元/kWh。如果储能日循环两次100MWh容量一天放的200MWh全部在峰时放出那么日套利收益约为13.68万元年化约5000万元。再看总投资若单位容量成本1200元/kWh100MWh加25MW功率设备约1.35亿元回收期大概三年多——这么算下来项目经济性看起来很好但一旦把运维、衰减、辅助服务考核扣掉回收期可能翻倍。这就是为什么复现论文不能只看“收益最大化”的漂亮数字。从这个角度说敏感性分析不是论文格式需求而是帮你判断模型的结论是“边界内成立”还是“抖一下参数就翻车”。5. 复现过程中的常见坑与验证手段5.1 结果对不上论文先按这个顺序排查复现中遇到结果和论文不一致大概率不是求解器问题而是模型定义问题。我排错的经验顺序如下核对目标函数符号。你是最大化收益还是最小化成本论文正文公式和实际代码是否一致很多代码写着“min”实际目标里却是收益项前面正号结果越优化越亏。核对效率参数口径。eta_ch和eta_dis是分开给的单程效率还是论文直接给了“往返效率”如果是往返效率90%对应单程效率是sqrt(0.9)左右不是0.9。核对SOC初末约束。单日模型有没有加“末时段SOC等于初值”或者“SOC终值落在某个区间”漏加这条约束经济性会被明显高估。核对时间粒度。论文如果按15分钟一个时段你按1小时建模复现充放电策略会完全变形。特别是负荷的变化节奏、电价的峰谷切换时间粒度不同会带来根本性差异。核对负荷数据单位。kW还是MW日电量是MWh还是kWh这个低级错误在复现里出现频率极高一个单位差1000倍你怎么都对不上。5.2 求解器输出的SOC曲线不对劲判断模型是否正常最快的办法是画三张图净负荷曲线、SOC曲线、充放电功率曲线。最典型的异常包括SOC长期顶在0.9或压在0.1说明约束条件过强或目标函数里缺少对充放电次数的成本惩罚求解器倾向于“撑满不动作”充放电功率频繁抖动脉冲可能是时间步长太短加上没有限制功率变化率也可能电价切换点让求解器利用0-1变量做跳变SOC曲线出现断崖式下跌或上涨大概率是SOC递推方程里容量单位、效率参数错位。遇到这些问题不要急着调求解器容差。先检查约束是不是漏了多数情况下是模型本身缺了“状态互斥”或“极值约束”。5.3 收敛性与模型简化参数化跑批的验证思路复现完成之后建议做一个“自检清单”我每次跑完都会过一遍检查项方法通过标准约束是否满足求解后重新计算SOC序列与约束表达式最大偏差小于1e-4充放电是否互斥统计同时充电且放电的时刻数应为0调峰率是否达标计算接入储能前后的峰谷差率符合论文假设经济量是否合理对比套利收益与调峰补偿占比不出现收益大于放电容量的极端值敏感性方向是否正确单价升高、收益下降价差变大、收益上升趋势单调最后说一下参数化跑批。优化问题调一次参数跑一次很费时间我习惯把所有经济参数集中到一个结构体里然后写一个循环批量跑敏感性。比如price_ratio_list [2, 3, 4]; result_table []; for i 1:length(price_ratio_list) param.price_peak param.price_valley * price_ratio_list(i); [Q_opt, P_opt, revenue] solve_storage_model(param); result_table [result_table; price_ratio_list(i), Q_opt, P_opt, revenue]; end这样不仅改动小而且结果可以直接导出表格写论文的时候也省事。复现这类EI论文里的储能调峰模型最大的体会就是Matlab代码反而是比较简单的一层真正难的是把“调峰需求—储能配置—经济性分析”这条逻辑链上的每个口径都对齐。你检索到的这篇论文正文可能只有几页但展开的经济参数、边界条件、约束假设才是复现的核心工作量。如果你正卡在某个结果对不上或是约束报错建议先回到经济性口径和SOC递推这两条线上找问题90%的Bug都藏在那里。
返回列表