资讯动态

基于分时电价机制的家庭能量管理策略优化:从MILP建模到MATLAB实现

发布时间:2026/9/8 16:40:47 来源:尧图企业网站定制
独立做这个“MATLAB下基于分时电价机制的家庭能量管理策略优化”项目时我遇到最多的问题不是“模型怎么建”而是大家不知道这套东西做完到底能干什么。有人以为是让家电自动断电有人以为只是给储能写一个定时充电程序其实都不对。分时电价给家庭侧创造了真正的“套利窗口”而家庭能量管理要做的是如何在一个有光伏、储能、电动汽车、多个可转移负荷的复杂场景里把每一度电的使用时刻尽量对准低电价时段。MATLAB刚好是把这个过程从“拍脑袋”变成“可计算、可对比、可复现”的绝佳工具。这篇文章我会从机制、建模、求解、代码实现、结果分析一直讲到落地时容易踩的坑适合正在做毕业设计、研究生课题或者准备做能碳管理方向产品的朋友参考。1. 分时电价机制背后的“套利空间”是家庭能量管理的经济驱动力1.1 峰谷价差到底能制造多少收益不先把经济账算清楚后面的优化策略很容易变成自嗨。分时电价的原则其实特别朴素电网在白天和傍晚用电高峰时发电侧、输电侧压力都大所以用较高的电价引导用户少用电到了夜里电网负荷率不足发电机组又不能轻易停机于是用很低的电价鼓励用户把用电需求挪到谷时。这种“峰高谷低”的结构本质就是把稀缺的输配电容量成本通过价格信号传导给用户。国内很多地区的典型工商业和居民分时电价峰段价差能达到0.6元/kWh到0.9元/kWh。以常见的家庭储能系统为例如果用一块10kWh的磷酸铁锂电池充放电综合效率按90%算实际一个充放循环可用的电量大约是9kWh。假设你每天晚上在谷段充电白天峰段放电用于家庭负载那么每个完整循环的价差收益大约是9×0.87.2元。如果全年这样操作300天对应的收益就是2160元。这个数字放到单户家庭角度看着不多但家庭能量管理研究真正的价值在于“规模复制”和“多资源协同”。一旦家里有电动汽车每天通勤需要充10~20kWh再把空调、热水器、洗衣机这些负荷全部纳入协调单户一年的节省达到3000~4000元并不夸张。所以家庭能量管理系统本质上做的事情就是在保证用户用电体验不下降的前提下通过自建储能、光伏自消纳、电器运行时刻平移、EV充电时间重排等手段去最大化利用峰谷价差。而“策略优化”研究的目标就是从数学上严谨地给出“每个时刻每台设备应该处于什么状态”的最优解而不是凭经验定几条if-else规则。1.2 先盘清楚家里有哪些“听话”的负荷在做建模之前我建议你先把自己研究场景里的家庭负荷分一下类。不是所有电器都适合被调度有些负荷你动它时间用户就会觉得体验变差。按可控程度我一般把家庭负荷分成四类负荷类型典型设备可控性调度难度与舒适度影响基础固定负荷冰箱、路由器、电视、灯具基本不可控只能作为必须满足的功率需求可转移负荷洗衣机、洗碗机、热水器时间可平移只需在用户允许窗口内完成即可可中断/可调节负荷空调、暖气、电热水器状态可周期开关或功率可调需保证温度维持在舒适范围内储能型资源家庭电池储能、电动汽车充电功率和时间都可控放电时还可能影响出行电量需设下限这里最容易被初学者忽略的是“可转移负荷”的建模细节。比如洗衣机程序不是简单地允许它“任意一个时间点功率不为零”而是要求它一旦开始运行就连续运行完整的工作周期中间不能断——更准确地说一个洗衣程序包含洗涤、漂洗、脱水等阶段总持续时间固定。所以优化时要约束它的“启动时刻”是唯一决策变量一旦启动在后续duration_i个时间段内都必须运行。可中断负荷则不一样。空调在保持室内温度区间的过程中是可以周期性启停的因此建模时通常用一个0-1变量表示某个时段是否开启并另加约束相邻时段的状态不能变化得太频繁或者一天内总启停次数不能超过设备限制。这样既得到经济性最优又不会把压缩机和风机折腾坏。把这些设备放进同一个优化问题里你会发现家庭能量管理不是让电器“少用”而是让电器“在对的时间用”。这个视角一旦建立后面所有数学约束都顺理成章。2. 把“家”变成可计算对象负荷、储能、光伏和电网交互建模2.1 为什么先定时间粒度和调度边界写代码前我建议先冷静想清楚一个问题你是用1小时间隔做日级调度还是用15分钟粒度做日内滚动优化这会直接决定优化模型的决策变量个数。以一天24小时、1小时间隔为例一个家庭里如果包含储能、EV、光伏和几台可转移负荷决策变量总数通常在200到300个之间MILP求解器处理这种规模非常轻松。如果改成15分钟粒度变量数翻四倍但精度并不会提升那么多因为家庭负荷曲线本身在分钟级的随机波动非常大精确到15分钟的策略未必能完美执行。对于第一版研究我强烈建议先用1小时步长做完整天的确定性优化。这个粒度足够看清楚负荷平移、储能充放、EV充电的经济规律而且画出来的结果图在论文或汇报中特别直观。等这套框架跑通后再在实时控制层用15分钟粒度做滚动修正。另外调度“边界”也很重要。家庭能量管理系统通常以电表关口为边界电网侧看进来是一个净负荷。光伏出力、储能放电、EV放电如果允许V2H都可以让关口净负荷下降甚至反向送电家庭负荷、储能充电、EV充电则是关口向电网取电的原因。把边界画清楚后每个设备的功率方向不会搞混。2.2 储能模型与避免同时充放电储能是家庭能量管理中最灵活的调节资源它的模型也最需要仔细推敲。我用离散时间动态方程描述SOC(t) SOC(t−1) (η_ch × P_ch(t) − P_dis(t) / η_dis) × Δt / E_bess其中SOC(t)是t时段结束时的荷电状态P_ch(t)是充电功率非负P_dis(t)是放电功率非负η_ch是充电效率η_dis是放电效率E_bess是电池额定容量。用这个式子时单位必须统一如果功率用kW、时间用h那么P×Δt单位是kWh要和E_bess一致。除了动态方程储能至少还有四个基本约束充电功率上限0 ≤ P_ch(t) ≤ P_ch_max放电功率上限0 ≤ P_dis(t) ≤ P_dis_maxSOC上下限SOC_min ≤ SOC(t) ≤ SOC_max一般锂电池建议0.1~0.9调度周期始末SOC相等SOC(0)SOC(T)这是为了保证“今天用的电不能是昨天偷偷留下来的”让方案具有可持续性还有一个隐藏约束新人经常漏掉同一时刻不能既充电又放电。如果模型里有 η_ch 小于1、η_dis 小于1优化器会聪明地让储能同时充放电来套利吗答案是即使不出现这种“白嫖损耗”的荒唐结果在物理上也绝不允许同时充放。处理办法是引入一个0-1变量u_bess(t)P_ch(t) ≤ u_bess(t) × P_ch_maxP_dis(t) ≤ (1 − u_bess(t)) × P_dis_max这样u_bess(t)1时只能充电u_bess(t)0时只能放电完美互斥而且因为约束全是线性的MILP可以直接处理。2.3 可转移负荷建模连续运行逻辑别写错可转移负荷洗衣机、洗碗机建模我见过很多同学直接用“全天某几个时段可以运行”来约束结果求出来的方案是“洗10分钟停20分钟再洗10分钟”完全不符合物理实际。正确建模思路是用“开始时刻”作为决策变量。假设第 i 台可转移设备运行持续时间为duration_i允许开始时段为[α_i, β_i]。令s_i(t)为0-1变量表示第i台设备是否在t时段“开始运行”。由于每台设备一天最多启动一次一般场景所以Σ s_i(t) 1, t ∈ [α_i, β_i]设备在t时刻是否处于运行状态y_i(t)可以从之前若干个时刻的启动状态推导出来。这个关系如果用矩阵形式表达会比较绕但在MATLAB里可以直接写成一个循环填充绝对约束for t 1:T for i 1:n_app for tau 0:duration_i−1 if t−tau 1 y_i(t) s_i(t−tau) end end end end这套约束的逻辑是如果设备在t−duration_i1到t之间任何时刻启动了那它在t时刻都必须处于运行状态。因为多台启动变量互斥且时间窗约束存在倒推出来的运行状态自然连续。要注意的是这个写法产生的约束偏多对24小时、三五台设备来说完全够用如果粒度变得更小可以改用开始时间位置的累计变量来压缩约束数量。2.4 光伏的数据输入方式光伏是家庭能量管理中典型的“看天吃饭”资源。在确定性优化研究中通常直接用一条预测曲线P_pv(t)它相当于家庭内部的“负负荷”——发出来的电优先自用用不完再卖给电网。但如果做实物或做鲁棒调度研究就需要考虑晴转多云时出力陡降的情况。我建议代码里把光伏曲线单独放在数据文件中不要写死在程序里。后面做敏感性分析时把输入曲线乘一个缩放在0.4到1.1之间的系数就能快速看不同天气条件下策略的表现。2.5 电网交互买电和卖电要分开建模并加互斥家庭和电网之间的交互通常需要区分两个变量从电网买电P_buy(t)和向电网卖电P_sell(t)。如果家里的光伏有“余电上网”政策卖电电价c_sell(t)通常会低于买电电价c_buy(t)甚至有的地区是固定上网电价不随时间变化。这里有一个新手很容易踩的坑如果模型里允许同一时间既买电又卖电优化器会干出“用1元/kWh买进再用0.4元/kWh卖出”赔本买卖吗它不会。但如果把某些电价政策设置成卖电电价在某时段高于买电电价它可就真的会疯狂双向套利。所以在建模时要么直接用互斥变量P_buy(t) ≤ M × v(t)P_sell(t) ≤ M × (1 − v(t))其中v(t)是0-1变量M是一个足够大的数。要么比较稳妥地接受一个近似反正结论上卖电价低于买电价时可以不设置互斥约束优化器自然避免赔本买卖。但谁也不能保证你的研究以后不会换一套电价参数建议一开始就把互斥约束写上一劳永逸。3. 把“省电费”翻译成一个MILP问题为什么选型数学规划而不是启发式3.1 决策变量选取与目标函数拆解把家庭能量管理写成优化模型时我习惯按“连续变量 离散变量”两条线来列。以1小时分辨率的24小时日调度为例连续变量储能充电功率P_ch(1:24)、储能放电功率P_dis(1:24)、从电网购电P_buy(1:24)、向电网售电P_sell(1:24)离散变量储能充放电互斥标志u_bess(1:24)、每台可转移设备的启动时段标志s_i(1:24)、EV充电状态u_ev(1:24)等目标函数非常直观就是最小化一天的净购电成本min J Σ_t [ c_buy(t) × P_buy(t) − c_sell(t) × P_sell(t) ] × Δt这里c_buy(t)和c_sell(t)是t时段的购电、卖电电价。家庭负荷的用电成本已经隐含在P_buy(t)里储能和EV的损耗已经体现在效率系数里所以不需要额外加“用电费用”项。当然如果目标里还要考虑电池寿命损耗可以在这个目标函数后加一个惩罚项比如每次充放电单位能量折算的损耗成本c_degrad乘以充放电电量之和。这部分我在后面落地章节会详细说。3.2 功率平衡等式模型的灵魂约束所有设备最后必须满足一条功率平衡等式。在家庭关口处这一时刻所有流入家庭的功率等于所有流出并在内部消耗的功率P_buy(t) P_pv(t) P_dis(t) P_load_base(t) ΣP_app(t) P_ch(t) P_ev(t) P_sell(t)公式里每一项都能翻译成自然语言左侧是外部和储能供过来的总功率右侧是家里所有设备和卖给电网的总功率。这个等式保证系统任何时刻不能凭空多出电也不能莫名少掉电。写代码时它就是一个Aeq × x beq等式矩阵24个时段对应24行把所有变量按顺序归组、系数填1或−1。有个实用技巧这些约束行中光伏、基础负荷这些输入量属于已知参数放在beq侧决策变量全部放在左侧。具体实现时可以先生成Aeq zeros(T, n_vars)然后逐个时段往里填。不要在循环里反复拼接矩阵预分配能快非常多。3.3 MILP为何是首选遗传算法别随便当主角很多朋友一上来就想用粒子群、遗传算法做“智能优化”因为听起来高级。但我要说句实在话家庭能量管理问题本质上是一个混合整数线性规划目标函数和约束条件几乎全是线性的这种情况下MILP能用分支定界法在几十秒内找到全局最优解。用遗传算法找同一道题可能要跑几十次才收敛到接近最优而且每次结果还带一点随机性写论文时“全局最优性”这张牌完全打不出来。除非你的模型引入了非线性的储能效率曲线、空调热力学方程或非线性电池老化模型那时才需要考虑把问题线性化后再用MILP或者实在线性化不了再用启发式。我的建议是第一版研究应该先用MILP跑出一个“理想最优解”当作基准之后如果要对比启发式算法的性能也有一个标准答案可以参考。实际调用的MATLAB函数就是intlinprog内置在Optimization Toolbox里不需要额外装其他求解器。3.4 intlinprog求解时最容易翻车的细节把问题写成MATLAB可求解的形式有几个细节特别容易让人抓狂。第一是intcon索引。intlinprog要求你告诉它哪些变量是整数变量传入的是“在完整决策向量x里的下标”。如果你把变量按顺序拼成一个长向量比如x [P_ch(1:24), P_dis(1:24), P_buy(1:24), P_sell(1:24), ..., s_i(1:24*n)]那么前96个是连续变量后面跟的全部0-1变量。这时intcon应该是97:length(x)的某个范围。真正写代码时别手动数用变量分组长度动态拼接n_ch 24; n_dis 24; n_buy 24; n_bess_01 24; n_app_start n_app * 24; intcon (n_ch n_dis n_buy 1):(n_ch n_dis n_buy n_bess_01 n_app_start);第二bounds 和 0-1 变量别冲突。有些人不小心把0-1变量在 lb/ub 里已经设成 [0,1]又额外加了线性不等式约束让它们大于等于0这其实没问题但会造成很多冗余约束增加求解时间。第三不可行问题定位。如果你的模型一跑就返回 infeasible不要一句“模型有问题”就卡住。实操中最有效的排查办法是从简单到复杂慢慢加约束。先只用储能和功率平衡跑通再逐步加入可转移负荷、EV、电网卖电等加到哪一步不可行问题就在哪一步新增的约束里。我早期做这个项目时因为可转移负荷的窗口设置成“最晚必须在20点前开始”但洗衣机程序运行2小时后和晚高峰的另一个固定负荷叠加后功率超过了关口容量上限导致最优解不存在——这类冲突不逐个排查根本发现不了。4. MATLAB工程目录与核心代码实现套路4.1 别把参数写死在脚本里用结构体统一管理MATLAB科研代码最常见的坏味道就是一打开脚本看到几十行散落的T24; price...; P_load...;。这种代码跑一次没问题但你要做多场景对比时魔改成本极高。我会建议你把项目的关键输入全部装进一个结构体paramsparams.T 24; % 调度时段数 params.dt 1; % 单位小时 params.E_bess 10; % kWh params.P_ch_max 3; % kW params.P_dis_max 3; % kW params.SOC_min 0.1; params.SOC_max 0.9; params.SOC_0 0.5; params.eta_ch 0.95; params.eta_dis 0.95; params.P_buy_max 10; % 关口容量 params.P_sell_max 5; params.P_ev_max 7; % EV充电功率上限 params.EV_target 20; % EV次日所需电量kWhprice_buy zeros(24,1); price_buy(1:7) 0.42; % 低谷时段 price_buy(8:10) 1.12; % 早高峰 price_buy(11:17) 0.75; % 平段 ... params.price_buy price_buy; params.price_sell 0.45 * ones(24,1); % 固定上网或平段售电价你可以在一个setup_params.m函数里返回这个结构体之后仿真脚本需要什么参数都从params里取。这样做的好处非常明显后面做敏感性分析时写一个 for 循环每个循环改的是params.E_bess这种字段而不是到一堆脚本里去改常量的引用位置。4.2 组装约束矩阵的通用套路用intlinprog时目标向量f的长度由决策变量个数决定。我先说明一下完整决策向量的排列方式方便对照代码理解x [P_ch(1:24) % 储能充电功率 P_dis(1:24) % 储能放电功率 P_buy(1:24) % 电网购电 P_sell(1:24) % 电网售电 u_bess(1:24) % 0-1 充放电互斥 s_app(1:n_app*24) % 可转移负荷启动标志按设备逐段排 ];目标函数系数向量 f 就很好写了f [zeros(1,24), zeros(1,24), params.price_buy.*params.dt, -params.price_sell.params.dt, zeros(1,24), zeros(1,n_app24)];注意储能充放电本身在目标函数里不直接扣钱它通过功率平衡影响购电和售电所以f里对应位置是0。接下来核心工作是构建等式约束矩阵 Aeq 和不等式约束矩阵 A。我用一个函数build_constraints(params)来干这件事结构大概如下function [Aeq, beq, A, b, lb, ub, intcon] build_constraints(params) T params.T; n_basic 4 * T; % 连续变量数量 n_bess_01 T; n_app length(params.app_duration); n_app_var n_app * T; n_vars n_basic n_bess_01 n_app_var;Aeq zeros(T, n_vars); % 功率平衡 beq zeros(T,1); for t 1:T idx_ch t; idx_dis T t; idx_buy 2*T t; idx_sell 3*T t; Aeq(t, idx_ch) 1; % P_ch 移到右侧其实等价于左侧为负 Aeq(t, idx_dis) -1; Aeq(t, idx_buy) 1; Aeq(t, idx_sell) -1; beq(t) params.P_load(t) - params.P_pv(t); end ...end上面这段代码只是为了说明思路功率平衡式左右侧正负号在写的时候一定要再推一遍否则符号反了结果会变成“越用越省”。我的建议是最后用一个小型实例手动验算比如把储能、光伏都去掉只留负荷和购电看 Aeq 能否正确返回“购电量等于负荷量”的结论。4.3 储能SOC递推约束的矩阵写法SOC递推式含SOC(t−1)也就是说下一时刻的状态和上一时刻的状态相互耦合。这个约束同样要写成矩阵形式才能喂给intlinprog。整理一下SOC(t) SOC(t−1) (η_ch · P_ch(t) − P_dis(t) / η_dis) · Δt / E_bess但等等这里有个小坑SOC(t)本身在基础决策变量里其实没有直接出现它是由储能充放电功率和时间累积出来的内部状态。所以我们可以把SOC写成一个辅助变量soc(0:T)加入决策向量也可以用消元方式去掉SOC变量。消元方式比较优雅更适合代码量少的脚本。如果用辅助变量决策变量会变长约束也更直观。我建议精力尚可的读者采用“含SOC辅助变量”的写法。具体排列顺序是x [P_ch(1:24), P_dis(1:24), P_buy(1:24), P_sell(1:24), SOC(0:24), u_bess(1:24), ...]这时 SOC 的上下界直接写到 lb 和 ub 中。SOC(0) 是初值SOC(24) 是末值如果有始末相等约束就在 Aeq 中加一行对应变量系数为1和−1。构建递推约束时对于 t1:24写 soc(t) − soc(t−1) − (η_ch·Δt / E_bess) · P_ch(t) (Δt / (η_dis·E_bess)) · P_dis(t) 0 把系数填进对应矩阵。这部分你只要耐心对齐好索引一次写对就不容易出bug。4.4 用intlinprog求解并处理结果目标、约束、边界都准备好后调用求解器非常轻松opts optimoptions(intlinprog, Display, iter, MaxTime, 300); [x_opt, fval, exitflag] intlinprog(f, intcon, A, b, Aeq, beq, lb, ub, opts);fval就是最小化后的净购电成本exitflag 1表示收敛到全局最优解。拿到x_opt后再从长向量里把各段变量切出来。我喜欢立刻把结果转成结构体res.P_ch x_opt(1:T); res.P_dis x_opt(T1:2T); res.P_buy x_opt(2T1:3T); res.P_sell x_opt(3T1:4T); soc_all x_opt(4T1:4TT1); % SOC(0)到SOC(24) u_bess x_opt(4TT2:4T2T1);之后做指标计算和数据可视化时只和res这个结构体打交道。保持代码模块化是我能给出的最实用建议之一。4.5 把电价和调度结果画成一张好看的图结果图是给导师、评委或读者看的第一印象。我习惯用两种图画结果第一种是“功率平衡堆叠面积图”把光伏出力、负荷曲线、储能充放电、电网交互画在同一张图里用不同颜色区分可以看到储能什么时候充电什么时候放电第二种是“SOC曲线电价分段背景图”用来展示储能策略和电价之间的跟随关系。电价分段背景可以这样处理figure; area(1:24, P_pv, FaceColor, [1 0.85 0.6], EdgeColor,none); hold on; ... xline(8, --, 峰段开始); xregion(8, 11); % 需要 MATLAB R2023a 以上才支持 xregion 如果版本支持不够可以用patch画一个半透明背景块for k 1:2:length(edge_idx) patch([edge_idx(k) edge_idx(k1) edge_idx(k1) edge_idx(k)], [yl(1) yl(1) yl(2) yl(2)], [0.9 0.9 0.9], FaceAlpha, 0.3, EdgeColor,none) end这段代码是示意实际运行时记得先把坐标范围记下来不然patch会改变坐标轴范围。画图部分虽然不影响优化结果但直接决定读者能不能一眼看出“优化策略是在谷段充电、峰段放电”的规律值得花心思。5. 别急着下结论用三组对照仿真讲清楚策略价值5.1 对照实验怎么设才有说服力单独看一条优化后的功率曲线图谁也不知道它到底好在哪里。做研究或者项目汇报必须有对照组。我建议至少跑三个方案方案0无优化按用户原始习惯用电没有储能、EV到家就充方案1固定时段策略储能每天0点到6点谷段充电8点到11点/18点到21点峰段放电EV到家后固定22点开始充电方案2MILP优化策略用前面构建的优化模型对负荷、储能、EV联合调度。方案1的设计要尽量贴近实际工程中常用的规则策略不让它显得太蠢才有对比价值。我之前见过有人把方案1设成“随机充电”结果当然是优化方案完胜但这种对比别人看一眼就知道不公平。合理的固定时段策略恰恰能帮你说明“MILP优化带来的收益不是全靠峰谷价差躺着赚而是来自多设备协调的时序安排比固定规则又高出一截”。5.2 从曲线到指标如何解读优化后的调度行为跑完仿真主要盯着几个数字就够了日净购电成本、峰段购电量比例、谷段购电占比、储能循环次数、光伏自消纳率。以一户典型居民为例假设夏季典型日基础负荷峰值约4kW日用电量约30kWh光伏日发电量约20kWhEV日充电需求20kWh10kWh储能。仿真结果可能长这样方案购电费用元售电收入元净成本元峰段购电比例无优化28.65.123.542%固定时段充放24.76.218.518%MILP优化22.36.815.59%这个表格里的数字是我为示意编的不同电价和负荷场景数值会变但趋势很一致优化策略最大的贡献不是把总用电量省了而是把购电行为大量迁移到谷段同时提高了光伏自消纳。你去看SOC曲线通常会发现夜间谷段可能是“EV和储能都在充”到上午光伏出力起来后如果负荷低光伏多余电量会存进储能傍晚峰值电价到来时储能光伏一起供电把购电功率压到很低的水平。解读仿真结果时还有一件事值得做把MILP解出来的若干“非直观规则”提炼出来。比如优化器在某个场景中会选择让EV在中午光伏大发时小电流补一点电而不是晚上才充满。这种小反直觉行为恰恰说明多资源协同优化比固定规则更有价值。5.3 三因素敏感性分析价格、容量、光伏条件单日的优化结果只能说明一天的情况。要回答“这套策略对一个家庭一年能省多少钱”这种问题就得做敏感性分析。我做的第一轮敏感性分析包含三个维度峰谷价差从0.4元/kWh到1.2元/kWh变化储能容量从5kWh到20kWh变化光伏曲线按晴、多云、阴三种典型日缩放。实现代码其实就是最外层套两层for循环或直接用表格枚举配置把参数写入params然后调用同一个求解脚本把fval、SOC数据、购电数据收集到结果表里。跑完后画出来的折线图能非常清晰地展示“容量越大收益越高是否线性”“价差低到多少策略就失去意义”这类结论。以我的经验结果通常是价差高于0.5元/kWh之后优化收益开始明显爬升储能容量从5增加到10kWh时收益提升最显著10再增加到20收益增长放缓边际递减效应很明显。做这个分析才能让人看懂“10kWh配储是当前户用市场主流”不是拍脑袋定的。6. 从MATLAB仿真到真实落地我踩过的坑和工程化建议6.1 不要再让储能“免费打工”寿命损耗必须进目标函数前面提过MILP模型会让储能每天只做对自己最划算的事。如果电价曲线的峰谷差足够大优化器可能让储能做“一天两充两放”上午充下午放晚上再充晚高峰再放。可问题是每一次充放电循环都在消耗电池寿命。锂电池的循环寿命不是无限的典型的磷酸铁锂电芯循环寿命在4000~6000次左右日历寿命和放电深度也会影响老化速度。如果把电池当成“零成本”资源优化的日套利收益看着很漂亮但实际折算到全生命周期内频繁深度充放可能会让电池提前退役钱等于换了个方式亏掉。一个工程上可接受的近似做法是把每次充放电的寿命损耗成本化加进目标函数。假设电池更换成本是C_battery元/kWh总循环次数是N_cycle单次“全充满全放空”的等效循环损耗成本约为c_degrad C_battery / N_cycle元/kWh比如电池系统单价1200元/kWh循环寿命5000次那单次深度循环的损耗大约0.24元/kWh。于是目标函数变成J Σ [ c_buy(t)·P_buy(t) − c_sell(t)·P_sell(t) ] c_degrad · (Σ P_ch(t) Σ P_dis(t))·Δt / 2这里的除以2是因为一个循环内充进去的和放出来的电量基本相等求和后总量是循环吞吐量的两倍不过如果你直接用总充电量或总放电量乘以损耗系数也可以只是系数标定要对齐。加入这个惩罚项后优化器会在“套利收益”和“电池消耗”之间自动做权衡你也会看到SOC曲线变得克制很多——不会动不动来一次深度循环。6.2 负荷和光伏预测误差为什么开环结果往往“好看不好用”确定性优化把所有输入当成已知但真实家庭的负荷曲线和光伏曲线都是“预测值”。如果早上做完日级调度后下午突然来一片云光伏出力骤降一半原定“光伏充电、支撑晚高峰”的计划很可能当场破产。对付这个问题业界标准做法是模型预测控制MPC滚动优化不是跑一次24小时计划就结束而是每个控制步长比如1小时都重新求解一次未来N小时的子问题只执行第一步指令到下一个小时再基于最新量测和预测刷新计划。在MATLAB里模拟MPC非常自然外层套一个for循环遍历仿真时间每个循环调用intlinprog或提前在外部用YALMIP建模求解后只保留下一个时段的控制量。滚动优化的价值在于它能把“预测误差”和“状态偏移”不断修正回来。如果你在论文里只做确定性日优化通常会被审稿人追问“你的误差场景下结果还健壮吗”这时拿MPC结果对比开环结果基本是标准答案。6.3 把控制指令下发到真实设备还存在“最后一公里”策略层的输出是“每小时建议功率/开关状态”但要真正执行还需要本地控制器去跟智能插座、逆变器、充电桩通信。这个层面做过实际项目的人都知道坑远不止算法本身通信协议不统一空调、热水器用Wi-Fi智能模块储能逆变器往往走ModbusEV充电桩很多只开放厂商私有API要统一接入数据中台需要不少协议适配工作控制延迟下发指令到设备响应之间可能有几秒到几十秒的延迟所以执行层通常需要一个小型状态机做防错安全兜底无论策略怎么说都必须保证电池不过充过放、用户手动优先级最高、停电后设备状态能安全恢复。我的建议是如果你目前的阶段是做研究或毕设重点先把策略层的MATLAB框架打磨扎实如果后续想接实物可以保留一个“策略输出接口”比如把每个时段的目标状态写成一个CSV或通过MATLAB的TCP/IP发送给本地网关这样模型层和硬件层解耦出问题也容易区分是谁的锅。6.4 代码可复用性换个电价机制或换套负荷数据得能在十分钟内跑起来项目做到中后期多组实验、多个电价版本、多套典型日负荷曲线并存是常态。我强烈建议你从一开始就严格区分“配置文件”、“数据驱动代码”和“结果分析脚本”。例如把每种电价政策放在一个data/price_2025_summer.m里返回params结构体把典型家用负荷曲线、光伏曲线也做成可独立调用的函数。这样当你想换一套电价机制比如加上尖峰电价、季节电价或者换一个城市的典型负荷曲线只需要改数据文件优化主程序完全不用动。我自己曾经踩过的坑是第一版代码把电价序列写在主程序头部后来又复制了主程序去做多场景对比结果一个数值改了另一个没改整整浪费两天去查为什么结果对不上。后来吸取教训所有运行参数由配置文件统一生成主程序只负责读取和求解不做任何参数硬编码。现在无论做参数扫描还是换场景都是在写循环和改数据文件再也不会把一个分支改漏。最后分享一个我实际的体会家庭能量管理这个课题难的不是intlinprog调用也不是画图漂亮而是把每个约束的物理意义想透再把这些物理意义准确转成数学约束和矩阵代码。仿真里跑通一天只能证明模型没写错要真正让人信服至少得覆盖不同季节、不同电价、不同家庭行为的多组实验。第一次跑这个项目建议老老实实按“简化模型 → 日级MILP → 固定时段对照 → 敏感性分析 → MPC滚动”这条路线走一遍。过程中每加一个约束就重新验证一次别一上来就追求把所有家电和复杂约束塞进去一步步来结果会远远超出预期。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价