基于MATLAB与MILP的家庭能量管理模型:空调、EV与可平移负荷联合调度

发布时间:2026/10/6 5:10:48
基于MATLAB与MILP的家庭能量管理模型:空调、EV与可平移负荷联合调度 做家庭能量管理系统仿真最耗时间的往往不是算法本身而是把空调、电动汽车、可平移负荷这些东西变成一套能被求解器接受的数学表述。我最近在MATLAB里搭了一套面向分时电价的家庭能量管理模型涉及空调、电动汽车和可平移负荷的联合调度目前已经跑通并做了几轮参数敏感性分析。这篇文章把建模思路、选型原因、核心代码和踩坑记录都整理出来给想用MATLAB做家庭能量管理模型、但不太清楚从哪下手的朋友一份可以直接参考的路径。先说清楚这套东西能干什么给定未来24小时的分时电价以及用户家庭里空调负荷、电动汽车、洗碗机/洗衣机这类可平移负荷的使用时间窗和电量需求模型自动算出每个15分钟时段应该开空调还是关空调、电动汽车什么时段充电、可平移负荷安排在什么时候启动目标是最小化一整天的电费同时不让用户舒适度跌破底线。值得做的事很多但要提醒一句如果只是为了交课程作业可以随便拿遗传算法凑一个优化目标如果是想认真研究家庭能量管理、或者后续做V2G/光伏储能扩展一定要从机理模型和MILP入手。下面是我按这个思路走完一遍的完整记录。1. 先把四类对象变成能扔进求解器的数学约束家庭能量管理的实质是一个带约束的混合整数优化问题。约束对象包括分时电价、空调热动态、电动汽车充电过程、可平移负荷的使用习惯四类下面挨个说建模的关键点。1.1 分时电价先弄清楚你面对的是TOU还是RTP分时电价Time-of-UseTOU是预先公布、按时间段固定价签的价格机制最常见的就是峰、平、谷三段。实时电价RTP则每小时甚至15分钟一变通常需要预测模型复杂度和误差来源都会增加。在这套模型里我优先按TOU处理因为TOU是目前家庭需求响应落地最广、也最容易解释清楚的形式。把24小时按15分钟一个时段切成96个点电价就是一个96维的列向量price。下面这组分时电价只是教学示例不代表任何地区的实际电价但结构是典型的三段式时段时间段示例电价元/kWh谷段00:00-08:000.35峰段08:00-14:001.15平段14:00-18:000.65峰段18:00-22:001.15平段22:00-24:000.65计算电费时目标函数里所有负荷功率乘上对应时段电价再乘时间步长。这里有一个新手容易忽略的点目标函数里的电价系数会直接决定优化器的调度行为但真正影响结果的是各时段电价的相对比值不是绝对数值。如果峰谷比只有1.2倍那模型没必要费劲平移负荷峰谷比达到3倍以上空调预冷、EV延迟充电这类操作才有明显的经济学意义。1.2 空调的等效热参数模型与“预冷”逻辑空调负荷不能只按“开1小时耗几度电”来处理因为它和室内温度强耦合核心价值恰恰在于可以利用建筑热惯性实现“预冷”在谷段提前把房间温度降下去峰段少开甚至不开靠墙体蓄冷维持舒适。这个逻辑用等效热参数模型Equivalent Thermal Parameters简称ETP模型表达最合适。ETP一阶模型把房间看成一个热容加一个热阻的简单结构室内温度随时间递推T_in(tdt) e^(-dt/(R*C)) * T_in(t) (1 - e^(-dt/(R*C))) * (T_out - R * Q_ac * u(t))其中R是房间等效热阻℃/kWC是等效热容kWh/℃Q_ac是空调额定制冷量kWu(t)是0/1开关状态。u(t)1表示压缩机运行制冷u(t)0表示自然升温。温度会向T_out - R*Q_ac这个平衡点收敛Q_ac越大、R越小降温能力越强。举个例子房间等效热阻R2℃/kW额定制冷量Q_ac5kW室外温度33℃则空调连续运行时温度理论上能压到33-1023℃。如果约束室内温度在2226℃这个制冷能力就不至于“不够用”。实际建模时要把电功率和制冷量分开目标函数用的是压缩机电功率P_el_ac热动态方程用的是制冷量Q_ac两者不要混成一个变量。等式里a exp(-dt/(RC))是热惯性系数。RC越大房间保温性越好空调停机后温度回升越慢这种房间做“预冷”的经济性才越好。我试过把时间常数从0.5小时调到3小时预冷策略带来的费用下降幅度差异非常明显。1.3 电动汽车可用充电区间才是难点电动汽车充电的约束核心不是“要不要充电”而是“充电只能在插电时段内发生”。假设车辆在10:00到家接入充电桩16:00离开那么充电可用窗口就是第40到64个15分钟时段。模型必须强制0:00-9:45之间u_ev0这是物理约束不写进去求解器就会给你一个“还没到家先把电充满”的诡异结果。SOC的递推方程是SOC(t1) SOC(t) eta * P_ev * u_ev(t) * dteta是充电效率P_ev是充电桩额定功率u_ev(t)是0/1变量。约束端点初始SOC在接入时刻已知比如30%离开时SOC必须不低于目标值比如85%任何时刻SOC都不能超过电池容量上限这里有个值得注意的经济问题如果EV可用窗口全部落在峰段而离开时又必须充到85%那省钱的空间很小峰段照充不误如果可用窗口跨峰谷优化器就会尽量把充电安排在谷段和平段宁可充电功率在这几个时段内连续拉满也不愿意在峰段分拆。1.4 可平移负荷连续性约束是最大的坑洗碗机、洗衣机这类负荷的特点是功率固定、运行时长固定、只能整体平移不能拆成几段。比如洗碗机功率1.8kW运行6个15分钟时段1.5小时必须在晚上某个窗口内连续完成。直接定义运行状态变量s(t为0/1然后加sum(s)6是不够的。因为这只能保证“有6个时段在运行”不能保证“这6个时段连在一起”。求解器很可能给你一个每隔半小时开一下的运行方案这在物理上根本不是一台洗碗机。正确做法是引入启动事件变量。启动标志可以这样构造start(t) s(t) - s(t-1) start(t) 0 sum(start) 1因为s是0/1变量如果s(t)1且s(t-1)0说明这个时段发生了启动start至少为1如果s(t-1)1且s(t)1start下限是0如果s(t)0且s(t-1)1start下限是负数但非负约束会把它压在0。再加上sum(start)1就强制整个运行窗口内有且仅有一次启动从启动起点连续运行D个时段直到完成。同时在允许窗口之外强制s(t)0这样负荷就被“钉”成一整段连续可平移的模块了。2. 为什么我选MILP而不是启发式算法很多人在线搜索“家庭能量管理模型MATLAB”时最先接触的是遗传算法、粒子群之类的智能优化代码。我一开始也试过后来切换到MILP混合整数线性规划原因是几个很实际的对比结论。2.1 目标函数与决策变量的完整定义把上面的对象统一到一个优化问题里决策变量包括空调启停变量u_ac(t)96个0/1变量电动汽车充电变量u_ev(t)96个0/1变量洗碗机运行状态s_dw(t)96个0/1变量洗衣机运行状态s_wm(t)96个0/1变量室内温度T_in(t)96个连续变量电池SOC(t)96个连续变量负荷启动事件标记start(t)若干连续变量目标函数是所有设备电费之和加一个抑制空调频繁启停的小惩罚项min sum( price(t) * (P_el_ac*u_ac(t) P_ev*u_ev(t) P_dw*s_dw(t) P_wm*s_wm(t) P_base(t)) * dt ) penalty*sum(start_ac(t))约束包括室内温度递推方程、温度上下限、EV窗口与SOC递推、可平移负荷连续性约束、启动时间窗约束。所有目标函数和约束都是线性或可以通过前述方法线性化的所以这是一个标准MILP问题可以直接交给intlinprog。2.2 从遗传算法换到MILP的真实理由遗传算法在文献里很常见写起来也不难但作为工程实践我有三点不能接受。第一遗传算法给出的解不保证是最优解而且每次运行结果可能不同。家庭能量管理模型即使只做24小时调度解空间也是96维0/1组合随机搜索对参数太敏感。做灵敏度分析时结果曲线里的毛刺到底是物理规律还是算法随机性导致的很难判断。第二约束处理麻烦。遗传算法处理约束要么罚函数、要么专门设计编码像连续运行这种强约束罚函数罚得不好就会产生“差不多连续”的不可行方案。MILP则把约束作为硬约束交给求解器解的可行性有保证。第三也是我最看重的一点MILP求解速度快到可以反复做参数扫描。我用96个时段、约300个约束intlinprog在普通笔记本上通常几秒内就能收敛到整数容差内遗传算法跑同样的96维问题可能要好几分钟而且还不一定能稳定找到更好的解。2.3 求解器的选型和求解速度对比MATLAB环境下我推荐YALMIP intlinprog的组合理由很朴素YALMIP负责把约束和变量集成一个可读性强的模型intlinprog是MATLAB自带的MILP求解器不需要额外安装Gurobi或CPLEX。研究阶段用intlinprog足够如果后续模型规模扩大到多家庭、多日滚动优化再考虑换成Gurobi求解速度可能快几倍到几十倍。我做过一个简单对比同样的模型intlinprog约3秒左右收敛换成Gurobi可能还不到1秒但对于单家庭单日调度3秒完全够用。真正决定求解速度的不是求解器本身而是变量数目——把时间粒度从1小时细化到15分钟变量数从24翻到96求解时间大概是平方级往上涨。所以做初步方案时先用1小时粒度确定逻辑没问题后再切成15分钟。3. MATLAB/YALMIP代码实现从数据准备到出图下面这套是我跑通的核心代码骨架经过了删减以保留关键逻辑读者可以在此基础上补全参数和约束后直接运行。前置条件MATLAB R2020以上版本安装了YALMIP工具箱。3.1 时段离散化和参数表准备% 基础时间设置 H 96; % 15分钟粒度一天96个时段 dt 15/60; % 时间步长单位小时 % 分时电价示例元/kWh按96时段构造 price zeros(H,1); price(1:32) 0.35; % 00:00-08:00 谷段 price(33:56) 1.15; % 08:00-14:00 峰段 price(57:72) 0.65; % 14:00-18:00 平段 price(73:88) 1.15; % 18:00-22:00 峰段 price(89:96) 0.65; % 22:00-24:00 平段 % 空调参数等效热阻、热容、额定制冷量、压缩机电功率 R_ac 2; % 等效热阻℃/kW C_ac 1.5; % 等效热容kWh/℃ Q_ac 5; % 额定制冷量kW P_el_ac 1.5; % 压缩机电功率kW T_out 33; % 室外温度示例取恒定 T_low 22; % 用户舒适度下限 T_high 26; % 用户舒适度上限 a_ac exp(-dt/(R_ac*C_ac)); % 电动汽车参数 P_ev 6.6; % 充电桩额定功率kW eta_ev 0.92; % 充电效率 Cap_ev 40; % 电池容量kWh SOC0 0.30; % 到家时初始SOC SOC_req 0.85; % 离开时需要达到的SOC ev_start 40; % 10:00接入充电桩 ev_end 64; % 16:00拔枪离开 % 可平移负荷参数 P_dw 1.8; % 洗碗机功率kW D_dw 6; % 洗碗机连续运行6个时段1.5小时 dw_window_start 80; % 洗碗机运行允许窗口起点20:00 dw_window_end 96; % 洗碗机运行允许窗口终点24:00 P_wm 1.5; % 洗衣机功率kW D_wm 4; % 洗衣机连续运行4个时段1小时 wm_window_start 84; % 洗衣机运行允许窗口起点21:00 wm_window_end 96; % 洗衣机运行允许窗口终点24:00 % 固定不可控负荷基础用电 P_base ones(H,1)*0.3; % 恒定0.3kW也可以按实际作息填向量这里我把室外温度简化成全天恒定真实应用应该用未来24小时预测温度序列。温度曲线的波动会影响空调预冷策略尤其是白天太阳辐射导致午后温度升高空调负荷会明显后移。3.2 变量定义与约束构建的核心片段% 决策变量 u_ac binvar(H,1); % 空调启停 u_ev binvar(H,1); % EV充电启停 s_dw binvar(H,1); % 洗碗机运行状态 s_wm binvar(H,1); % 洗衣机运行状态 Tin sdpvar(H,1); % 室内温度 SOC sdpvar(H,1); % 电池SOC(kWh) st_ac sdpvar(H,1); % 空调启动事件连续变量 st_dw sdpvar(H,1); % 洗碗机启动事件 st_wm sdpvar(H,1); % 洗衣机启动事件 Constraints []; % 空调室内温度递推方程 Constraints [Constraints, Tin(1) 25]; for t 1:H-1 Constraints [Constraints, Tin(t1) a_ac*Tin(t) (1-a_ac)*(T_out - R_ac*Q_ac*u_ac(t))]; end Constraints [Constraints, T_low Tin T_high]; % 空调启动事件与启停抑制抑制压缩机频繁启停 Constraints [Constraints, st_ac u_ac - [0; u_ac(1:end-1)]]; Constraints [Constraints, st_ac 0]; % EV充电约束 Constraints [Constraints, u_ev(1:ev_start-1) 0]; % 到家前不允许充电 Constraints [Constraints, u_ev(ev_end1:H) 0]; % 离家后不允许充电 Constraints [Constraints, SOC(ev_start) SOC0*Cap_ev]; % 初始电量 for t ev_start:H-1 Constraints [Constraints, SOC(t1) SOC(t) eta_ev*P_ev*u_ev(t)*dt]; end Constraints [Constraints, SOC(ev_end) SOC_req*Cap_ev]; Constraints [Constraints, 0 SOC Cap_ev]; % 洗碗机连续运行启动一次窗口约束 Constraints [Constraints, s_dw(1:dw_window_start-1) 0]; Constraints [Constraints, s_dw(dw_window_end1:H) 0]; Constraints [Constraints, sum(s_dw) D_dw]; Constraints [Constraints, st_dw s_dw - [0; s_dw(1:end-1)]]; Constraints [Constraints, st_dw 0]; Constraints [Constraints, sum(st_dw) 1]; % 洗衣机与洗碗机同理 Constraints [Constraints, s_wm(1:wm_window_start-1) 0]; Constraints [Constraints, s_wm(wm_window_end1:H) 0]; Constraints [Constraints, sum(s_wm) D_wm]; Constraints [Constraints, st_wm s_wm - [0; s_wm(1:end-1)]]; Constraints [Constraints, st_wm 0]; Constraints [Constraints, sum(st_wm) 1];这里出现了两个容易混淆的点。第一洗碗机窗口约束写成“允许窗口之外的s_dw等于0”但这并不要求洗碗机一定在窗口内运行到结束sum(s_dw)D_dw配合sum(st_dw)1和窗口外的0值才严格保证它是一个完整的连续模块。第二EV的SOC递推循环我只写了ev_start到H-1其实ev_end之后车辆已经不在家这段递推保留不保留都无所谓因为SOC约束只在ev_end处加了下限如果后续要做V2G放电才需要把离段之后的SOC动态单独处理。3.3 求解、结果提取与可视化% 目标函数 Objective sum( price .* (P_el_ac*u_ac P_ev*u_ev P_dw*s_dw P_wm*s_wm P_base) * dt ) ... 0.10*sum(st_ac); % 启停惩罚单位元/次 % 求解 ops sdpsettings(solver, intlinprog, verbose, 1, showprogress, 0); optimize(Constraints, Objective, ops); % 结果提取 ac_on value(u_ac); ev_on value(u_ev); dish_on value(s_dw); wm_on value(s_wm); temp_in value(Tin); soc_kwh value(SOC); total_cost value(Objective); % 绘图示意电价曲线、空调启停和EV充电时序 figure; t_h (0:H-1)*dt; % 小时刻度 stairs(t_h, price, LineWidth, 1.5); hold on; stem(t_h, ac_on*max(price), o, MarkerSize, 4, DisplayName, 空调运行); stem(t_h dt, ev_on*max(price)*0.9, x, DisplayName, EV充电); xlabel(时间(h)); ylabel(电价/运行状态); legend(分时电价, 空调运行, EV充电); grid on;出图时可以再多画两张一张室内温度曲线叠加舒适度上下限用来检查空调预冷是否真的把温度控制住了一张SOC曲线叠加EV充电功率柱状图用来检查充电是否被集中安排到低价时段。这两张图是判断模型行为是否合理的最直接手段我在第四章的灵敏度分析里反复用到。4. 仿真结果与灵敏度分析调参时我在关注什么模型跑通之后真正有价值的阶段是参数敏感性分析。家庭能量管理模型不是“运行一次拿个电费数字就算完事”的作业题而是要回答这类问题空调设定温度提高一度能省多少电费电动汽车傍晚到家到底比中午到家省多少峰谷价比为多少时平移负荷才划算4.1 基准场景下费用构成和负荷曲线解读以我给的参数为例总电费大概在十几元一天量级其中空调负荷占比最大EV充电次之可平移负荷和固定负荷占小头。这不奇怪用电量最大的可调度对象就是空调和EV它们的调度自由度又最大。看负荷曲线时最值得关注的是空调运行时段有没有被集中到00:00-08:00谷段。如果室外温度全天恒定、分时电价峰谷明确模型应当会在早上低谷期提前把房间温度从25度拉低到24度甚至23度然后在上午阳光上来之前利用热惯性少开空调。室内温度曲线会在峰段缓慢爬升到26度附近而不会平平稳稳贴在25度一整天——出现后者说明预冷逻辑没起作用通常是热容参数设得太小导致温度回升太快预冷毫无性价比。EV充电时序的关注点则是SOC曲线是否在低价时段出现阶梯状上升峰值是否恰好停在充电桩功率允许上限以及是否为了满足目标SOC而在高价段充了一段“不得不充”的电。以10:00接入、16:00离开、要求达到85%SOC为例平段只有14:00-16:00这2小时充入电量有限剩下必须峰段充倒在预期之内。如果你想省更多的钱把接入时间推到22:00之后是最直接的办法因为整夜都是谷段。4.2 空调设定温度每提高1度省多少电费把T_low和T_high整体抬1度比如从22~26改成23~27空调运行时间会缩短电费下降。下降幅度和房间热惯性直接相关热容C越大温度上限放宽带来的收益越大热容越小房间温度波动快温度上限放宽对空调运行时间的影响反而小。这个场景的工程意义在于长期来说用户在不明显降低舒适感的前提下把空调设定温度从24度调整到25度比任何复杂的优化算法都有效。能量管理系统能做的是把这个信息量化出来优化器算完一次基准场景后再做一次温度偏好1度的对比输出“调整设定温度一年可省电费XX元”。这种结果给用户的冲击力比给他一条调度曲线大得多。4.3 EV到达时间和电池容量的影响EV接入时间决定了可充电窗口处于哪些电价段。我做过一个直观对比同样是目标SOC 85%接入时间从10:00改到20:00充电窗口一部分落在峰段、一部分落在平段22:00以后再改到22:00以后整个充电窗口都是谷段。后两种情况电费差距可能达到三分之一甚至一半因为峰段电价比谷段贵接近三倍。电池容量和充电功率对调度的影响也很直接。容量40kWh的电池如果允许在谷段用6.6kW功率连续充3小时左右就足以从30%到85%对一块大电池来说谷段窗口往往够用但如果充电功率只有3.3kW谷段8小时也最多充26.4kWh对某些大电池可能就需要平段甚至峰段补充。这就是为什么要同时考虑功率和容量两个参数不能只看SOC目标。4.4 峰谷价差比例对平移行为的影响如果峰谷价差比例只有1.5倍可平移负荷平移的动力很弱因为洗碗机和洗衣机本来用电量就不大平移到谷段省下来的钱可能只有几角钱而当峰谷比达到3倍甚至4倍平移收益变得可观模型会把洗碗机启动时间直接推到22:00之后。实际操作中我会固定所有负荷参数把平段电价保持0.65不变峰段电价从0.85逐级调整到1.35观察洗碗机启动时段和EV峰段充电量的变化。当峰段电价超过某个阈值后EV会尽量把充电挤到平段洗碗机会滑到窗口末尾启动空调预冷深度也会增加。这个“阈值点”就是需求响应的价值点也是日后向用户解释“为什么电价政策调整会影响你家电费”的关键数据。5. 我踩过的坑和给新手的建议这套模型我在实现过程中踩过的坑不止三个有逻辑层面的有小细节层面的下面按影响大小排序。5.1 空调连续启停惩罚不加的话结果没法用最大的坑出现在空调启停策略上。如果不加任何启停限制MILP求解器给出的最优解常常是空调以15分钟甚至更短的周期反复启停开一个时段、停一个时段、再开一个时段。从用电费用角度看这确实“最优”因为线性热动态模型没有任何机制惩罚压缩机启停损耗但对真实的空调来说频繁启停轻则影响舒适度重则缩短压缩机寿命甚至电流冲击比连续运行更费电。我的解决方案有两个层次。最简单的是在目标函数里加一个很小的启停惩罚项0.05到0.2元/次量级要低于空调省下来的电费否则会压制正常调度。更严格的方案是给空调增加最小运行时间和最小停机时间约束比如“一旦开启至少运行2个时段”“一旦关闭至少停机1个时段”这组约束需要引入额外的状态变量代码复杂度会高不少。家庭场景先加惩罚项就够了如果是研究论文或工程项目还是建议把最小启停时间约束写全。5.2 时间粒度选15分钟还是1小时1小时粒度对家庭能量管理模型来说往往太粗。空调预冷策略在1小时粒度下会显得很笨要么预冷一整小时要么不预冷很难表达“提前半小时把温度降下来”这种精细操作。可平移负荷也存在同样问题一个1.5小时的洗碗机在1小时粒度下只能表达为2小时或1小时总有一个时段对不上。15分钟粒度是我认为的甜点。它既能捕捉空调热动态的主要变化和电价切换时刻又不至于让整数变量扩到288个5分钟粒度导致求解明显变慢。如果做滚动优化或者家庭用能规划我建议用15分钟作为基础粒度但前期调试阶段先用1小时粒度把逻辑跑通确认约束没有矛盾之后再切成15分钟省下的调试时间非常可观。5.3 YALMIP与intlinprog配合的常见问题YALMIP本身只是个建模层实际求解由intlinprog完成。我遇到过的几个坑如下二元变量用binvar定义连续变量用sdpvar定义不要把0/1决策变量定义成sdpvar再手动加整数约束那样代码难读且容易出错。intlinprog对数值尺度敏感。电价、功率、SOC这些量纲差异不大但如果你把惩罚项设成0.0001这种量级求解器可能认为它低于整容差直接忽略。目标函数里各项数量级最好都在10^0附近这个细节能避免大量莫名其妙的次优解。状态递推约束用for循环写96次在YALMIP里会生成一个很长的约束列表运行速度还能接受但建模时间会随H线性上涨。如果后续模型扩大到几百个时段考虑用矩阵形式替代循环。另外intlinprog是分支定界算法家族本身不做全局性随机搜索但这不意味着结果一定是全局最优它是在给定的整数容差默认大约1e-4内的整数最优。对家庭能量管理这种实际场景偏差极小完全够用。5.4 参考资料与进一步扩展方向标题里带了“参考文档”三个字我直接给新手指几条查找资料的路径。家庭能量管理系统综述可以搜“Home Energy Management System Demand Response Review”IEEE Trans. on Smart Grid和Applied Energy这类期刊上有大量高质量综述会把家庭负荷分类、优化方法、求解工具对比得很清楚。空调负荷建模这块建议直接搜“Equivalent Thermal Parameters air conditioning”或“Building thermal model”ETP模型的源头文献大多来自热工领域参数辨识方法也成熟。可平移负荷调度看“Appliance Scheduling Smart Home Residential”这类文献几乎必提整数线性规划。中文资料方面知网上用“家庭能量管理”“分时电价”“需求响应”“可平移负荷”几个关键词组合能找到大量硕士论文其中参数设置和MATLAB实现细节比英文期刊更适合入门。这个模型后续有几个很自然的扩展方向加屋顶光伏需要把PV出力曲线作为负负荷引入目标函数加储能电池其SOC递推和EV类似但约束更灵活充放电都可以优化加V2G双向充电EV可以变成放电电源目标函数里要处理放电收益这会把调度自由度提高一个量级但约束也会复杂得多。还有就是从单日优化扩展到滚动优化每15分钟一次重算用最新温度预测和价格信息修正后续决策这是工程落地真正要走的路。我自己跑这套模型最大的体会是家庭能量管理的核心不完全是“省多少钱”而是理解“哪些弹性是可用的”。空调热惯性、EV充电窗口、可平移负荷的连续运行需求每一种弹性都有对应的数学模型把这些模型组合成一个线性约束集剩下的求解反而不难。如果你也在搭类似模型建议先不要急着堆算法把设备细分成可控项、半可控项和不可控项一项一项写成约束模型自然就好了。