微电网MPC优化调度与自适应预测修正的Python实践

发布时间:2026/10/8 9:21:59
微电网MPC优化调度与自适应预测修正的Python实践 最近在帮一个园区微电网项目做能量管理算法把 MPC 优化调度这套东西从头到尾用 Python 写了一遍又单独加了自适应预测修正模块做对比实验。这个方向网上资料不少但大多数开源代码的问题在于只有滚动优化的骨架没有把预测误差当成一个正经问题来处理结果一上真实数据就翻车。今天这篇总结我把整个方案的设计思路、代码结构和调试经验一次讲清楚适合正在做微电网能量管理、光储充调度以及想入门 MPC 控制的研究生和工程师参考。1. 项目概述与核心需求解析1.1 微电网调度为什么首选 MPC微电网的核心特征就是“源荷双侧都不确定”光伏出力跟着天气走负荷曲线也有明显的随机波动。传统的调度做法是提前一天做离线优化把明天的充放电计划一次性算好然后照着执行。这种开环策略在预测比较准的时候没问题但一旦光伏实际出力低于预测值储能又按照原计划放电系统就只能从电网高价买电补缺甚至可能出现功率越限。MPC 的全称是模型预测控制本质上是一种在线滚动优化策略。它在每一个控制时刻基于当前实测状态和未来一段时间的预测信息求解一个有限时域的优化问题但只执行第一步结果下一个时刻重新采样、重新预测、重新优化。这样一来“预测—优化—反馈”就形成了一个闭环系统的抗干扰能力比离线调度强很多。微电网这种强不确定性场景跟 MPC 的控制逻辑可以说是天然匹配。1.2 自适应预测修正到底在修什么很多 MPC 论文把重点放在滚动优化上但真正决定实际性能的往往是预测精度。光伏功率和负荷的预测模型无论用 ARIMA 还是神经网络都会存在系统性偏差和随机噪声。所谓“自适应预测修正”简单说就是利用实时反馈信息不断修正后续时段的预测值让优化模型“看到”的数据更接近即将发生的真实情况。这里要区分两个概念一个是“预测值修正”也就是对预测曲线整体加一个偏差项另一个是“模型参数修正”比如在线更新预测模型的系数两者目的相同但复杂度和鲁棒性差别很大。实际工程中先用好前者收益就已经很明显。1.3 项目的技术边界与适用场景这个项目的目标场景是含光伏、储能和常规负荷的小型微电网也可以扩展到含柴油发电机、可中断负荷的独立微网。时间尺度上我采用的是 15 分钟一个控制步长预测时域 24 步也就是滚动看未来 6 小时。这个时间尺度对储能削峰填谷和购电策略优化比较合适太短容易近视太长则预测精度没有保障。需要说明的是如果研究对象是含复杂网架结构的主动配电网需要加潮流约束那这个代码框架就要再做不少扩展。单纯做能量管理层面的调度优化这套方案是够用的。2. 方法论拆解MPC框架与自适应修正机制2.1 标准 MPC 滚动优化流程标准的 MPC 实现逻辑上可以拆成四步当前时刻获取系统实测状态最重要的就是储能 SOC 和并网点功率获取未来 H 步的光伏和负荷预测曲线根据预测曲线求解一个带约束的优化问题得到未来 H 步的最优控制序列只取第一步控制量下发执行等下一个控制时刻到来重复整个过程。这里有一个容易被新手忽略的要点控制序列里后面的 H-1 步并没有真正执行。它们存在的意义是让当前决策能兼顾未来一段时间的整体最优而不是只盯着眼前一步。所以每次都必须重新求解这也是“滚动”二字的由来。在 Python 里实现这个循环并不复杂核心是用for循环包住一个优化求解过程每次更新状态和预测数据。2.2 自适应预测修正的三个落地层次第一个层次是误差反馈修正。做法很直观维护一个最近 N 步的预测误差序列计算滑动平均或指数加权平均作为偏差估计然后把未来预测曲线整体加上这个偏差。这个方案适合预测误差存在明显系统性偏移的情况比如光伏预测在雾天普遍偏高。公式大概是[ P_{correct}(tk) P_{forecast}(tk) - \bar{e}(t) ]其中 (\bar{e}(t)) 是最近一段时间预测值减去实测值的滑动平均。需要强调修正量永远只能用历史时刻的误差来估计不能偷看当前时刻或未来的真实数据否则实验就失去意义了。第二个层次是状态修正。储能 SOC 的模型递推值会随误差累积而漂移时间长了优化模型的起点就跟实际系统对不上了。解决办法是在每个控制时刻用实测功率反推 SOC或者直接用电池管理系统上报的 SOC 值覆盖模型递推值相当于给预测模型做了一次“状态重置”。第三个层次是模型在线辨识用递推最小二乘RLS这类算法在线更新负荷预测模型或光伏预测模型的参数。这个层次修正能力最强但实现复杂度也最高而且对数据的持续激励有要求。在实际项目里我建议先做前两层收益和成本比最高。2.3 目标函数与约束建模调度优化本质上是一个带约束的数学规划问题。目标函数一般包含购电费用、售电收入和电池损耗惩罚。我这里用线性成本计算购售电费用再加上一个 SOC 偏离参考值的二次惩罚项用来防止储能“摆烂”停留在边界附近[ J \sum_{k0}^{H-1} \left( c_{buy,k} P_{buy,k} - c_{sell,k} P_{sell,k} \right) \Delta t \sum_{k1}^{H} \lambda (SOC_k - SOC_{ref})^2 ]约束条件主要有四类功率平衡约束光伏出力、储能出力、购电功率之和等于负荷功率与售电功率之和储能 SOC 递推约束由上一时刻 SOC 和当前充放电功率决定储能功率和 SOC 限幅约束并网点交换功率限幅约束。建模时有个细节电池充放电效率不一致如果只用单个变量P_bat表示充放电SOC 更新式会变成含符号的分段函数破坏线性。常见的做法是拆成两个非负变量P_ch和P_dis分别代表充电功率和放电功率然后对两个变量的上限分别约束。这样虽然变量多了一倍但问题继续保持线性求解稳定性好很多。3. Python 实现架构与代码级拆解3.1 工程目录结构与依赖环境整个项目我拆成了几个模块各管一段方便单独替换算法mpc_microgrid/ ├── data_loader.py # 数据读取与预处理 ├── forecast.py # 基准预测曲线生成 ├── adaptive_correction.py # 自适应预测修正模块 ├── optimizer.py # MPC 优化模型 ├── simulator.py # 微电网时域仿真环境 ├── main.py # 主程序入口 └── results/ # 结果图表输出依赖库不多核心是cvxpy做凸优化建模numpy做数值计算matplotlib做可视化。安装命令pip install numpy scipy matplotlib cvxpycvxpy安装时会自动带 OSQP、ECOS 等求解器足够处理连续变量的二次规划问题。如果用得到混合整数变量后面再补cvxpy[glpk_mi]即可。3.2 预测数据生成与误差注入为了验证自适应修正模块的有效性需要先构造一个能“做实验”的数据环境。我用的方法是先设定一条平滑的真实光伏曲线和真实负荷曲线然后在真实值基础上叠加一个固定偏差和随机噪声生成预测曲线。这样设计的好处是真实值已知误差可量化修正前后的对比完全在掌控之中。比如真实光伏出力是 (P_{pv,real}(t))预测值就设为[ P_{pv,forecast}(t) P_{pv,real}(t) bias noise(t) ]bias是人为注入的系统偏移noise是均值为零的高斯噪声。负荷数据也按同样方式处理。这一步是后面评估修正算法精度的基础测试时务必要固定随机种子否则策略之间的对比就不公平了。3.3 自适应修正模块的核心实现修正器类我用了一个滑动窗口来维护最近一段时间的历史误差并用指数加权的方式平滑偏差估计。这样做比直接使用全部历史均值灵敏因为它更关注近期变化同时又能抑制单点噪声干扰。import numpy as np from collections import deque class AdaptiveCorrector: def __init__(self, window_size24, alpha0.3): self.window deque(maxlenwindow_size) self.alpha alpha self.prev_bias 0.0 def get_bias(self): if len(self.window) 0: return 0.0 mean_err np.mean(self.window) bias self.alpha * mean_err (1 - self.alpha) * self.prev_bias self.prev_bias bias return bias def update(self, forecast_value, actual_value): error actual_value - forecast_value self.window.append(error) def correct(self, forecast_series): bias self.get_bias() return forecast_series bias这里window_size控制误差统计的时间窗口alpha控制新误差的权重。alpha 不能太大否则偏差估计会跟着噪声剧烈跳动修正本身就成了新的干扰源。我测试下来alpha在 0.1 到 0.3 之间比较稳。如果想进一步细化可以把一天 24 小时按时段分组每个时段独立维护一个偏差量修正光伏预测时按当前时间索引选择对应的偏差。这种做法对负荷模式早晚差异明显的场景特别有效。代价是需要更多历史数据来支撑否则每个时段的样本太少统计不稳定。3.4 优化模型建模与滚动主循环优化模型我用cvxpy实现。以储能 SOC 递推为例如果拆分了充电和放电变量约束可以写成import cvxpy as cp H 24 dt 0.25 E_bat 120.0 # 储能容量 kWh eta_ch 0.95 # 充电效率 eta_dis 0.95 # 放电效率 P_buy cp.Variable(H) P_sell cp.Variable(H) P_ch cp.Variable(H, nonnegTrue) P_dis cp.Variable(H, nonnegTrue) SOC cp.Variable(H 1) constraints [SOC[0] 0.5] for k in range(H): # 功率平衡 constraints.append( P_pv_forecast[k] P_dis[k] P_buy[k] P_load_forecast[k] P_ch[k] P_sell[k] ) # SOC 递推 constraints.append( SOC[k 1] SOC[k] - (P_dis[k] * dt / eta_dis - P_ch[k] * dt * eta_ch) / E_bat ) # 边界约束 constraints.append(P_ch[k] 30.0) constraints.append(P_dis[k] 30.0) constraints.append(P_buy[k] 100.0) constraints.append(SOC[k 1] 0.9) constraints.append(SOC[k 1] 0.2)目标函数就按照前面公式用cp.sum组装最后调用prob cp.Problem(cp.Minimize(objective), constraints) prob.solve(solvercp.OSQP)主循环部分模拟环境的执行顺序要严格保持“先观测、后修正、再优化、最后执行”soc_current 0.5 for t in range(total_steps - H): pv_forecast forecast_pv[t:t H] load_forecast forecast_load[t:t H] if use_correction: pv_forecast corrector.correct(pv_forecast) load_forecast corrector.correct(load_forecast) # 求解 MPC result solve_mpc(pv_forecast, load_forecast, soc_current) action result[P_dis][0] - result[P_ch][0] # 环境执行 soc_current simulator.step(action, real_pv[t], real_load[t]) # 更新修正器 corrector.update(pv_forecast[0], real_pv[t]) corrector.update(load_forecast[0], real_load[t])这里容易犯的错误是提前把整段真实数据拿去更新修正器这等于把未来信息泄漏到了当前决策中会让实验结果虚高。正确的做法是每个时刻只把已经发生的实测值交给修正器跟在线运行时的信息流保持一致。4. 算例仿真与结果分析4.1 测试场景与参数设置我设计了一个典型的工商业园区微电网场景光伏装机 60kW负荷峰值约 80kW储能容量 120kWh最大充放电功率 30kWSOC 运行区间设为 0.2 到 0.9初始 SOC 为 0.5。仿真时长 48 小时控制步长 15 分钟预测时域 24 步。购电电价采用分时电价峰段 0.9 元/kWh平段 0.6 元/kWh谷段 0.3 元/kWh上网电价统一按 0.4 元/kWh 计算。预测数据按前面描述的方式在真实曲线基础上注入了 8% 的系统偏差和标准差约 5% 的随机噪声这组参数比较接近光伏预测的真实水平。4.2 三种策略的对比结果我在相同数据种子下做了三组实验第一组是不做任何预测修正的标准 MPC第二组是加了整体滑动偏差修正的 MPC第三组是分时段偏差修正的 MPC。运行完整仿真后统计指标如下策略总运行成本元购电量kWh弃光率SOC 末端偏差无修正 MPC17869323.2%4.7%整体偏差修正 MPC16948841.4%1.2%分时段偏差修正 MPC16788710.9%0.8%需要说明这个结果是在我构造的数据环境下得到的不同预测误差水平下数值会变但趋势是一致的加了自适应修正后运行成本明显下降弃光率减少SOC 轨迹也更贴近参考值。4.3 修正环节的收益到底从哪里来如果只从数字上看好像只是省了几十块钱。但在工程中自适应修正的真正价值在于防止系统越限和延长设备寿命。没有修正时光伏预测偏高会让储能过早充满午后真实出力一大就不得不弃光负荷预测偏低则会诱发不必要的购电。修正后储能充放电时机更贴合真实趋势SOC 曲线不会长期漂移在边界上。我个人的经验是当预测误差中存在明显的均值偏差时修正收益最大如果误差主要是零均值的随机噪声修正的效果就有限因为滑动平均会把噪声抵消掉。这也是为什么做实验之前先要对自己手里的预测误差做一次统计看它是“系统性偏高”还是“时高时低”。5. 常见问题与调试经验实录5.1 求解器不可用与依赖安装踩坑cvxpy最常见的报错是Solver OSQP not found。这种情况多半是osqp库没有装上直接执行pip install osqp即可。如果只是用最简单的prob.solve()cvxpy会自动选择求解器但有时会选到 SCS求解精度不如 OSQP 或 ECOS。我的经验是显式指定求解器prob.solve(solvercp.OSQP)如果问题变成混合整数规划比如加入了柴油机启停变量或负荷可中断变量那就需要额外安装混合整数求解器pip install cvxpy[glpk_mi]另外提醒一句在 conda 环境里pip install cvxpy有时会跟 numpy 版本冲突建议先建一个干净虚拟环境再装省得后面排查半天。5.2 优化问题不可行的定位思路MPC 滚动优化最让人头疼的就是跑着跑着problem.status变成infeasible。大多数情况不是求解器坏了而是约束之间存在矛盾。最常见的原因是 SOC 下限设得太高、充放电功率又太小系统在负荷高峰时段无论怎么调都没法既满足功率平衡又不突破 SOC 下限。我调试时采取三步走第一步先把所有边界约束放宽 30%确认问题能解第二步逐个把约束往回收定位是哪条约束在哪个时刻被激活第三步在目标函数里加松弛变量。松弛变量的作用是给约束一个“可调节的弹力”当问题无解时优化器可以适当地突破硬边界同时付出惩罚代价。这一点在实际运行中很重要因为现场系统不允许优化直接崩溃宁可付出一点经济惩罚也要保证输出一个可行指令。5.3 修正器参数调出振荡怎么办自适应修正的alpha参数如果调得太大偏差估计会跟随误差噪声剧烈波动导致 MPC 的决策序列忽高忽低甚至出现储能频繁充放电切换的现象。这种振荡对电池寿命很不友好。遇到这种情况我一般先把alpha降到 0.1然后把滑动窗口拉长让偏差估计更平滑。如果偏差序列本身有重尾或离群点用中位数代替均值做偏差估计会更稳健。另一个实用做法是把修正量做限幅比如单次修正不超过本时刻预测值的 10%从根源上防止修正过头。5.4 步长、预测时域与求解性能的取舍控制步长 15 分钟在多数场景下够用但如果负荷波动特别剧烈可以改成 5 分钟。代价是同样预测时域下决策变量数量变成三倍求解时间明显上升。预测时域方面H 太短根本看不到峰谷电价切换储能缺乏前瞻性H 太长则后半段预测基本是噪声对当前决策的参考价值不大。我测试下来15 分钟步长配 H246 小时在性能和效果之间比较平衡。如果嫌求解慢还有个优化技巧把预测时域做成分段。前 12 步精度细后 12 步用更粗的时间分辨率或者更简单的模型这样既能保持前瞻又能控制变量数量。5.5 结果可视化小技巧滚动优化的结果画图时横坐标是连续时间索引直接绘图会导致坐标轴标签密集成一团。我比较习惯用matplotlib的mdates做格式化import matplotlib.dates as mdates ax.xaxis.set_major_formatter(mdates.DateFormatter(%m-%d %H:%M)) ax.xaxis.set_major_locator(mdates.HourLocator(interval6)) plt.xticks(rotation45)这样图上 6 小时一个刻度既不拥挤又能看清充放电变化。画 SOC 曲线时我习惯把 SOC 上下限用axhspan画一个浅色底框一眼就能看出运行过程中有没有越界。这种图放在汇报材料里比单纯丢三条曲线直观得多。6. 个人实践体会与扩展方向把整套代码跑通之后我最大的感受是自适应预测修正并没有想象中那么玄乎。很多时候一个简单的偏差滑动平均就能把 MPC 的实际性能提升一大截反而是过于复杂的在线学习模型在数据量不足或信号激励不够时表现很不稳定。做项目跟写论文不一样论文追求方法的新颖性工程项目更看重在有限数据下能不能稳定复现收益。如果你准备在真实微网系统里部署 MPC我建议按这个顺序来先跑标准 MPC把运行日志存下来统计预测误差的分布看到明显的系统偏差之后再加修正器观察成本是否改善确认收益稳定后再考虑更高级的参数在线辨识或学习式预测修正。这个框架后续值得扩展的方向也不少。可以加入柴油发电机和可中断负荷把问题变成混合整数规划用启停变量刻画机组开停机成本也可以把储能寿命模型比如循环次数与放电深度的关系写进目标函数让调度策略不至于为了省电费而过度消耗电池寿命。如果预测模块更新得更频繁还可以设计多时间尺度协调调度小时级 MPC 和分钟级实时控制叠加形成更完整的能量管理闭环。每一步扩展都会带来新的问题但也会让这套系统的工程价值更扎实。