
简介面向综合能源优化调度与需求响应研究者的MATLAB仿真程序包。以纽约市某装有被动与主动蓄热的办公楼为背景结合三级需求费率与系统运营商日前调度确定的每小时电价构建锥形需求响应模型并兼顾建筑人员热舒适性。问题以随机最优控制语言描述采用模型预测控制MPC近似求解代码注释清晰可直接运行并输出对比结果图。压缩包共11个文件以9个.m代码文件为主辅以1个PDF参考文献和1个.mat数据文件整体仅1.59MB目录结构紧凑便于对照论文研读与二次开发。运行优化例程需要CVX工具箱下载后若缺依赖可私信解决。目前已有1727人学习下载。资源提供完整的MPC蓄热需求响应实现含主程序、参数设定与绘图脚本适合希望快速复现论文结果、开展综合能源调度或需求响应研究的工程师与学生参考使用。1. MPC 在综合能源优化调度里到底解决了什么问题做综合能源系统的人大都有过这种经历单机效率模型建得很细风电光伏出力预测也接上了但一跑日内调度结果还是被现场工程师一句“这方案没法落地”怼回来。原因多半不在算法而在你把一个滚动变化的系统当成了静态规划问题在解。综合能源系统里电、热、气三个网络惯性差异巨大电的秒级响应、热的分钟级滞后、气的管网缓冲叠加分布式光伏和负荷的不确定性传统的单次优化拿到的是“未来 24 小时全知视角”的最优解但执行到第 3 个小时就已经和实际状态脱节了。模型预测控制把“优化”和“反馈”缝合在一起核心是滚动时域、反复求解每到一个采样时刻基于当前实测状态更新预测模型在线求解一个有限时域的最优控制问题然后只执行第一步下一个周期重复。对综合能源调度来说这意味着每一次决策都带着最新信息而需求响应信号也能以惩罚项或约束的形式实时进入优化目标。适合两类人一类是做园区级能源管理系统、需要把调度策略写到实际控制器里的工程师另一类是研究电-热-气耦合调度的学生需要一个结构清楚、能把 MPC 和需求响应逻辑分开改的仿真框架。2. 综合能源系统里模型怎么建才值得被 MPC 反复调用MPC 是模型驱动的算法模型质量直接决定控制效果上限。但这里有个常见误区把每个设备的机理模型建得越细越好。真实情况恰恰相反——用于 MPC 内部的预测模型应当比详细仿真模型更简化因为每个采样周期都要重新求解一遍优化问题非线性程度过高或连续状态过多会导致求解时间超出采样周期控制器根本跑不起来。综合能源调度的 MPC 模型通常采用线性或混合整数线性形式把重点放在能量平衡和响应关系上。2.1 设备层建模效率系数与可行域是第一优先先看设备层。光伏和风电在调度问题里很少用非线性功率曲线而是直接采用预测出力序列作为不可控电源的边界条件。燃气轮机或内燃机用线性化的效率模型就够了输入燃料功率输出电功率和余热功率转换成线性关系即可。储能部分是最需要写清楚的状态方程因为它是跨时段耦合的核心设备。以蓄电池为例离散时间状态空间形式为% battery_state_update.m % x: SOC, u: 充放电功率, P_pred: 净负荷预测, dt: 采样间隔 % 状态转移SOC(k1) SOC(k) - eta*dt/Cap * u_charge dt/(eta*Cap) * u_discharge function x_next battery_state_update(x, u, C_bat, eta, dt) % u 0 表示放电u 0 表示充电 x_next x - (u * dt) / C_bat / eta; % 简化后的统一形式 % 若需要区分充放电效率拆成两种效率系数分别处理即可 end这里统一效率系数是线性化折中的常见做法适合 MPC 快速求解。如果要更精细地区分充放电损耗可以拆成两个互斥变量并引入整数约束但求解规模会变大需提前评估。储能模型的另一个关键点在 SOC 的上下限约束不能设死在 0 和 1——实际运行中为了保护电池寿命通常限制在 0.1 到 0.9这个在约束矩阵里直接体现出。热系统部分蓄热罐的状态方程和蓄电池类似区别在于热损失项必须显式建模否则长时间尺度仿真时热量会凭空多出来。热负荷的惯性比电负荷大所以热侧的预测时域可以短一些也能相应降低计算负担。2.2 目标函数与需求响应信号的衔接目标函数在综合能源 MPC 里通常包含三部分从电网购电成本、燃料成本、设备运行维护成本。需求响应如果不参与建模就只在约束端改变允许的用电区间如果参与目标函数就把削减负荷的补偿收益或激励价格作为负成本项加进去。目标函数的离散形式写成% objective_fun.m % x: 决策变量向量, c: 成本系数向量 % 成本构成购电成本 燃料成本 运维成本 - 需求响应补贴 function f objective_fun(x, price_grid, price_fuel, om_cost, dr_incentive) % 从决策向量中拆出各设备出力 P_grid x(1); % 电网购电功率 P_gt x(2); % 燃气轮机出力 P_dr x(3); % 需求响应削减量 f price_grid * P_grid price_fuel * P_gt om_cost * abs(P_gt) - dr_incentive * P_dr; end这个函数在日常仿真中会被反复调用注意两个细节。第一运维成本使用绝对值的写法在 MATLAB 里会引入非线性实际工程中通常用线性近似或引入辅助变量替代否则求解器要切换成非线性规划速度明显变慢。第二需求响应补贴项前的负号意味着削减负荷对优化器是一个收入项系统会在满足舒适度的前提下自动权衡“削减多少最划算”——这正是价格型需求响应的核心逻辑。表 2-1 给出了综合能源 MPC 中常用设备的建模复杂度参考来自我拆过的几个园区能源站项目的经验值供选型时参照。设备类型变量类型MPC 内部模型复杂度建模要点光伏/风电不可控输入低直接采用预测序列不加动态方程燃气轮机连续控制变量低线性效率曲线注意爬坡约束蓄电池连续状态控制中SOC 状态方程 充放互斥约束蓄热罐连续状态控制中需加散热损失项可削减负荷连续/整数中是否引入整数变量取决于响应规模电锅炉连续控制低简单线性转换效率建模时另一个容易忽略的是爬坡约束。燃气轮机和电锅炉在相邻采样点之间的出力变化有物理上限不能无限制地从一个出力点跳到另一个点。这个问题在写约束矩阵时需要额外添加一组差值约束否则 MPC 求解出的轨迹在仿真回放时会因为速率超限而被执行机构限幅控制效果和优化结果不一致。这个差异在需求响应发生切换的时段尤为醒目——市场价格信号剧烈波动时优化器可能试图让设备出力瞬间跳变而实际系统根本做不到。2.3 约束矩阵的组织方式状态变量和输入变量要分开排列写 MPC 程序时约束矩阵的组织直接影响 debug 效率我的经验是把决策变量按固定顺序排列并规定好索引范围。这样约束矩阵的每一行都能对应到一条物理含义明确的约束排查问题比用 cell 数组保存约束方便得多。决策变量下标物理量类型1:Nh蓄热罐各时刻放热功率控制变量Nh1:NhNp燃气轮机各时刻出力控制变量NhNp1:NhNpNe储能各时刻充放电功率控制变量末尾若干需求响应削减量控制变量变量排序确定后再组装约束矩阵就能用矩阵分块的方式写出所有物理约束。之后每加一种设备或新的需求响应合约只需在索引表里追加不需要改动既有的约束生成函数。这种方式对代码复用的提升非常明显尤其是把程序从单场景仿真迁移到多场景对比实验的时候。3. MPC 滚动优化的 MATLAB 实现从状态更新到求解循环模型建好之后接下来就是 MPC 控制器本体。综合能源 MPC 的代码量比想象中少核心就是一个“预测-优化-执行-滚动”的循环难在细节不出错。以下从一个具体算例出发展示完整的 MATLAB 实现框架这套结构可以直接扩展应用到电-热耦合系统。3.1 预测模型与滚动时域设置MPC 的预测模型直接复用第 2 章建立的状态空间方程。滚动时域有两个关键参数预测时域 Np 和控制时域 Nc。预测时域决定优化器向前看多远控制时域决定当前时刻优化器可以调整几个步长的控制变量。Nc 通常取 Np 的 1/3 到 1/2能有效降低优化问题的决策变量数量对计算速度影响显著。% mpc_controller.m % 综合能源MPC主循环基于线性模型linprog求解 % Np24, Nc8, dt1h Np 24; Nc 8; dt 3600; % 采样时间(秒) % 读取光伏、负荷、电价预测数据 load forecast_data.mat; % 包含 P_pv, P_load, Price 三个数组 % 储能参数 C_bat 100; % kWh (倍率按1C计算) eta 0.95; % 充放电统一效率 soc_min 0.2; soc_max 0.9; soc_init 0.5; % 决策变量组织(单个时域内): % [P_grid(1:Np), P_bat(1:Np), P_dr(1:Np)] % 燃气轮机在另一个案例中加入此处聚焦电储能需求响应 % 记录每步结果 soc_trace zeros(1, 24); p_grid_trace zeros(1, 24); p_bat_trace zeros(1, 24); p_dr_trace zeros(1, 24); soc soc_init; for k 1:24 % 1. 目标函数系数 f [Price(k:kNp-1); zeros(Np,1); zeros(Np,1)]; % 2. 约束矩阵 A*x b % 自变量总数 3*Np n_var 3 * Np; % 功率平衡约束: P_grid(ki) P_bat(ki) P_load(ki) - P_pv(ki) - P_dr(ki) Aeq zeros(Np, n_var); beq P_load(k:kNp-1) - P_pv(k:kNp-1); for i 1:Np Aeq(i, i) 1; % P_grid Aeq(i, Npi) 1; % P_bat Aeq(i, 2*Npi) 1; % P_dr end % SOC 状态转移约束线性化展开 % soc(i1) soc(i) - P_bat(i)*dt/C_bat/eta A_soc zeros(Np, n_var); b_soc zeros(Np, 1); for i 1:Np A_soc(i, Npi) dt / C_bat / eta; if i Np % soc(i1) soc_max soc(1) - sum(...) soc_max end end % 简化的SOC边界检查详细展开略 % 实际实现时会构建 soc(i) 的累计表达式 % 3. 边界约束储能功率限幅、DR限幅 lb [-inf*ones(Np,1); -20*ones(Np,1); zeros(Np,1)]; ub [ inf*ones(Np,1); 20*ones(Np,1); 5*ones(Np,1)]; % 4. 调用线性规划求解 options optimoptions(linprog, Display, off, Algorithm, dual-simplex); [x_opt, fval, exitflag] linprog(f, A, b, Aeq, beq, lb, ub, options); % 5. 只执行第一步 p_grid_trace(k) x_opt(1); p_bat_trace(k) x_opt(Np1); p_dr_trace(k) x_opt(2*Np1); soc soc - (p_bat_trace(k) * dt) / C_bat / eta; soc_trace(k) soc; end这段代码的逻辑说明如下。目标函数系数 f 由电价序列构成第一段储能和需求响应段的系数为零——储能本身的运行成本已折算在效率损失里需求响应削减成本单独建模。功率平衡约束 Aeq*xbeq 是硬约束物理意义是每一时刻电网购电加储能放电加需求响应削减量等于净负荷这是综合能源系统最基本的能量守恒关系。SOC 状态转移约束把蓄电池的跨时段耦合写入优化问题本质是把第 2 章的状态方程改写成约束条件。边界约束中的 inf 表示电网购电无上限储能充放电功率限幅根据实际设备参数修改。需要注意 exitflag 的检查。linprog 在约束不可行时会返回负值这种情况在滚动优化中时有发生——光伏骤降、负荷突增时预测数据更新会让约束矛盾。处理办法是加入松弛变量把硬约束放宽为软约束这是工程落地的关键细节第 5 章专门讲。3.2 求解器选型通用还是专用MATLAB 里能做 MPC 求解的路径不少自带的 linprog 适合线性规划quadprog 适合二次规划YALMIP 加外部求解器如 Gurobi、Cplex适合混合整数问题。对综合能源 MPC 来说如果只涉及连续变量linprog 或 quadprog 完全够用因为问题规模和求解速度不是瓶颈。但一旦在需求响应中引入 0-1 变量比如“削减或不削减”的二值决策就必须借助 YALMIP 配合整数求解器。求解路径适用场景优缺点linprog / quadprog纯连续变量、无整数约束零依赖、求解快但无法处理逻辑约束YALMIP Gurobi含 0-1 变量、混合整数建模灵活但需要外部求解器许可自定义 ADMM分布式系统、多主体可保护信息隐私但调参难度高我的经验是第一版仿真全部用 linprog 跑通确认逻辑无误后再按需切换求解器。原因是调试阶段最怕问题出在求解器配置而不是模型本身把变量层做对了换求解器只是改一行调用代码的事。在更换求解器时注意 Gurobi 建模时维度检查的方式和 linprog 不同约束矩阵要显式转换为 double 类型。MPC 的执行层代码则要判断是否有必要为每个采样周期调用一次求解器。在 1 小时采样周期的园区场景单次求解时间在毫秒级完全没问题但如果采样周期缩到分钟级、设备数扩张到几十台就要评估求解耗时并考虑控制时域压缩策略。4. 需求响应嵌入方式价格型与激励型两条路线都写清楚需求响应与 MPC 的结合在建模上有两条清晰的路线价格型需求响应把分时电价直接写进目标函数优化器自动削峰填谷激励型需求响应则把削减量建模为可调节变量并支付补偿费需要配合一定的合约约束。两条路线在综合能源的框架下各有做法可以同时存在但代码里的处理方式差异明显。4.1 价格型需求响应电价直接进目标函数价格型需求响应是最容易实现的形式。在电网峰谷价差足够大的前提下优化器天然会选择在电价低时多购电给储能充电在电价高时放电或削减负荷。这种机制完全不需要修改约束条件只需要把目标函数系数换成实际的实时电价序列就行。现实中分时电价TOU机制在工商业用户中普及度很高MPC 滚动优化可以让用户以分钟或小时级频率响应电价变化。% price_based_dr.m % 价格型需求响应直接修改目标函数中的购电成本系数 % Price_TOU: 72小时的分时电价序列 (元/kWh) Price_TOU [0.32*ones(1,8), ... % 谷段 0:00-8:00 0.72*ones(1,4), ... % 峰段 8:00-12:00 0.52*ones(1,5), ... % 平段 12:00-17:00 0.72*ones(1,5), ... % 峰段 17:00-22:00 0.32*ones(1,2)]; % 谷段 22:00-24:00 % 在MPC循环中目标函数系数直接用 Price_TOU(k:kNp-1) % 其余部分与 3.1 节代码完全一致 f [Price_TOU(k:kNp-1); zeros(Np,1); zeros(Np,1)];价格型需求响应在 MPC 框架中最理想的工作方式是电价信号在优化周期内完全已知分时电价提前公布因此预测时域内不存在价格不确定性。此时 MPC 的行为接近于最优调度但依然保留了处理实时扰动的能力——比如光伏实际出力低于预测值时下一轮优化会自动减小储能充电功率避免额外的峰段购电。这种“提前规划实时校正”的分工正是 MPC 在需求响应场景中的核心价值。4.2 激励型需求响应削减量作为决策变量激励型需求响应与价格型的区别在于不是通过价格信号间接引导而是根据电网或上级调度方的削减指令直接调整自身用能计划并获得补偿。在综合能源优化调度中激励型需求响应通常建模为可调负荷约束——用户上报可削减的负荷量和削减成本优化器在追求总成本最小的目标下决定是否削减、削减多少。代码实现上需要增加两类约束。第一是削减量上限约束即每个时刻可削减的负荷量有物理上限第二是削减次数上限约束即一个调度周期内总削减次数不超过合约规定值。后者需要引入整数变量才能精确表达。% incentive_dr.m % 激励型需求响应引入削减决策变量和合约约束 % 假设全天最多允许削减3次每次削减量不超过5kW % % 决策变量扩展为: % [P_grid(1:Np), P_bat(1:Np), P_dr(1:Np), delta(1:Np)] % delta 为 0-1 变量delta(i)1 表示第i时刻发生削减 Np 24; n_var 4 * Np; % 扩展后的决策变量数 % 削减量上限P_dr(i) 5 * delta(i)delta(i)为0-1 % 削减次数约束sum(delta) 3 % 使用YALMIP声明整数变量 % yalmip(clear) % delta binvar(Np, 1); % P_dr_decl sdpvar(Np, 1); % % % 约束加入 % Constraints [Constraints, P_dr_decl 5 * delta]; % Constraints [Constraints, sum(delta) 3]; % % % 目标函数加入削减补偿项补偿单价40元/次 % Objective Objective 40 * sum(delta) - 0.5 * sum(P_dr_decl);这个建模方式的关键点在于削减次数通过整数变量 delta 约束每次启动削减产生固定费用体现在 40 * sum(delta)削减电量本身获得收益-0.5 * sum(P_dr_decl)。固定费用项让优化器不会轻易开启削减动作收益项则保证该削减的时候一定削减。这个“固定费用单位收益”的组合结构反映了实际需求响应合约的商业逻辑用户希望尽可能减少启停次数因为每次削减都涉及生产计划调整。4.3 两种需求响应方式的对比与联合接入实际项目中价格型和激励型需求响应往往同时存在用户既面对分时电价又参与了电网的紧急需求响应项目。此时需要将两种机制同时嵌入 MPC 模型但要注意优先级设计——紧急削减指令具有强制性必须在约束端体现不能只放在目标函数里让优化器自行权衡。对比维度价格型 DR激励型 DR信号形式分时/实时电价削减指令 补偿价格响应方式优化器自动调整决策是否响应 调整多少建模位置目标函数成本系数整数决策变量 约束典型合约周期固定电价表月/年按次签约日/周MPC 接入复杂度低高需混合整数求解信息披露需求电价公开用户需上报削减潜力和成本联合接入时一个值得关注的细节是激励型需求响应的削减基线和实际用电曲线会出现偏离。基线设定争议在工程中很常见不同测算法得出的削减量差异可能高达 20% 以上。如果做仿真研究建议在代码里保留两种基线算法平均法、回归法方便后续对比。5. 从能跑到能用的关键一跳三个参数调优与验证技巧MPC 控制器从“仿真能跑”到“现场能用”差距往往不在模型而在参数整定和鲁棒性设计。这里展开三个真正影响控制效果的细节。预测时域 Np 的选择依据不能只看计算量。Np 至少应该覆盖对象动态响应的主要时间尺度对电储能动态响应是分钟级的Np 取 612 就够了对蓄热系统热惯性决定其时间常数可能长达数小时Np 至少要取到 24 才能看到完整的充放热循环。更合理的做法是先做阶跃响应实验测量对象达到稳态的调节时间然后取调节时间的 1.52 倍作为预测时域。不要为了计算速度把 Np 压缩到比动态尺度还短否则 MPC 会变得短视失去滚动优化的意义。软约束的实现是在硬约束不可行时的标准解法。把功率平衡约束从 Ax b 改成 Ax b 加上松弛变量同时目标函数里加入松弛惩罚系数。具体做法% soft_constraint_example.m % 引入松弛变量 slack放宽功率平衡约束 slack sdpvar(Np, 1); % 非负松弛变量 Constraints [Constraints, Aeq * x - beq slack]; Constraints [Constraints, slack 0]; Objective Objective 1000 * sum(slack);惩罚系数 1000 的含义是让优化器宁可花 1000 元也不违反功率平衡约束但物理上存在极端情况比如电网断电此时约束无法完全满足松弛变量允许系统以可量化的代价继续运行。工程上还会把松弛变量乘以放大系数分层设置轻微越限用低惩罚严重越限用高惩罚。代码验证可以从 SOC 曲线的物理合理性入手。正常情况下 SOC 轨迹应该是一条平滑曲线——放电时段单调下降充电时段单调上升切换点出现在电价谷峰交界处。如果 SOC 曲线出现锯齿状抖动说明惩罚权重设置不合理或预测数据存在质量问题。把 MPC 调度结果和政策性增强rule-based对比时不要只比较成本数字应该同时对比设备启停次数——MPC 方案节省的成本可能来自更频繁的设备切换在现场是行不通的。最后一个验证技巧是影子价格检验。求解完线性规划后获取功率平衡约束的对偶变量MATLAB 中 linprog 输出的 lambda 字段对偶变量的数值就是该时刻电能的边际成本。这个数值应该和分时电价形态一致电价高峰期边际成本高低谷期边际成本低。如果影子价格出现倒挂说明储能容量设置或约束边界有问题这时回查设备参数往往能发现不合理的地方。对偶分析是顺手可做但很多人不知道的验证手段一次检查能省下大量 blind debug 时间。本文还有配套的精品资源点击获取