ARTICLE DETAIL

资讯详情

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

基于MATLAB与MILP的家庭能源管理仿真:负荷建模与用电调度优化

基于MATLAB与MILP的家庭能源管理仿真:负荷建模与用电调度优化 1. 家庭能源管理仿真系统为什么这套程序值得自己搭去年年底查电费账单的时候我愣了好几秒——家里没电动车没地暖常规电器就是空调、热水器、洗衣机、洗碗机、冰箱和一堆照明然而冬季一个月电费硬生生冲过了五百。峰谷电价这几个字在账单上挂了大半年但我从没仔细算过把那些大功率电器的运行时间错开晚高峰一年到底能省多少为了把这个问题算明白我用MATLAB搭了一套家庭能源管理系统HEMS仿真程序。核心逻辑其实不复杂把家里每种电器的运行特征抽象成数学约束把所有电器的用电成本之和设为目标函数交给求解器去找一个什么时候该开哪台电器的最优排程。这套程序的价值不止是算出电费能省多少而是让你把家电调度从一个拍脑袋的经验问题变成一个可量化、可比较、可复现的优化问题。如果你正在研究家庭能源管理、想验证某个调度策略的效果或者在做相关的课设和竞赛项目这篇文章应该对你有用。我下面会从系统设计、负荷建模、优化策略、MATLAB OOP架构到实测结果完整走一遍我当时的思路和踩坑过程。1.1 选型问题为什么是MATLAB而不是Python/C先说选型。家庭能源管理程序的主要任务是处理几类数据电价时间序列、光伏出力曲线、各个设备的运行状态以及最后的设备调度决策。它涉及两个比较重的计算环节——时间序列的模型构建和离散优化问题的求解。MATLAB在这两个环节上都有天然优势。时间序列天然是矩阵操作MATLAB的向量化运算能力让电价曲线、负荷曲线这类输入可以直接用一句表达式生成和处理优化方面MATLAB自带的Optimization Toolbox里有linprog、intlinprog、fmincon这些现成的求解器装完即可用不用像Python那样先去装PuLP、cvxpy或者SCIP也不用操心求解器的许可问题。特别是混合整数线性规划MILP的求解intlinprog表现相当稳定对家庭能源管理这种规模的问题完全够用。另外还有一点不能忽略电力系统方向的论文、资料、工具箱很大一部分都落在MATLAB生态里。我本身是做电力系统仿真背景切入的用MATLAB调试更顺手遇到问题搜到的参考代码也基本都是这个框架。当然如果后续要上真实硬件做嵌入式部署Python或C更合适但作为策略验证和科研仿真MATLAB是性价比很高的选择。1.2 系统总体架构一个三层结构的仿真流程我最终实现的程序逻辑上分成三个层次数据输入层负责准备电价曲线、光伏出力预测、各设备参数。这一层的数据统一规范成以15分钟为时间步长、一天96个时段的序列结构。优化决策层把家电调度问题建模成一个MILP问题调用求解器计算未来24小时内的最优开关状态和功率分配。结果输出层把求解结果还原成每个设备的启停时间表、功率曲线和费用明细并用MATLAB绘图函数把结果可视化方便和未优化的原始方案做对比。采用这个分层是因为三层之间的耦合度很低你换一套电价政策只改数据输入层换一个求解算法只动决策层增加一种家电只需要按接口往模型里加约束。这个结构对我后期反复调策略帮助很大。比如我想把空调的舒适温度区间从正负1度调整到正负2度只用改设备参数文件里的两个数调度核心代码完全不用碰。需要说清楚的是这个架构面向的是仿真验证而不是实时控制。真实家庭里的HEMS会放在云端或本地边缘设备上运行采集实时数据并滚动求解我这里先做的是离线仿真用一天的历史或预测数据求解一次把整套逻辑跑通再考虑往实时方向扩展。2. 家用电器负荷建模调度策略的精度取决于这一步很多初做家庭能源管理的人容易犯一个错一上来就急着写优化程序结果优化目标写完了却发现最基础的设备行为模型写不扎实后面所有结果都不可信。负荷建模是整个项目里我最花时间、也最影响最终效果的部分。2.1 负荷分类四种不同脾气的家电不同家电的调度自由度完全不同。我把常见的家庭负荷分成四类每一类在优化模型里的处理方式都不一样刚性负荷照明、冰箱、电视、路由器这类设备。特点是必须开、不可移、功率基本固定。在模型里它们的功率直接作为固定值叠加进总功率曲线不参与任何调度决策。可平移负荷洗衣机、洗碗机、烘干机这类设备。特点是运行时间可以整体平移但一旦开始运行功率曲线基本固定而且需要连续跑完整个工作周期。优化变量通常是它的启动时刻。温控负荷空调、电热水器、电暖器。特点是有热惯性温度可以在一个舒适区间内浮动功率不是简单开或关而是根据当前温度与目标温度的偏差来决定。这类设备最值得做调度因为能在用户几乎无感知的情况下改变用电时段。储能设备家庭储能电池、电动汽车充电桩。特点是既能充电也能放电存在SOC荷电状态上下限约束调度自由度最大但模型也最复杂。把这四类设备分开建模之后优化问题的结构就清晰了。写约束的时候本质上是在回答四个问题哪些时刻必须开哪些设备可以挪到什么时候开温控设备在什么温度范围内允许关掉储能设备在什么时间充、什么时间放把这些答案写成线性方程组优化问题也就成型了。2.2 每类负荷的数学模型与MATLAB参数化先说刚性负荷。这类最简单就是一条功率基线序列P_base(t)直接读入一天96个时段的功率值。我在程序里把它定义成一个数组优化完的总功率直接叠加这一项不做任何决策。可平移负荷的模型稍复杂一点。以洗衣机为例它的工作周期典型是45分钟按15分钟一个时段就是3个时段每个时段的功率固定比如依次是0.2kW、1.5kW、0.3kW对应注水、洗涤、甩干。调度的关键是确定启动时刻t_start一旦确定它后面每个时段的功率就完全确定了。用数学语言表达就是引入一个二进制变量u(t)表示洗衣机是否在t时段启动约束一天最多启动一次而且必须在用户设定的时间窗内比如早上7点到晚上10点。这个模型简单但非常实用我后来扩展了多状态洗衣机本质思路一样只是把每个状态拆成了独立变量。温控负荷我用的是等效热参数模型EHPC * dT(t)/dt (T_env(t) - T(t)) / R Q_heat(t) - Q_cool(t)这个方程是温控负荷建模的核心。C是等效热容R是等效热阻T_env是环境温度T是室内温度或水箱温度Q_heat是制热/制冷功率。空调和热水器的差异只是Q的方向不同。离散化到15分钟步长后它变成一个线性差分方程可以放进MILP模型。因为要求解0-1优化问题我把空调开/关建模成二进制变量并用线性约束把温度状态变量和开关变量绑在一起保证温度只在空调运行时变化。热水器模型类似只是时间常数比房间短得多——水箱加热快散热也快所以调度窗口更窄。我在热水器模型里额外加了一条最低水温约束避免为了省钱把热水温度压到洗澡都没法洗。这条约束本质上是把使用舒适度前置到了模型里而不是等优化完再去评判结果合不合理。储能设备是最标准的一类SOC状态变量s(t)满足递推关系s(t1) s(t) P_ch(t)*eta_ch - P_dis(t)/eta_dis再加上充放电功率上限约束、SOC上下限约束。在家庭场景里储能电池通常是为光伏消纳服务的所以我在模型里加了一条电池不能同时充放电的约束用两个互斥的二进制变量控制防止求解器给出边充边放的荒唐方案。2.3 建模时最容易忽略的两个细节第一个细节是单位统一。我一开始直接用kW、小时做单位后来发现和电价、光伏出力的单位对不上经常出现差1000倍的错误。全部统一成kW / 15min时段之后所有数据自动就对齐了。第二个细节是最小运行时长约束。很多人建模洗衣机只约束了启动时刻忘了约束一旦启动必须连续运行完整周期。这个约束写成线性形式就是在洗衣机启动后的连续3个时段内功率必须等于额定序列值。如果漏了这条约束求解器会给出一个洗衣机开到一半停掉、半小时后又开的方案数学上成本最低物理上根本不成立。这个坑我在第一次仿真时就踩过后面细说。负荷类型典型设备调度自由度核心约束刚性照明、冰箱无固定功率序列可平移洗衣机、洗碗机启动时刻可调时间窗、连续运行温控空调、热水器功率按需开关温度舒适区间储能电池、EV充电桩充放电量/时刻可调SOC上下限、充放互斥3. 用电调度优化策略把该什么时候用电变成数学问题设备模型建完之后核心就是调度策略本身。调度策略的本质是在满足所有设备约束的前提下找到一组决策变量让目标函数最小。这里我把整个构建优化模型的过程拆开讲一遍。3.1 目标函数与约束一个标准的MILP问题目标函数我取全天总电费也试过更丰富的形式——电费加上一个轻微的舒适度惩罚项避免优化器为了省钱把空调关过头。不过为了把逻辑讲清楚先只说电费最小化minimize sum_t ( P_total(t) * price(t) * dt )其中P_total(t)是t时段的全屋总功率包含刚性负荷、可平移负荷、温控负荷和储能充放电功率price(t)是t时段的电价。如果所有决策变量都是连续的直接上linprog但可平移负荷的启动时刻和温控设备的启停是0-1变量所以整个问题是一个混合整数线性规划MILP用intlinprog求解。约束条件分三大类设备自身的约束可平移负荷的时间窗和连续运行、温控设备的温度上下限、储能的SOC和功率限制。家庭总功率约束进线容量限制。比如入户电表是8kW那么任何时刻全屋总功率不能超过8kW这是保护线路安全不可违背的硬约束。电表/并网约束如果家里有光伏或储能还要限制不允许向电网倒送功率或者倒送上限具体取决于当地政策。我这里先假设不允许反送。把这三类约束用矩阵形式组织起来就是intlinprog需要的A*x b结构。这个环节最费工夫的不是数学本身而是把设备模型转成约束矩阵时容易出错。我建议的做法是先搭一个只有一台洗衣机加一台空调的测试案例把约束矩阵打印出来和手算结果对比确认无误后再扩展到全屋设备。3.2 求解器选型为什么我用intlinprog而不是遗传算法关于求解算法我见过不少人一上来就用遗传算法GA或粒子群PSO理由是智能算法听起来先进。但实际对比下来对家庭能源管理这种规模的问题——设备数量一般不超过10个时间步长96个时段未知变量几百个——MILP求解器远比启发式算法合适。原因有三点。第一MILP求解器内部用分支定界法能保证找到全局最优解遗传算法只能给出近似解而且每次跑的结果可能不一样做仿真研究时结果不可复现非常痛苦。第二MILP求解速度快在我这台普通笔记本上全屋10台设备的MILP问题intlinprog一般几秒到几十秒就解完了遗传算法要设置种群、迭代次数动辄好几分钟。第三MILP对约束的处理是精确的遗传算法加复杂约束通常靠罚函数罚系数本身怎么定都麻烦还容易不稳定。当然MILP不是万能的。如果目标函数是非线性的比如考虑电池老化成本的非线性项或者设备模型涉及连续非线性关系那MILP就用不了这时才需要fmincon或元启发式算法。但对家庭能源管理这个场景把问题线性化大多数时候是可行的关键是愿意花时间把非线性关系用分段线性近似表示。3.3 各类电器的具体调度逻辑下面给出每类电器我实测下来最实用的调度策略可平移负荷洗衣机/洗碗机把启动时刻设计成待优化变量约束在用户设置的时间窗内启动。优化结果绝大多数情况下是洗衣机被安排到电价最低的凌晨时段启动用户早起就能用。如果不想让它半夜工作就把时间窗改成早上8点到晚上10点求解器会在区间内选成本最低的时刻通常落在午后光伏出力最高或电价次低的时段。温控负荷空调/热水器核心是预冷/预热策略。电价低谷期提前把房间或水箱温度升至舒适区间边缘电价高峰时段允许温度自然漂移。房间热惯性通常能提供30到60分钟的调度窗口热水器热容小只有10到20分钟。这个窗口就是省钱的来源。储能电池/EV逻辑是低价充电、高价放电。但要注意充放电效率损耗——铅酸电池效率约80%锂电池约90%充放一个循环会吃掉部分价差收益。如果峰谷价差小于15%储能调度反而是亏钱的。所以我在模型里加了一条逻辑只有当峰谷价差超过阈值才允许放电避免过度调度。4. 基于MATLAB OOP架构的程序实现从脚本到可扩展类这一步是我把程序从一次性脚本升级为可复用框架的关键。如果只是自己算一次结果MATLAB脚本就够了但如果需要反复更换设备参数、对比不同用户场景、甚至添加新设备类型那一定要用面向对象OOP的方式组织代码。4.1 为什么用OOP用一个基类统一所有设备的接口设备多了之后一个问题立刻暴露出来洗衣机、空调、电池的行为差异很大但调度需要它们提供一个统一的接口——输出自己的决策变量索引范围、输出参与的约束矩阵块、输出它的功率曲线形状。OOP的设计思路是定义一个抽象基类ApplianceBase包含所有设备共有的属性名称、额定功率、类型、时间步长和抽象方法构建设备约束、提取功率曲线。每种具体设备继承基类实现自己的约束构造逻辑。这样一来Scheduler调度器只需要面向基类编程完全不用关心具体设备内部怎么建模。我后来加过一台新风系统设备只需要继承基类实现两个方法调度器代码一行没改。4.2 类图与核心方法设计我实现中定义了这几个核心类ApplianceBase基类定义name、p_rated、schedule_type属性声明build_constraints()、get_power_curve()、get_var_indices()三个抽象方法。ShiftableAppliance可平移负荷子类。属性有start_window、duration_steps、power_profile。实现的约束是启动时间窗约束和连续运行约束。ThermostaticAppliance温控负荷子类。属性有t_current、t_min、t_max、thermal_capacity、thermal_resistance。实现的约束是温度差分方程、温度上下限约束、功率与启停变量的耦合约束。StorageAppliance储能子类。属性有soc_min、soc_max、charge_power_max、discharge_power_max、efficiency。实现的约束是SOC递推方程和充放互斥约束。Scheduler优化核心类。接收所有设备对象、电价序列、刚性负荷序列、总功率上限构建目标函数和约束矩阵调用intlinprog把结果解析回每台设备的时间表。这套设计不是一开始就长这样是我重构了两轮才稳定下来的。第一版用纯脚本写所有设备约束堆在一个巨型函数里加一台设备就得改主函数数据还容易传错。后来按OOP重构主程序变得非常清爽直接就是创建设备对象 - 传入Scheduler - 求解 - 画图四步调试效率提升明显。4.3 核心代码框架展示下面贴一个简化版的核心代码去掉了部分边界检查方便看清整体结构。首先是基类定义classdef ApplianceBase handle properties name char p_rated double % 额定功率kW schedule_type char % fixed, shiftable, thermostatic, storage n_steps double % 一天的总时段数 end methods (Abstract) A build_constraints(obj, var_start_idx, n_vars) p get_power_curve(obj, decision_vector) idx get_var_indices(obj) end endScheduler类的核心算法部分如下classdef Scheduler handle properties appliances % cell array of ApplianceBase price % 电价序列96x1 p_base % 刚性负荷序列96x1 p_max % 进线功率上限 end methods function [x_opt, fval] solve(obj) % 遍历设备统计各自变量索引 % 逐设备累积约束矩阵 A_total []; b_total []; Aeq_total []; beq_total []; for k 1:length(obj.appliances) app obj.appliances{k}; idx app.get_var_indices(); [A_a, b_a, Aeq_a, beq_a] app.build_constraints(idx); % 按变量索引拼装到总约束矩阵中 end % 目标函数总电费 f ...; % 由电价和功率系数向量乘积得到 options optimoptions(intlinprog, Display, off); [x_opt, fval] intlinprog(f, intcon, A_total, b_total, ... Aeq_total, beq_total, lb, ub, options); end end end这里有个关键点intlinprog的输入是f, intcon, A, b, Aeq, beq, lb, ub的规范形式优化变量的排序必须和约束矩阵的列一一对应。我踩过的坑是设备A的变量索引和设备B的变量索引拼接时如果不小心漏掉某个设备的变量个数后面所有约束都会错位而且这种错误很难肉眼发现。后来我在build_constraints里强制让每个设备自己记录变量索引范围拼装后做一次维度校验——size(A_total, 2)必须等于变量总数。这一步看似多余实际救了我很多次。5. 典型场景仿真一栋普通家庭一天能省多少钱光说不练肯定不行。我用一个典型的三口之家数据跑了完整仿真这里把场景参数和结果复盘一遍。你可以拿这套参数做基准回头换成自己的数据看结果。5.1 仿真场景与参数设定家庭设定为建筑面积约90平米空调一台制冷功率2.5kW电热水器一台3kW100L洗衣机一台整周期3个时段平均功率0.8kW洗碗机一台整周期2个时段功率1.2kW冰箱和照明等刚性负荷全天约0.5kW基线总进线容量8kW。电价采用典型的居民峰谷电价峰段8:00-22:000.8元/kWh谷段22:00-8:000.35元/kWh。未优化的默认方案设定为空调18:00回家后一直开到23:00热水器19:00加热到50度洗衣机20:00开始洗洗碗机21:00开始工作。这个时间表其实非常符合多数家庭的真实习惯——一天辛苦下来所有家务都堆在晚饭后恰好也是电价最贵的时段。5.2 优化结果与成本对比优化后的方案很有意思洗衣机被挪到了凌晨1点洗碗机挪到了凌晨2点热水器改在下午14:00提前把水温提到55度晚饭后不再加热空调则变成22:00后关闭凌晨4点到6点之间短时运行一次利用低谷电价维持早晨起床前的基础温度。方案全天电费峰段用电量谷段用电量电费降幅默认习惯22.2元25.1kWh6.0kWh-优化调度16.0元13.4kWh15.2kWh27.7%可以看到单日电费降低了约27.7%一个月下来就是180多块。这个数字的核心来源是峰段用电占比从80%降到了47%左右谷段电价比峰段低了56%整体成本自然就下来了。再往深看一层空调的调度收益比洗衣机加洗碗机加起来还大因为空调连续运行时间长、功率高是典型的电价敏感负荷。这个结论对我后续策略设计影响很大家庭里如果只能优先调度一类设备优先管空调其次是热水器。5.3 参数敏感性什么时候调度策略效果最好我把几个关键参数跑了一遍敏感性分析结论值得记下来峰谷价差是调度收益的第一驱动力。价差低于0.2元/kWh时优化几乎没什么收益因为可平移负荷带来的成本降幅和用户不便程度相比不划算价差超过0.4元/kWh后收益曲线接近线性上升。空调的热惯性或者说房间保温性直接影响预冷策略的可行性。保温好的房间热阻R值大可以提前两小时预冷保温差的房间预冷窗口只有30分钟调度收益大概差了40%。可平移负荷的灵活性洗衣机时间窗越宽优化收益越高。如果把接受度从晚上10点前必须洗完放宽到晚上任何时间都可以洗收益还能再增加约8%。这些结论反过来指导了实际策略的参数配置把可平移负荷的时间窗尽量放宽把空调温度舒适区间尽量拉大是成本最低的两种调参方式。6. 从这个项目里踩过的坑和未来可以继续做的方向6.1 坑一连续运行约束缺失导致的荒谬调度前面提到过第一次跑洗衣机模型时我没有加连续运行约束结果intlinprog给出了一个数学模型上最优、物理上荒谬的方案洗衣机在晚上8点启动洗了15分钟后关掉然后在凌晨2点又启动洗了15分钟。原因很简单——我把洗衣机的功率模型定义成了启动后的每个独立时段都可以自由决定开或关求解器发现只开着几个功率最低的时段最便宜。这个问题的本质是建模时把单次连续周期错误地建模成了每个时段独立决策。修复方法是引入启动变量u(t)0-1变量表示t时段是否开始一个洗涤周期然后约束周期内功率 sum_{t_start} u(t_start) * power_profile并确保sum(u) 1。加上这个约束后调度结果就合理了。这个错误后来成了我给所有可平移负荷建模时的默认检查项——任何连续过程都必须显式建模连续约束而不是默认求解器会自己理解。6.2 坑二MILP求解时间失控与约束矩阵维度错位当我把设备数量从3台扩展到8台之后intlinprog的求解时间从几秒飙升到几十秒偶尔逼近一分钟。原因是温控设备的温度约束和启动变量的组合约束引入了比较多的大M条款模型规模暴增。我做了两件事优化一是把时间步长从10分钟改成15分钟一天从144个时段降到96个时段模型规模缩小了三分之一调度精度损失很小——家电的启停本来也不至于精细到10分钟。二是把所有约束矩阵统一用稀疏矩阵存储intlinprog在稀疏模式下速度明显更快。改完之后求解时间稳定在20秒以内。维度错位那个坑前面也提过本质是手拼约束矩阵时列数对不上。我最后的解决办法是写了一个verify_dimensions方法每次求解前自动检查size(A_total, 2)是否等于变量总数不等就直接报错不再硬着头皮往下解。6.3 方向从离线仿真到滚动时域与硬件联动把离线版本跑通之后目前我在尝试两个扩展方向。第一个是滚动时域控制——每个15分钟周期重新求解一次未来24小时的调度计划但只执行下一个时段的最优决策。这是把HEMS从仿真工具变成控制策略的必经一步能有效应对预测误差温度预报偏差、光伏出力突变或者你临时决定提前回家开空调滚动求解都会自动纠正。第二个方向是接入真实的智能插座或Home Assistant接口把程序输出的调度计划转换成实际插座通断命令这就涉及硬件和通信协议了。从我的实践体会来说MATLAB做家庭能源管理仿真这条路是走得通的关键要把每个设备的模型约束写扎实想清楚优化目标和约束的对应关系。程序本身不复杂真正花时间的是不断发现和修正建模中的物理假设。最后说一句经验之谈无论模型跑出来的结果多漂亮一定要花时间把结果图和直觉对照一遍——如果某个调度结果让你一眼就觉得这也太离谱了那大概率不是智能算法太聪明而是你的约束还少写了一条。
返回列表