ARTICLE DETAIL

资讯详情

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

基于Matlab+CVX的储能调峰调频优化建模与实现

基于Matlab+CVX的储能调峰调频优化建模与实现 简介面向电力系统研究人员与工程师该资源基于MATLAB编程语言与CVX凸优化工具箱构建了储能系统参与调峰调频的完整优化模型可解决新能源并网场景下负荷波动与电网频率稳定问题。压缩包共10个文件包括6个可运行的m脚本、2个mat数据文件、1篇TPWRS参考论文及1个md说明文档整体体积179.8MB主程序、调峰/调频单独执行脚本、负荷与PJM调频信号数据分层排列便于按模块调用。已有243人参与学习。资源不只给出最终模型还覆盖储能动态建模、凸优化问题转化、控制策略设计与经济性分析等关键环节配合论文和说明文档能帮助读者快速掌握从数学建模到仿真求解的完整链路适合具备一定MATLAB基础并希望深入研究储能辅助服务场景的中高级学习者。1. 储能调峰调频模型先想清楚再写CVX储能调峰调频模型本质上是把“储能什么时候充、什么时候放、功率留多少给AGC调频”变成一个数学优化问题。很多人拿到“基于matlab编程实现的储能调峰调频模型matlabcvx.rar”这类资源第一反应是找里面的cvxrun.m直接跑但忽略了一个反直觉的事实调峰和调频对储能的需求是互相拖后腿的。调峰要的是能量吞吐能力在负荷高峰持续放电数小时调频要的是功率响应速度频繁正负调节而且SOC最好停留在中间区域。两个目标不写进同一个优化问题里或者只把约束简单拼在一起最终算出来的储能容量和功率往往要么偏大要么在AGC考核时出现“有容量但调不出来”的尴尬。这篇文章就干一件事用MatlabCVX把这个调峰调频模型从数学式写到可运行代码再谈目标权重、求解器选择和结果验证。适合刚开始做储能电站规划、微电网经济调度的人也适合已经有混合整数规划经验、想快速验证想法的人。下文默认你有基础的Matlab语法但不需要提前装CVX。2. 储能调峰调频模型的时间尺度、目标函数与约束怎么写2.1 调峰目标minmax削峰与购电成本模型先定义调度周期。调峰常见的离散粒度是15分钟或1小时一天对应T96或T24个时段。记第t个时段的原始负荷为 $P_{\rm load}(t)$储能净功率为 $P_b(t)$放电为正、充电为负那么储能平抑后的系统净负荷是$$ P_{\rm net}(t) P_{\rm load}(t) P_b(t) $$调峰有两个常用目标。第一个是“削峰填谷”直接最小化净负荷峰值$$ \min_{P_b, y} \quad y $$约束里加上 $P_{\rm net}(t) \le y$这是一个标准的minmax问题。写成线性目标后CVX可以直接处理不需要额外工具。第二个是“最小化购电成本”更适合有分时电价的市场环境。目标函数为$$ \min \sum_{t1}^{T} c(t) \cdot P_{\rm net}(t) $$这里的 $c(t)$ 是时段购电价格。这个目标会自然地让储能去“低充高放”但它不会主动约束峰值所以实际工程中往往会再加上一个峰值约束或峰值惩罚项。两种目标没有绝对优劣如果你要写调峰调频模型第一个minmax目标更贴近“调峰”的本意后文以它为主。储能自身的约束必须完整。功率限值约束$$ -P_{\max} \le P_b(t) \le P_{\max} $$SOC递推关系先按理想储能处理效率为1$$ SOC(t) SOC(t-1) - \frac{P_b(t) \cdot \Delta t}{E_{\rm rated}} $$其中 $\Delta t$ 是单时段小时数$E_{\rm rated}$ 是额定容量。再加上SOC上下限和周期末回位约束。到这里调峰的模型框架已经成立。2.2 调频目标用AGC调节容量做线性收益调频和调峰的时间尺度不一样。AGC指令是秒级/分钟级的而优化模型的粒度是15分钟所以不能在校验里模拟每一秒的调节过程。常见做法是在每个15分钟时段内把调频能力抽象成两个变量上调节容量 $R_{\rm up}(t)$ 和下调节容量 $R_{\rm down}(t)$单位都是MW。上调节容量表示该时段储能“还能多向外输出多少功率”包括减少充电和转为放电。受到两个因素限制一是功率可用容量二是SOC剩余电量。写成线性约束就是$$ R_{\rm up}(t) \le P_{\max} - P_b(t) $$$$ R_{\rm up}(t) \le \frac{(SOC(t)-SOC_{\min}) \cdot E_{\rm rated}}{\Delta t} $$注意第一式里如果当前正在充电$P_b(t)$ 是负数那么 $P_{\max} - P_b(t)$ 会大于 $P_{\max}$表示“少充一点就能释放功率”物理含义正确。下调节容量对称$$ R_{\rm down}(t) \le P_{\max} P_b(t) $$$$ R_{\rm down}(t) \le \frac{(SOC_{\max} - SOC(t)) \cdot E_{\rm rated}}{\Delta t} $$有了这两个变量调频收益可以写成$$ F_{\rm fr} \sum_{t1}^{T} \lambda_{\rm agc}(t) \cdot \left( R_{\rm up}(t) R_{\rm down}(t) \right) \cdot \Delta t $$$\lambda_{\rm agc}(t)$ 是AGC调节里程价格单位是元/MWh。整个目标里它是线性项所以调频收益不会破坏问题的凸性。2.3 统一变量为什么这个模型适合用CVX来写把调峰、调频放在一起决策变量是$$ x \left[ P_b(1..T), SOC(1..T), y, R_{\rm up}(1..T), R_{\rm down}(1..T) \right] $$目标函数就是$$ \min \quad y - F_{\rm fr} / \text{scale} $$所有约束都是线性等式或不等式。这是一个线性规划问题。CVX的优势不在于能解线性规划本身而在于建模语言接近数学表达式不用自己把minmax转成矩阵。写出来的代码几乎能对着公式核对这对调参和排错非常重要。需要注意量纲一致。$y$ 是功率$F_{\rm fr}$ 是能量功率乘时间两者直接相减会出问题。要么把调峰目标也换成费用要么把调频收益除以一个基准值做归一化。归一化的具体做法在第4章专门讲这里先记住多目标必须统一量纲或统一尺度。3. MatlabCVX实现储能调峰调频模型的完整代码与参数3.1 CVX安装与求解器选择写代码前先确认环境。CVX 2.2对Matlab版本支持比较久从R2016b到R2024a都能用新版本Matlab下安装也顺畅。安装步骤很简单解压到任意目录比如D:\cvx然后在Matlab命令行切到该目录运行cvx_setup看到版本信息和求解器列表就说明装好了。CVX自带的免费求解器有Sedumi和SDPT3。小规模线性规划够用但如果T取96甚至288变量到几百个SDPT3可能偏慢。正式做项目时建议再装Mosek或Gurobi用cvx_solver mosek切换。它们都支持线性规划、二阶锥和整数规划商用许可按年付费但学术界有免费授权。基础模型只用线性规划免费求解器也能跑所以先不要在这个步骤卡住。3.2 基础调峰模型的最小可运行代码下面这段代码可以直接复制到Matlab里运行它实现了最基础的调峰目标最小化净负荷峰值不考虑调频。% 储能调峰调频模型 - 基础调峰最小化净负荷峰值 T 96; % 一天96个时段15分钟一个点 dt 0.25; % 每个时段对应小时数 E_rated 10; % 储能额定容量MWh P_max 2.5; % 充放电功率上限MW SOC_0 0.5; % 初始SOC SOC_min 0.1; % SOC下限 SOC_max 0.9; % SOC上限 % 构造一个演示用负荷曲线单位MW P_load 10 5*sin((1:T)/T*2*pi) randn(1,T)*0.5; cvx_begin quiet variables P_b(T) SOC(T) y minimize( y ) subject to SOC(1) SOC_0 - P_b(1)*dt/E_rated; for t 1:T -P_max P_b(t) P_max; % 功率限值 SOC_min SOC(t) SOC_max; % SOC限值 P_load(t) P_b(t) y; % 最小化净负荷峰值 if t 1 % SOC递推关系理想储能效率为1 SOC(t) SOC(t-1) - P_b(t)*dt/E_rated; end end SOC(T) SOC_0; % 周期末回到初始SOC cvx_end % 画图对比 plot(1:T, P_load, b, 1:T, P_loadP_b, r) legend(原始负荷, 储能平抑后负荷) xlabel(时段); ylabel(功率/MW)这段代码的核心思路是用辅助变量y代替“求最大值”这个非光滑目标通过minimize(y)和P_load(t)P_b(t)y两条语句完成minmax转换。SOC(1)单独赋值是为了避免循环里引用SOC(0)越界。这里假设效率为1。实际储能充电效率 $\eta_c$ 和放电效率 $\eta_d$ 都低于1模型要改成充电功率 $P_{ch}$ 和放电功率 $P_{dis}$ 两个非负变量SOC递推关系变成$$ SOC(t) SOC(t-1) \frac{\eta_c P_{ch}(t)\Delta t}{E_{\rm rated}} - \frac{P_{dis}(t)\Delta t}{\eta_d E_{\rm rated}} $$这时必须加一个很小的充电/放电惩罚项比如0.01*sum(P_chP_dis)否则模型可能同时充放电。原因是minmax目标本身不会惩罚“一边充一边放”的低效行为。3.3 在代码里加入调频约束与目标在基础调峰基础上加入上/下调节容量变量并把调频收益计入目标。为了让代码简洁下面直接用充放电分离变量效率按95%处理。% 储能调峰调频模型 - 调峰调频容量 eta_c 0.95; % 充电效率 eta_d 0.95; % 放电效率 lambda_agc 80; % AGC里程价格元/MWh scale_fr P_max; % 归一化基准避免量纲混乱 cvx_begin quiet variables P_ch(T) P_dis(T) SOC(T) y variables R_up(T) R_down(T) minimize( y - lambda_agc * sum(R_up R_down) * dt / scale_fr ... 0.01 * sum(P_ch P_dis) / P_max ) subject to for t 1:T 0 P_ch(t) P_max; 0 P_dis(t) P_max; if t 1 SOC(1) SOC_0 (eta_c*P_ch(1) - P_dis(1)/eta_d)*dt/E_rated; else SOC(t) SOC(t-1) (eta_c*P_ch(t) - P_dis(t)/eta_d)*dt/E_rated; end SOC_min SOC(t) SOC_max; P_load(t) - P_ch(t) P_dis(t) y; % 上调节容量约束 R_up(t) P_max - P_dis(t) P_ch(t); R_up(t) (SOC(t) - SOC_min) * E_rated / dt; R_up(t) 0; % 下调节容量约束 R_down(t) P_max - P_ch(t) P_dis(t); R_down(t) (SOC_max - SOC(t)) * E_rated / dt; R_down(t) 0; end SOC(T) SOC_0; cvx_end % 查看结果 fprintf(优化后的净负荷峰值: %.2f MW\n, cvx_optval); fprintf(平均上调节容量: %.2f MW\n, mean(R_up)); fprintf(平均下调节容量: %.2f MW\n, mean(R_down));这里的调频约束写法值得展开。R_up(t) P_max - P_dis(t) P_ch(t)表达的是当前放电越多可继续上调节的空间越小当前充电越多取消充电释放的功率越大上调节空间反而大。R_up(t) (SOC(t)-SOC_min)*E_rated/dt则把SOC限制转换成功率限制因为SOC剩余电量除以剩余时间就是平均功率。两者同时成立才真正表示“既有功率余量也有电量余量”。3.4 求解失败时的排查参数CVX运行后如果出现Status: Failed或者Infeasible优先检查三类问题。第一数值尺度。E_rated*dt/dt得到的功率量级可能和负荷功率差几十倍。比如E_rated10MWh, dt0.25SOC相关约束里的(SOC-SOC_min)*E_rated/dt会到36MW而P_max只有2.5MWCVX可能出现数值告警但结果仍可用。解决方法是把功率单位统一成标幺值或者把所有约束都用MW表示。第二初始SOC和终止SOC的可行性。如果SOC_00.1SOC_min0.1且SOC(T)必须回到0.1但P_b在整个周期内被要求大量充电模型必然不可行。给SOC_0留出裕量一般设0.5比较稳。第三求解器容忍度。默认误差是1e-4有的模型会得到Solved/Inaccurate这时可以设置cvx_precision high或者调整求解器参数。如果是用Gurobi还可以在求解前执行cvx_solver_settings(OutputFlag, 1)查看详细迭代。4. 调峰与调频协同优化的权重调节与分层策略4.1 加权目标函数的系数标定第3章代码里用了lambda_agc * sum(R_upR_down) / scale_fr作为调频收益项但lambda_agc取多少直接决定优化结果偏向调峰还是调频。如果凭感觉设跑出来的SOC轨迹会很怪收益系数设大储能整天在SOC上下边界来回顶调峰效果很差设小调频容量形同虚设。我常用的标定方法是先做两次单目标求解。第一次只最小化y得到基准峰值y0。第二次只最大化sum(R_upR_down)得到基准调频容量fr0。然后构造归一化目标$$ \min \quad \frac{y}{y0} - \alpha \cdot \frac{\sum(R_{\rm up}R_{\rm down})}{fr0} $$其中 $\alpha$ 是一个无单位的权重0到1之间。这样两个目标的量级都在1左右$\alpha$ 的含义变成“愿意放弃多少调峰能力来换取调频容量”。代码实现很简单在CVX里把目标写为cvx_begin quiet minimize( y/y0 - alpha * (sum(R_upR_down)/fr0) ) ... cvx_end实际标定alpha时先取0、0.1、0.2、0.3、0.5、0.7、1.0跑一组观察“峰值增加比例”和“调频容量提升比例”。当alpha从0.3升到0.5时如果峰值只增加1%调频收益却提高20%说明这个区间非常划算如果峰值直线上升而调频容量增长趋缓后面再加大权重就没意义了。4.2 分层优化的实现先算SOC轨迹再切功率加权法适合方案比选但实际工程中AGC系统往往不允许储能把SOC轨迹修改得过于自由因为AGC下发指令时只关心当前可调容量。所以另一种常见做法是分层第一层跑调峰模型得到参考SOC轨迹 $SOC_{\rm ref}(t)$第二层固定SOC轨迹把调频容量作为约束优化功率分配的细节这里有一个简化技巧第二层不需要重新求解完整优化问题而是根据调峰功率和SOC计算一个“可调频裕量”。伪代码如下% 假设P_b_opt和SOC_opt来自第一层调峰解 for t 1:T R_up_avail(t) min(P_max - P_b_opt(t), ... % 功率裕量 (SOC_opt(t) - SOC_min) * E_rated / dt); % 电量裕量 R_dn_avail(t) min(P_max P_b_opt(t), ... (SOC_max - SOC_opt(t)) * E_rated / dt); end这种方法牺牲了一部分调频收益因为SOC轨迹没有为调频留出中间位置但胜在实现简单而且符合调度员“调峰计划优先、调频裕量校验”的操作习惯。如果希望SOC轨迹同时兼顾调频就在第一层目标里加入一个“SOC偏离中间值”的软约束让储能平时尽量停在0.5附近再预留快速调节空间。4.3 两种策略的结果对比与适用场景策略目标函数调峰效果调频容量适用场景调峰优先最小化净负荷峰值峰值最低偏低只靠自然余量配网侧削峰填谷、线损治理调频优先最大化AGC调节里程收益峰值可能升高高SOC被压到中间区间独立储能参与调频市场归一化加权y/y0 - alpha*fr/fr0可调可调容量规划、投资测算分层优化固定SOC轨迹再算调节裕量接近调峰最优中已有调度计划、需AGC考核从这张表能看出没有“完美”的储能调峰调频模型只有适合当前业务目标的取舍。写代码时我建议把单目标函数、加权目标、分层目标全部封装成三个脚本共用参数文件和负荷数据文件这样比写一个带开关的大函数更易维护。5. 让储能调峰调频模型从能跑变成能用的三个验证技巧5.1 用CVX的status和gap判断结果是否可信跑完CVX后不要只看结果图。先用disp(cvx_status)查看求解状态。Solved是最理想的情况说明求解器在默认容差内找到了最优解。如果你看到Solved/Inaccurate说明目标值可能存在数个小数的误差通常不影响工程判断但如果SOC约束很紧建议调高精度。线性规划求解器在最优解处会输出对偶间隙CVX默认不显示但可以通过cvx_optval和cvx_slack间接检查约束是否打满。一个最简单的方法把某个关键约束的右侧值改小1%重新求解如果目标值变化很小说明该约束不是瓶颈如果目标值剧烈变化说明这个约束决定了整个方案的边界。在做储能容量规划时这个技巧能帮你快速找到“卡脖子”的是功率还是容量。5.2 功率与SOC曲线的一致性检查做完优化先画SOC曲线再画功率曲线逐时段核对符号关系。SOC下降的时段P_dis必须大于零SOC上升的时段P_ch必须大于零。由于模型里加了充放电惩罚项正常求解结果不会出现同段充电又放电但如果惩罚系数设成0就可能看到P_ch和P_dis同时大于零的情况。检查代码% 检查同一时段是否同时充放电 bad_idx find(P_ch 0.01 P_dis 0.01); if ~isempty(bad_idx) warning(以下时段同时充放电: %s, num2str(bad_idx)); end同时充放电虽然在某些市场规则下是真实存在的比如储能同时报调峰和调频计划但线性模型里没有引入这些市场细节时同时充放电只会虚增成本必须排查。5.3 灵敏度分析的快速做法调峰调频模型最终要给容量决策提供依据所以E_rated和P_max不能只算一个点。写一个简单循环把E_rated从2扫到20步长2P_max从0.5扫到5步长0.5跑同一个加权重构模型记录每组参数下的净负荷峰值和调频容量。最后画一张二维热力图X轴是E_ratedY轴是P_max颜色是综合评分直接能看到“再增加容量已经无收益”的拐点。这个扫描只需要几行代码但结果比单独跑一次模型有说服力得多。具体做法是把第4章的加权求解封装成一个函数[y_peak, fr_total] run_store_model(E_rated, P_max, alpha)然后在循环里调用。如果循环耗时较长优先覆盖P_max的细分因为调频能力对功率更敏感E_rated的步长可以放宽到2MWh。记住一点储能调峰调频模型的价值不在那一个最优解而在多个方案之间的边际效果对比。本文还有配套的精品资源点击获取
返回列表