基于Matlab+Yalmip的分布式储能容量优化配置方法
2026/9/12 3:10:28 网站建设 项目流程

最近在帮几家企业做分布式储能的前期测算,大家问得最多的一个问题出奇一致:光伏和负荷曲线都在手里,储能到底该配多大?配小了,削峰填谷不明显,收益掰扯不明白;配大了,投资回收期越拉越长,老板看着成本表直皱眉。这个问题放到专业语境里,就是“考虑产销者的分布式储能容量配置策略”,而且大多数情况下,我们都是直接在 Matlab 里完成数据整理、优化建模、求解和结果可视化。这篇文章就把我实际做测算时用的思路和代码框架完整摊开,包括目标函数怎么建、约束怎么写、求解器怎么选,以及哪些地方最容易踩坑。

无论你是做园区光储项目方案的工程师,还是在学校研究分布式储能规划的研究生,这套方法都能直接拿去过一遍:先用典型日数据跑通模型,再根据实际场景慢慢加约束、加敏感性分析。不用一上来就追求完美,先把最核心的逻辑表达清楚,后面扩展才不会乱。

1. 配储容量策略的核心逻辑:这是一个“先想清楚收益,再决定装多大”的问题

1.1 产销者到底指什么,为什么储能决策会变复杂

“产销者”(prosumer)这个词,是由生产者和消费者组合出来的概念。放在电力系统里,最典型的就是那些装了屋顶光伏的工商业用户,白天光伏出力超过负荷,余电上网,晚上负荷高,又得从电网买电。同一个主体,在不同时间点分别扮演“发电方”和“用电方”,所以叫产销者。

为什么这个身份会改变储能配置的思路?因为储能的价值不再只是单纯的消纳光伏,而是同时作用在两条线上:一条是减少从电网买电,另一条是提高自发自用比例甚至参与电力市场交易。光伏大发时段你可以把多余电量存下来,等电价高或者负荷大的时段再放出去,相当于人为地平移了一部分电能。如果只把储能当成“电池”来配,不考虑产销者自身负荷曲线与光伏曲线的匹配程度,配出来的结果往往要么偏大要么偏小。

在实际工程项目里,我们还要面对峰谷电价、上网电价、变压器容量限制、并网要求、储能循环寿命等多重因素。容量配置策略表面上看是算一个“多少千瓦、多少千瓦时”,实际上是在回答一系列问题:储能在什么时刻充放电、每天循环多少次、一年下来能替代多少高价电、又能通过售电回收多少成本。这些运行层的细节反过来说明了为什么需要用一个优化模型来做容量配置,而不是凭经验拍脑袋。

1.2 表面是容量决策,背后是运行策略耦合

如果直接问“储能配多大”,很多人第一反应是算一个公式:光伏装机乘一个比例,或者按负荷峰值乘一个比例。但这么做往往吃亏。因为储能容量和运行策略是强耦合的——同样的 100 kWh 电池,如果运行策略合理,一年能帮你转移的电量可能很差很多。

举例来说,一块 50 kW / 100 kWh 的储能,如果每天固定晚上充满、早上放空,收益主要来自峰谷价差;但如果负荷高峰出现在中午后两点,光伏又在这个时段多发,适合的调度策略就应该是“午间充电、下午放电”,而不是机械地按照“充一放一”的常规套路。而这些运行决策,又直接决定了储能最终能创造多少价值,进而影响你觉得“配多大容量划算”。

所以正规的做法是把容量配置建模成一个嵌套的优化问题:外层确定额定功率和额定容量,内层在给定的容量下,对每个典型日做充放电策略优化,算出最优运行收益。把内层收益带回外层,再比较不同容量组合下的总成本。用数学规划的语言来说,这其实就是一个两层优化问题,不过在大多数工程简化模型里,可以把它合并成一个包含容量变量和调度变量的大规模数学规划,一次性求解。

1.3 为什么选择 Matlab 来做这件事

这几年 Python 在数据处理和深度学习领域很火,但电力系统优化这块,Matlab 的生态和积累依然很深。Yalmip 这个建模工具箱尤其好用,它让优化模型的表达方式非常接近数学公式本身,不需要把问题手动改写成矩阵形式。同时 Matlab 自带的数据处理、绘图、报表输出能力,也能让项目交付更顺畅。

我自己跑这种容量配置优化时,基本流程是:用 Excel 或 Python 把光伏和负荷数据处理成典型日序列,导入 Matlab;用 Yalmip 搭建优化模型;调用求解器求解;再写几个绘图脚本把 SOC、充放电功率、购售电曲线画出来。整个过程思路清晰,也方便后续在模型里加储能寿命衰减、需求响应价格等更复杂的模块。

2. 数学模型到底怎么写:目标函数、约束条件和求解器选型

2.1 目标函数:把全生命周期成本压缩到一年

储能容量配置的优化目标,一般习惯写成“年化总成本最小化”。这样把投资成本、运行成本和收益统一到同一个时间尺度上,比较起来最直观。年化总成本大体由四块组成:

  • 储能的投资年值:额定功率乘以单位功率成本,加上额定容量乘以单位容量成本,然后乘以等额年值系数;
  • 年运维成本:通常和容量或者循环电量挂钩;
  • 年购电费用:从电网买电的电费支出;
  • 年售电收益:余电上网或者参与现货市场带来的收入,作为负成本计入目标函数。

如果用数学公式表达,就是:

min F = CRF x (Cp x P + Ce x E) + Com x E + Σ weight(k) x Σ [ρbuy(h) x Pbuy(h,k) - ρsell(h) x Psell(h,k)]

其中,CRF 是等额年值系数,计算方式是 r(1+r)^n / ((1+r)^n - 1),r 是折现率,n 是储能寿命。Cp 是单位功率投资成本,Ce 是单位容量投资成本,P 和 E 分别对应额定功率和额定容量。Com 是单位容量的年运维成本。后面那个求和式则是在所有典型日上累加购电支出、减去售电收入,weight(k) 表示第 k 个典型日在一年中出现的天数。

这里要注意的是,目标函数看起来只是在算经济账,但通过运行变量 Pbuy 和 Psell 的优化,储能的自发自用行为、峰谷套利行为都会被自然而然地带出来。只要购电电价高于售电电价,模型就倾向于先让光伏满足本地负荷,而不是主动买电再卖电做无意义的循环。

2.2 约束条件:功率平衡、SOC边界和首末端一致性

目标函数建好以后,还要给模型加上一组物理和运行约束,否则求解器可能会给出“理论上不可能实现”的方案。最基本的包括以下几类:

  1. 功率平衡约束:任一时刻,光伏出力加上放电功率加上购电功率,必须等于负荷加上充电功率加上售电功率。这个约束的本质是能量守恒,是整个模型的中枢。

  2. 充放电功率限制:充电功率和放电功率都不能超过储能额定功率,并且都是非负的。这里也会引申出一个工程细节:要不要加“不能同时充电和放电”的约束。理论上,由于充放电都有损耗,模型在正常电价下不会选择同时充放,但如果遇到某些极端价格波动,或者求解器数值精度不足,可能会出现微小同时充放的现象。工程上想彻底避免,就得引入二进制变量来互斥,但这样会把线性规划升成混合整数线性规划,求解难度有所上升。

  3. SOC 递推约束:下一时刻的电池电量等于当前电量加上本时段净充电量。如果时间步长是 1 小时,那么每步储能电量变化就是充电功率乘以充电效率,减去放电功率除以放电效率。

  4. SOC 上下限约束:为了延长电池寿命,一般不允许电量随便放到 0 或充到 100%,工程上常用 10% 到 90% 作为边界。上下限都写成额定容量乘以一个系数的形式,这样容量变量和电量变量就被联立在一起。

  5. 首末端 SOC 一致性约束:为了模拟“每一天都是独立运行周期”,通常会要求储能每天的初始电量和日末电量相同。这个约束让模型不能“吃老本”——不能第一天把电池放空、第二天又靠初始电量占便宜,必须保持可持续的日循环。

2.3 求解器选型:MILP 是常规解法,启发式算法要慎用

上面这套模型,如果所有变量都是连续的,本质上就是一个线性规划问题;一旦加入“防止同时充放电”的二进制变量,就变成了混合整数线性规划。对于 MILP,工程上最常用的求解器是 Gurobi 和 CPLEX,两者性能都很强,而且高校都有学术授权渠道。如果没有商业求解器,SCIP、CBC 这类开源求解器也能跑,只是大规模问题的求解速度会慢不少。

我在实际测算中通常直接用 Yalmip 建模,求解器设置为 Gurobi。原因是 Yalmip 的语法几乎和数学公式一一对应,写起来不费劲,后面想切换求解器也只需改一行配置。至于遗传算法、粒子群这类启发式算法,也不是不能用,但它们在处理 SOC 递推这样带强耦合时序约束的问题时,经常陷入局部最优,而且每次运行结果可能不一样。所以在能做数学规划求解的情况下,优先用数学规划,把启发式算法留给那些非线性太强、无法线性化的扩展问题。

3. Matlab 代码实现:一套可以直接改着用的基础框架

3.1 先做数据整理,再写模型,顺序千万别反过来

很多新手一上来就打开 Matlab 写优化模型,结果写到最后发现数据格式不对,回头改代码改到怀疑人生。我的习惯是先把数据处理成“典型日矩阵”的格式:每一列是一个典型日,每一行是一天 24 个小时,光伏和负荷各生成一个 HxK 矩阵,再单独定义一个权重向量,用来表示每个典型日包含的天数。

典型日怎么来?最简单的做法是按季节划分,比如春夏秋冬各取一个代表日。更精细一点的方法是用 k-means 算法对全年 8760 小时的光伏-负荷组合做聚类,选出 4 到 12 个典型日。聚类的好处是能保留全年不同天气类型和负荷模式的差异,又不至于让优化模型规模爆炸。我自己做可研的时候,通常先用 4 个典型日跑出初步结果,再用 12 个典型日验证结果的稳定性,如果两者差异不大,说明这个配置策略对数据细节不敏感,可信度比较高。

3.2 核心代码注释与关键模块解析

下面这段代码是整套容量配置模型最核心的部分,采用 Yalmip 建模,调用 MILP 求解器。实际使用中需要把 PV 和 Load 替换成你自己的数据。

%% 分布式储能容量配置基础框架(Yalmip + MILP) % 需要预装Yalmip工具箱以及可用的MILP求解器(Gurobi/CPLEX/SCIP等) % 输入矩阵说明: % PV(H,K) 每个典型日各小时的光伏出力,单位 kW % Load(H,K) 每个典型日各小时的负荷,单位 kW % weight(K) 每个典型日在一年中代表的天数,例如 90 90 90 95 % 输出:P_opt, E_opt 分别为最优额定功率和额定容量 clear; close all; clc; dt = 1; % 时间步长,单位小时 H = 24; K = 4; % 24小时,4个典型日 PV = rand(H,K) * 50; % 示例数据,实际请替换为聚类后的光伏曲线 Load = rand(H,K) * 80; % 示例数据,实际请替换为聚类后的负荷曲线 weight = [90 90 90 95]; % 每个典型日对应的天数 % 成本与效率参数,单位均为元、kW、kWh Cp = 1200; % 储能功率成本,元/kW Ce = 800; % 储能容量成本,元/kWh r = 0.06; % 折现率 n = 10; % 储能寿命,年 CRF = r * (1 + r)^n / ((1 + r)^n - 1); Com = 0.02 * Ce / 10; % 年运维成本,按容量折算 eta_ch = 0.92; % 充电效率 eta_dis = 0.92; % 放电效率 % 分时电价,单位元/kWh,这里先给一个简单示例 rho_buy = ones(H,1) * 0.6; % 购电价格 rho_sell = ones(H,1) * 0.35; % 售电价格 % 决策变量定义 P = sdpvar(1,1); % 储能额定功率,kW E = sdpvar(1,1); % 储能额定容量,kWh Pch = sdpvar(H,K); % 充电功率 Pdis = sdpvar(H,K); % 放电功率 Ebat = sdpvar(H+1,K); % 电池电量状态,kWh,首行对应初始SOC Pbuy = sdpvar(H,K); % 购电功率 Psell = sdpvar(H,K); % 售电功率 Constraints = []; Objective = 0; for k = 1:K for h = 1:H % 功率平衡:光伏+放电+购电 = 负荷+充电+售电 Constraints = [Constraints, PV(h,k) + Pdis(h,k) + Pbuy(h,k) == ... Load(h,k) + Pch(h,k) + Psell(h,k)]; % 充放电功率限制 Constraints = [Constraints, 0 <= Pch(h,k) <= P]; Constraints = [Constraints, 0 <= Pdis(h,k) <= P]; Constraints = [Constraints, Pbuy(h,k) >= 0]; Constraints = [Constraints, Psell(h,k) >= 0]; end for h = 1:H % SOC递推:假设自放电率忽略不计 Constraints = [Constraints, Ebat(h+1,k) == Ebat(h,k) + ... (eta_ch * Pch(h,k) - Pdis(h,k) / eta_dis) * dt]; end % SOC上下限约束,取额定容量的10%到90% Constraints = [Constraints, 0.1 * E <= Ebat(:,k) <= 0.9 * E]; % 首末端SOC一致,这里取初始SOC为额定容量的20% Constraints = [Constraints, Ebat(1,k) == 0.2 * E]; Constraints = [Constraints, Ebat(H+1,k) == 0.2 * E]; % 累积运行成本:购电费用减去售电收入 Objective = Objective + weight(k) * ... sum(rho_buy .* Pbuy(:,k) - rho_sell .* Psell(:,k)); end % 加上投资年值和运维成本 Objective = Objective + CRF * (Cp * P + Ce * E) + Com * E; % 求解设置 ops = sdpsettings('solver', 'gurobi', 'verbose', 2); sol = optimize(Constraints, Objective, ops); % 结果输出 if sol.problem == 0 P_opt = value(P); E_opt = value(E); fprintf('最优配置结果:P=%.2f kW, E=%.2f kWh\n', P_opt, E_opt); else disp('求解失败'); disp(sol.info); end

3.3 结果可视化:SOC曲线和充放电功率曲线怎么画

求解完成之后只给一个功率和容量数字,说服力是不够的。做项目汇报时,我一般会同时输出两类图:一类是典型日的储能充放电功率曲线,另一类是 SOC 曲线。这两张图能直观说明储能一天是怎么跑的,也能用来验证模型结果是否符合物理直觉。比如,如果 SOC 曲线突然出现不正常的跳变,多半是某个约束写错了或者单位没对齐。

下面这段代码画第一个典型日的充放电功率曲线和 SOC 曲线:

k_plot = 1; % 想查看第几个典型日 t = 1:H; figure; subplot(2,1,1); plot(t, value(Pch(:,k_plot)), 'LineWidth', 1.5); hold on; plot(t, value(Pdis(:,k_plot)), 'LineWidth', 1.5); legend('充电功率','放电功率'); xlabel('时刻/h'); ylabel('功率/kW'); title('典型日充放电功率'); subplot(2,1,2); plot(0:H, value(Ebat(:,k_plot)) / max(E_opt,1e-6) * 100, 'LineWidth', 1.5); xlabel('时刻/h'); ylabel('SOC/%'); title('典型日SOC变化曲线');

画图之后,我还会把目标函数里的各项成本拆出来打印一遍,比如年购电成本、售电收入、投资年值、运维成本,分别看看哪一项对最终结果影响最大。这远比只看一个总成本数字更有用。

3.4 从单用户配置扩展到多产消者群体

单个产销者的模型跑通之后,下一步经常要做的是“共享储能”或“社区储能”的场景。这时多个产销者共用一个储能系统,决策变量就多了两层:第一层是储能总容量和总功率,第二层是每个产销者对储能的充放电权利分配。建模时目标函数要改为整个群体总年化成本最小,同时还要加入公共变压器容量约束、各用户单独计量约束以及利益分配机制。

在这个扩展场景里,我会把上述代码做成一个子函数,每次传入某类用户的负荷和光伏曲线以及分配到的储能份额,单独算出该用户的运行收益;外层再用一个循环或另一个优化层去搜索总容量和分配比例。虽然计算时间会成倍增加,但换来的结论对园区级项目非常关键:与其给每栋楼各配一套储能,不如集中建一套大的共享储能,利用不同用户的峰谷错位效应相互错峰,整体容量能下降不少。

下表是我在某个园区项目里的测算对比,仅作为思路展示,不代表任何具体报价:

场景额定功率额定容量年化总成本相对独立配置成本
每个用户独立配置合计 185 kW合计 430 kWh46.8 万元基准
共享储能优化配置120 kW280 kWh35.2 万元下降约 25%
共享储能但固定比例分配130 kW320 kWh38.6 万元下降约 17%

4. 案例测算与结果解读

4.1 参数设置与基础数据

为了讲清楚结果怎么读,我在这里放一个典型的工商业产销者案例。某工厂屋顶铺设了 100 kWp 光伏,全年发电量大约 11 万 kWh,工厂年用电量约 32 万 kWh。园区峰谷电价差距约 0.7 元/kWh,具体分为峰时 1.0 元、平时 0.6 元、谷时 0.3 元。上网电价按 0.35 元/kWh 计。储能投资成本按当前行业常见水平估算:单位功率成本 1200 元/kW,单位容量成本 800 元/kWh。折现率取 6%,寿命按 10 年计算,充放电效率均为 92%。

先做一下年化系数计算:CRF = 0.06 x 1.06^10 / (1.06^10 - 1),算下来大约是 0.1359。也就是说,如果容量投资是 100 万元,折算到每年约 13.59 万元。这个换算能帮我们把一次性投资放到年度经营现金流里比较,是项目测算非常关键的一步。

4.2 不同配置方案的经济性对比

为了说明优化配置的差别,我在同一个数据基础上对比了四个方案:无储能、按固定比例简单配置、优化模型推荐配置、以及过度配置。结果都是示意性数据,重点看趋势。

场景额定功率额定容量年投资+运维成本年电费净支出年化总成本
无储能--0 万元18.6 万元18.6 万元
固定 30 kW / 60 kWh30 kW60 kWh2.1 万元14.7 万元16.8 万元
优化配置 40 kW / 110 kWh40 kW110 kWh3.8 万元12.4 万元16.2 万元
过度配置 80 kW / 200 kWh80 kW200 kWh6.9 万元11.9 万元18.8 万元

从这张表能很清楚地看到,储能容量不是越大越好。过度配置虽然把电费净支出降低到 11.9 万元,但投资和运维成本上升得更快,反而导致年化总成本比无储能还高。优化配置方案把年化总成本压到 16.2 万元,比固定配置又省了 0.6 万元左右。这就是做容量优化配置的价值——它解决的不是“能不能省钱”的问题,而是“在什么位置省钱最划算”的问题。

4.3 结果怎么读:功率比、临界价差和灵敏度

拿到最优结果 P=40 kW、E=110 kWh 之后,不要只报数字。我一般会再往下挖三个维度:

第一是功率容量比。这个例子中 P/E 大约是 0.36,也就是说储能时长接近 2.75 小时,属于目前工商业储能常见的“2到4小时”区间。如果结果出现 0.1 以下的功率容量比,通常意味着储能只在极少数时段放电,收益更多来自容量电价而非峰谷套利;如果超过 1,那更像功率型储能,收益逻辑完全不同。

第二是临界峰谷价差。把峰谷价差从 0.7 元往下扫,看到某个价差条件下最优容量突然归零,那个点就是储能投资的临界价差。这个参数放在项目谈判里非常关键,因为很多客户会问“如果电价政策调整了,这套配置还划不划算”。

第三是灵敏度分析。我通常会分别调整光伏装机、负荷峰值、电池成本、折现率四个输入参数,上下浮动 20%,重算最优容量。如果某个参数变化一点,最优容量就剧烈波动,说明这个项目对那个参数高度敏感,交付时就要重点提示风险。

5. 常见坑位与排查心得

5.1 求解失败与不可行问题

用 Yalmip 求解时最常遇到的问题是模型不可行,也就是sol.problem不等于 0。常见原因有三个。

第一个是 SOC 边界约束和首末端一致性约束互相冲突。如果额定容量 E 被优化器试探到一个特别小的值,比如接近于 0,那么Ebat(1)=0.2EEbat(H+1)=0.2E会让电池电量几乎全程被压在极低水平,SOC 上下限又要求电量在 0.1E 到 0.9E 之间,两者很容易形成矛盾。解决办法是给 E 加一个合理下限,比如至少 10 kWh,或者把初始 SOC 约束放宽为Ebat(1,k) <= 0.2E这样的不等式,让模型有更多自由度。

第二个原因是数据单位不统一。光伏可能给的是 MW,负荷给的是 kW,功率平衡方程两边差了 1000 倍,模型自然无解或者给出离谱结果。我在跑数据之前一定会统一单位,全部转成 kW 和 kWh,再检查一遍典型日的负荷峰值和光伏峰值是否在合理范围。

第三个原因是时间步长和容量单位混用。如果原始数据是 15 分钟一个采样点,那么 SOC 递推里的 dt 就是 0.25 小时,而不是 1。漏改 dt 会导致模型以为 15 分钟跑完了一小时的电量,结果 SOC 频繁触界,最终配置结果失真。

5.2 Yalmip 跟求解器环境配合的坑

Yalmip 本身只是一个建模接口,不带求解器。如果没装 Gurobi 或 CPLEX,它默认会去找 Matlab 自带的线性规划求解器,或者用一些基础的开源求解器,跑小型问题可能没问题,但一旦变量数量上去,速度会慢到怀疑人生。我在配置环境时一般会按下面这个顺序处理:

先安装 Yalmip,然后把求解器安装目录加入 Matlab 路径。Gurobi 的学术许可以学校邮箱申请,CPLEX 也有类似渠道。如果暂时申请不到商业求解器,可以先用 SCIP 或者 CBC,它们能处理 MILP,只是大规模场景下性能差距比较明显。另外提醒一句,Matlab 版本太老可能和新版 Gurobi 不兼容,建议在装求解器之前先看一下官方兼容性列表。

5.3 典型日数据不足导致配置结果偏激进

用 4 个典型日跑优化,很多时候结果会偏激进,因为典型日代表的是“平均状态”或者“聚类中心状态”,那些极端连续高温天、阴雨天、节假日低负荷天都被平均掉了。储能容量在这种模型里往往偏低,因为它每天都能按照理想模式充放一次,实际运行中却不一定有这么多机会。

所以我一般至少会用两种方式做校验。第一种是增加典型日数量,比如从 4 个增加到 12 个,比较结果是否稳定;第二种是取全年 8760 小时数据直接做一次运行模拟,固定容量后评估全年逐时 SOC 变化和收益情况,这一步不是优化,而是仿真验证。如果仿真年收益和优化模型估算的收益差超过 10%,说明典型日选取不够合理,需要重新聚类。

5.4 从测算到落地的额外建议

模型和代码再完善,也只是把物理世界简化成了数学问题。到了真正落地阶段,还要额外考虑几个模型里没体现的东西。比如电池循环寿命衰减,如果每天满充满放一次,电芯衰减速度会比浅充浅放快很多,这会影响全生命周期的收益估算。更精细的做法是用雨流计数法统计放电深度分布,再折算等效循环次数;不过在容量配置阶段,我更建议先用一个简单的等效循环折算系数去判断结果是否稳健,不必一上来就上复杂模型。

再比如动态电价行情。现在很多地方现货市场价格波动越来越大,固定峰谷电价假设已经开始失真。如果项目所在地区有现货市场,建议在模型中引入几个典型电价场景,把容量配置结果对电价场景的敏感性列出来,否则算出来的“最优”很可能只是特定历史电价下的最优。

最后说两句自己的体会

模型第一次跑通的时候,我也一度觉得“就这么简单?”。但后来拿结果跟实际项目对比,发现差距往往不在求解器精度,而在输入数据的质量和对运行约束的理解。光伏预测偏差、负荷波动、电价变化,任何一个环节数据没处理好,优化结果都会偏差很大。所以我现在的习惯是:先用一个最简单的基础模型把代码链路跑通,再逐步加约束、加场景,每次只改动一个变量,确保每一步结果都可解释。这个方法放到储能容量配置里很管用,放到其他类似的工程优化问题里也是一样。希望这套框架能帮你少走点弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询