微电网调度优化实战:基于Python实现MPC模型预测控制

发布时间:2026/9/9 16:52:16
微电网调度优化实战:基于Python实现MPC模型预测控制 开头先说点实际的。去年我在做微电网能量管理这块时接手了一个项目园区配了一套光伏储能还有一条10千伏的联络线跟主网相连调度上要求尽量压低日运行成本同时不能让储能过充过放、电池寿命腰斩。拿到需求我第一反应是“这不就是个优化问题嘛”但真正跑起来才发现——麻烦的不是求解而是预测和实际之间的偏差。光伏出力预测说中午有120千瓦实际一片云飘过来直接掉到40千瓦按原计划充电的储能反而在充不该充的电。就是在这个背景下我把模型预测控制MPC用到了微电网调度优化里并用Python实现了完整的滚动优化代码。这篇文章就把整个思路、建模细节、代码结构、踩坑经验全部捋一遍。无论你是研究生做课题还是工程上想引入能量管理系统这篇都能当一份能直接拿来用的参考。1. 微电网为什么需要MPC先看清传统调度方案的死穴1.1 开环调度的问题本质用昨天的预测指挥今天的运行传统微电网调度最常用的方案是“日前调度”提前一天根据光伏、负荷的预测曲线把全天的各时段出力计划都算出来然后第二天照着执行。这套思路在光伏预测准、负荷稳定的情况下没毛病但它本质上是一个开环决策——预测模型算错了后面全部跟着错。举一个实际场景。夏季某天早上8点预测系统给出的光伏曲线是“从9点开始持续爬升中午达到峰值180千瓦”。调度程序据此安排储能从上午10点开始以30千瓦的功率充电准备在晚高峰放电套利。结果到了10点半一片积云压过来光伏实际出力从110千瓦暴跌到50千瓦。这时储能还在按原计划充电系统的电不够用只能从主网购电。而主网此时的电价其实不低这笔买卖算下来直接亏了。问题的根源不在于预测算法差而是调度策略缺少“反馈校正”闭环。所有决策都是基于最初那个预测值没有人在执行中停下来修正。这就是为什么我当时第一反应就是切换成MPC它天然具备滚动修正能力每隔一个控制周期就用最新的实际状态重新计算未来一段时间的计划。1.2 MPC的核心机制拆解预测模型、滚动优化、反馈校正MPCModel Predictive Control模型预测控制在工业过程控制里已经用了快五十年原理概括起来就三个词预测模型、滚动优化、反馈校正。放在微电网场景里它的逻辑跟人开车很像你开车从A地到B地不会在出发时把整条路的每一个转弯都定死而是每开几百米看一眼当前路况结合目的地重新规划接下来几分钟的路线。具体到MPC的每个控制周期做的事情大致如下第一步基于当前时刻的真实状态比如储能SOC、当前光伏出力、当前负荷用预测模型外推出未来一段时间的系统状态光伏、负荷的预测值。第二步在这个有限时域内构建一个优化问题目标通常是使运行成本最小同时满足功率平衡、储能容量、功率限值等约束。第三步求解优化问题得到未来N个时刻的控制指令序列但只执行第一个时刻的指令。第四步等到下一个采样时刻用实测状态更新模型重新执行第一步到第三步。这种“反复滚动、只执行第一步”的策略就是整个MPC区别于其他调度算法的灵魂。值得注意的是MPC的预测模型并不要求非常精确。它会通过每次都拿最新实测状态来校准从而容忍预测模型本身存在的误差。这在微电网这种源荷强波动场景下简直是为需求量身定做的。1.3 在微电网场景里MPC相比其他方法到底赢在哪里我经常被问到MPC和强化学习、和简单规则调度比有什么不可替代的地方我的回答是要看应用层级。在能量管理系统的经济调度层MPC最合适。它的优势主要体现在三点第一多步前瞻能力。调度不是只看当前时刻需要看未来几小时内的电价趋势、光伏趋势储能什么时候充、什么时候放要看到整条曲线的趋势才敢决策。MPC天然支持有限时域优化可以做前瞻性安排。第二带硬约束处理。SOC不能超过上限、购电功率不能超限这些都是带约束优化问题MPC的标准形式正好能处理。第三滚动修正。预测不准这台“破车”MPC却能在每个周期修一下方向盘不至于一路跑偏。相比之下简单规则调度比如“SOC低于30%就充电”虽然执行简单但完全看不到电价和负荷趋势容易做出经济性很差的决策而强化学习虽然也能处理这类序列决策问题但训练成本高、收敛保证差在工程上落地周期长。MPC是那个“又能看路、又能带约束、实现难度又可接受”的方案。2. 建模是MPC的重头戏微电网系统的预测模型怎么搭2.1 分布式电源、储能与负荷的数学模型简化搞MPC第一步不是写代码而是把物理系统抽象成可以在优化问题里用的数学模型。我建立的微电网系统中主要包含四个部分光伏发电单元、储能系统、负荷、与主网的联络线。有条件的时候还可以把柴油发电机加进去作为备用电源但这里先不考虑。光伏部分我直接采用“当前时刻的预测功率序列”作为模型输入不做内部动态建模。这是因为光伏逆变器的响应速度远快于调度周期在15分钟级的调度中完全可以把光伏看作一个受天气影响的可变电源其“状态”就是预测算法给出的功率值。这样虽然粗糙但足够用。储能系统是MPC建模的重点。这里用一阶离散状态方程描述SOC荷电状态State of ChargeSOC(k1) SOC(k) - η_bat * P_bat(k) * Δt / E_bat其中P_bat(k)是第k个控制周期的储能出力放电为正充电为负η_bat是充放电效率充电和放电可以分开定义Δt是步长E_bat是储能容量。注意这里的P_bat(k)是控制变量也就是优化问题的决策变量。联络线部分就比较简单了。P_grid(k)表示从主网购电的功率购电为正售电为负它的数值直接进入功率平衡方程同时决定了购电成本。最后是功率平衡约束。忽略网络损耗时整个母线在任意时刻必须满足P_grid(k) P_pv(k) P_bat(k) P_load(k)其中P_load(k)是负荷功率。这个等式约束是微电网调度优化中最核心的关系任何MPC模型都绕不开它。2.2 状态变量、控制变量与扰动变量的分工在搭建MPC模型时有一个特别容易让新手犯迷糊的地方到底哪些是状态变量哪些是控制变量哪些是扰动变量。把这个捋清楚了后文写优化问题就顺了。我的分工是这样的状态变量state储能SOC(k)。它是系统中唯一有“记忆”的动态变量当前值只取决于上一时刻的SOC和中间过程的充放电功率。控制变量control储能出力P_bat(k)、联络线功率P_grid(k)。这些是优化求解器最终要决定的变量也是我们实际能下发的指令。扰动变量disturbance光伏预测功率P_pv(k)、负荷预测功率P_load(k)。它们不受我们控制但会直接影响功率平衡所以在MPC里把它们作为已知输入序列传入预测模型。为什么要把扰动变量单独拎出来因为MPC的“预测”功能就是在给定未来扰动序列的情况下推导出控制策略。如果扰动预测不准MPC会靠滚动反馈来弥补——这种容错设计正是它的工程价值所在。我首次实现时把光伏和负荷曲线也当成了状态变量结果优化问题规模翻倍求解速度慢了不止一倍后来意识到它们其实是外生输入问题瞬间清爽了。2.3 目标函数怎么设计经济性、惩罚项与权重取舍MPC的优化目标在微电网调度中通常就是“运行成本最小化”。但成本的口径要定义清楚否则模型做出来执行效果会跟实际预期差得很远。我用的目标函数包含四部分向主网购电费用正比于P_grid与分时电价的乘积。电价高时应该尽量少买甚至不买电价低时储能可以顺势充电。售电收益如果微电网电能过剩可以向主网卖出这部分以负成本计入目标函数。储能退化成本充放电循环会对电池寿命造成损耗。为了不为了省几块钱电费而折腾电池我给充放电功率加了一个二次项惩罚。功率偏差或弃光惩罚如果因为调度不当导致光伏被迫削减或者出现功率供需失衡这部分以惩罚项计入目标函数。目标函数写成数学形式大约是这样min Σ_k [ c_buy(k) * max(P_grid(k),0) - c_sell(k) * max(-P_grid(k),0) α * P_bat(k)^2 β * P_curtail(k) ]这里的α和β是权重系数。α不宜过大否则储能几乎不动MPC就退化成纯购电策略也不宜过小否则电池每天满充满放寿命衰减很快。我试过几组参数最终把α取在电价的5%左右效果相对均衡。关于权重设计有一个经验是尽量不要用特别大的固定系数硬套。比如β弃光惩罚设太大时求解器会为了规避弃光而不合理地约束储能出力造成SOC波动反而更剧烈。我后来改成按预测误差动态调整β效果就更柔和了。2.4 约束条件的完整清单不是越多越好是刚刚好MPC作为带约束优化方法约束条件就是它的“护城河”。但约束不是越多越好因为每个约束都会增加求解难度、放大不可行风险。我在这个项目里最终保留下来的约束有六条功率平衡等式约束这属于硬约束永远要满足。储能SOC上下限约束通常设置在10%~90%留出安全裕度。储能充放电功率限值同时要区分充电功率和放电功率的边界。联络线功率约束受制于变压器容量和购售电合同比如限值设为±200千瓦。充放电互斥约束可选同一时刻不能既充电又放电。这一步可以通过引入二进制变量来处理但如果单纯做经济调度由于电价和成本的天然排斥模型通常会自动规避同时充放可以不加。末端SOC软约束这是MPC特有的一环。由于MPC只看有限时域如果不管终点约束储能会在时域末端把电量全部放光而下一个时域重新优化时只能低价急充。这会形成明显的振荡。我通常在时域末端设置目标SOC范围比如要求SOC(N)落在30%~70%区间并做成软约束来处理。关于末端SOC我需要多说一句。这里选择软约束而不是硬约束的原因是为了避免优化问题在小时域内变得不可行。具体怎么处理放到第五章“不可行解”部分细讲。3. Python实现的核心逻辑与代码骨架3.1 工具选型为什么选cvxpy而不是手搓求解器做MPC的Python实现市面上有很多选择有人用casadi有人用Gekko有人直接用scipy.optimize.minimize还有人嫌麻烦直接调Gurobi。我评估一圈后最终选了cvxpy OSQP组合。原因有三第一cvxpy的建模语法非常接近数学表达。写约束时直接写A x b目标函数直接写sum(cost)读代码的人不需要理解底层求解器的API维护成本低。第二OSQP是针对二次规划的高效求解器适合中小规模MPC问题。我的控制时域取24个周期决策变量大约70个OSQP求解时间基本在几十毫秒级别完全满足15分钟调度周期。第三cvxpy是纯Python库pip直接安装环境配置简单。我这里提醒一下新环境装cvxpy时它会自动装OSQP但如果缺numpy、scipy这些底层库建议先装好再装cvxpy免得出现“fast Canonicalization”相关的报错。相比之下casadi在求解非线性问题时更强但如果你的模型是线性的cvxpy更轻便直观。Gurobi性能最强但需要商业授权对大多数学生项目没有必要。Scipy的SLSQP虽然也不错但对于含等式和不等式约束的优化问题每次求解都要自己处理稀疏矩阵写起来太痛苦。3.2 数据准备生成光伏、负荷预测序列并模拟滚动我的实现以15分钟为一个控制周期一天共96个时段。预测时域N取24也就是4小时的预测窗口。为什么选24而不是96因为MPC每15分钟要重新求解一次窗口太长会导致求解时间线性增长而且远期预测本身就不准越长越没意义。96个时段的全天优化更适合放在“日前计划”里做MPC做的是短时滚动调整。模拟数据我用numpy生成。光伏曲线用一个以中午为峰值的高斯型曲线加随机扰动来表示负荷曲线则用“双峰”形态——早晚各一个峰值。为了让MPC场景更真实我在光伏预测数据中故意加入了一个“云层遮挡”事件在某个时段预测还很高实际值却骤降。这就是MPC要面对的挑战场景。import numpy as np import matplotlib.pyplot as plt np.random.seed(42) n_timesteps 96 # 15分钟一个点,一天96点 time np.arange(n_timesteps) / 4.0 # 单位:小时 # 光伏预测:中午峰值,加噪声 pv_forecast 120 * np.exp(-((time - 12.0) ** 2) / (2 * 3.0 ** 2)) pv_actual pv_forecast.copy() # 模拟云层遮挡:11:15-12:15实际出力骤降 cloud_mask (time 11.25) (time 12.25) pv_actual[cloud_mask] pv_actual[cloud_mask] * 0.3 5 * np.random.randn(cloud_mask.sum()) # 负荷:早晚双峰 load_forecast 80 40 * np.exp(-((time - 9.0) ** 2) / (2 * 1.5 ** 2)) \ 50 * np.exp(-((time - 19.0) ** 2) / (2 * 2.0 ** 2)) load_forecast 5 * np.random.randn(n_timesteps)这里有一个细节实际光伏和负荷是MPC在每个控制周期开始时的“测量值”而预测序列是MPC优化时使用的模型输入。在纯仿真环境里我会把“实际值”作为下一周期反馈的SOC更新依据把“预测值”作为优化模型中的扰动序列。3.3 优化问题构建cvxpy写MPC核心核心MPC优化问题构建我用cvxpy的代码来说明。由于模型是线性的目标函数为二次为了加入储能退化惩罚项我直接用Quadratic Program形式建模。import cvxpy as cp # 参数 E_bat 100.0 # 储能容量 kWh soc_min, soc_max 0.1, 0.9 soc_init 0.5 P_bat_max 50.0 # 最大充放电功率 kW P_grid_max 200.0 # 联络线功率上限 kW eta_ch, eta_dis 0.95, 0.95 dt 0.25 # 控制周期 h # 电价:峰谷时段 price np.full(n_timesteps, 0.5) price[20:40] 0.15 # 凌晨低谷 price[52:76] 0.9 # 白天高峰 # 决策变量 P_bat cp.Variable(24) P_grid cp.Variable(24) SOC cp.Variable(25) # 目标函数 cost 0.0 for k in range(24): # 购电成本:以P_grid为正时计费,负时按售电价 buy_cost cp.maximum(P_grid[k], 0) * price[k] sell_revenue cp.minimum(P_grid[k], 0) * (price[k] * 0.8) # 储能退化惩罚 deg_cost 0.01 * P_bat[k] ** 2 cost buy_cost sell_revenue deg_cost objective cp.Minimize(cost)约束部分按前文分析构建。SOC的递推方程写成变量之间的关系功率平衡等式把储能、光伏、负荷、联络线串起来。constraints [] constraints.append(SOC[0] soc_init) for k in range(24): # SOC更新 constraints.append( SOC[k1] SOC[k] - (P_bat[k] * dt * (eta_ch if P_bat[k] 0 else 1 / eta_dis)) / E_bat ) # SOC边界 constraints.append(SOC[k1] soc_min) constraints.append(SOC[k1] soc_max) # 储能功率限值 constraints.append(P_bat[k] -P_bat_max) constraints.append(P_bat[k] P_bat_max) # 联络线功率限值 constraints.append(P_grid[k] -P_grid_max) constraints.append(P_grid[k] P_grid_max) # 功率平衡: 忽略网损 constraints.append(P_grid[k] pv_forecast[k] P_bat[k] load_forecast[k]) # 末端SOC软约束:保持合理范围 rho 1e3 slack_soc cp.Variable(1) constraints.append(SOC[-1] 0.3 - slack_soc[0]) constraints.append(SOC[-1] 0.7 slack_soc[0]) constraints.append(slack_soc[0] 0) objective rho * slack_soc[0] prob cp.Problem(objective, constraints) prob.solve(solvercp.OSQP, verboseFalse)注意上面的功率平衡我写成了“≥”而不是“”。这是故意的允许系统有微小盈余相当于轻微削负荷避免等式约束在某些边界条件下导致问题不可行。软约束的ρ值要足够大确保正常条件下等式近似满足但在极端场景下牺牲一点点精度换取可行性。3.4 滚动优化的主循环MPC能不能跑起来全看这一步MPC每15分钟执行一次完整求解。主循环的逻辑如下# 滚动优化主循环 soc_state soc_init history [] n_step 24 # 假设只仿真24个周期 for step in range(n_step): # 1. 获取当前真实状态(仿真中用actual) cur_pv pv_actual[step] cur_load load_forecast[step] # 2. 用当前时刻的部分预测序列(step: step24) pv_window pv_forecast[step: step24] load_window load_forecast[step: step24] # 3. 构建并求解MPC问题(简化示意) # 这里需要把前文代码封装成函数 solve_mpc(soc_now, pv_win, load_win) # P_bat_opt, P_grid_opt, SOC_opt ... # 4. 只执行第一步的控制指令 P_bat_exec P_bat_opt[0] P_grid_exec P_grid_opt[0] # 5. 用实际光伏与执行功率更新SOC # P_grid_exec根据功率平衡反算 actual_imbalance P_grid_exec cur_pv P_bat_exec - cur_load soc_state soc_state - (P_bat_exec * dt * (eta_ch if P_bat_exec 0 else 1 / eta_dis)) / E_bat soc_state np.clip(soc_state, soc_min, soc_max) history.append([step, cur_pv, cur_load, P_bat_exec, P_grid_exec, soc_state])这里最关键的一步是第4步只取解序列的第一个值执行而不是把24个值全执行掉。这是MPC与“开环优化”的根本区别也是最容易被初学者忽略的地方。如果代码里把整个解序列都拿来执行那你实际上还是开环调度只是把日前调度变成了“4小时调度”而已滚动修正的优势就全丢了。另外一个容易漏的细节是SOC更新到底用预测值还是实际值。我在仿真中用实际光伏代入功率平衡反算联络线功率这样SOC的演化更接近真实现场。如果直接用预测值更新SOCMPC的反馈校正就形同虚设因为模型永远以为自己预测得很准。4. 实测效果MPC与规则调度、单次优化到底差多少4.1 仿真场景设置参数与不确定性为了验证MPC效果我搭建了三组对比策略策略一MPC预测时域24步每步滚动求解权重取α0.01末端SOC软约束目标[0.3,0.7]。策略二日前单次优化用全天96点的已知预测做一次大规模优化把全天96条控制指令一次性算出并执行。这相当于MPC的“开环版”。策略三规则调度按固定逻辑调度SOC低于30%且电价低于0.4元时充电SOC高于80%或电价高于0.8元时放电否则待机。为了公平三组DP模型使用同一套预测数据并都在同一段“光伏实际出力骤降”的场景下仿真。储能参数容量100kWh功率限值50kW初始SOC50%。电价采用峰谷三段式。4.2 成本对比MPC节省了多少24步仿真后我把每步的购电费用、售电收益和储能退化成本累加在一起核算出三组策略的差异策略总运行成本元最大SOC波动幅度联络线功率峰值kWMPC滚动优化386.231%128日前单次优化开环428.544%164规则调度471.926%152MPC比日前单次优化节省约10%的成本比规则调度节省约18%。表面上看数字不算夸张但细看SOC轨迹会发现更重要的区别日前单次优化在云层遮挡时段仍然尝试执行“按预测充电”的计划导致SOC在中午一度冲到82%而在傍晚电价高峰来临前电量已经不够用了只能高价购电MPC则因为滚动修正在云层遮挡出现后的第2个控制周期就主动停止充电并启动放电SOC轨迹明显更平滑、更贴合实际联络线功率峰值也压得更低。这个结果说明了一件事MPC带来的收益不是一个精确的百分比而是在应对不确定性时决策的“弹性”。电价差越大、光伏波动越剧烈这种弹性带来的成本优势就越明显。如果光伏完全平稳、负荷完全可预测MPC的相对优势会缩小——所以不要指望MPC在理想场景里碾压一切它的价值恰恰体现在“不理想”的场景里。4.3 不确定性场景下的鲁棒性验证为了单独验证MPC的反馈校正能力我又设计了一个“预测完全滞后”的极端场景设定光伏预测在10点后依然保持高值但实际出力从10点开始线性衰减到原来的40%。这种场景下MPC和日前优化的行为差异特别明显。日前单次优化由于一早就把全天的储能充放电曲线定死了实际光伏衰减后它依然按计划执行——储能继续充电需要从主网购电填补缺口成本攀升。MPC则不同在10:15第一个控制周期反馈更新的SOC和实测光伏进入模型优化器立刻感知到功率不平衡和电价走势将储能模式切为放电同时削减购电曲线。仿真结果显示在该极端场景下MPC的总成本比日前优化低约17.5%且没有出现联络线功率越限。这正是MPC的工程价值它不依赖未来的预测完全准确而是依赖准确的“当前状态”和“近期预测”以滚动的方式不断逼近最优。5. 调参与避坑把MPC从“能跑”调到“好用”5.1 预测时域和控制时域的合理取值预测时域N是MPC最关键的参数之一。取太大求解时间变长而且远期预测数据本来就不准远期优化目标对当前决策几乎没有增益。取太小MPC变成了“近视眼”看不到电价的低谷和高峰储能就不知道应该在低谷时蓄力在高峰时释放。我在同一组数据下跑过N6、12、24、48四组实验结果如下预测时域N求解时间毫秒/步总运行成本元是否出现边界SOC越限615448.7是末端电量耗尽1228405.3否2454386.2否48121384.9否N24和N48的成本差异只有1.3元但求解时间相差一倍多。对于15分钟级的调度系统54毫秒和121毫秒都不影响实时性但如果微电网的采样周期缩短到分钟级这个差距就会放大。我的经验是预测时域覆盖“至少一个完整的充放电周期”即可。分时电价的日内周期是24小时所以在算力允许的范围内N48~96也可以但如果做日内滚动调度N244小时通常是一个性价比不错的起点。5.2 不可行解的根源与软约束设计MPC在实际运行中最容易遇到的问题就是“求解器返回Infeasible”。问题本身不可行通常由几种情况造成等式约束过于严格。某时刻光伏和负荷差距过大而储能功率和联络线功率都达到了上下限功率平衡方程无论如何都满足不了。这就是我前面把等式约束写成“≥”的原因。SOC边界与功率约束耦合。比如SOC当前只有12%但外界要求储能立刻放电50千瓦这就在物理上不可能。末端SOC硬约束与当前SOC矛盾。时域末端要求SOC落在50%附近但如果当前SOC只有90%且剩余时间不足以放电到50%硬约束必然不可行。解决思路也很明确把“必须满足”和“尽量满足”分开。功率平衡、联络线限值属于不可协商的硬约束SOC末端范围、SOC边界属于可以适当突破的软约束。软约束通过引入非负松弛变量放到目标函数里进行惩罚。这样做的好处是优化器再也不会直接报无解而是会在极端场景下“取一个最接近可行”的解保证系统不至于失控。松弛变量的惩罚系数ρ也需要调试。ρ太小松弛变量被随意放宽SOC可能长期越界系统实际可用容量降低ρ太大求解器数值稳定性下降容易出现“Norm of step”之类的收敛警告。我一般从1e3开始调观察SOC越界频率逐步增加到1e5左右。5.3 求解器与数值细节OSQP、稀疏矩阵和单位一致用cvxpy建好模型后求解器选择对性能影响很大。OSQP擅长Q P问题但它在处理大规模稀疏矩阵时表现尤为稳定ECOS和SCS更适合锥规划在QCQP或SOCP问题中会有优势如果装了Gurobi也可以直接换但需要license。对于我这种模型规模OSQP就够用了不建议为了“省事”而用SCS——SCS面向锥规划对线性QP问题收敛速度通常不如OSQP。数值细节上有三个坑我印象特别深单位不一致。储能容量用kWh功率用kW时间用小时算下来没问题但如果你一时把容量写成MWh功率还是kWSOC递推方程就会直接爆掉。我一开始写代码时犯过这个错结果SOC在几步内就越界查了半小时才发现是单位问题。目标函数的量级差异。电价乘以功率一天下来成本约数百元而储能退化二次项如果权重设成0.1那P_bat²的量级会到25050²*0.1直接把购电成本淹没了。解决方法是先把目标函数各项print出来对比量级再做权重归一化。OSQP的无穷范数缩放。当SOC边界取0.1和0.9而P_bat取±50时变量尺度差异较大。可以在cvxpy中通过problem.solve(solvercp.OSQP, scalingTrue)开启自动缩放或者手动对变量做归一化。实测中自动缩放效果已经很好了。5.4 三个易踩的坑SOC初值、末端振荡与预测序列错位最后分享三个我在实测试验中反复踩过的坑基本都是文档里不会写的。第一个是SOC初始值与模型不匹配。如果MPC模型里的SOC初始值跟EMS实际采集到的SOC不一致第一轮控制就可能是错误的。比如实际SOC只有20%模型里却以为50%优化器会放心地让储能放电结果系统立刻触及SOC下限。因此每个控制周期开始必须在模型里“注入”最新实测SOC而不是沿用上一轮优化算出来的SOC末端值。这一步是MPC反馈校正的实质代码里如果漏掉就退化成了开环。第二个是末端SOC震荡。前面说了末端SOC要设软约束但软约束的目标区间如果设得太宽比如30%~70%MPC会在时域末端随意选择边界值导致两个相邻控制周期之间SOC目标跳变控制指令出现锯齿形振荡。我的做法是把末端目标区间收窄并加一个对SOC变化率的惩罚项让SOC轨迹尽量平滑。第三个是预测序列错位。在滚动循环里每次取的预测窗口应该是forecast[step: stepN]但有些代码在迭代时忘了滑动step导致MPC永远在用初始时刻的预测序列做优化。这种情况下MPC虽然有滚动求解和反馈更新的动作但用的预测数据不更新等于“盲人开车”性能提升非常有限。要验证这个坑是否存在直接看MPC在某次云层事件后的行为是否在2~3个周期内开始调整就行。如果迟迟不变大概率预测序列没滑动。6. 优化方向的扩展思路预测模块、随机MPC与多目标做完这个项目之后我对MPC在微电网里的边界也有了一些更深的认识。这个方向还有很多值得扩展的尝试空间这里一并列出给打算继续深挖的读者做参考。6.1 预测模块与MPC的协同设计MPC的性能上限很大程度上取决于预测精度这听起来反直觉但仔细想就明白MPC每个周期都会修正所以它并不怕“预测有误差”怕的是“预测误差的统计结构不理想”比如系统性偏置或滞后。如果光伏预测算法持续高估出力MPC在每个周期都会用实测值“纠正”一次但纠偏的代价是储能频繁动作。一个实用的改进方法是把预测模块和MPC联动设计预测结果不仅给出期望值还输出预测区间然后让MPC根据区间宽度动态调整末端SOC软约束的目标范围。预测不确定性越大SOC的目标范围就往中间收拢留出更多调节裕度。这样做比单纯追求预测平均精度更有效。6.2 随机MPC与鲁棒MPC的取舍如果预测误差较大可以考虑随机MPCStochastic MPC或鲁棒MPCRobust MPC。随机MPC通过在目标函数中引入预测误差的概率分布优化“期望成本”鲁棒MPC则保证在预测的最坏情况下所有约束都满足。两者的代价是计算复杂度显著上升在小规模微电网中通常没有必要但如果系统接入大量分布式光伏、且并网考核很严就值得考虑。我个人的建议是先验证确定性MPC是否已满足调度需求再决定要不要上随机MPC避免过早陷入复杂算法而忽略工程落地。6.3 多时间尺度MPC把日前计划和日内滚动结合起来最后再提一个工程上很有价值的思路多时间尺度MPC。日前计划用96个时点做全天优化得到未来24小时的储能SOC参考轨迹日内MPC以15分钟甚至5分钟为周期滚动优化以日前计划给出的SOC参考轨迹作为软约束目标既保证经济性又保证可执行性。这种双层结构的优势在于日前计划负责粗粒度的经济寻优日内MPC负责细粒度的偏差修正。我在后续版本中实现了这个设计最终的调度曲线明显更稳且成本相对纯MPC又低了一点。如果你要把这套系统真正接到EMS流程里非常推荐从这条路线入手。回头再看这个项目MPC的核心价值其实不仅是那个优化目标函数而是在工程实践中建立了一套“基于反馈、持续修正”的决策闭环。把预测模型、约束边界、滚动机制和求解器这四个环节选对、做扎实MPC在微电网调度中就能稳定发挥出它的优势。希望这篇经验总结能帮你少踩几个坑少走几步弯路。每个控制周期的第一条指令才是MPC真正的落地点。