☰
基于模型预测的混合储能微电网双层能量管理及Matlab实现
2026/10/22 5:57:04 网站建设 项目流程

做混合储能微电网能量管理的人,最近基本都在聊一个词:双层模型预测。标题里的“基于模型预测算法的混合储能微电网双层能量管理系统研究”,听起来像个学术项目的名字,但落到Matlab里,它要解决的核心问题特别直白:光伏和负荷不停波动,微电网里面的锂电池和超级电容怎么配合,才能在保证供电稳定的同时,又少花电费、又不把电池冲到过放。这篇文章就是我复现这个系统时的完整思路和Matlab实现记录。适合正在写论文的研究生、想做储能控制仿真的工程师,以及被MPC矩阵搞得头疼的初学者。

我之前在模拟项目中从单层MPC开始,后来发现单层模型要同时考虑经济调度和实时功率分配,预测步数一长,矩阵规模就爆炸。于是按照多数文献里的做法,拆成上层调度、下层分配两层,模型预测控制器负责滚动优化,Matlab里的quadprog负责把每一步的二次规划问题解出来。今天这篇文章不绕弯路,直接从“为什么这么做”讲到“代码怎么落地”,再附上我调参数时踩过的坑。

1. 整体思路:为什么是“双层”加“模型预测”

1.1 微电网能量管理要解决什么问题

先把问题定义清楚。微电网里一般有光伏、负荷、储能,还可能和大电网有功率交换。能量管理系统要做的不是“缺电就放、多电就充”这么简单,而是要在满足功率平衡的前提下,让运行成本尽量低,同时把储能的社会责任管好,比如SOC不能越限、寿命不能损耗太快。

光伏和负荷都有很强的随机性。光伏中午可能猛增,傍晚又骤减;负荷可能因为一台大电机启动而产生尖峰。这些扰动发生的时间尺度也不一样,有的以小时计,有的以秒计。如果只用一个控制器去处理所有这些尺度,问题规模会非常大,而且不同控制目标的优先级也容易互相干扰。

我做单层MPC时就遇到过这个问题:把经济性、平抑波动、SOC管理全部塞进一个目标函数,预测时域稍微拉长,决策变量一下就上百个,求解时间和解的稳定性都很难接受。所以双层结构几乎成了标准做法。

1.2 双层架构的设计逻辑

双层架构的实质是“时间尺度分层”。

上层负责长时间尺度,通常是15分钟左右一个周期,有时候也做一小时。这一层输入光伏和负荷的短期预测结果,还有分时电价,目标函数是运行成本最小,输出是未来一段时间里各单元的基准功率,包括并网功率和储能总功率设定值。

下层负责短时间尺度,也就是秒级甚至毫秒级。这一层接收上层给过来的设定值,再根据实时功率偏差,把总功率分配给锂电池和超级电容。锂电池承担慢慢变化的低频分量,超级电容承担突然冲击的高频分量。

这样拆开之后,上层解决“该不该充、该不该放、跟电网买多少电”的问题,下层解决“谁来充、谁来放、动作快慢怎么配合”的问题。两个控制器都不需要把对方的问题全揽下来,矩阵维度和控制目标都清晰很多。

1.3 为什么是MPC不是PID也不是单层优化

有人会问,双层结构里用最简单的那套方法行不行?比如上层用优化调度,下层用PI控制。其实也可以跑,但效果差在两类场景:一是约束处理,二是未来信息的利用。

PID本质上是基于当前误差的反馈控制,它看不到未来。当光伏预测到马上要大幅增加时,PID不会提前调整储能,只会等母线电压或频率变化了才动作。MPC不一样,它手里有一份未来Np步的预测轨迹,相当于开车时看前方几百米的路况,而不是只看车头前那一米的地面。

单层静态优化虽然能处理约束,也能看到未来,但它是一次性算完就不再更新的,一旦预测偏差大,控制效果就失控。MPC用的是滚动优化,每一步算完只取第一个控制量,然后再用实时状态做反馈,重新预测、重新求解。这就是它名字里“模型预测控制”中反馈校正的含义。

2. 系统建模:混合储能分工与数学描述

2.1 光伏、负荷与电网交互的模型

先约定功率方向,不然后面代码里正负号会乱。

我习惯用这样的规定:光伏出力为正,负荷消耗为正,储能充电功率为正,放电为负,电网向微电网供电为正,向电网送电为负。功率平衡式写成:

Ppv + Pgrid + Pbat + Psc = Pload

这里Pbat和Psc可正可负,实际就是储能参与平衡的净功率。

光伏模型不需要太复杂,仿真时直接用给定曲线就行。负荷模型也一样,取历史数据或典型日曲线。要额外加扰动的话,可以在曲线上叠加一个高频白噪声或阶跃变化。这样做的目的是测试下层的动态响应能力。

电网模型主要体现为交换功率限制。比如变压器容量决定了Pgrid上下限,如果微电网运行在孤岛状态,那Pgrid直接等于0,约束变成等式。这是双层模型中一个重要的场景切换开关。

2.2 锂电池与超级电容的功率分配

混合储能的核心价值是把能量型和功率型储能组合起来。锂电池能量密度高,单位能量成本低,但它频繁快速充放会严重影响寿命。超级电容功率密度高,响应速度快,寿命几乎不受充放电次数影响,但存不了多少电。

所以功率分配的基本思路是:让超级电容吃掉功率曲线里的高频毛刺,让锂电池承担平缓的整体充放电斜率。工程上最常用的办法是低通滤波。把需求功率P_need经过一个低通滤波器,低频部分给锂电池,高频部分给超级电容,公式就是Pbat = LPF(P_need),Psc = P_need - Pbat。

但光靠低通滤波有个问题:它完全不考虑SOC。锂电池快没电了,滤波器还是让它出功率,最后SOC直接越限。所以更好的做法是把滤波后的结果作为MPC的参考值,在目标函数中让实际功率尽量接近参考值,同时把SOC偏差作为惩罚项放进优化里。

2.3 目标函数与约束条件的数学表达

双层MPC里每一步都要解一个优化问题。上层目标函数我习惯写成:

min Σ( price(k) * Pgrid(k) + λ1 * (P_bat_total(k) - P_bat_ref(k))^2 + λ2 * SOC_penalty(k) )

第一项是买电成本,第二项是让储能总功率跟踪计划,第三项是SOC越限的保险惩罚。约束条件包括功率平衡等式、Pgrid上下限、电池功率和SOC上下限。

下层目标函数和上层不同,它不再关心电价,而是专注于功率分配和平抑波动。我常用的形式是:

min Σ( w1 * (P_bat(k) - P_bat_ref(k))^2 + w2 * (P_sc(k) - P_sc_ref(k))^2 + w3 * (SOC_bat(k) - SOC_bat_target)^2 + w4 * ΔP_sc(k)^2 )

其中最后一项是为了限制超级电容的功率变化率,防止它过度抖动。下层约束包括电池功率限值、电量变化、超级电容功率限值和SOC限值。

这套目标函数写成矩阵形式之后,就是一个标准的二次规划问题。这也是我选择在Matlab里用quadprog的原因,不需要额外装求解器,函数原生支持,直接构造H矩阵和f向量就能解。

3. Matlab实现细节:双层MPC的代码结构

3.1 总体框架与模块划分

整个仿真程序我分成几个文件来写,不会全挤在一个脚本里。

  • main.m:初始化参数,读取光伏/负荷/电价数据,启动双层循环,存储结果,绘图。
  • mpc_upper.m:上层MPC函数,输入当前状态、预测序列和约束参数,输出上层控制决策。
  • mpc_lower.m:下层MPC函数,输入实时功率需求、SOC状态,输出电池和超级电容的功率。
  • model_update.m:负责状态更新,比如根据控制量计算下一时刻SOC。
  • plot_results.m:把仿真结果画出来,包括功率曲线、SOC曲线和成本曲线。

主循环大概是这个结构:

for k = 1:T_total if mod(k, N_up) == 1 % 每个上层周期调用一次上层MPC u_ref = mpc_upper(x, pv_pred, load_pred, price, params); end % 每个控制周期调用下层MPC [Pbat, Psc] = mpc_lower(x, P_demand_t, u_ref, params); % 更新状态 x = model_update(x, Pbat, Psc); end

N_up是上层调度周期和控制周期的比值,比如上层15分钟一次,下层1秒一次,那N_up就是900。

3.2 上层调度MPC的搭建要点

上层MPC的状态变量一般只需要电池SOC,控制变量是并网功率Pgrid和储能总功率P_storage。状态空间方程里,SOC变化量由储能功率和电池容量决定。

构造quadprog输入矩阵时,最麻烦的是把未来Np步的所有约束统一写成矩阵不等式。我习惯先把预测模型整理成离散状态空间形式,然后循环累加生成预测输出矩阵。代码大致这样:

function u_opt = mpc_upper(x0, pv, load, price, params) Np = params.Np; Nc = params.Nc; % 构造预测矩阵 % ... % 目标函数:H = 2*(Model'*Q*Model + R) H = ... f = ... % 不等式约束:A*u <= b A = ... b = ... % 功率平衡等式约束 Aeq = ... beq = ... lb = ...; ub = ...; options = optimoptions('quadprog','Display','off'); u_opt = quadprog(H, f, A, b, Aeq, beq, lb, ub, [], options); end

这里要特别注意,quadprog要求H矩阵严格对称,最好在构造时用H = (H + H') / 2处理一下,否则求解器可能报“Hessian must be symmetric”的警告。

3.3 下层功率分配MPC实现

下层MPC和前者的区别在于,控制变量变成了两个,P_bat和P_sc,而且预测时域短得多。

我给的参考值来自上层调度结果加上当前实时功率误差。简单说,P_demand = u_ref_total + (P_need_now - u_ref_total_current)。然后下层在这个总需求下进行混合储能分配。

下面是个简化版函数:

function [Pbat, Psc] = mpc_lower(x, P_need, params) % 输入:当前SOC、当前需求、参考分配 Np = params.Np_lower; u_ref_bat = params.u_bat_ref(1:Np); u_ref_sc = params.u_sc_ref(1:Np); C = ...; % 预测输出矩阵 D = ...; % SOC偏差输出矩阵 H = params.q1 * (C'*C) + params.q2 * (D'*D); f = -params.q1 * C' * u_ref_bat - params.q2 * D' * (SOC_target - SOC_cur); % 加上功率平衡约束、SOC上下限、功率限值 A = ...; b = ...; options = optimoptions('quadprog','Display','off'); u = quadprog(H, f, A, b, [], [], lb, ub, [], options); Pbat = u(1); Psc = u(2); end

别把这个当完整代码看,主要作用是说明矩阵H和f是怎么拼出来的。实际工程中,预测矩阵构造和约束矩阵生成会占据大量代码行数,这才是MPC实现里最需要仔细的部分。

3.4 滚动优化与状态更新

MPC的核心是“滚动”。每个控制周期都执行一次:测量/估计当前状态,基于预测模型求解未来Np步的优化问题,然后把最优序列的第一个控制量作用到系统上,下一拍再重复。

Matlab仿真里状态更新用差分方程:

SOC(k+1) = SOC(k) - η * P_bat(k) * Ts / E_rated

充电和放电的效率不同,实际代码里要分开写。如果简单处理,可以统一用一个充放电效率,仿真偏差不会太大,但物理上不严谨。

还有一点容易被忽略:下层MPC执行周期短,上层MPC执行周期长。两层之间传递的不是一个静态值,而是一组未来的参考轨迹。也就是说,上层每15分钟算出来的不是单一功率值,而是未来一小时的计划曲线,下层在每个控制周期里只从这条曲线上取当前时刻附近的值,再叠加实时误差修正。这样即使光伏突然跳变,上层还没有重新计算,下层仍然有东西可追。

4. 参数整定与仿真结果的分析方法

4.1 预测时域与控制时域的选择

参数整定是另一个大坑。预测时域Np和控制时域Nc的选择直接决定计算量和控制性能。

如果上层采用15分钟步长,我建议Np至少覆盖4到6小时,也就是16到24步。Np太短,无法把握电价峰谷和光伏日内规律;太长,预测精度下降,矩阵维度过大,quadprog求解时间飙升。Nc可以远小于Np,比如Np=24,Nc=6,这样只让前几个控制量自由变化,后面保持不动,能显著降低决策变量个数。

下层因为控制周期短,Np一般设成5到20步。我在秒级仿真中常用Np=10到15。Np过小,超级电容来不及出力,波动平抑效果差;Np过大,又容易产生不必要的功率往复,让SOC跟着震荡。

4.2 权重系数怎么调

目标函数里的权重系数w1、w2、w3、w4,不同的配比会带来完全不同的行为。我调参的经验是先定框架,再细调。

先让功率跟踪权重w1、w2为1,SOC惩罚权重w3设为0.01,功率变化率惩罚w4设为0.1,跑一遍看SOC曲线和功率曲线。如果SOC长时间偏离目标,就把w3往上调,调到SOC曲线能基本回到目标附近但又不至于让功率跟踪变差。

如果超级电容功率出现强烈抖动,就把w4调大,让它的变化率受限。如果电池频繁反向充放,说明分层能力不够,可以适当提高低通滤波时间常数,或者增加上层参考值的平滑度。

下表是我常用的一组初始值,做仿真时可以以此为起点:

参数推荐起始值作用
Np_upper24覆盖未来6小时
Nc_upper6降低决策变量数
Np_lower10秒级滚动窗口
w1 / w21功率跟踪权重
w30.01 ~ 0.1SOC回归权重
w40.1 ~ 0.5超级电容变化率抑制

4.3 怎么评估控制效果

仿真结束后不能只看两张曲线好看。我一般会算几个量化指标。

并网功率波动平抑率最直接,把系统接入储能后的并网功率标准差和未接储能时的标准差做对比,用百分比表示。

SOC维持率可以统计仿真时长内SOC处于安全范围内的比例,最好接近100%。锂电池SOC如果频繁冲到上限,寿命和安全性都会出问题。

运行成本就是把每个步长内电网买电费用累加,同时考虑储能的损耗模型。注意,如果没有电价数据,这块只能做相对比较,不能当绝对值用。

最后画图时建议把以下五条曲线放在同一张图里:光伏出力、负荷、电网交换功率、锂电池功率、超级电容功率。再单独画一张SOC变化图。这样一眼就能看出功率分配逻辑是否合理。

5. 常见问题与排查技巧实录

5.1 QP求解失败或不可行

我遇到最多的报错是“Quadratic programming problem is infeasible”。这一般不是控制器本身写错,而是约束条件给得太紧或者初始状态就不在可行域里。

比如SOC初始值设为95%,但上层MPC预计未来几小时光伏很强,给电池下了充电指令。充电意味着SOC继续上升,而SOC上限约束是90%,这个优化问题当然无解。

排查思路很简单:第一步看初始值是否满足所有约束;第二步临时把上下限放宽,看看能否解出来,能解出来说明约束太紧;第三步在目标函数里加松弛变量,给SOC越限一个惩罚而不是硬约束,这样即便预测稍有偏差,优化也不会直接崩溃。

5.2 SOC越界与功率震荡

仿真跑到中间SOC直接打到上下限,通常是因为MPC没有做足够远的预测,或者SOC权重太低。只盯着当前几步,系统会只顾眼前功率平衡,到后面才发现SOC要过界,但已经来不及了。

解决办法有两个。一是把SOC惩罚项改成非线性程度更高的形式,比如SOC偏离目标越远,惩罚增长越快。二是加终端约束,强制预测时域末尾的SOC落在目标附近,比如SOC(Np)和目标SOC的偏差小于某个阈值。终端约束效果很好,但要注意别把约束设置得过死,否则又会出现不可行问题。

功率震荡的问题大多出在下层,尤其是超级电容的功率变化率没有被约束。仿真时看起来就是Psc在两三个控制周期内从正的最大跳到负的最大,这种高频往复在实际系统里根本没法执行。给Psc加变化率约束,或者增加w4权重,就能明显改善。

5.3 Matlab实现中与quadprog相关的坑

quadprog用起来简单,但坑不少。最典型的是H矩阵不正定。由于构造矩阵时用的是离散状态空间预测模型,如果Q矩阵为半正定且R为零,整个H可能变成半正定,quadprog会拒绝计算。

我的处理方法是给H加一个极小的正则项,比如H = H + 1e-8 * eye(size(H)),保证数值上有严格正定性。这样不会改变控制性能,但能避免一大堆警告。

另一个坑是在循环里反复调用quadprog,每次都重新构造稀疏矩阵,导致仿真速度极慢。我建议把所有不变的结构矩阵提前算好存到params结构体里,循环内只更新与当前状态相关的f向量和b向量。这样速度能提升好几倍。

还有一个容易被忽略的点:quadprog默认用的算法对于大规模问题不一定快。可以在optimoptions里指定'Algorithm','interior-point-convex',同时设置'MaxIterations'和'OptimalityTolerance'。如果问题规模太大,直接把部分约束改稀疏矩阵构造,内存占用会小很多。

5.4 代码执行慢:如何加速

双层MPC仿真如果每个步长都做一次完整的二次规划,仿真时长可能让你等到怀疑人生。我做了一个15分钟上层、1秒下层、仿真24小时的案例,最开始用最笨的写法跑了将近20分钟还不一定能结束。

优化之后快了很多。核心操作有四个。

第一,所有MPC预测矩阵都用稀疏矩阵表示。Matlab对稀疏矩阵的运算在速度上有明显优势。

第二,上层MPC不需要每步都调用,只有到达上层调度周期才重新计算,其他时刻沿用上一次的参考轨迹。

第三,在生成H和f时,避免在循环内使用动态增长的向量。提前用zeros初始化好,循环里只做索引赋值。

第四,如果后段仿真只是为了验证算法,可以把控制周期从1秒改成2秒甚至5秒。实时响应会差一点,但趋势和逻辑不会变,用来调参效率极高。

6. 工程化落地的几点体会

代码跑通以后,我最大的感受是:仿真里的“完美”和工程里的“能用”之间还有一段不小的距离。模型预测控制确实强,但强在假设你知道精确模型,而实际系统里光伏预测有误差、通信有延迟、执行器有响应时间。

我在实际调参时发现,把上层控制周期设成5到15分钟是一个比较平衡的选择。太快了,预测信息和计算能力跟不上,而且调度指令频繁变化,底层的功率分配也跟着乱;太慢了,光伏突变完全补不上,储能压力全堆到下层,SOC很容易过界。

另外,双层结构中上层给下层传参考轨迹时,别只传一个单一数值。传一整段预测曲线,可以让下层在下一次上层调度到来前有平滑的过渡依据。我在代码里就是这么做的,效果比“每个周期只更新一个点”稳定得多。

还有一个细节想提醒大家:储能SOC的初始值和目标值要跟上层调度的设定保持一致。如果SOC目标设成50%,但初始值是80%,仿真前几个小时肯定都在努力回归目标,后端的功率曲线和成本曲线大概率都偏离正常情况。先让系统运行一段时间进入稳定状态,再统计结果,才比较有说服力。

如果之后要扩展这个项目,我建议先把单层MPC跑通,再改成双层;先把固定负荷跑通,再加随机扰动;先把并网模式跑通,再做孤岛切换。一步步来,排查问题会轻松很多。这套框架同样适合加入其他储能类型或者多台机组协调,只要下层模型里增加相应状态量和约束矩阵就行。

最后再说一个我踩过的坑:不要把MPC的所有参数都放到一个巨大的结构体里而不做注释。我有一段时间为了写论文方便,把所有参数全堆在init脚本里,结果仿真几天后改一个参数都像大海捞针。后来把所有变量按功能模块分组,每个参数加一行注释,调参效率明显提升。代码能调通不算结束,能让别人快速看懂你的代码,才是真正把项目做扎实了。

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

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

立即咨询