基于MILP的微网储能容量优化配置:Matlab+YALMIP实战解析

发布时间:2026/10/3 14:53:47
基于MILP的微网储能容量优化配置:Matlab+YALMIP实战解析 去年接到一个园区微网项目业主上来就问储能怎么配光伏装了200kW负荷峰值接近250kW想上一套储能但容量和功率该选多少厂家报价单上一排配置让人心里没底。我最初也走过捷径按“负荷的20%配储能”的行业惯例估了一套50kW/100kWh结果一跑整年运行数据储能在午间光伏大发时段很快充满傍晚峰段电量又不够放全年套利收益连设备折旧都覆盖不了。这件事让我彻底改了思路——储能容量配置必须当成一个数学规划问题来解不能靠拍脑袋。这篇文章就把我后来实际落地的那套方法完整梳理一遍基于混合整数规划MILP做微网储能容量优化配置编程环境是Matlab建模用YALMIP求解器用intlinprog或Gurobi。内容包括问题拆解、数学模型、完整代码、数据预处理、结果复盘和坑位清单适合正在做微网规划、储能经济性分析相关课题的研究生工程师也适合入行不久想搞懂“储能到底怎么配才合理”的设计人员。你把这套方法跑通之后换成自己的负荷和光伏曲线就能直接用。1. 为什么是混合整数规划储能配置问题的数学本质1.1 拍脑袋定容量的教训先说那个50kW/100kWh的失败案例。当时我的逻辑是负荷峰值250kW取20%做储能功率再按2小时倍率配容量这算是工程上最常见的快速估算办法。但问题出在哪儿呢微网里的储能价值主要由三部分构成峰谷价差套利、光伏弃电消纳、以及故障或极端天气下的支撑能力。这三者全都和负荷曲线、光伏出力曲线在时间维度上的耦合强相关。我实测算了一下那条园区负荷曲线白天的谷底大约在80kW附近但中午光伏大发时系统净负荷接近0甚至反向下午4点以后负荷爬升到240kW而此时光伏已经衰减到不足50kW。50kW的储能功率看起来够用但100kWh的容量在午间一个小时内就会被光伏盈余充满续充能力趋近于零到晚间峰段100kWh按95%放电效率放完也就95kWh对应电价最高的3小时平均只能提供30kW出头的支撑功率对峰段负荷削减几乎杯水车薪。这个案例说明一个道理储能配置的“最优解”和“可行解”之间差距可能非常大。工程经验可以作为初值参考但最终必须落到数学优化上让模型自己去权衡“多配一度电、多配一千瓦换来多少年度收益”。1.2 问题拆解投资决策层和运行调度层的耦合储能容量优化配置这个问题的结构其实很清晰——它天然是两层决策耦合在一起。外层是投资决策选多大的额定功率P_esskW、多大的额定容量E_esskWh。这两个变量决定了储能系统的初始投资属于长期决策一旦建成就很难改。内层是运行调度在给定的容量和功率下逐小时决定储能充多少、放多少、什么时候从电网买电、什么时候卖电、要不要切负荷、要不要弃光。这些是短期运行决策在全年8760个小时里每天都在变化。关键在于这两层不是独立的。你配置的容量大了运行层的调节空间就大逐时能捕捉到的价差收益就多但投资成本也上去了容量配小了投资省了但运行层处处受限该充的时候充不进去该放的时候放不出来购电成本降不下来。所以必须把两层放在同一个优化框架里同时求解。这也是为什么储能容量优化不能像单纯的经济调度那样只管运行也不能像简单的静态评估那样只算经济账。1.3 为什么LP不够MILP刚刚好有人会问这问题看起来就是个线性规划LP嘛目标函数和约束都是线性的直接用线性规划求解不就行了理论上如果你允许储能系统“同时充电和放电”那么LP确实能给出一个结果。但那个结果在物理上毫无意义——模型会发现让一股电流充进去、另一股放出来能量被效率系数白白吃掉两次却能同时满足功率平衡和SOC约束。为了避免这种虚功率解你必须引入充放电互斥逻辑也就是“充电状态”和“放电状态”不能同时为1。这种0-1状态变量就是整数变量。同理购电和售电状态在任何时刻也只能取其一又要一组0-1变量。再加上容量本身可以选择离散档位比如按50kWh一档递增整型变量会进一步增加。所以这个问题的标准形态就是混合整数线性规划MILP一部分连续变量表达各时段的功率和能量状态一部分0-1整数变量表达互斥状态和离散决策目标函数和所有约束均保持线性。MILP算法成熟求解器通过分支定界法处理整数变量Matlab自带的intlinprog就能解规模大了可以换Gurobi或CPLEX开箱即用。2. 完整数学模型目标函数、约束体系与线性化处理2.1 目标函数怎么拆从一次性投资到年化运行成本储能容量优化的目标函数我没直接用“总投资最小”而是用“年化总成本最小”。原因是投资和运行在不同时间尺度上不折算到同一基准没法比较。年化总成本拆成四块C_inv储能系统投资成本的等年值。一次性投资c_E·E_ess c_P·P_ess通过等年值系数CRF折算到每年。C_om年运行维护成本通常按初始投资的2%~3%估算。C_ope年运行成本主要是从电网购电的费用减去向电网售电的收益。C_pen可靠性惩罚成本包括失负荷惩罚和弃光惩罚用来保证优化不会为了省钱而牺牲供电质量或可再生能源消纳。目标函数写出来就是min C_total C_inv C_om C_ope C_pen其中等年值系数的公式是CRF rho * (1rho)^Y / ((1rho)^Y - 1)rho是折现率Y是储能系统寿命年数。这里我踩过一次坑一开始偷懒把一次性投资直接除以寿命年数平均摊结果忽略了资金的时间价值。对一个10年寿命的项目直接用简单平均和用CRF折现年化成本能差10%以上直接影响最优容量档位的选择。2.2 变量体系连续量与0-1整数量的分工建模前先列一张变量表把模型的结构看清楚。我的习惯是先把变量都列出来再写约束不然写到一半容易乱。变量类型含义维度E_ess连续/离散储能额定容量kWh标量P_ess连续/离散储能额定功率kW标量P_ch(t)连续t时段充电功率kWT×1P_dis(t)连续t时段放电功率kWT×1u_ch(t)0-1整数充电状态标志T×1u_dis(t)0-1整数放电状态标志T×1SOE(t)连续t时段储能能量状态kWh(T1)×1P_buy(t)连续t时段向电网购电功率kWT×1P_sellout(t)连续t时段向电网售电功率kWT×1u_buy(t)0-1整数购电状态标志T×1u_sell(t)0-1整数售电状态标志T×1P_shed(t)连续t时段切负荷功率kWT×1P_curtail(t)连续t时段弃光功率kWT×1这里一个小设计点我没有直接用百分比SOC作为状态变量而是用能量型变量SOE单位kWh。这个选择后面会解释它直接避开了一类双线性项是建模时的关键简化。2.3 约束体系功率平衡、能量递推与互斥逻辑约束体系是这个模型的重头戏我按功能拆成五组来写。功率平衡约束。每个时段负荷功率必须等于光伏出力减去弃光、加上储能放电减去充电、加上购电减去售电、再加上切负荷P_load(t) P_pv(t) - P_curtail(t) P_dis(t) - P_ch(t) P_buy(t) - P_sellout(t) P_shed(t)这里P_shed和P_curtail是松弛变量让模型在极端情况下不会无解。正常工况下惩罚系数会把它们压到0。储能能量递推约束。储能能量在相邻时段的关系是SOE(t1) SOE(t) eta_ch * P_ch(t) * dt - P_dis(t) * dt / eta_diseta_ch和eta_dis分别是充电和放电效率。这一步必须用能量型SOE如果改成SOE(t)除以E_ess得到百分比SOC再乘以E_ess变量就会出现变量和变量相乘的双线性项MILP直接变MINLP求解难度完全不同。我的做法是全程用kWh做能量单位百分比SOC只在约束边界里出现通过soc_min·E_ess和soc_max·E_ess来限定SOE的范围。充放电功率上下限与互斥约束0 ≤ P_ch(t) ≤ P_ess · u_ch(t) 0 ≤ P_dis(t) ≤ P_ess · u_dis(t) u_ch(t) u_dis(t) ≤ 1前两条把充放电功率限制在额定功率范围内第三条保证任何时刻不能同时充放。没有这三条求解器一定会用“同时充放”的虚功率解占便宜。储能能量边界与日循环约束soc_min · E_ess ≤ SOE(t) ≤ soc_max · E_ess SOE(1) SOE(T1)第二条强制储能一个运行周期典型日结束后回到初始能量状态保证优化结果是可重复执行的运行策略而不是慢慢把电池能量耗尽得到的一次性收益。购售电互斥约束0 ≤ P_buy(t) ≤ M · u_buy(t) 0 ≤ P_sellout(t) ≤ M · u_sell(t) u_buy(t) u_sell(t) ≤ 1M是一个足够大的常数big-M一般取负荷峰值的1.2到1.5倍就够。这组约束防止模型在同一时段又买电又卖电在分时电价场景下这是必然要加的不然模型会在低谷时段低价买电、立即高价卖出制造出根本不存在的套利空间。2.4 线性化处理避开双线性项的常规操作MILP建模最需要留意的地方就是双线性项。上面提到的百分比SOC和E_ess相乘是一个另一个常见陷阱是效率系数和功率的乘积看起来线性但如果充放电效率被建模成功率的函数模型就变非线性了。工程项目中把效率视为常数是完全可以接受的简化实际锂电池在常规工作区间内效率差异不大。big-M的选择也需要点经验。M取太大会放大求解器数值误差导致0-1判断失真M取太小又会错误砍掉可行域。我的经验值是M取负荷峰值的1.5倍或储能额定功率上限的1.2倍都能稳定收敛。切记不要图省事直接填1e6那种做法在小规模模型里偶尔能跑场景一复杂就出各种诡异问题。3. Matlab实现路线YALMIP建模与求解器联调实战3.1 环境准备YALMIP和求解器怎么配Matlab里做MILP有两条路直接用自带intlinprog或者装YALMIP工具箱统一建模。我都试过结论是如果你只需要跑一次、规模不大intlinprog足够如果你要反复改模型结构、加约束、换求解器对比YALMIP的效率高得多。YALMIP是一个Matlab的建模层工具把优化模型用符号方式写出来然后自动转化为求解器需要的标准形式。安装很成熟从YALMIP官网下载压缩包解压后加进Matlab路径就行。求解器方面Matlab R2014a之后的intlinprog可以直接被YALMIP调用不需要额外装东西如果学校或公司有Gurobi或CPLEX许可证安装后在YALMIP里指定solvergurobi即可。我用一张表对比下几个求解器的实际体验求解器获取难度小规模T≤24中规模T8760简化说明intlinprogMatlab自带秒级可能数分钟无需额外安装够用Gurobi商业许可/学术许可毫秒级明显更快工业界主流分支定界实现优秀CPLEX商业许可/学术许可毫秒级明显更快和Gurobi同级别SCIP免费中等较慢开源方案依赖配起来略麻烦我的建议先用手头就有的intlinprog跑通模型确认数学层没问题再决定要不要引入商业求解器。模型写错了换再快的求解器也只是更快地得到错误答案。3.2 核心代码逐段拆解下面这段是完整的单典型日建模代码以24小时为例你跑通后可以直接把T改成任意时段。代码设计成“先参数、再变量、后约束”的顺序方便定位问题。%% 基础参数设置 T 24; % 时间步数24表示一天 dt 1; % 时间步长单位小时 eta_ch 0.95; % 充电效率 eta_dis 0.95; % 放电效率 rho 0.08; % 折现率 Y 10; % 储能寿命年数 cE 1500; % 单位容量成本 [元/kWh] cP 800; % 单位功率成本 [元/kW] CRF rho * (1rho)^Y / ((1rho)^Y - 1); % 等年值系数 % 分时电价示意数据峰、平、谷三段 c_buy ones(24,1) * 0.5; c_buy(8:11) 1.0; % 早高峰 c_buy(18:21) 1.2; % 晚高峰 p_sell 0.35; % 上网电价固定 % 负荷和光伏曲线示意数据 P_load [120;110;105;100;95;90;85;80;100;150;180;190;... 170;160;150;145;155;180;220;240;230;200;160;135]; P_pv [0;0;0;0;0;10;40;80;120;150;170;180;... 175;160;140;100;60;20;0;0;0;0;0;0]; %% 决策变量 E_ess sdpvar(1,1); % 额定容量 kWh P_ess sdpvar(1,1); % 额定功率 kW P_ch sdpvar(T,1); % 充电功率 P_dis sdpvar(T,1); % 放电功率 u_ch binvar(T,1); % 充电状态 0-1 u_dis binvar(T,1); % 放电状态 0-1 SOE sdpvar(T1,1); % 储能能量状态 kWh P_buy sdpvar(T,1); % 购电功率 P_sellout sdpvar(T,1); % 售电功率 u_buy binvar(T,1); % 购电状态 0-1 u_sell binvar(T,1); % 售电状态 0-1 P_shed sdpvar(T,1); % 切负荷功率 P_curtail sdpvar(T,1); % 弃光功率 %% 约束条件 C []; % 容量边界 E_min 20; E_max 500; P_min 10; P_max 200; C [C, E_min E_ess E_max]; C [C, P_min P_ess P_max]; % 充放电功率边界与互斥 C [C, 0 P_ch P_ess .* u_ch]; C [C, 0 P_dis P_ess .* u_dis]; C [C, u_ch u_dis 1]; % 能量递推 C [C, SOE(2:T1) SOE(1:T) eta_ch*P_ch*dt - P_dis*dt/eta_dis]; % 能量上下界与日循环约束 soc_min 0.1; soc_max 0.9; C [C, soc_min*E_ess SOE(1:T1) soc_max*E_ess]; C [C, SOE(1) SOE(T1)]; % 购售电互斥 M 1.5 * max(P_load); C [C, 0 P_buy M .* u_buy]; C [C, 0 P_sellout M .* u_sell]; C [C, u_buy u_sell 1]; % 功率平衡 C [C, P_load P_pv - P_curtail P_dis - P_ch P_buy - P_sellout P_shed]; % 虚拟变量非负 C [C, P_shed 0, P_curtail 0]; %% 目标函数 C_inv CRF * (cE * E_ess cP * P_ess) / 1000; % 年化单位千元 C_om 0.02 * (cE * E_ess cP * P_ess) / 1000; % 运维 C_ope sum(c_buy .* P_buy * dt - p_sell * P_sellout * dt) / 1000; C_pen (1e4 * sum(P_shed) 1e3 * sum(P_curtail)) / 1000; Objective C_inv C_om C_ope C_pen; %% 求解 options sdpsettings(solver, intlinprog, verbose, 2); sol optimize(C, Objective, options); if sol.problem 0 fprintf(最优容量: %.1f kWh, 最优功率: %.1f kW\n, value(E_ess), value(P_ess)); else disp([求解失败: , sol.info]); end这段代码里有几个地方值得单独说。第一功率平衡约束我直接写成了一个向量等式YALMIP会把24个时段的等式自动展开不需要写循环。第二目标函数里我把单位统一成千元避免数值量级差太多导致求解器收敛困难。成本系数动辄几百万功率变量是几十几百量级差太远会让线性规划的预处理出问题。这个习惯帮我省过很多次排查时间。第三sol.problem 0是YALMIP的标准判定方式表示求解成功且找到了最优解。如果返回4或5分别对应无界和无可行解这时需要回头查约束而不是怀疑求解器。3.3 从单日模型扩展到全年典型日加权单日模型跑通只能算入门实际项目中我从来不用一条典型曲线代表全年那样误差太大。更稳妥的做法是从全年数据里挑出几个典型日每个典型日代表一段时期按天数加权叠加运行成本容量变量仍然全局共享。如果选了D个典型日第d类日对应的权重是w_d比如夏季工作日占60天权重就是60/365目标函数中的运行成本部分改成C_ope sum_d w_d * sum_t ( c_buy(t) * P_buy_d(t) * dt - p_sell * P_sellout_d(t) * dt )约束里所有逐时变量都要加一个下标d比如P_ch_d(t)、SOE_d(t)。容量变量E_ess和P_ess不带d因为它们是一次性投资决策对所有典型日一视同仁。这样模型求解出来的容量是在全年多个典型场景下“综合表现最优”的方案而不是只对某一天最优。我实际做过对比只用一个典型日配出来的容量比用12个典型日加权少了约22%年化总成本却只便宜了3%相当于为了省3%的成本牺牲了大量极端场景下的供电可靠性。所以多场景加权不是可选优化是必选项。4. 数据准备与边界条件典型日浓缩与参数标幺化4.1 从8760小时到典型日的降维处理全年8760个小时的数据直接扔进MILPT8760会带来8760组二进制变量求解规模直接爆炸。最靠谱的做法是先做典型日浓缩把数据降维到几十个时段再优化。我的标准流程分三步第一步把全年数据按“天气类型工作日/非工作日”粗分类比如夏季晴朗工作日、夏季阴雨工作日、冬季晴朗周末、过渡季阴雨天等。这一步先用人的经验把极端工况框住避免聚类结果里全是形状相似的中等工况。第二步对每一类内部用K-means聚类选取类中心曲线作为候选典型日。特征向量可以选负荷曲线和光伏出力曲线的组合也可以用净负荷曲线负荷减光伏作为主特征因为净负荷才是储能真正需要响应的对象。第三步根据每类的天数占比确定权重w_d。最终典型日数量控制在4到12个之间。数量太少日内光伏尖峰和晚峰负荷的错峰特征会丢失数量太多求解时间成倍上升可边际信息增量递减。我常用的一个组合是8个典型日春、夏、秋、冬各一个晴朗工作日加一个多云/阴雨日。这样既覆盖了光伏出力差异也覆盖了负荷的季节性差异。4.2 边界条件和成本参数的参考取值参数取值直接决定优化结果不能随便拍。下面是截至当前比较常见的一组参考值具体项目里务必拿厂商实际报价和当地电网政策替换。参数典型取值说明磷酸铁锂电芯成本800~1500元/kWh含电芯、模组逐年下降PCS变流器成本500~1200元/kW双向变流器BMS与安装集成300~800元/kWh视项目复杂度而定储能寿命8~12年磷酸铁锂循环寿命对应折现率6%~10%采用项目资本金内部收益率要求充电效率0.92~0.97含DC/DC、PCS损耗放电效率0.92~0.97同上SOC运行范围0.1~0.9延长寿命与可用容量折中峰时购电价1.0~1.3元/kWh各省差异大按实际峰谷时段谷时购电价0.3~0.5元/kWh同上失负荷惩罚1e4元/kWh约等于中断供电的用户损失弃光惩罚1e3元/kWh低于售电价但高于零体现消纳意愿这里特别说下失负荷惩罚的取值逻辑它本质上不是真实成本而是“宁可多花钱建储能也不允许切负荷”的权重表达。把惩罚系数设成购电电价的100倍以上模型在可行时就不会轻易选择切负荷。同时对切负荷变量设置非负约束保证模型可以通过增加储能容量而不是丢掉约束来找到可行解。4.3 量纲陷阱单位不统一定会悄悄毁掉结果Matlab默认忽略单位所有数字就是一串浮点数所以单位统一完全靠建模的人自己把握。这个坑我掉进去过好几次现在总结成三条铁律。第一条功率和能量的单位必须显式区分。功率是kW能量是kWh两者通过时间步长dt小时相乘转换。dt1时可以偷懒不乘但只要把步长改成15分钟dt0.25忘了乘dt的模型结果会完全失真。我这边的工程模板里所有涉及能量的公式都显式写上dt哪怕dt1也不省略。第二条成本和价格的量纲要统一。购电价单位是元/kWh功率单位是kW所以单时段购电成本是c_buy * P_buy * dt单位是元/kWh × kW × h 元对得上。有人直接把c_buy * P_buy当成成本当dt不等于1小时时就会悄悄差出一个倍数。第三条惩罚系数和投资成本的量纲也要对齐。如果储能投资成本算完是“千元”而运行成本算出来是“元”两者直接相加惩罚项会被无限放大或忽略。我在代码里统一在目标函数各项后面除以1000转成千元这个习惯持续到现在。5. 结果复盘与敏感性验证配置数字是否可信5.1 运行曲线怎么读储能行为是否符合物理直觉优化跑完拿到一组容量和功率数字之后我的第一反应不是看数字本身而是把优化出来的典型日逐时运行曲线画出来用物理直觉去验证一遍。正常的运行曲线应该长这样夜间低谷电价时段储能从电网购电充电保持一个较低但不在SOC下限的能量水平上午光伏逐渐爬升若负荷不高光伏盈余先充入储能午间光伏大发如果光伏功率超过负荷与充电需求之和多余部分售电或弃光取决于上网电价傍晚光伏跌落、负荷爬升储能开始放电削峰晚峰时段尽可能维持到放电结束日末SOC回到与日初相同的位置准备第二天循环。如果曲线出现以下任一现象基本可以判定约束写漏了储能充放电切换非常频繁且无规律SOC在日初和日末差异很大却不影响目标函数某时段充放电功率同时为正。前两种大概率是漏了日循环约束或切换惩罚后一种是漏了互斥约束。我还会单独检查一次“不配储能”对比工况。把E_ess和P_ess强制为0模型退化成纯购电优化这时候的运行成本是微网在无储能条件下的基准。储能工况的年度总成本必须显著低于基准值否则说明在给定的参数条件下储能根本不值得配这时候“优化结果”告诉你的是别建而不是给你一个凑合的数字。5.2 敏感性分析光伏渗透率、峰谷价差和可靠性惩罚容量优化只跑一版参数结果在项目汇报时是站不住脚的。业主一定会问如果光伏再多装100kW储能要不要跟着加如果峰谷电价差缩小了投资回报还有没有所以敏感性分析不是加分项是必交付项。我常用的三个维度如下光伏渗透率变化。把光伏容量系数从0.5变到2.0观察最优E_ess和P_ess的走势。趋势通常是这样光伏渗透率较低时储能主要做峰谷套利容量随渗透率缓慢上升渗透率超过某个阈值后午间弃光风险陡增储能容量加速上升因为它还要承接越来越多的光伏盈余转移。这个拐点位置本身就是很有价值的规划信息。峰谷价差变化。把峰时电价从0.8元/kWh拉伸到1.6元/kWh谷时电价不变。价差越大储能每度电的套利空间越厚最优容量基本单调上升。如果价差缩小到不足以覆盖单位容量年化成本最优容量会直接跳变到0模型给出的答案是“不建”。失负荷惩罚变化。惩罚从1e3提到1e5储能容量配置会明显上升因为模型倾向于用储能保障供电而不切负荷。这个维度的敏感性结果可以反向推导出项目对供电可靠性的重视程度体现在造价上值多少钱。每次敏感性分析我会在参数循环外套一层for循环固定其他参数不变单独扫一个参数把结果画成曲线。通常半小时就够跑完但对项目汇报的说服力提升是决定性的。5.3 用全年仿真给优化结果对账优化模型基于典型日计算本质上是降维近似所以拿到配置结果后必须做一次全年逐时仿真对账确认配置方案在真实8760小时数据上的表现和优化模型估计值偏差不大。对账方法很简单固定优化得到的E_ess和P_ess把典型日加权模型换成全年逐时模型但整数变量只保留运行层充放互斥、购售互斥容量变量不再参与决策。逐时模型是MILP但规模不算太离谱用intlinprog可以跑跑不动就退化成启发式规则调度。对账的核心指标有两个一是年购电成本二是全年SOC越界次数和能量不平衡总量。偏差在5%以内说明典型日浓缩质量很好偏差超过10%回头检查典型日的数量和聚类特征是否选得不合适。还有一个容易被忽视的偏差来源典型日模型每天强制SOC回到起点但实际连续运行中储能可以从前一天带过一个已经部分充电的状态。典型日模型因此会略微低估储能可用的跨日调节能力导致容量配置偏保守。解决方法是把典型日按连续日期顺序连接起来仿真或者在典型日模型中允许SOE(1)和SOE(T1)在前后几小时内小幅浮动。6. 求解效率优化与高频坑位自检6.1 三种降低求解规模的做法即使是8个典型日、每典型日24个时段MILP的整数变量规模也到了8×24×4768个0-1变量加上连续变量intlinprog还能对付。但如果你把时域拉到8760小时直接求解整数变量会到3万多个分支定界树能把你等哭。我的经验是优先用下面三种手段控制规模。第一种是典型日压缩前面已经讲过不再重复。第二种是容量变量离散化。与其让E_ess连续取值不如在建模前生成候选容量序列比如50、100、150、200、250kWh五档用五个0-1变量选一档。这样容量决策的整数结构更清晰还能直接输出可采购的标准规格。代价是可能错失非标准档位的最优解但工程上本来就会采购标准规格这个损失可以接受。第三种是投资层和运行层解耦迭代。先固定一组容量候选值对每个候选值求解纯运行调度问题只用连续变量很快然后用运行结果拟合成本曲线再对容量做整数搜索。这个启发式的“两步法”不一定保证全局最优但收敛速度快一个数量级。我一般先用两步法摸个底再用全MILP精确校核最优解附近的一个小区间兼顾速度和精度。6.2 高频坑位自检清单最后分享一份我每次交付前都会过一遍的自检清单里面每条都是实际流过的血坑位现象根本原因解法求解结果同时充放电漏了充放互斥约束增加u_chu_dis≤1模型提示无可行解功率平衡里缺松弛变量增加P_shed和P_curtail及惩罚项SOC越界但运行正常忘记把SOE限制到soc_min·E_ess和soc_max·E_ess之间补上能量上下界约束求解时间过长big-M取得太大数值病态M改为负荷峰值的1.5倍左右目标函数单位混乱投资、运行、惩罚单位未统一全部除以1000转成千元典型日结果年化偏差大于10%典型日数量太少或不代表极端场景增加典型日数量覆盖阴雨天容量结果为0储能年化成本高于套利收益检查参数这可能是正确结论反复振荡不收敛效率系数和加载逻辑出现非线性检查是否有变量相乘项改成常数效率其中“容量结果为0”那条最容易误判。我有一次给一个电价极低地区的微网做优化模型给出的最优配置是0——因为当地工业电价便宜峰谷价差又小储能的年化成本确实收不回来。起初我以为模型写错了排查两天后确认参数无误最后如实告诉业主“当前电价结构下不建议建储能”。这个结论虽然不漂亮但比拍一个误导投资的容量数字负责任得多。还有一条关于初始化的经验如果你在YALMIP里设置sdpsettings(solver,intlinprog,intlinprog.MaxNodes,1e6)限制了分支节点数求解器报告“达到节点上限退出”时拿到的不是严格最优解。这时要么放宽节点限制要么把当前可行解作为初值在它周围加一个小邻域重新求解可以显著改善解质量。我自己在项目交付时有个固定动作跑完优化后会把典型日扩展到12个日类型再做一次复核看容量结果是否稳定在同一个区间。如果两次配置结果差异在10%以内说明结果对典型日选取不敏感可以放心写入报告如果差异大通常意味着原始数据里存在被聚类抹掉的重要工况这时候回看数据分布比在模型里补约束更有效。这套基于混合整数规划的储能容量优化方法我前后在三个不同场景的微网项目里落地过——园区光伏微网、海岛独立微网和厂区光储充一体化项目每次都把典型日加权、敏感性分析和全年对账三步走完才交付。MatlabYALMIP这条链路最大的优势不是求解速度而是改模型快加了新的约束、换了目标函数代码结构不动跑一版就知道影响有多大。如果你也在做类似的项目建议先把单典型日模型跑通再逐步扩到多场景加权一步一个脚印地把每个阶段的输出都验证一遍最后拿到的容量配置一定有底气。