ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

共享储能容量配置与调度联合优化:碳交易与电网波动惩罚下的Matlab实现

共享储能容量配置与调度联合优化:碳交易与电网波动惩罚下的Matlab实现 做电力系统优化这些年我最大的感受是储能配置方案早已不是过去那种“算个峰谷价差、套个静态收益”的简单模型了。碳交易把碳排放变成有价格的成本项电网侧又对联络线交换功率的稳定性盯得越来越紧共享储能电站的容量配置和日内调度必须放到一个框架里联动求解。这篇内容以Matlab代码实现为主线围绕“碳交易成本建模、电网交互波动惩罚、共享储能容量配置与运行调度联合优化”三层问题展开适合正在做储能投资规划、微电网/园区调度的研究生和工程师参考。看完你至少能搭出一套可复现的两阶段优化框架而不是只停留在读论文的层面。1. 碳交易、波动惩罚和共享储能为什么必须放进同一个模型1.1 碳交易引入后储能收益结构发生了哪些变化先讲碳交易。碳排放配额的政策逻辑并不复杂火电等排碳主体每年拿到一定量的免费配额实际排放量一旦超过配额就需要到碳市场购买缺口如果配额有富余也可以挂牌出售。放在电力系统优化里这等于给火电出力加上了一个“单价”标记排得越多成本越高。问题在于很多做储能配置的人第一版模型里根本不关心碳排放只盯着低储高放套利、容量租赁这些直接现金流。但实际算下来储能在碳中和背景下的间接收益非常可观。举个很直观的数字假设储能多吸纳100 MWh弃风弃光电量替代了同等电量的火电火电碳排放强度按0.8 tCO2/MWh算碳价按60元/t那单次循环对应的碳减排收益就是 100×0.8×60 4800元。如果这个储能系统年循环次数超过300次碳收益就是百万量级的资金完全可以左右“配多大容量”这个决策。所以我一直建议碳交易不能作为后处理分析项而是要在目标函数构建阶段就参与优化。传统模型的目标只是运行成本最小化现在要变成“运行成本 碳交易成本 电网交互惩罚 投资年值”整体最小化。这四类成本之间存在耦合储能配置容量越大、调度越灵活火电出力就越低碳交易成本越小但投资年值和运维成本会上升。平衡点在哪里正是优化模型要回答的问题。1.2 电网交互波动惩罚一个常被忽略的工程问题再说电网交互波动。这个约束带有很强的工程背景。共享储能和上级电网之间存在一条交换功率通道如果储能运行策略只追求电能量市场收益很容易出现这样的场景午间光伏大发时储能从电网购电充电晚间负荷高峰期又满功率放电交换功率在几个小时内从 0 跳到额定值再跳回来。对上游电网来说这种功率突变相当于在联络线上制造大量短期功率冲击会增加调频压力加速变压器等设备的损耗甚至触发AVC/AGC系统频繁动作。工程上解决这个问题的思路是在目标函数中增加一个惩罚项即对交换功率相邻时段的变化幅度施加惩罚。常见做法有两种。一是用一阶差分绝对值之和也就是一范数惩罚(\lambda \sum_{t2}^{T} |P_{grid}(t) - P_{grid}(t-1)|)二是二次平方惩罚即二范数。实践中我更推荐一范数理由很简单绝对值函数可以引入辅助变量做线性化原问题仍然是线性规划或混合整数线性规划求解速度快、稳定性高二次惩罚会引入SOCP约束如果项目时间紧、求解器不熟悉光是处理二阶锥就够折腾。惩罚系数的量纲需要特别注意功率单位是kW或MW系数单位就必须对应为元/kW或元/MW。如果功率用kW、时间用小时系数乘出来就得到成本值一旦单位错位结果会完全失真。这一点我后面还会再强调。1.3 配置与调度联合优化的必要性共享储能和传统自备储能还有一个本质区别投资主体和受益主体分离。用户侧储能“谁投资、谁运行、谁收益”比较好办共享储能是独立的运营商建站通过向多个新能源场站、用户提供充放电服务来获得收益。这种商业模式决定了“容量配置”和“运行调度”必须解耦又联动。如果只做配置优化不涉及调度策略很容易用固定利用率、固定循环次数等粗糙假设算出来的容量往往偏大。反过来说只做调度优化不涉及容量配置又必须在给定储能容量下进行无法回答“建多大更合理”的问题。所以最优做法是构建双层优化结构外层把储能额定功率 (P_r) 和额定容量 (E_r) 当作决策变量内层在给定配置下优化日内96点或24点的充放电计划。这也是目前期刊和工程实践里最主流的研究思路。需要说明的是双层问题在数学上不一定满足凸性外层是非线性整数规划内层是线性规划。求解时有两个选择工程做法是外层用启发式算法PSO、遗传算法等内层调用线性规划求解学术严谨做法是用KKT条件或强对偶理论把下层问题写成上层约束转化为单层MPEC模型。代码实现难度差异很大后者对Matlab和Gurobi/Cplex的操作要求极高我复现时通常先做前者跑通之后再考虑单层化改造。2. 数学模型怎么搭两阶段优化与约束体系2.1 目标函数拆解投资年值、运行成本、碳交易成本与惩罚项模型的目标函数需要把几类在时间尺度上完全不同的成本统一折算。投资成本是一次性发生的运行与调度成本是逐时段产生的两者不能直接相加因此要把总投资成本按折现率换算成年值。储能投资年值的计算公式是这样(C_{inv} \text{CRF} \cdot (c_e E_r c_p P_r))其中 (\text{CRF} \frac{r(1r)^n}{(1r)^n-1})(r) 是折现率(n) 是储能寿命。举例来说若能量成本 (c_e 1500) 元/kWh功率成本 (c_p 800) 元/kW配置 (E_r1000) kWh、(P_r500) kW初始投资就是 150万 40万 190万元。取 (r0.06,n10)CRF约为0.1359年化投资约25.8万元。这就是目标函数里第一项。第二项是运维成本一般按额定功率比例折算即 (C_{om} c_{om} P_r)单位是元/kW·年。第三项是逐时段的购售电成本目标是最小化从电网购电的费用减去向电网售电的收益。第四项是碳交易成本表达式为(C_{co2} p_{co2} \sum_{t1}^{T} (e_g - \sigma_g) P_g(t) \Delta t)其中 (e_g) 是火电碳排放强度(\sigma_g) 是配额分配系数(P_g(t)) 是火电出力。若实际排放高于配额这一项成本为正若减排明显低于配额该项可以为负也就是收益。第五项就是第一节提到的电网交互波动惩罚项。整体优化方向是最小化总成本。许多论文喜欢写成“净收益最大”的形式其实物理意义完全等价只是符号方向不同我习惯用成本最小化和求解器的默认习惯一致省去额外处理。2.2 储能运行约束与SOC递推细节调度层约束是整个模型最容易写错的地方尤其是SOC递推和充放电互斥逻辑。SOC采用归一化方式表示取值0到1之间递推关系如下(SOC(t1) SOC(t) (\eta_{ch} P_{ch}(t) - \frac{P_{dis}(t)}{\eta_{dis}}) \Delta t / E_r)这里 (\eta_{ch}) 是充电效率(\eta_{dis}) 是放电效率。注意放电功率除以效率是因为放电过程中电池内部有损耗从电网或新能源侧获取的“等效电量”比实际放出的电量更多。很多初学者把效率乘在放电项上结果SOC越放越高显然是方向反了。同时充电功率和放电功率不能同时为正。物理上电池不会一边充一边放但数值优化问题不会天然排除这种情况必须显式加约束(0 \le P_{ch}(t) \le u(t) P_r)(0 \le P_{dis}(t) \le (1-u(t)) P_r)其中 (u(t)) 是0-1二进制变量。这个约束引入后问题就变成混合整数线性规划(MILP)。有些简化的复现版本不加互斥约束认为电价信号不会导致同时充放电这在大多数场景下成立但加入二进制变量更稳妥尤其在引入波动惩罚后极端情况下确实可能出现“一边充一边放”来压低波动惩罚的怪异行为。功率平衡约束也要写清楚。我采用的系统结构是新能源出力 (P_{res}(t))、储能放电 (P_{dis}(t))、电网购电 (P_{buy}(t)) 和火电出力 (P_g(t)) 共同满足负荷 (P_L(t))、储能充电 (P_{ch}(t)) 和电网售电 (P_{sell}(t))(P_g(t) P_{res}(t) P_{dis}(t) P_{buy}(t) P_L(t) P_{ch}(t) P_{sell}(t))火电出力还需要满足上下限约束和爬坡约束新能源出力上限按预测曲线给定储能SOC要满足上下限约束 (SOC_{min} \le SOC(t) \le SOC_{max})。最后一个细节是SOC的初值通常设 (SOC(1) SOC_{min}) 或0.2并且最好要求调度周期结束时SOC回到初始值否则优化结果会把最后时段的电池“掏空”不具备实际可操作性。2.3 双层求解框架外层配置、内层调度双层优化的整体数据流是这样的外层算法产生一组 (P_r) 和 (E_r)传入内层调度模型内层调度模型求解给定容量下的最小运行成本、碳交易成本和波动惩罚成本外层根据内层返回的总成本再结合投资年值更新候选配置。两者反复迭代直到收敛。外层选择启发式算法时我比较推荐粒子群算法(PSO)。原因有两个一是变量的维度很低只有 (P_r) 和 (E_r) 两个决策变量PSO在这种低维问题上收敛快二是Matlab自带的particleswarm函数可以直接使用不需要额外安装工具箱。有的复现版本用遗传算法也能跑通但需要写选择、交叉、变异算子代码量大且调参麻烦。内层调度问题是一个MILP可以用Yalmip建模后交给Cplex或Gurobi求解。Yalmip是一个Matlab下的建模工具底层对接多个求解器。需要注意的是外层每迭代一次就要重新构建一次内层模型如果数据规模大、时段多总计算时间会明显拉长。一个加速技巧是先把新能源出力和负荷曲线、电价序列等参数准备好内层只更新与 (P_r)、(E_r) 相关的约束系数不要整个模型从零开始重新搭。3. Matlab代码实现的核心环节3.1 建模环境准备Yalmip、Cplex/Gurobi与Matlab自带工具箱先整理环境。我用的组合是Matlab R2021a Yalmip Gurobi 9.5也可以用Cplex。如果你的机器上已经装了Gurobi又想装Cplex完全没有冲突Yalmip通过sdpsettings(solver,gurobi)指定求解器即可两个求解器可以共存于同一环境不要听信“相互冲突”的说法。如果不想装商业求解器纯用Matlab自带的优化工具箱也能跑。内层如果去掉互斥二进制变量可以直接用linprog保留二进制变量则用intlinprog。这俩函数都是内置的避免软件安装冲突问题。只是求解速度上Gurobi/Cplex对整数规划的节点剪枝策略优化更好计算大规模算例时差距会非常明显。我的经验是先期开发和调试用自带求解器跑小算例最终仿真用Cplex或Gurobi这样能隔离“模型本身有误”和“求解器性能差”两类问题。安装完Yalmip后在Matlab命令行运行yalmiptest能列出当前环境下所有可用求解器。如果看到cplex、gurobi后面标注的是错误的版本多半是求解器安装的位数32位/64位与Matlab不匹配或者Yalmip的路径没添加干净需要重新设置setpath。3.2 调度层核心代码变量定义、目标函数与约束下面给出调度层的关键代码片段整体结构是我调通后留的缩写版。假设T24时段长度dt1小时储能额定功率P_r和额定容量E_r由外层传入。% 决策变量 P_ch sdpvar(1, T); % 充电功率 P_dis sdpvar(1, T); % 放电功率 P_buy sdpvar(1, T); % 电网购电 P_sell sdpvar(1, T); % 电网售电 P_g sdpvar(1, T); % 火电出力 SOC sdpvar(1, T1); % 归一化SOC u binvar(1, T); % 充放电互斥变量 Y sdpvar(1, T-1); % 波动惩罚辅助变量 % 目标函数 Obj sum(c_buy .* P_buy - c_sell .* P_sell) * dt ... p_co2 * (e_g - quota_rate) * sum(P_g) * dt / 1000 ... lambda * sum(Y) ... c_om * P_r; % 约束 Cons []; Cons [Cons, SOC(1) SOC_init]; for t 1:T Cons [Cons, SOC(t1) SOC(t) (eta_ch * P_ch(t) - P_dis(t)/eta_dis) * dt / E_r]; Cons [Cons, P_ch(t) 0, P_ch(t) u(t) * P_r]; Cons [Cons, P_dis(t) 0, P_dis(t) (1 - u(t)) * P_r]; Cons [Cons, SOC_min SOC(t1) SOC_max]; Cons [Cons, P_g(t) P_res(t) P_dis(t) P_buy(t) P_load(t) P_ch(t) P_sell(t)]; Cons [Cons, P_g_min P_g(t) P_g_max]; end Cons [Cons, SOC(T1) SOC_init]; % 调度周期末回到初值 % 波动惩罚的线性化 for t 2:T Cons [Cons, Y(t-1) P_buy(t) - P_sell(t) - (P_buy(t-1) - P_sell(t-1))]; Cons [Cons, Y(t-1) -(P_buy(t) - P_sell(t) - (P_buy(t-1) - P_sell(t-1)))]; end需要特别解释几个地方。碳交易项里的/1000是因为火电排放强度用的单位是kg/kWh碳价单位是元/t乘积再除以1000才能统一到元。功率单位我统一用kW所以各项成本直接相加时单位一致。SOC初值和末值相等是为了保证调度方案在工程上可持续否则储能每天一个充放周期才最赚钱结果就会出现末尾电量被抽空的短视行为。目标函数里我用P_buy - P_sell的差值来定义交换功率这隐含一个前提同一时段不会同时购电和售电。实际上在波动惩罚存在的情况下模型可能会为了平滑曲线而同时买卖但这种情况物理上不合理。加一个约束P_buy(t)*P_sell(t)0会引入非线性不太好处理。由于购电价通常高于售电价目标函数自然会避免同时买卖所以实践中可以不加这个约束我跑下来的结果也没有出现同时买卖的情况。3.3 配置层实现外层寻优与数据传递外层用particleswarm来做容量寻优。写法和一般优化问题差别不大核心是内层函数要返回总成本包括投资年值、运维成本以及内层调度的最小成本。lb [100, 200]; % 下界P_r100kW, E_r200kWh ub [2000, 4000]; % 上界 options optimoptions(particleswarm, SwarmSize, 30, MaxIterations, 50, Display, iter); [x_opt, fval] particleswarm((x) innerProblem(x, data), 2, lb, ub, options);innerProblem函数的实现思路是function totalCost innerProblem(x, data) P_r x(1); E_r x(2); % 用Yalmip构建并求解内层调度 % 求解得到运行成本 runCost % 投资年值 invCost CRF * (c_e * E_r c_p * P_r) % 运维成本 omCost c_om * P_r totalCost invCost omCost runCost; end这里有个性能优化点Yalmip每次从零建模很耗时我在实际项目中把原始问题参数化内层循环里只更新和P_r、E_r相关的系数向量约束模板不重新生成运行速度能提升数倍。如果只是复现论文直接每次重新建模也可以但要意识到外层迭代50次、每次内层又是MILP求解总耗时可能在几分钟到几十分钟之间要有心理准备。外层启发式算法的另一个问题是它无法保证全局最优。论文里如果审稿人问起全局最优性我一般会补充说明外层PSO获得的是近似最优解随后用局部搜索或穷举小步长网格对最优配置附近做二次校验。把网格步长设为额定功率10kW、容量50kWh遍历最优解周围区域确认没有更优配置后再写进结果分析这样可以大幅提升结果的可靠性。3.4 结果可视化的几行实用代码仿真跑完之后结果可视化是论文和汇报最关注的部分。我常画的四类图是储能充放电功率曲线、SOC变化曲线、电网交换功率对比有/无惩罚、碳交易配额使用情况。核心代码很简单t 1:T; figure; subplot(2,1,1); stairs(t, P_dis_opt - P_ch_opt); grid on; ylabel(储能功率/kW); xlabel(时段/h); subplot(2,1,2); plot(t, SOC_opt(2:end) * 100, LineWidth, 1.5); grid on; ylabel(SOC/%); xlabel(时段/h); saveas(gcf, dispatch_curve.png);要注意stairs适合功率这类分段常数信号plot适合SOC这种连续变化量。这两类图形在Matlab里区分清楚出来的图会专业很多。导出图片时我习惯用exportgraphics(gcf, filename.png, Resolution, 300)而不是saveas后者在Windows和Linux下渲染精度差异较大论文投稿用的图建议直接走exportgraphics。4. 算例参数设置、验证与灵敏度分析4.1 一套可以直接用的基础参数很多复现者卡在第一步参数怎么定我把自己做测试用的典型参数列成一张表这套参数来自一篇关于共享储能优化配置的参考论文量纲我已经统一过。参数数值备注储能额定功率范围 (P_r)100~2000 kW外层寻优边界储能额定容量范围 (E_r)200~4000 kWh外层寻优边界单位能量成本 (c_e)1500 元/kWh磷酸铁锂体系常见值单位功率成本 (c_p)800 元/kW含PCS、BMS等储能寿命 (n)10 年折现率 (r)0.06运维成本 (c_{om})50 元/kW·年充电效率 (\eta_{ch})0.95放电效率 (\eta_{dis})0.95SOC范围0.1 ~ 0.9碳价 (p_{co2})60 元/t按碳市场近期价格调整火电排放强度 (e_g)0.8 kg/kWh配额系数 (\sigma_g)0.7基准线分配法波动惩罚系数 (\lambda)100元/kW需要灵敏度验证这里有一个值得注意的点碳价和配额系数对结果影响极大。如果碳价取10元/t碳交易成本在目标函数里基本可以忽略如果取100元/t储能投资的吸引力会显著增加。写论文时不能只给一个固定碳价一定要做碳价灵敏度分析这是审稿人最喜欢提的问题之一。4.2 如何验证模型的正确性模型跑通之后先别急着调参数先验证模型逻辑是否正确。我的惯例是做三组测试。第一组是“无储能测试”把 (P_r) 和 (E_r) 都设为零模型应该退化成纯火电新能源电网购售电模型目标函数扣除投资年值和运维成本。此时把储能相关约束全部剔除观察功率平衡约束是否还满足购售电结果是否符合经济预期。第二组是“无穷大波动惩罚测试”把 (\lambda) 设成一个极大值比如 (10^6)最优调度应该使交换功率全天不变也就是所有时段的购售电差几乎相同。如果结果仍然出现大波动说明惩罚项的线性化约束写错了。第三组是“等电价测试”把购电价和售电价设成全天不变且不考虑碳交易那么储能的套利空间消失合理结果应该是储能尽量不运行SOC维持初值。如果此时储能还在频繁充放说明目标函数里存在隐含收益来源比如碳交易项或波动惩罚项构造有误。这三组测试是我每次复现代码都会跑的 sanity check。速度很快却能把模型里90%的隐性错误暴露出来。4.3 碳价与波动惩罚系数的灵敏度测试思路灵敏度分析可以回答两个决策者最关心的问题碳价涨到多少时共享储能才值得投资电网波动惩罚设置多大才能明显改善交换功率曲线具体做法是固定其他参数不变让碳价从0以10元/t为步长增加到150元/t记录每个碳价下的最优配置 (P_r)、(E_r) 和对应总成本。把结果画成二维曲线一般能看到一个拐点碳价较低时容量配置不敏感碳价超过某个阈值后储能容量随碳价近似线性上升。这个拐点对应的碳价就是储能在碳市场上的“盈亏平衡信号”。波动惩罚系数的测试则相反通常关注曲线从剧烈波动到平缓的“拐弯区间”。把 (\lambda) 从0按对数刻度增加到10000记录交换功率相邻时段最大变化量和总成本的变化。随着 (\lambda) 增大波动量单调下降但总成本会上升。最终取值应该选在“波动量下降到平台期、总成本代价尚可控”的那个区间而不是机械地取任意数值。5. 踩坑记录常见报错与调试心得5.1 求解器选择和版本匹配的坑第一个高频问题Yalmip报No suitable solver。这通常不是模型问题而是环境配置问题。可能原因有三个Yalmip没有检测到已安装的求解器、求解器版本过于老旧、Matlab路径里存在多个版本的Yalmip或求解器残留。处理方法是重建路径清理掉旧版本后重新addpath(genpath(...))再跑一次yalmiptest。第二个问题装了Gurobi后Cplex用不了。两者默认都会设置为Yalmip的全局求解器但Yalmip只是按配置调用不存在“抢占”关系。如果你在代码里明确写了sdpsettings(solver,cplex)Yalmip就会调用Cplex写gurobi则调用Gurobi。可以同时安装不需要卸载任何一个。我目前是Gurobi做MILP主力Cplex偶尔用来交叉验证最优解两个都在用。第三个问题Matlab运行大算例中途闪退。这个我踩过好几次主要原因是内存爆炸。外层PSO迭代时如果每次循环都重新生成不必要的大数组或者Yalmip约束被反复拼接内存会在几十次迭代后失控。解决办法是循环开始前预先分配constraints []避免频繁动态扩展有条件的话减少粒子数和迭代次数先保证模型能跑再逐步扩大寻优规模。5.2 模型构建中的常见错误模型层面的错误比求解器配置更容易被忽略。我总结出三个高发点。一是SOC递推公式的充放电效率方向写反。前面提过充电要乘效率、放电要除效率如果写成充电也除效率SOC曲线会出现“充不进去、放不完”的异常现象最优解永远是满充满放。判断方法很简单给定初始SOC为0.5让储能以额定功率充电1小时理论上SOC应该变为 (0.5 0.95 \times 1 / E_r)如果计算机结果和手算不一致公式方向有问题。二是波动惩罚项只考虑购电波动而忽略售电。交换功率的正负方向用P_buy - P_sell定义如果只看购电功率储能大量放电时售电功率飙升但购电侧没有变化惩罚项形同虚设交换功率曲线仍然会出现大尖峰。正确做法是把差值作为整体纳入绝对值。三是约束条件里SOC上下界的编号错位。SOC的定义是 (T1) 维但调度功率是 (T) 维循环里很容易出现SOC(t1)写成SOC(t)导致最后一个调度时段的约束没有覆盖或者第一个时段约束重复。这类错误不一定会报错但会让结果莫名其妙排查起来很耗时间。5.3 结果不合理时从哪里查起如果跑出来的配置结果极端比如储能容量直接冲到上界或者SOC长期贴在边界上不要急着怀疑算法先回头检查以下三个维度。第一检查时间尺度是否统一。比如负荷数据是15分钟一个点而电价是逐小时数据两者混用会导致功率平衡约束实际错位。我一般把时间分辨率统一到15分钟即T96投资成本按年化不变运行成本和碳收益按时段累计。此时SOC递推里的dt要改成0.25小时功率单位不变计算结果才合理。第二检查目标函数各成本项的量级是否匹配。储能投资年值是几十万量级购售电成本是每天几十到几百的量级。如果碳交易成本或者波动惩罚系数设置过大模型会把全部注意力放在强行压低惩罚项上甚至牺牲经济性。这时候可以分别输出各项成本的数值确认它们在总成本中占比合理再决定是否需要缩放系数。第三检查火电机组的最低技术出力约束。很多算例把火电下限设成0这在物理上不合理。火电最低技术出力一般为额定出力的30%~50%。如果下限为0模型会倾向于用储能替代火电的深度调峰碳交易收益和波动惩罚都会被过度放大配置结果自然偏大。设置合理的火电深度调峰下限能让结果更符合实际。最后多说一句这套代码的设计体会。我在复现过程中反复感受到碳交易和电网交互波动惩罚这两个机制表面上只是“多了两个成本项”实际上改变了储能的盈利边界。不加入碳交易储能容量往往会偏低因为部分减排收益没有被捕捉不加入波动惩罚储能配置又会偏激进因为它没考虑对电网的负面影响。两者一起纳入优化框架之后得到的配置方案既经济上可行、又运行上可接受这是这套模型最大的价值。你在自己的算例上调试时如果发现某个参数对结果影响异常大先别急着改模型试着把它从固定值改成动态输入用灵敏度分析驱动参数选择会比盲目调参省力得多。
返回列表