☰
基于MPC的微电网调度优化:Python实现与滚动控制实战
2026/10/8 9:46:52 网站建设 项目流程

做微电网调度的同学应该都有体会:光伏出力忽高忽低、负荷峰谷变幻莫测,储能充放电切来切去,稍微没调度好,电费账单就不好看了。这个问题我在做项目时反复折腾过,最早用规则调度,后来换成开环优化,最终还是模型预测控制(MPC)把性能真正提上来了。本文基于我实际跑通的Python代码实现,把MPC微电网调度优化从建模到仿真完整拆解一遍,包括为什么不选别的方案、电池SOC怎么建模、求解器怎么配、参数怎么调,以及踩过的坑。适合正在做微电网能量管理、储能优化控制、研究生课题或工程预研的同学参考。

1. 项目概述:微电网调度为什么必须上MPC

1.1 微电网调度的本质与核心痛点

微电网通常由光伏、风电这类分布式电源,加上储能电池、本地负荷组成,可以并网运行也可以离网运行。所谓调度优化,本质就是在满足负荷需求的前提下,决定每一时刻储能充多少放多少、跟主网交换多少功率,目标是让运行成本最低,同时保证电池不滥用、系统功率不失衡。

这里面最大的难点不是数学推导,而是不确定性。光伏出力跟天气强相关,中午猛增、傍晚骤降,负荷也有明显的峰谷差。如果你在上午十点就决定“下午三点储能放50kW”,到下午三点实际负荷和预测值差了30kW,这个决策就废了。所以调度方案必须能滚动修正,这正是MPC最擅长的事。

传统做法主要有三类:第一类是查表式规则,比如“电价高就放电、电价低就充电”,简单粗暴,但没法统筹考虑SOC约束和功率平衡,经济性差;第二类是单次开环优化,把全天24小时的决策一次性求出来,预测准还行,预测一偏就全盘皆输;第三类就是今天要讲的MPC,在每个采样时刻重新预测未来一段时域,求解当前时段的控制序列,但只执行第一步,然后滚动推进。

1.2 MPC方案的三板斧与项目定位

MPC之所以能应对不确定性,靠的是三个核心机制。第一,预测模型,用状态空间表达式描述储能SOC等关键变量随控制量变化的规律;第二,滚动优化,不是求一次解就完事,而是每个控制周期都重新求解一个有限时域优化问题;第三,反馈校正,每次求解前用实际测量的SOC和功率数据刷新状态初值,把模型失配和预测误差的影响压下去。

本项目面向的是一个典型的并网型工商业微电网,光伏装机200kW,储能容量400kWh,最大充放电功率100kW,采样周期15分钟,预测时域取4小时(16步)。控制目标是让一个周期内的购电成本最低,同时平滑储能出力、减少电池循环损耗。整条链路用Python实现,优化求解部分用Cvxpy建模,后端调用开源求解器,全过程不依赖商业软件。

2. 系统建模:从物理过程到优化问题

2.1 微电网各组成部分的数学模型

做MPC第一步不是写代码,而是把系统的物理特性转换成数学表达。我这里先列一下各部分模型,这些是后续约束条件和状态转移方程的基础。

光伏系统在调度层面不需要建模逆变器内部电磁暂态,只关心它的最大出力预测值P_pv(k),在每个控制周期内被视为不可调度的负负荷,直接参与功率平衡计算。负荷模型同理,取节点预测值P_load(k)。这两项数据可以来自历史同期均值、数值天气预报加回归修正,也可以用LSTM等数据驱动方法预测,文章后面会讲我在实验中用的数据准备方式。

储能系统需要重点建模,因为它有动态过程和约束。用一阶离散状态空间模型描述电池SOC变化:

SOC(k+1) = SOC(k) - η_c * P_ch(k) * Δt / C + P_dis(k) * Δt / (η_d * C)

其中η_c是充电效率,η_d是放电效率,C是电池容量(kWh),Δt是采样时间(h)。注意充放电功率这里分开定义,方便添加互斥约束和效率系数。实际代码里我用的是功率平衡等式中的净功率P_bat(k),效率系数通过分段线性化近似处理,既保证精度又不引入过多计算复杂度。

与主网的交互功率P_grid(k)是功率平衡的阀,并网模式下可正可负,正表示从电网购电,负表示向电网售电,受到联络线容量限制。功率平衡关系是MPC中最重要的等式约束:

P_pv(k) + P_dis(k) + P_grid(k) = P_load(k) + P_ch(k)

这个等式在每个控制步都必须严格满足,否则优化结果物理上不可执行。

2.2 MPC预测模型与状态空间表达

MPC的预测模型可以写成标准的状态空间形式:

x(k+1) = A * x(k) + B * u(k) + E * d(k) y(k) = C * x(k)

对应到这里,状态量就是SOC(k),控制量是储能充放电功率和电网交互功率,扰动量d(k)是光伏出力和负荷预测。之所以要把问题写成这个标准形式,是因为Cvxpy和大多数求解器都对线性优化问题有高效的求解算法,而且MPC的滚动优化框架天然需要一个能在每个步长上递推的状态方程。

我在代码中把预测时域内的所有决策变量堆叠成一个向量,然后通过矩阵拼接构建目标函数和约束。这种方法叫单变量展开法,虽然变量数量随预测时域线性增加,但对100kW级别的微电网完全够用——16步预测、每步3个控制变量,总共也就几十个决策变量,求解时间在毫秒级,实时性没有任何问题。

2.3 目标函数与约束条件的工程化设计

目标函数我采用了加权多目标的形式,这也是实际项目中最实用的方案:

min Σ [ c_buy * max(P_grid, 0) - c_sell * min(P_grid, 0) ] * Δt + Σ [ w1 * ΔP_bat(k)^2 + w2 * (SOC(k) - SOC_ref)^2 ]

第一项是购电成本与售电收益,体现了经济调度主目标;第二项是储能出力平滑项,防止电池功率在相邻时段剧烈跳变;第三项是SOC回稳项,让电池在调度周期结束后尽可能回到参考值附近,为下一轮滚动做准备。权重w1和w2的取值我后面会单独讲,因为它们直接决定控制行为风格。

约束条件包括以下几组:

  • 储能功率上下限:充放电功率绝对值不超过额定值
  • SOC范围:一般取20%到90%,留出安全余量
  • 功率平衡等式
  • 联络线功率限制
  • 储能SOC终点约束:要求终端SOC落在目标区间,避免“把电用光”的短视行为

这种带终端约束的处理方式比单纯加SOC惩罚项更硬核,因为它从优化问题的结构上保证了滚动过程的可行性与收敛性,工程上非常关键。

3. Python实现:MPC调度器的代码架构与求解流程

3.1 环境准备与项目整体模块划分

实现MPC不需要特别复杂的开发环境,我用的是Python 3.8以上版本搭配numpy、pandas、matplotlib和cvxpy。如果是从零开始搭环境,记得先装好numpy和pandas,cvxpy安装时会自动拉起求解器依赖,一般不会出问题。我在Windows和Linux上都跑过同一套代码,性能差别不大,建议实验室环境用conda管理依赖,避免系统Python被装乱。

整个项目我拆成了5个模块,每个模块只干一件事:

  • data_loader.py:负责读取光伏、负荷、电价历史数据,生成预测序列
  • model.py:定义微电网参数、状态空间系数矩阵和约束边界
  • mpc_controller.py:MPC核心逻辑,构建优化问题并调用求解器
  • simulation.py:闭环仿真主循环,模拟一个完整调度周期
  • plot_results.py:结果可视化和指标计算

模块化的好处很明显——调试MPC时不用在几百行代码里翻来翻去,出问题直接定位,换参数也方便。有人说“就一个调度算法搞这么多文件”,但实际项目要反复调参和换数据,结构化才是省时间的做法。

3.2 核心代码:优化问题构建与求解

MPC控制器是整个系统的发动机。我贴一段核心代码框架,说明构建优化问题的关键步骤:

import cvxpy as cp import numpy as np def solve_mpc(pv_pred, load_pred, price_buy, price_sell, soc_current, params): N = params['horizon'] dt = params['dt'] C = params['capacity'] p_bat_max = params['p_bat_max'] soc_min, soc_max = params['soc_min'], params['soc_max'] eta_c, eta_d = params['eta_ch'], params['eta_dis'] p_ch = cp.Variable(N) # 充电功率 p_dis = cp.Variable(N) # 放电功率 p_grid = cp.Variable(N) # 电网交换功率 soc = cp.Variable(N+1) # SOC轨迹 cost = 0 for k in range(N): cost += price_buy[k] * cp.pos(p_grid[k]) * dt cost -= price_sell[k] * cp.neg(p_grid[k]) * dt constraints = [soc[0] == soc_current] for k in range(N): constraints += [ soc[k+1] == soc[k] - eta_c * p_ch[k] * dt / C + p_dis[k] * dt / (eta_d * C), p_pv[k] + p_dis[k] + p_grid[k] == p_load[k] + p_ch[k], p_ch[k] >= 0, p_ch[k] <= p_bat_max, p_dis[k] >= 0, p_dis[k] <= p_bat_max, p_grid[k] >= -p_grid_max, p_grid[k] <= p_grid_max, soc[k+1] >= soc_min, soc[k+1] <= soc_max ] prob = cp.Problem(cp.Minimize(cost), constraints) prob.solve(solver=cp.ECOS, verbose=False) return p_ch.value, p_dis.value, p_grid.value, soc.value

几个关键点:充放电功率分开建模并用非负约束保证物理方向正确;在功率平衡中p_ch和p_dis放在等式两侧对应实际流动方向;pos和neg函数把购电和售电天然拆开,不用引入整数变量,求解效率特别高。如果后续想避免同一时刻既充又放,可以加pch[k] + pdis[k] <= p_bat_max这个线性约束,压缩兼得空间。

求解器方面,cvxpy支持多个后端,我实测下来ECOS在中小规模线性规划上最快最稳,OSQP在需要热启动时表现不错。问题规模不大时,直接用ECOS即可,不用额外装MOSEK,免费开源求解器完全够用。

3.3 闭环仿真主循环与滚动执行逻辑

MPC的精华在滚动。仿真主循环做的事情很简单:每个采样时刻,用当前SOC作为状态初值,用最新预测数据调用求解器,得到整个预测时域的控制序列,但只取出第一个时刻的控制动作施加给微电网,然后推进到下一个采样点,重新测量SOC,重复以上过程。

for k in range(total_steps): pv_pred = forecast_pv(k) load_pred = forecast_load(k) p_ch, p_dis, p_grid, _ = solve_mpc( pv_pred, load_pred, price_buy[k:k+N], price_sell[k:k+N], soc[k], params ) u_ch[k] = p_ch[0] u_dis[k] = p_dis[0] soc[k+1] = update_soc(soc[k], u_ch[k], u_dis[k], dt, C)

这个循环就是MPC闭环的核心。每一步求解花费在50到200毫秒之间,采样周期是15分钟,计算延迟完全可以忽略。值得强调的是“只执行第一步”这个操作,看起来浪费了后面15步的计算结果,但正是这种“边计划边修正”的策略,让MPC对预测误差的容忍度远超开环优化。

4. 仿真实验与结果分析

4.1 数据准备与实验场景设计

仿真数据我采用了一个典型夏季工作日的实测光伏和负荷曲线,采样间隔15分钟,共96个点。光伏出力呈明显的单峰形状,中午达到180kW左右,夜间为零;负荷则有两个高峰,上午10点和晚上8点附近,最大负荷约160kW。分时电价按峰平谷设置:8点至11点、18点至23点为峰段电价1.2元/kWh,6点至8点、11点至18点为平段电价0.7元/kWh,23点至次日6点为谷段电价0.35元/kWh。

比较有意思的是,这个场景恰恰暴露了规则调度的缺陷——如果单纯“谷充峰放”,在上午光伏和负荷双高时段的决策就会很僵硬,储能可能在电价还不太高的时候就提前放完。MPC通过对未来4小时的联合优化,会在光伏高发时段压低购电,在电价尖峰时段释放储能,行为上更像一个“有远见”的操盘手。

4.2 典型日调度结果的三种可视化解读

跑完整个96步仿真后,我通常先看三张图:功率平衡图、SOC变化曲线、成本累计图。

功率平衡图上能看到MPC在每个时刻都严格满足功率平衡,光伏、储能、电网三者协同动作。最直观的规律是:夜间谷段电价低,储能以额定功率从电网充电,SOC一路爬升;上午峰段叠加负荷爬坡,储能按需放电削峰;午后光伏大发,电网购电趋近于零甚至倒送,同时有余电就充回电池。

SOC曲线是判断控制效果的第一指标。合理的MPC行为应该让SOC在安全边界内平滑变化,没有反复的充放切换。我实测的SOC轨迹大致在25%到90%之间波动,收盘时能回到目标区间附近,没有任何越界情况。如果发现SOC轨迹频繁“撞墙”,多半是权重没调好或约束矛盾,后面会讲排查方法。

成本曲线对比更有说服力。同一个场景,用贪婪算法(只要电价合适就充放)和MPC分别跑全天,MPC的购电总成本大约降低11%。省下的钱主要来自两个环节:一是光伏大发时段及时调整储能充电策略,避免原本计划中多余的购电;二是峰段之前科学预留SOC容量,减少高价时段买电。这个数字在不同季节和典型日会有浮动,但趋势非常稳定。

4.3 与开环优化、规则调度的对比分析

项目中我特意做了三组对比实验,控制变量只有“决策方式”不同,模型参数和数据完全一致。

方案全天成本(元)SOC越限次数充放切换次数求解耗时/步
规则调度(谷充峰放)约980014无
开环优化(09:00决策全部)约920180.3s
MPC滚动优化(15min)约860060.12s

规则调度胜在简单,但对电价和光伏的配合明显不够精细;开环优化在预测准确时理论成本更低,但一旦下午实测负荷比预测高,傍晚就会出现SOC偏低、被迫高价购电的情况;MPC则因为不断用实测值修正计划,整体表现最稳。这个对比也验证了MPC的核心价值:不是预测得准,而是对预测不准具有天然的包容能力。

5. 工程化落地中的常见问题与调优经验

5.1 目标函数权重与预测时域的整定规律

MPC最让人头疼的就是参数整定,尤其是目标函数里那几项权重。我走过不少弯路,后来总结了一套实用规律。

先说预测时域N。N太短,MPC就变成“近视眼”,看不到电价尖峰和光伏余量,行为接近贪婪算法;N太长,峰值负荷和电价波动被平均化,且计算量上升。对15分钟采样、24小时调度周期的问题,N取16(4小时)是一个很好的起点。N=16时能覆盖上午峰段和中下午光伏高发,计算量又小。如果光伏占比更高,建议N取24或32,把整个白天都纳入视野。

再说权重w1(出力平滑项)。这个参数设大了,储能出力被压得很平,削峰填谷效果变差;设小了,功率曲线剧烈振荡,对电池寿命不友好。我的经验是先用相对值调试:把购电成本归一化到1,w1从0.01开始调,看功率曲线是否抖动,必要时翻倍或减半再试。类似的,SOC回稳项w2通常比w1小一个数量级,它只负责引导终端状态,不要让它主导当前经济决策。

5.2 无可行解问题与约束矛盾的排查流程

初版代码最容易踩的坑就是求解器报“problem infeasible”——优化问题无可行解。很多人第一反应是求解器出问题了,实际九成是约束自相矛盾。

我这里说一个最典型的例子:SOC返回目标设置太紧。比如你要求终端SOC必须回到50%,但预测时段内电价非常低、根本不需要放电,储能没有足够放电空间让SOC降下来,问题就无解。解决办法有两种,一是放宽终端约束,把等式改成区间约束,允许SOC落在45%到55%之间;二是增加SOC回稳惩罚项作为软约束,让矛盾不再硬碰硬。

排查流程我一般按三部走:先把所有等式约束单独跑一遍,确认变量维度匹配;再把不等式约束逐个放开,看是哪个约束导致不可行;最后检查数据预处理,看SOC初值是否落在约束边界之外。这几个步骤能在五分钟内定位大多数infesible问题。

5.3 模型失配与预测更新的工程应对

MPC虽然抗扰动,但不是万能的。如果模型失配严重——比如蓄电池实际容量衰减到标称的80%,或者充放电效率跟建模值差太多——控制效果会明显下降。

工程上我常用三个手段应对。第一是定期校准模型参数,每个月根据实际充放电数据重新辨识电池容量和效率,这个用最小二乘就能做;第二是缩短控制周期,把15分钟压缩到5分钟甚至1分钟,让反馈修正更频繁,代价是求解频率上升,对算力要求更高;第三是在状态更新时做简单滤波,用实测SOC和模型预测SOC的偏差对后续预测做纠正,相当于加一个反馈项,效果非常明显。

还有一个实践细节:每次滚动求解前,一定要把当前实测SOC读入模型作为状态初值,而不是用上一轮预测的SOC值。这个看起来是常识,但我在早期的代码里就因为复用了上一次预测的SOC导致误差累积,越跑越偏。

5.4 提速技巧与代码调试心得

MPC求解速度直接影响系统实时性。虽然本项目的15分钟采样周期对求解时间不敏感,但如果后续把控制周期压缩到分钟级,提速就是刚需。我实测的几个有效方案按效果排序如下:

  • 求解器热启动:Cvxpy支持通过warm_start=True复用了上一轮的求解结果作为初值,二次规划类问题能提速30%到50%
  • 减少决策变量维度:比如把充放电功率合并成带正负符号的单个变量,变量数直接减三分之一
  • 约束矩阵预计算:把与预测时域无关的常量矩阵提前拼接好,避免在循环里重复构造
  • 换用OSQP求解器:在需要更高实时性的场景下,OSQP的迭代速度通常比ECOS更快

调试方面,我的习惯是先开环测试再闭环测试。先给MPC一组固定预测数据,跑一遍优化检查约束是否满足、目标函数是否合理;确认无误后再接闭环仿真。这个顺序能帮你把“算法逻辑问题”和“动态反馈问题”分开定位,少掉很多头发。

6. 扩展方向与个人实践建议

这套MPC调度框架还有一个很大的优势:可扩展性强。想加入储能寿命衰减模型?在目标函数里增加一个基于充放电深度的惩罚项就行。想考虑离网运行?把电网交互功率约束改成强制为零即可。想引入多种分布式电源或柔性负荷,只需在功率平衡等式和目标函数中追加对应变量。所有扩展都建立在状态空间模型和约束框架之上,不需要推翻重来。

我个人在实际项目中体会最深的一点是,MPC落地的难点往往不在理论而在工程细节——数据预测怎么准、权重怎么调、约束怎么放松、异常情况怎么兜底。把每一个细节都用代码固化下来,你手里这套Python调度器就不只是科研工具,而是能直接迁移到实际微电网能量管理系统里的核心控制逻辑。如果后面再迭代,我大概率会优先把光伏和负荷的预测模块从统计模型升级成滚动LSTM,跟MPC无缝对接,那又是一篇新文章了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询