ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

共享储能日前经济调度:Matlab+YALMIP完整建模与求解

共享储能日前经济调度:Matlab+YALMIP完整建模与求解 简介共享储能电站用户日前优化经济调度的 Matlab 完整源码面向电力系统研究者、电气工程专业学生及储能调度算法入门者重点解决多时段电价与负荷波动下的充放电策略优化问题。压缩包内共 2 个文件均为 m 脚本源码整体仅 4KB轻量易读资源结构清晰便于快速定位与修改参数其中基础案例构建了包含充放电效率、容量与功率约束的储能模型进阶案例引入电价波动、负荷预测误差等不确定性因素便于对照学习不同场景下的调度方法。目前已有 401 人学习下载。通过运行与拆解代码可掌握日前调度建模流程、约束处理技巧与结果分析方法也能延伸到粒子群、动态规划等优化算法的实践应用适合用于课程设计、论文复现或实际项目预研。1. 共享储能经济调度从“各自为政”到“统一出清”的日前优化共享储能电站的日前优化经济调度解决的不是“怎么充放电”的物理问题而是“在已知次日负荷、电价和储能状态的前提下如何安排每个用户的充放电计划使整体经济性最优”的决策问题。它把传统单用户储能变成了多用户共用的资源池通过集中式优化或分布式协调把峰谷价差收益、需量电费削减和服务费分摊统一进一个目标函数。这个场景在工业园区、商业楼宇和新能源配储项目中非常常见Matlab YALMIP 是当前最主流的建模求解组合。本文直接从数学模型讲到可复现的完整源码覆盖约束构造、求解器选型、参数整定和结果校验适合正在做储能调度算法、写毕业论文或做项目落地的工程师。2. 共享储能日前调度的数学本质目标函数与约束边界2.1 为什么日前优化必须“统一建模”而不能逐户独立优化共享储能电站的核心特征是“一个电池多个用户”。如果每个用户单独优化自己虚构的储能那么电站的总充放电功率必然超配因为没有任何机制保证“你想充电时别人恰好也在放电”。日前优化的意义就在于提前一天用负荷预测数据和分时电价曲线把所有用户的功率需求叠加上储能功率变量在统一的约束条件下求全局最优解。这里的关键不是算法多复杂而是约束能不能精确表达物理边界。日前优化的时间尺度通常是 24 小时、15 分钟或 1 小时一个时段。时段越细越能反映电价尖峰和负荷陡坡但决策变量和约束数量成倍增长。对于 10 个用户、96 个时段的模型决策变量大约有 10×2×961920 个连续变量加上储能 SOC 状态变量规模并不大用线性规划或混合整数线性规划都能在几秒内解完。2.2 目标函数购电成本 服务费 惩罚项的标准结构目标函数通常写成最小化总成本的形式% 目标函数minimize 总成本 % C_grid : 从电网购电成本用户侧 % C_fee : 支付给储能电站的服务费 % C_penalty : 负荷越限或 SOC 越界的惩罚项 objective sum(sum(C_grid .* P_buy)) ... % 分时电价购电成本 sum(sum(C_grid .* P_sell)) * 0.8 ... % 余电上网收益折价系数 sum(sum(fee_rate .* (P_dis P_ch))) ... % 储能服务费 C_penalty;参数说明1 到 3 行把电网交互功率分成购电 P_buy 和售电 P_sell 两个非负变量避免用单一净功率导致目标函数在多时段耦合时失去单调性。服务费按充放电功率绝对值之和计算是共享储能电站回收投资的主要方式。fee_rate 是每 kWh 的服务费率通常在 0.1~0.3 元/kWh 之间。C_penalty 用来处理软约束比如“用户申报负荷违约”或“SOC 未回到初始值”惩罚系数取 1000 以上才会对目标产生实质影响。2.3 约束条件功率平衡、SOC 递推和共享容量分配约束条件分为三类缺一不可。2.3.1 用户功率平衡约束这里有个关键逻辑用户负荷由电网购电、储能放电和自己可能的光伏出力共同满足。公式为% 每个用户每个时段的功率平衡 % P_load(i,t) P_ch(i,t) P_buy(i,t) P_dis(i,t) P_pv(i,t) Constraints [Constraints P_load P_ch P_buy P_dis P_pv];注意P_ch 和 P_dis 是同一个储能对不同用户分配的充放电功率不是用户自己的储能。它们必须满足“同用户同时段不能同时充放电”的逻辑但这是由共享储能的物理约束统一限制的不需要每个用户单独加二进制变量。2.3.2 储能 SOC 递推约束储能核心的动态约束也是模型能否反映电池特性的分水岭% SOC 递推SOC(t1) SOC(t) - P_dis*dt/eta_dis P_ch*dt*eta_ch for t 1:T-1 Constraints [Constraints SOC(:, t1) SOC(:, t) ... - P_dis(:, t) * dt / eta_dis ... P_ch(:, t) * dt * eta_ch]; end参数说明eta_dis 常取 0.9~0.95eta_ch 取 0.92~0.97。这两个效率参数直接决定了储能的实际可用容量设错会导致调度结果过于乐观。SOC 的初值通常取 0.2~0.5终值要求等于初值否则第二天无法继续循环调度。这个“SOC 回位约束”是日前优化最容易遗漏的约束。2.3.3 共享储能的物理上限约束% 电站总充放电功率不能超过额定功率 % 总 SOC 不能超过电站总容量 Constraints [Constraints sum(P_ch, 1) P_rated * ch_ratio ... sum(P_dis, 1) P_rated * dis_ratio ... sum(P_ch, 1) sum(P_dis, 1) P_rated ... % 功率耦合约束 SOC_total SOC_min ... SOC_total SOC_max];这里最容易出错的是“用户维度”和“电站维度”的混淆。同一个 P_ch 变量如果定义成 N_user × T 的矩阵那 sum(P_ch, 1) 是电站总充电功率如果定义成单个变量就无法区分每个用户的调用量。建模前必须把变量维度想清楚我一般在代码开头用注释明确写出每个变量的行列含义。2.4 求解器选型为什么用 YALMIP 而不是手写梯度下降日前优化经济调度本质是线性规划问题可以用 linprog 手写但约束修改成本高。更主流的是用 YALMIP 建模后端接 Gurobi、CPLEX 或开源的 GLPK。Gurobi 对大模型支持最好但需要 License教学和演示用 GLPK 也够用。选型标准就两条一是模型是否有二进制变量有则强制用 MILP 求解器二是变量规模超过 5000 个时优先用 Gurobi。3. Matlab 完整源码实现从 YALMIP 建模到结果落盘3.1 变量定义与维度设计源码严格按“先定义集合、再定义变量、后写约束”的顺序组织。完整代码结构如下%% 共享储能电站的用户日前优化经济调度 % 清理环境 clear; clc; close all; % 基础参数 T 96; % 时段数15分钟一个点 N 10; % 用户数量 dt 0.25; % 时间步长小时 % 储能系统参数 E_rated 2000; % 电站总额定容量kWh P_rated 500; % 电站额定功率kW SOC_min 0.1; % SOC 下限 SOC_max 0.9; % SOC 上限 SOC_init 0.3; % 初始 SOC eta_ch 0.95; % 充电效率 eta_dis 0.92; % 放电效率 % 用户负荷数据模拟生成实际使用时替换为实测 rng(2025); % 固定随机种子保证可复现 P_load 100 80 * rand(N, T) ... 50 * sin((1:T)/T * 2 * pi); % 每个用户96点负荷曲线 P_pv 20 * max(0, sin((1:T)/T * 2 * pi)); % 光伏出力 P_pv repmat(P_pv, N, 1); % 假设每个用户都有光伏 % 分时电价 price zeros(1, T); price(1:32) 0.4; % 23:00-7:00 谷段 price(33:48) 1.0; % 8:00-12:00 峰段 price(49:72) 0.8; % 12:00-18:00 平段 price(73:96) 1.2; % 18:00-22:00 尖峰段3.2 YALMIP 变量建模与约束组装%% 定义优化变量 P_buy sdpvar(N, T, full); % 用户购电功率 P_sell sdpvar(N, T, full); % 用户售电功率 P_ch sdpvar(N, T, full); % 用户调用储能充电功率 P_dis sdpvar(N, T, full); % 用户调用储能放电功率 SOC_user sdpvar(N, T1, full); % 每个用户视角的 SOC 分配 % 储能总 SOC 是用户 SOC 之和 SOC_total sum(SOC_user, 1); %% 约束条件 Constraints []; % 1. 功率平衡 Constraints [Constraints, P_load P_ch P_buy P_dis P_pv]; % 2. SOC 递推与边界 Constraints [Constraints, SOC_user(:, 2:end) SOC_user(:, 1:end-1) ... - P_dis * dt / eta_dis P_ch * dt * eta_ch]; Constraints [Constraints, SOC_user(:, 1) SOC_init * E_rated / N / E_rated * N]; % 初值分配 Constraints [Constraints, SOC_user(:, end) SOC_user(:, 1)]; % 回位约束 % 3. 电站层约束 Constraints [Constraints, sum(P_ch, 1) sum(P_dis, 1) P_rated]; Constraints [Constraints, SOC_total SOC_min * E_rated, ... SOC_total SOC_max * E_rated]; Constraints [Constraints, P_buy 0, P_sell 0, P_ch 0, P_dis 0];3.3 求解配置与参数说明%% 求解配置 % 目标函数 fee_rate 0.15; % 服务费元/kWh objective sum(sum(price .* P_buy)) ... - 0.8 * sum(sum(price .* P_sell)) ... fee_rate * sum(sum(P_ch P_dis)); % 调用求解器 ops sdpsettings(solver, gurobi, ... verbose, 1, ... showprogress, 1, ... savesolveroutput, 1, ... solveroutputfile, solution.mat); optimize(Constraints, objective, ops);参数说明sdpsettings 的 solver 字段指定后端求解器。如果没有 Gurobi改成 glpk 或 linprog 也能跑但大模型速度会慢数倍。showprogress 设为 1 可以看到 YALMIP 各阶段的耗时便于定位瓶颈在建模还是求解。savesolveroutput 会把求解器返回的原始数据结构存到 solution.mat调试时非常有用。3.4 结果提取与误差检查求解完成后需要从 sdpvar 对象中提取数值并做合理性检查%% 结果提取 P_buy_opt value(P_buy); P_dis_opt value(P_dis); P_ch_opt value(P_ch); SOC_opt value(SOC_total); % 约束违约检查应该有符号误差极小 residual P_load P_ch_opt - P_buy_opt - P_dis_opt - P_pv; max_residual max(abs(residual(:))); fprintf(最大功率平衡误差%.2e kW\n, max_residual);如果 max_residual 大于 1e-6说明模型定义有误优先检查 SOC 递推公式里的 dt 单位是否统一以及效率参数放置位置是否正确——很多入门者把 eta_ch 和 eta_dis 写反导致 SOC 越算越少最终模型无解。4. 参数敏感性分析与场景对比工程落地的关键一步4.1 四类关键参数的取值影响同一个模型参数不同调度策略完全不同。以下参数在实际项目中需要重点标定参数典型范围对结果的影响错误设置的后果eta_ch / eta_dis0.9~0.97决定储能净收益效率每降 1%峰谷套利空间缩水 3%~5%模型可解但方案亏损fee_rate0.1~0.3 元/kWh直接决定用户是否愿意调用储能费率过高用户全部不调用SOC_min0.05~0.2保护电池避免过放设置过高浪费可调度容量服务费模式功率计费 / 容量计费改变用户行为模式计费方式和调度目标不匹配4.2 有光伏与无光伏场景的对比实验在共享储能电站的实际项目中用户是否配光伏会明显改变最优调度策略。用以下脚本做两组场景对比%% 场景 A无光伏P_pv 全为 0 P_pv zeros(N, T); optimize(Constraints, objective, ops); cost_no_pv value(objective); P_dis_no_pv value(P_dis); %% 场景 B有光伏恢复 P_pv P_pv repmat(20 * max(0, sin((1:T)/T * 2 * pi)), N, 1); optimize(Constraints, objective, ops); cost_with_pv value(objective); P_dis_with_pv value(P_dis); fprintf(无光伏总成本%.2f 元\n, cost_no_pv); fprintf(有光伏总成本%.2f 元\n, cost_with_pv); fprintf(储能放电量变化%.2f kWh\n, ... sum(P_dis_with_pv(:)) - sum(P_dis_no_pv(:)));运行这段脚本后通常会看到两个现象有光伏时总成本下降但储能放电量可能不降反升因为光伏出力在午间压低电价储能会把充电时段挪到午间低价段把放电集中到晚间尖峰段。这就是把“按天优化”的价值——它不是把光伏和储能割裂开而是合并成一个决策单元。如果光伏出力和电价曲线不同步模型会自动找到最优充放策略。4.3 Milp 与 LP 的混合整数扩展如果加入了“储能禁止同时段充放电”的严格约束就必须引入二进制变量。YALMIP 支持 binvar 变量但会把模型从 LP 变成 MILP求解时间从秒级增加到分钟级。工程上多数情况不需要显式加这个约束因为目标函数中充放电都增加服务费成本模型天然会避免同时充放电。如果你在结果中发现了同时充放电优先检查价格参数的符号是否写反而不是急着加二进制变量。5. 从仿真到项目落地结果校验与调整技巧5.1 校验约束是否满足的标准化测试序列调度结果不能只看目标函数值必须逐条核对约束。我的做法是写一个独立的校验脚本读取优化结果后重新计算所有约束而不是信任求解器返回的求解状态。重点校验三个地方SOC 终值是否等于初值误差需小于 1e-3、每个时段的功率平衡是否严格满足、储能的累计充放电量与 SOC 变化是否一致。下面的代码片段能快速定位问题%% 约束校验核心代码 soc_check SOC_init; for t 1:T soc_check soc_check ... - sum(P_dis_opt(:, t)) * dt / eta_dis ... sum(P_ch_opt(:, t)) * dt * eta_ch; diff(t) SOC_opt(t1) - soc_check; end if max(abs(diff)) 1e-6 warning(SOC 递推不一致检查 dt 与效率参数); end5.2 收敛慢或求解失败时的参数整定顺序当 Gurobi 报 infeasible 时按以下顺序排查先把约束里所有非零初值设为 0验证模型骨架是否正确再逐步加入 SOC 回位约束、功率耦合约束、效率系数。如果加了效率系数才报无解说明初始 SOC 设置不合理——常见情况是 SOC_init 设成 0.5而 SOC_max 只有 0.55加上充放电损耗根本无法在一天内完成有效调度。5.3 网格搜索服务的费率定价技巧共享储能电站的运营方需要回答“服务费定多少能覆盖成本同时保证用户参与度”。用一层简单的参数扫描就能算出盈亏平衡点fee_list 0.05:0.05:0.4; for i 1:length(fee_list) fee_rate fee_list(i); optimize(Constraints, objective, ops); revenue(i) fee_rate * sum(value(P_ch P_dis), all); cost_battery(i) value(objective) - revenue(i); end plot(fee_list, revenue, -o, fee_list, cost_battery, -s); legend(服务费收入, 用户购电成本); grid on;如果收入曲线与成本曲线没有交点说明储能投资回报模型本身有缺陷需要重新核算电池循环寿命和维护成本。这个技巧在向决策层汇报时非常实用——一张交叉图就能说清楚定价逻辑而不是给出一堆 sdpvar 对象和约束方程。本文还有配套的精品资源点击获取
返回列表