这是一篇最近在忙的项目复盘。需求侧虚拟储能楼宇微网MATLAB优化调度这三个词拆开看都不算新鲜但合在一起就是一个非常典型的交叉领域问题怎么在MATLAB里把“看不见的储能”建模、调度、跑通最终体现在电费账单和新能源消纳率上。这篇文章我尽量讲透从物理概念到代码实现再到我实际调试中踩过的坑希望对正在做微网优化或者需求响应方向的朋友有参考价值。1. 楼宇微网为什么需要虚拟储能项目设计思路拆解1.1 储能不是只有电池楼宇本身就是一个能量缓冲区做微网调度的人都有个执念就是储能容量越大越好。但真到实际项目里电池的成本、寿命、消防合规都是硬约束。楼宇微网的场景很特殊——它不光有电负荷还有大量的热负荷比如空调、热水、通风。这些东西有一个共同特征它们消耗电能但最终服务的是“冷/热量的累积效果”而不是瞬时功率。这就给调度留了一个窗口。拿写字楼最典型的中央空调来说房间温度设定在24到26度之间人体感受几乎没有差异。但如果允许温度在23到28度之间被动漂移那空调主机的功率曲线就完全可以配合电价来走。电价贵的时候少开机让楼宇的蓄热特性扛一会电价便宜的时候多开机把温度提前降下来。这个过程楼宇本身就在扮演一个“充放电的储能设备”——电价低谷给楼宇“充电”蓄冷电价高峰让楼宇“放电”释放冷量。这就是需求侧虚拟储能的核心逻辑。它不需要额外的物理装置不需要多花一分钱设备成本只需要把楼宇的热动态模型和运行约束写进优化调度里。对这个项目来说最核心的目标就是一个在不牺牲用户舒适度的前提下把楼宇微网的运行成本降到最低同时尽可能多消纳光伏。1.2 优化调度解决的不是“控制问题”而是“计划问题”注意区分一个概念这个项目做的是“优化调度”不是“实时控制”。优化调度解决的是未来24小时或者未来若干个时段内每一台设备应该工作在什么功率水平储能应该在什么时候充、什么时候放虚拟储能的“温度预设曲线”应该怎么走目标是让整个系统的运行成本最低、新能源利用率最大。它本质上是一个“计划”而实时控制是在扰动出现后跟随计划做修正。在MATLAB里落地的时候这就意味着我们面对的是一个数学规划问题——通常建模为混合整数线性规划或者二次规划。需要把楼宇的热动态方程、设备工作约束、电价曲线、光伏出力预测、分时电价机制全部写进约束条件和目标函数里然后交给求解器去算。很多做电力系统的人熟悉物理仿真一上来就想搭Simulink模型但对调度问题来说这不是最优解后面我会详细说为什么。1.3 这个项目的受众和知识储备要求如果你正准备入门微网优化调度这个项目是非常好的练手场景。它比单纯的电池储能调度问题多了一层“热动态建模”的复杂度但又不是那种重到需要做模型预测控制MPC的工业级系统。你需要具备三个基础第一熟悉MATLAB的基本语法和矩阵操作第二对线性规划和非线性规划有基本概念知道什么是决策变量、目标函数、约束第三对楼宇空调系统的工作原理有直观理解——简单说知道空调功率怎么影响房间温度。如果你现在还是个新手也不用太紧张。这个项目最难的部分不在MATLAB本身而在“怎么把物理过程翻译成数学公式”。一旦翻译完成后面的代码只是把这个翻译结果用求解器的接口写出来而已。我会在下面几节把“翻译”的过程一步步拆开。2. 核心数学模型拆解怎么把“舒适温度”变成储能容量2.1 热动态模型一阶等效热参数法楼宇热动态建模有一类经典的简化方法叫一阶等效热参数模型在建筑能耗仿真和需求响应研究中用得非常多。它的物理图像是把房间的蓄热特性抽象成一个热容节点C把墙体、窗户的传热阻力抽象成一个热阻R室外温度作为边界条件空调提供的冷量Q_AC作为控制输入。写成微分方程就是C · dθ_in/dt (θ_out - θ_in) / R Q_AC这个方程的意思很直白房间温度的变化率等于从室外渗入的热量加上空调提供的冷量除以楼宇的热容。热容越大温度变化越慢楼宇的“虚拟储能容量”也就越大。这其实就是为什么混凝土结构的楼宇比轻钢结构更适合做虚拟储能——热容大蓄冷能力强。在离散化的调度模型里我们把这个微分方程转成差分形式取调度步长为Δt通常取15分钟或1小时θ_in(t1) θ_out(t) - Q_AC(t) · R ε · (θ_in(t) - θ_out(t) Q_AC(t) · R)其中ε是衰减系数与热容和热阻有关可以表示为ε e^(-Δt/(R·C))。这个公式看着有点绕但它有个非常好的性质——只要知道当前时刻的温度、未来时刻的室外温度和空调功率就能直接推算出下一时刻的温度。这意味着“温度状态”可以作为一个线性状态变量进入到优化模型里不会带来非线性问题求解的效率会高很多。2.2 虚拟储能的等效模型SOC和充放电功率要让优化调度器把楼宇当成储能来用需要定义两个关键指标虚拟储能的荷电状态VSOCVirtual State of Charge和虚拟充放电功率。VSOC的定义非常直观就是当前温度在允许温度区间里的位置。假设温度上限是θ_max下限是θ_min那么VSOC(t) (θ_max - θ_in(t)) / (θ_max - θ_min)为什么这么定义因为温度高意味着冷量不足相当于储能放空了温度低意味着蓄冷充足相当于储能充满。当θ_in趋近于θ_min时VSOC趋近于1满电状态当θ_in趋近于θ_max时VSOC趋近于0亏电状态。虚拟充放电功率的定义也顺理成章。在开关型空调的简化模型下虚拟放电功率等于空调的额定功率P_AC_rated虚拟充电功率等于空调额定功率减去实际消耗功率。调度器通过改变空调的启停状态或压缩机频率就能控制虚拟储能“充了多少、放了多少”。如果采用变频空调模型那功率就是连续可调的模型从混合整数线性规划变成线性规划计算难度陡降。但如果考虑到一台空调的启停次数限制或者考虑控制精度MOILP会更契合实际工程。2.3 目标函数和约束条件的设计逻辑这个优化调度问题的目标函数分三块向电网购电的费用、电池储能的折损成本、用户舒适度惩罚项。至于光伏出力因为光伏发电的边际成本近乎为零在目标函数里不需要专门加一项“光伏成本”只需要在功率平衡约束里把它作为负的负荷参与平衡即可。购电费用Σ C_grid(t)·P_grid(t)其中C_grid(t)是分时电价P_grid(t)是向电网购电的功率。电池折损成本Σ(C_bat·|P_bat(t)|)其中C_bat是电池单位充放电量的等效成本这是一个经验值需要对电池全生命周期成本做折算。舒适度惩罚Σ λ·max(0, θ_in(t) - θ_comfort_max, θ_comfort_min - θ_in(t))λ是惩罚系数。加这个惩罚项的意义在于调度器可能会为了省电而把房间温度推到极端值这虽然“合法”但不“合理”所以要用惩罚项把它拽回到舒适区间附近。约束条件里最关键的有四条功率平衡约束、电池SOC动态方程、楼宇热动态方程、设备出力上下限。写出来就是P_grid(t) P_PV(t) P_bat_dis(t) P_load(t) P_AC(t) P_bat_chg(t)SOC_bat(t1) SOC_bat(t) (P_bat_chg(t)·η_chg - P_bat_dis(t)/η_dis) · Δt / E_batθ_in(t1) f(θ_in(t), θ_out(t), Q_AC(t)) // 即2.1节的热动态差分方程 0 ≤ P_grid(t) ≤ P_grid_max, 0 ≤ P_AC(t) ≤ P_AC_rated, SOC_bat_min ≤ SOC_bat(t) ≤ SOC_bat_max这套数学模型是整个项目的基石。有读者可能觉得热动态方程引入温度变量后模型的复杂度是不是会很高这其实取决于房温惩罚函数如何处理及模式的选取。选用线性化的惩罚项后该问题可直接落入线性规划求解范畴。3. MATLAB代码架构与核心实现3.1 为什么选用Yalmip工具箱而不是手写求解器很多初学优化调度的朋友会问MATLAB里做优化为什么不直接用自带fmincon或者linprog原因很简单fmincon适合小规模非线性问题但要手动把目标函数和约束写成m函数代码又长又容易出错。linprog虽然能处理线性规划但它需要你手工把问题整理成标准的矩阵形式——你必须在脑内把所有约束条件变成A·x ≤ b的矩阵表达。当系统规模变大比如楼宇里有多台空调、多个储能手工整理矩阵的过程非常折磨人而且排查bug的难度会让人崩溃。Yalmip是个建模层工具它允许用贴近数学表达式的语法来描述优化问题然后自动转化成求解器需要的标准形式。你只需要定义决策变量、写目标函数、写约束最后调用optimize()函数。它内部会自动判断问题类型调用合适的求解器。在我的实际使用中优化问题的求解效率和代码可读性都得到了很大的提升。本项目里我用的是Yalmip Gurobi的组合。Gurobi是目前最成熟的商用线性求解器之一速度非常快而且对学生有免费学术许可。如果你实在没有Gurobi用Yalmip自带的默认求解器或者开源求解器SCIP也可以只是大规模场景下速度会有差距。3.2 数据准备生成负荷、光伏和电价曲线在写调度代码之前我们先准备好输入数据。这个项目我建议做24个小时的调度时间步长取1小时这样数据的量级比较直观调试起来也方便。后面要扩展到96时段或者288时段15分钟/5分钟一个点改动成本很低。三条核心输入数据曲线负荷曲线P_load楼宇的基础用电负荷包括照明、插座、电梯等。我这里用一个经验公式生成叠加上白天高、夜间低的波动特征再加一点随机扰动模拟实际场景。光伏出力曲线P_PV典型的光伏出力形状——6点左右开始上升中午12点达到峰值下午18点之后归零。这里需要做归一化处理峰值按楼宇屋顶可装光伏容量折算。分时电价曲线C_grid我采用工商业常见的峰谷电价机制——峰时段08:00-11:00和18:00-21:00电价1.1元/kWh平时段07:00-08:00、11:00-18:00电价0.67元/kWh谷时段21:00-次日07:00电价0.38元/kWh。在数据生成过程中一个常被忽略的坑是时间对齐。光伏出力和负荷曲线的时间轴必须严格从1到24一一对应否则后面所有约束条件里的时标索引都会错位导致约束条件错误。3.3 决策变量和约束条件的Yalmip建模Yalmip的建模其实非常直观最核心的步骤就是定义sdpvar变量、写出目标函数和约束、然后求解。以下是我在这个项目中使用的核心代码框架已做关键步骤提炼% 参数定义 T 24; % 调度时段数 dt 1; % 时间步长小时 % 决策变量 P_grid sdpvar(1, T); % 从电网购电功率 P_bat_chg sdpvar(1, T); % 电池充电功率 P_bat_dis sdpvar(1, T); % 电池放电功率 SOC_bat sdpvar(1, T1); % 电池SOC状态 Theta_in sdpvar(1, T1); % 楼宇室内温度状态 P_AC sdpvar(1, T); % 空调功率 VSOC sdpvar(1, T1); % 虚拟储能SOC % 目标函数购电成本 电池损耗 舒适度惩罚 objective sum(C_grid .* P_grid) ... sum(C_bat .* (P_bat_chg P_bat_dis)) ... sum(lambda .* max(0, Theta_in(1:T) - theta_max, theta_min - Theta_in(1:T))); % 约束条件 constraints []; % 功率平衡约束 constraints [constraints, P_grid P_PV P_bat_dis P_load P_AC P_bat_chg]; % 电池SOC动态方程 constraints [constraints, SOC_bat(2:T1) SOC_bat(1:T) ... (P_bat_chg * eta_chg - P_bat_dis / eta_dis) * dt / E_bat]; % 楼宇热动态方程 constraints [constraints, Theta_in(2:T1) Theta_out - P_AC * R ... epsilon * (Theta_in(1:T) - Theta_out P_AC * R)]; % 虚拟储能SOC定义 constraints [constraints, VSOC (theta_max - Theta_in) / (theta_max - theta_min)]; % 边界约束 constraints [constraints, 0 P_grid P_grid_max]; constraints [constraints, 0 P_bat_chg P_bat_chg_max]; constraints [constraints, 0 P_bat_dis P_bat_dis_max]; constraints [constraints, SOC_bat_min SOC_bat(1:T1) SOC_bat_max]; constraints [constraints, 0 P_AC P_AC_rated]; constraints [constraints, theta_min Theta_in(1:T1) theta_max]; constraints [constraints, SOC_bat(1) SOC_bat_init, SOC_bat(T1) SOC_bat_init]; % 求解 options sdpsettings(verbose, 1, solver, gurobi); optimize(constraints, objective, options);这段代码已经是可以直接跑通的核心骨架。需要特别解释的是暖通载荷约束那一行公式很多时候是调试优化的重灾区。热动态方程里书写了一个容易出错的地方——室内温度Theta_in(1:T)和Theta_out、P_AC的时标对应关系。仔细看你会发现Theta_out和P_AC的索引是1到T而Theta_in的右侧用的是1到T、左侧是2到T1这表示t时刻的温度和空调功率共同决定了t1时刻的温度。初值和末值需要额外定义比如早上8点上班前的初始温度设为26度。如果不给初始温度赋值验证结果会变得很不可预测。3.4 模型求解结果的呈现方式求解完成后最重要的就是结果可视化。我用MATLAB的plot函数把四个关键图绘出来了这里简述一下绘图思路。功率平衡图把P_grid、P_PV、P_bat_dis、P_AC、P_load画在同一张堆叠图上直观看出每个时刻各功率如何平衡供需。温度曲线图把Theta_in曲线和theta_min、theta_max上下限带画在一起验证温度是否越界。这张图也是检验舒适度约束有没有生效的直接证据。电池SOC和虚拟储能SOC对比图两张图上下排列你会看到电池SOC有很明显的充放电切换而虚拟储能SOC是一条缓变的曲线——楼宇在平缓地“充冷、放冷”不像电池那样能瞬间切换这就是两者物理特性差异的直观体现。电价与购电功率关系图把电价曲线和P_grid画在一起你会非常直观地看到谷时购电增多、峰时购电减少。我在调试中最喜欢看的图是第一张和第三张。温度曲线反而看得少因为只要约束满足温度基本都会老老实实待在舒适区间里。功率平衡图和SOC变化曲线一旦出现毛刺或不连续九成都是约束写错了。4. 典型场景调试与问题盘点4.1 求解器无法求解或提示infeasible怎么办infeasible问题可能是优化调度中最常见的bug尤其是加了热动态方程之后。原因多半是约束条件自相矛盾比如温度上下限设得太窄而室外温度太高时空调功率却面临上限导致制冷量怎么样都不足以把温度压到上限以内。如果空调的最大功率不足以在高温天气下维持舒适温度调度模型就会报infeasible。排查思路我有一个固定套路。先把舒适度温度上限制得宽松一点比如扩大到16到30度看看问题是否可解。如果在更宽的温度范围内可以求解那就是温度区间和空调功率之间的约束冲突如果连宽温度范围都不可解那就要回头检查热动态方程的符号有没有写反。这是个非常经典的坑空调制冷时Q_AC的正负号定义难道是在降低室内温度吗公式里的符号一旦写反约束构建出看似可以解、实际物理世界无法成立的条件组合。另一个常见原因是SOC初值设置和边界条件矛盾。比如说电池初始SOC是0.8但你要求末值SOC也是0.8而中间遇到一个非常大的峰谷价差求解器想拼命把电池放空再充满但电池的充放电功率和容量限制跟不上——就会出现达不到末值的约束而报infeasible。这种问题要么放宽末值约束为SOC(T1) ≥ SOC_min要么干脆去掉末值约束让调度器自由决定。4.2 求解结果对真实场景的意义使用商业求解器Gurobi时即使报“Optimal solution found”也不代表方案能在真实系统中实际运行。以我测试的经验有时模型会输出一个非常极端的策略——在电价低的时段把空调开到最大功率拼命给楼宇蓄冷在电价高的时段完全不工作任由温度飘到接近上限。这从数学上确实是最优解但在真实楼宇中完全不可行。原因有两点首先是空调的压缩机并不能时刻都满负荷运行它有最小启停时间的限制其次是房间的使用者会直接感受到温度的剧烈波动温度从23度飙到28度再降回23度体验非常不好。针对前者有改造模型的空间——引入最小开关机时间约束作为一种混合整数约束。针对后者调整舒适度惩罚系数λ就能解决。λ调大调度器会把温度控制在更窄的区间附近λ调小调度器会更激进地利用温度漂移省钱。这是一个成本与体验的平衡实际项目中需要反复调试来确定合适的λ值。我在做实验时发现λ取一个经验值很关键如果λ远小于电价差那么调度器完全无视舒适度如果λ远大于电价差那虚拟储能就没有利用价值调度器会一直维持恒定温度空调功率恒为定值问题退化成纯电池储能调度。合适的λ应该让温度在舒适区间内自然波动但又不触碰上下边界。4.3 参数灵敏度分析的经验做完整项目之后我强烈建议加做一组参数灵敏度分析这是论文审稿人和工程领导都爱看的东西。我做了三个参数的敏感性扫描楼宇热容C、舒适度区间宽度、分时电价价差。结果非常有意思热容C增大时虚拟储能容量变大系统对电池储能的依赖明显减小。这符合物理直觉——楼宇本身能扛的时间越长越不需要电池来削峰填谷。在C很大时电池甚至只会做非常浅度的充放电循环。这说明如果有条件做建筑保温改造或者增加建筑围护结构的热惯性其经济性收益完全可以量化——这个项目的模型能直接给出这笔账。舒适度区间从24-26度扩展到23-28度时总运行成本下降非常可观。这个结论对项目谈判很有价值如果业主愿意接受一定程度的温度漂移电费节省是肉眼可见的同时这也量化了“舒适度换经济性”的权衡曲线。电价价差增大时虚拟储能的削峰填谷行为会更加明显室内温度的波动幅度也随之增大。这说明分时电价的引导作用和用户舒适度损耗是耦合的——电价机制的设计者对这一点的理解至关重要。4.4 MATLAB代码层面容易踩的坑代码层面有三个高频报错值得提醒一下。第一个是Yalmip变量与MATLAB内置函数的冲突。如果你给变量取名叫sum、max、min这些MATLAB内置函数名后面再调用sum()、max()函数时会有概率被当作变量调用报错信息让人摸不着头脑。我的原则是变量名一律用含义清晰且不冲突的词比如P_grid、SOC_bat不用任何缩写。第二个是Yalmip表达式与逻辑判断混写。MATLAB的if语句接收的是逻辑值但Yalmip的约束是变量对象比如if SOC_bat(1) 0.2这种写法在Yalmip里并不会被解释为逻辑判断而是构造了一个约束条件对象。这是新手最常犯的错误——把约束条件和程序逻辑混在一起。第三个是求解器的许可问题。Gurobi如果没有正确配置license会在求解时直接报错而不是自动降级到其他求解器。我建议用Yalmip的sdpsettings函数显式指定‘solver’, ‘gurobi’这样报错时能迅速定位到是许可证问题还是模型问题。5. 实验方案设计与结果分析5.1 三种调度模式的对比实验设计对比实验我建议从三个维度做对照模式一是不带任何储能和虚拟储能的纯网购模式作为基准方案模式二是只带电池储能但不考虑虚拟储能的调度模式模式三是电池和虚拟储能协同调度模式即本项目的完整方案。对比指标至少要有三个总运行成本、光伏消纳率、峰值购电功率。我实测下来的典型结果大致如下表所示基于某典型夏日的算例数据调度模式总运行成本元光伏消纳率峰值购电功率kW纯网购基准以上千元计60%以下最高电池储能成本明显下降上升到80%左右有所下降电池虚拟储能成本最低接近100%最低需要强调的是不同负荷特性、不同电价机制下三组数值的差距有所不同但虚拟储能带来的边际收益始终为正。如果你的算例中虚拟储能没有带来明显的成本下降大概率是参数设置出了问题——比如温度舒适度区间过窄或者室外温度过低导致空调负荷很小虚拟储能的“可调度容量”太小。5.2 这一结果背后的工程启示从项目实验来看最重要的一条结论是楼宇微网的优化调度不能只盯着电池和光伏要把楼宇自身的“热惯性”作为一种主动资源纳入调度范畴。这不仅仅是省了电池容量投资的问题更改变了微网的设计思路——如果虚拟储能足够大甚至可以减少电池储能的配置容量直接降低初始投资成本。第二条结论是经济最优解必然牺牲一定程度的舒适度这笔账要算得清。虚拟储能不等于白拿的能量它本质上是利用人体对温度的一定容忍度来换取用能灵活性。在实际项目中设计者必须和业主明确说明这一点并且拿出λ参数的量化数据来说明“每降低1度舒适度波动范围能节省多少电费”。这份数据在商业谈判和项目决策中非常关键。还有一条对于做研究的人很有价值虚拟储能的SOC曲线是平缓、连续变化的而电池SOC曲线是阶梯状、高频切换的。如果你在论文里画两种SOC的对比图审稿人能一眼看懂你在研究什么问题——这是在展示两种不同物理特性的储能互补性。单是这种对比呈现方式就能为论文增色不少。6. 项目后续扩展方向与经验总结6.1 从日前调度走向实时闭环这个项目目前做的是日前开环调度——根据前一天的光伏预测、负荷预测和电价曲线计算未来24小时的最优计划。但实际运行时光伏出力预测一定会有偏差负荷也有随机波动如果不做修正日前计划在当天执行时就会走样。扩展方向之一是实现模型预测控制MPC即滚动优化——在每个小时开始前重新求解一次未来N个时段的优化问题只执行第一步的计划然后把实测数据作为新的初始状态再滚动。我这边实测过把本项目的模型套进MPC框架代码改动量不大核心是加了一个for循环做滚动求解每步更新初始温度、荷电状态和最新预测数据最终效果比开环调度要稳健很多。这一扩展最大的价值是让项目从“论文里的算例”走向“能落地的系统”。因为真实楼宇的工况一定会偏离预测而MPC天然就有“不断用新信息修正计划”的能力。6.2 从单栋楼宇走向多楼宇聚合另一个值得做的扩展是把单栋楼宇的虚拟储能模型扩展为多楼宇聚合模型。多楼宇之间可以通过共享母线连接也可以各自独立并网但在同一个聚合商的调度框架下协作。多楼宇聚合的核心价值是“多样性平滑”不同楼宇的热容、朝向、使用模式不同它们的虚拟储能可调度特性互为补充。有些楼宇白天蓄冷能力强有些楼宇夜间散热快聚合起来在电网层面看就是一个波动更小、调节能力更强的虚拟储能集群。这在电力市场辅助服务的场景下价值会呈指数级放大。当然这也带来一个技术复杂度提升模型变量数量随楼宇数量线性增长约束条件规模也随之增大求解时间会拉长。实测下来当楼宇数量超过30栋时Gurobi的求解时间就不再是“秒级”了这个时候需要做一些聚合或者分解算法来加速。6.3 几点实操心得最后写几条我个人在这个项目中沉淀下来的实操习惯仅供参考。第一MILP模型起步时一定先用小规模数据调试再用全规模数据跑。我习惯先拿一个6时段的模型验证逻辑正确性——此时即使迭代过程不够严谨也能肉眼检查温度序列是否合理、功率是否平衡。确认无误后再扩展到24时段和96时段。直接拿24时段甚至96时段起步调试一旦结果不合理想定位是哪个约束引出的问题排查效率极低。第二参数命名要带单位。在MATLAB代码里变量的命名习惯极其影响排错效率。P_grid、SOC_bat一律不用注释也能看出是功率和荷电状态而像lambda这种没有物理含义的变量名时间久了连自己都容易忘。建议所有关键参数写成C_grid_per_kwh元每千瓦时、R_thermal_K_per_W热阻开尔文每瓦这样的长名称。即时代码稍微长一些换取的是调试时不用反复翻参数表确认物理含义。第三求完解后第一件事是查温度曲线的“违界率”而不是想着怎么解释结果。户外温度变化大时如果舒适度约束太紧而空调功率受限温度曲线就会顶在上边界上形成一段平坦线——这种情况在论文里往往是“约束起作用”的正常表现但在实际工程里意味着用户开始感到不适了要回头调整λ或者放宽温度区间。这个项目的核心价值是它把“能量效率”和“用户感受”放在同一个优化框架里解决。它不是一个单纯的储能配置问题也不是一个单纯的自动控制问题而是一个围绕“柔性”做决策的系统工程问题。未来楼宇微网的方向一定不是堆更多的硬设备而是让每一度电都有温度、时间和空间的柔性。这个项目只是为此打了一个底子。