ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

混合储能微电网双层能量管理系统:模型预测控制与Matlab实现

混合储能微电网双层能量管理系统:模型预测控制与Matlab实现 今年搭混合储能微电网的双层能量管理系统时我又一次把“双层”做成了“两个独立控制器各干各的”——上层调度指挥了半天下层一个功率突变就把计划打得稀碎。后来把模型预测算法重新梳理透才明白所谓双层不是两层各写一个MPC那么简单。这篇就把整套系统的设计思路、MPC原理和Matlab代码实现全部摊开来说包括仿真中掉进去的坑适合正在做模型预测控制、混合储能或微电网系统研究的同学直接参考。这个项目做的具体是一个并网型微电网含光伏、风机、电池、超级电容、常规负荷再加一个和主电网的连接点。结构不算复杂麻烦全在控制上——既要让日运行成本尽量低又要在秒级时间内扛住功率冲击还不能让电池频繁深度充放导致提前退役。用模型预测算法做双层能量管理正好把这两个互相打架的目标拆给两个时间尺度去解决。1. 为什么单层控制器搞不定微电网储能调度1.1 微电网波动的多时间尺度决定了控制必须分层微电网里的扰动从来不是单一节奏的。光伏遇到云层遮挡输出功率在分钟级往下掉风机碰上阵风功率是秒级波动负荷那边更随意几毫秒到几秒都可能出现冲击。再叠加分时电价这种小时级的外部信号一个微电网的控制问题实际上横跨了毫秒到小时五个数量级。单层控制器在这个跨度下会非常尴尬。如果决策周期做得足够短想跟上秒级波动那么预测时域不可能太长因为优化算力撑不住导致“未来几个小时怎么运行更经济”这个问题根本没机会被考虑。反过来如果把优化周期拉长到小时级做经济调度那秒级的功率冲击谁来管电池、逆变器还没反应过来母线电压就不好看了。还有一层原因是数学结构上的。经济调度天然适合写成线性规划或混合整数规划变量是各时段的功率计划、启停状态、购售电状态而实时控制更适合用状态空间模型做MPC变量是每步的控制增量。两种问题强行揉进一个优化器要么模型被简化到失去物理意义要么求解时间长得没法投入实时运行。所以在工程实践里更稳妥的做法是拆成两层上层慢决策管经济性下层快控制管动态响应。这个思路在电力系统里其实很经典类似“自动发电控制经济调度”的分工只是到了微电网和储能场景实时性要求更高下层也必须用上MPC才跟得上。1.2 双层架构的信息流与职责划分这个系统的双层架构我最终是这样定的。上层是运行调度层采样周期15分钟预测时域取6小时输入是光伏、负荷、电价的超短期预测值输出是未来各时段储能的基准功率和并网功率计划。它关心的唯一问题是在满足功率平衡和储能约束的前提下这一天的购电成本、售电收益、储能老化代价加起来怎么最省。下层是实时控制层采样周期1秒预测时域30秒输入是上层刚下发的基准功率加上本地实时测量值输出是电池和超级电容各自实际充放多少功率。它不关心明天电价贵不贵只关心接下来几十秒里储能能不能又快又稳地把功率跟踪上同时把高频毛刺滤掉。两层之间不是一次性的“下发指令、执行完事”而是滚动迭代每个上层周期到来时下层把最近的实际SOC、功率限幅情况反馈上去上层基于新状态重新算一轮计划。这样即使预测有误差系统每个15分钟都会修正一次路径不会一条道走到黑。一句话总结就是上层管“明天怎么跑更省钱”下层管“接下来几秒钟怎么跟得上”中间用一条功率基准指令和一个状态反馈闭环串起来。2. 混合储能系统的对象建模电池与超级电容的互补逻辑2.1 一次负荷冲击暴露单一储能的短板先说为什么非要用混合储能。假设系统里只有一组额定功率100kW的电池某个时刻负荷突然跳涨300kW功率平衡要求储能瞬间补上这个大缺口。电池能不能硬扛物理上勉强能扛但代价很大大倍率放电会让电芯温升加速、循环寿命明显缩短而且很多BMS在软件层面就限制了短时功率实际能放出来的功率远小于额定值。那只有超级电容行不行超级电容功率密度高瞬时几百千瓦很轻松但能量密度低得可怜。一套能把300kW顶住10分钟的超级电容容量成本会高得离谱。就算容量够它也没法承担几小时的平抑任务。所以最合理的组合就是电池加超级电容并联。电池用能量密度换长时间支撑超级电容用功率密度换瞬时响应。控制上的分工也就顺理成章低频、长时间分量交给电池高频、瞬态分量交给超级电容。这也是混合储能领域常说的“高低频分解”思路。2.2 等效电路模型与关键参数选取建模这块我的做法偏工程实用没有上复杂的电化学模型。电池用一阶戴维南等效电路开路电压加内阻加一个RC网络够描述动态特性超级电容用串联RC模型就行。SOC估算用安时积分加开路电压校正和大多数BMS的思路一致。项目里用的参照参数如下表实际参数要根据具体设备规格调整项目电池储能超级电容额定容量500 kWh5 kWh最大充放功率100 kW50 kWSOC运行区间0.2 ~ 0.90.1 ~ 0.95响应时间秒级毫秒级循环寿命数千次数十万次在MPC的状态方程里储能模型其实可以非常简洁。离散化之后的状态更新就是SOC_bat(k1) SOC_bat(k) - η_bat * P_bat * Δt / E_bat SOC_sc(k1) SOC_sc(k) - η_sc * P_sc * Δt / E_sc这里η是充放电效率Δt是采样周期E是额定容量。符号约定要统一放电方向功率为正SOC下降充电方向为负SOC上升。别小看这套符号约定我在代码里因为充电时SOC反而上升导致优化方向反了这种低级错误调试了整整一个下午。真正容易出问题的是效率项。如果MPC预测模型里效率取固定常数而仿真plant模型里是按DC/DC变换器的功率-效率曲线算的两者就会出现明显的模型失配MPC滚出来的控制序列看起来合理实际执行效果却总差一截。我后来把效率分成充电效率和放电效率两个值再按功率区间做分段线性化预测精度才勉强够用。2.3 把容量约束和效率约束写成优化问题能识别的形式储能约束要写进优化问题不能只在模型里摆着。常用的约束集合整理如下P_bat_min ≤ P_bat(k) ≤ P_bat_max P_sc_min ≤ P_sc(k) ≤ P_sc_max SOC_bat_min ≤ SOC_bat(k) ≤ SOC_bat_max SOC_sc_min ≤ SOC_sc(k) ≤ SOC_sc_max |P_bat(k) - P_bat(k-1)| ≤ ΔP_bat_max |P_grid(k)| ≤ P_grid_max其中爬坡约束尤其重要。电池的功率变化率限制是保护电池寿命的关键手段之一它相当于告诉MPC你可以让电池出力但不能让它在1秒内从-50kW跳到80kW。超级电容就不太需要爬坡约束它的本性就是快。还有功率平衡等式约束微电网内部功率之和必须时刻平衡P_pv P_wt P_bat P_sc P_grid P_load这个等式是所有微电网MPC的硬约束也是最容易造成优化无解的原因之一。后面避坑部分我会专门讲怎么处理。3. 模型预测控制算法在两层控制器里分别扮演什么角色3.1 MPC滚动优化的核心机制MPC最核心的思想可以拿开车导航类比。导航不会在出发时把所有路口的转向一次性定死而是每走一段根据实时路况重新计算接下来的路径。MPC也是这个逻辑在每个采样时刻用当前状态和预测模型向前优化未来N步但只执行第一步到下一个采样周期重新算一遍。这带来一个关键优势反馈校正。即使预测模型有误差只要每个周期能拿到真实状态做校正系统就不会彻底跑偏。我在做单层MPC对比实验时故意在预测模型里加了15%的光伏预测误差MPC的跟踪效果还是能把误差压在5%以内。这就是滚动优化和开环优化的本质区别。MPC的标准代价函数可以写成下面这种形式后续两层控制器都是它的一种变形J Σ( w1 * (y(k) - y_ref(k))^2 w2 * Δu(k)^2 w3 * (SOC(k) - SOC_ref(k))^2 )w1管跟踪精度w2管控制动作的剧烈程度w3管SOC的偏离程度。三个权重配比不同MPC的性格完全不同。3.2 上层MPC目标函数从运行成本到储能老化惩罚上层的经济调度MPC目标函数是运行经济性。以我的项目为例包含三项购电成本按分时电价乘从电网买的功率售电收益光伏大发时向电网卖电的收入储能老化惩罚电池功率越大、SOC越深折算的寿命损耗成本越高。写成形似J_up Σ( c_buy(k) * P_grid_buy(k) - c_sell(k) * P_grid_sell(k) α * |P_bat(k)| β * (SOC_bat(k) - SOC_ref)^2 )其中α是电池功率导致的寿命损耗系数β是SOC偏离目标值的老化惩罚系数。为什么加SOC偏离项因为电池长期停在满充或满放状态会加速衰减让SOC尽量待在0.5附近比反复冲击上下限要划算得多。上层MPC的决策变量包含电池功率、超级电容功率、并网功率、购售电状态等。因为是15分钟一个采样点、预测6小时总共24步决策变量规模大约一百多个用混合整数二次规划求解毫无压力几十毫秒就能出结果。这里有个容易误解的地方上层MPC不追求让超级电容精确跟踪任何指令它只管给一个相对平缓的基准功率带。超级电容的主要用途在下层上层只需要保证它SOC不要太离谱就行。3.3 下层MPC目标函数功率跟踪与超级电容SOC恢复下层的实时MPC目标函数完全不同它关心的不是钱是跟踪精度和动态品质J_down Σ( λ1 * (P_bat(k) P_sc(k) - P_ref(k))^2 λ2 * (P_bat(k) - P_bat(k-1))^2 λ3 * (SOC_sc(k) - SOC_sc_ref(k))^2 )第一项是整个混合储能系统实际出力要贴着上层给的参考值走第二项是电池的爬坡惩罚权重拉大逼着MPC尽量让电池出力变化平缓第三项是超级电容SOC维持在参考值附近保证它随时有容量应对下一次冲击。有意思的是下层MPC里我并没有显式地做高通滤波但爬坡惩罚权重不一样之后高频分量自然就落到超级电容头上了。因为电池每步功率变化要罚重金而超级电容不受这个限制MPC优化下来一定是电池出平稳部分、电容啃毛刺。这就是把高低频分解问题转化成了权重设计问题比额外加一个滤波环节要干净利索得多。4. Matlab代码实现从数学模型到可复现的工程框架4.1 文件组织与数据流设计我写这类仿真目录结构基本固定。sheep_dispatch/ ├── data/ # 预测序列光伏、负荷、电价 ├── model/ # 模型参数与状态方程函数 ├── controllers/ # upper_mpc.m lower_mpc.m ├── plant/ # 仿真对象带效率曲线和非线性的储能模型 ├── plot/ # 结果可视化脚本 └── main_sim.m # 双层滚动主循环这样划分的好处是调参不容易找错地方。每个模块参数集中在model/params.m里定义仿真主循环只负责调度控制器只负责算指令plant只负责把指令变成真实的功率和SOC。后面做敏感性分析时改参数只需动一个文件不会牵扯到控制器逻辑。4.2 求解器配置Yalmip搭配Gurobi还是用内置quadprogMatlab里做MPC优化我推荐用Yalmip做建模层。它的语法接近数学公式定义约束和目标函数非常直观而且底层求解器可以随时切换。项目里上层MPC用Gurobi求解MIQP下层MPC用OSQP或Matlab自带的quadprog都能跑。如果只是做研究验证没有Gurobi学术授权也不影响quadprog对付连续变量的QP绰绰有余。只有当上层MPC引入购售电0-1状态变量时才需要真正的混合整数求解器。实际规模不大时Yalmip自带的bnb分支定界也能顶一顶只是速度慢一些。最需要注意的是循环里的建模方式。千万不要在滚动优化的每一步重新定义sdpvar变量和约束集合那样内存占用会以肉眼可见速度疯涨跑几百步就开始卡。正确做法是在仿真开始前一次性定义优化问题循环内只更新参数数值再调用optimize函数。4.3 上层MPC核心代码骨架拿上层MPC做一个简化示意%% 上层MPC经济调度采样15min预测24步 function [P_bat_ref, P_sc_ref, P_grid_ref] upper_mpc(param, forecast, soc_now) % 变量定义只做一次 P_bat sdpvar(1, param.H_up, full); P_sc sdpvar(1, param.H_up, full); P_grid sdpvar(1, param.H_up, full); SOC_bat sdpvar(1, param.H_up1, full); u_sell binvar(1, param.H_up); % 购售电状态 % 目标函数购电成本 - 售电收益 老化惩罚 J sum( param.c_buy .* (1-u_sell) .* P_grid ... - param.c_sell .* u_sell .* P_grid ... param.alpha * abs(P_bat) ... param.beta * (SOC_bat(2:end) - param.soc_ref).^2 ); % 约束集合 C []; C [C, SOC_bat(2:end) SOC_bat(1:end-1) - param.eta_bat * P_bat * param.dt_up / param.E_bat]; C [C, SOC_bat(1) soc_now]; C [C, SOC_bat param.soc_bat_min, SOC_bat param.soc_bat_max]; C [C, P_bat param.P_bat_min, P_bat param.P_bat_max]; C [C, P_sc param.P_sc_min, P_sc param.P_sc_max]; C [C, abs(P_grid) param.P_grid_max]; C [C, forecast.P_pv forecast.P_wt P_bat P_sc P_grid forecast.P_load]; ops sdpsettings(solver,gurobi,verbose,0); optimize(C, J, ops); P_bat_ref value(P_bat); P_sc_ref value(P_sc); P_grid_ref value(P_grid); end这套代码去掉约束细节核心逻辑已经完整。注意状态变量SOC_bat多了一个维度为了把初始SOC和后续每一步的状态更新串起来这是MPC建模的常见技巧。4.4 下层MPC核心代码骨架下层MPC结构类似但变量和约束简单很多%% 下层MPC实时功率跟踪采样1s预测30步 function [P_bat_cmd, P_sc_cmd] lower_mpc(param, P_ref, soc_bat_now, soc_sc_now) P_bat sdpvar(1, param.H_down, full); P_sc sdpvar(1, param.H_down, full); SOC_bat sdpvar(1, param.H_down1, full); SOC_sc sdpvar(1, param.H_down1, full); J sum( param.lambda1 * (P_bat P_sc - P_ref).^2 ... param.lambda2 * diff([P_bat_prev, P_bat]).^2 ... param.lambda3 * (SOC_sc(2:end) - param.soc_sc_ref).^2 ); C []; C [C, SOC_bat(2:end) SOC_bat(1:end-1) - param.eta_bat * P_bat * param.dt_down / param.E_bat]; C [C, SOC_sc(2:end) SOC_sc(1:end-1) - param.eta_sc * P_sc * param.dt_down / param.E_sc]; C [C, SOC_bat(1) soc_bat_now, SOC_sc(1) soc_sc_now]; C [C, P_bat param.P_bat_min, P_bat param.P_bat_max]; C [C, P_sc param.P_sc_min, P_sc param.P_sc_max]; C [C, abs(P_bat(2:end) - P_bat(1:end-1)) param.delta_bat_max]; optimize(C, J, sdpsettings(solver,quadprog,verbose,0)); P_bat_cmd value(P_bat(1)); P_sc_cmd value(P_sc(1)); end函数只返回第一步的指令值这也是MPC“只执行第一步”原则的体现。4.5 双层滚动主循环的实现主循环把两层串起来%% 双层滚动主循环 for k 1:sim_steps t k * dt_down; % 每15分钟触发一次上层调度 if mod(t, dt_up) 0 [P_bat_ref, P_sc_ref, P_grid_ref] upper_mpc(param, forecast, soc_bat_now); end % 每秒触发下层跟踪参考取上层计划当前时刻的值 P_ref_now P_bat_ref(ceil(t/dt_up)) P_sc_ref(ceil(t/dt_up)); [P_bat_cmd, P_sc_cmd] lower_mpc(param, P_ref_now, soc_bat_now, soc_sc_now); % 仿真对象更新用带效率曲线的plant模型 [soc_bat_now, soc_sc_now, pv_actual] plant_update(param, P_bat_cmd, P_sc_cmd); end上层计划是阶跃型参考下层负责让实际出力平滑地逼近它。这个过程看着简单调试时特别容易出现上层参考跳变时下层还没来得及跟踪就被下一轮调度刷新了参考值的情况。解决思路是让上层采样时刻和下层采样时刻对齐或者在下层参考值外面加一个变化率限制器。5. 仿真场景设计、评价指标与结果解读5.1 典型工况怎么构造才有说服力做仿真最怕只有一个“理想平稳工况”。我设计场景时习惯叠加三类典型事件让系统真正“忙”起来光伏云影遮挡t300秒时光伏从1MW在30秒内跌到0.3MW之后再爬回来负荷投切t600秒时突然接入0.4MW冲击负荷分时电价切换每4小时切换一次峰谷电价迫使上层调度做出不同决策。这三类事件分别覆盖了秒级波动、分钟级渐变、小时级经济性三个时间尺度正好检验双层架构能不能各司其职。如果仿真只跑平稳工况MPC的滚动优势根本体现不出来一个PI控制器可能都够用。5.2 四类核心评价指标与对比表我习惯用四个指标评判系统好不好日运行成本反映经济调度效果电池峰值倍率反映电池承受的瞬态压力倍率越高寿命损耗越大SOC越限次数反映约束边界是否被频繁触碰并网功率波动率反映微电网与主网交换功率的平稳程度波动率越大越不友好。同在“光伏突变负荷投切”工况下单层MPC和双层MPC的对比结果大致长这样评价指标单层MPC双层MPC日运行成本基准值下降约8%~12%电池峰值倍率基准值下降约30%以上SOC越限次数基准值显著减少并网功率波动率基准值下降约35%~50%这些数值是同类系统仿真的典型相对水平具体值取决于电池容量、电价曲线和工况设置不必纠结绝对值重点看趋势双层架构确实同时改善了经济性和动态品质电池寿命相关的指标提升尤其明显。5.3 从曲线形态判断控制策略是否达到了设计意图曲线比表格信息量大得多。我拿到仿真结果第一眼看的是电池功率曲线——它应该是平滑的没有高频毛刺然后看超级电容功率曲线——它应该是张牙舞爪的承担了所有尖峰再看并网功率曲线——它应该贴着参考值走既不落后也不振荡。如果电池功率曲线出现了明显抖动或者超级电容出力很小而电池在剧烈折腾说明下层MPC的爬坡惩罚权重λ2不够大或者上层参考值下发频率太高。这些都是曲线形态直接暴露出来的问题光看指标平均值反而会被掩盖掉。6. 这套系统里最容易踩的坑6.1 模型失配预测模型和仿真对象必须“同源”最经典的坑是预测模型和plant模型参数对不上。我早期把预测模型里的电池效率设为常数0.95但plant模型里按功率-效率曲线算轻载时效率只有0.85MPC每次预测都高估电池可用容量结果SOC轨迹越跑越偏。解决思路很简单预测模型和plant模型用同一份参数plant里有的非线性预测模型至少要做分段线性近似别图省事全部常数化。否则后面所有调试都会迷失在“为什么预测和实际对不上”的泥潭里。6.2 约束不可行硬约束会把优化问题逼到死角上层MPC的功率平衡等式加并网功率上限一旦光伏预测偏乐观而实际出力不够约束就会互相矛盾Gurobi直接报infeasible。处理方案有二一是给等式约束加松弛变量让功率平衡允许有微小偏差代价函数里加大对松弛变量的惩罚二是把并网功率上限从硬约束改成软约束允许短时越限但重罚。我实测下来加松弛变量是最省事的不会因为数值原因让整个仿真中断。6.3 采样时间与预测时域太快算不完太慢失去意义双层采样时间不是随便拍的。上层用过15分钟下层用过1秒。有次我把下层采样时间改到0.1秒去追求“更精细的控制”结果MPC每步求解时间和采样时间接近整个仿真进度条肉眼可见地停滞而且跟踪效果并没有本质提升。经验是采样时间至少要满足求解时间小于1/5采样周期这一条经验法则。预测时域则是够用就好上层预测6小时能覆盖夜间低谷和早高峰电价切换下层预测30秒足够覆盖负荷冲击后的动态过程。6.4 权重系数的调参顺序权重系数尽量不要闭着眼一起调。我的顺序是先把λ1拉到足够大保证跟踪精度再把λ2逐步加大观察电池功率曲线开始变平滑就停下最后调λ3让超级电容SOC能在负荷间隙回到参考值附近。每一步都留当时的仿真结果做基线改一个参数对比一次不然最后系统出了问题根本不知道是谁引入的。7. 如果让我重做一遍我会换一种做法这个项目做完之后最深的体会是先把闭环逻辑用最笨的方式跑通再去堆算法复杂度。如果重新来我会先用理想电源模型模拟储能让上层调度和下层跟踪先联调通过再逐步把电池效率曲线、超级电容自放电、预测误差这些真实因素加进去。每一步加进一个非理想因素就重跑一遍基线场景记录指标变化这样出了问题能立刻定位是哪一层哪个环节引起的。还有一件事我觉得值得提醒所有做类似方向的人Matlab仿真里“跑通”不等于“跑对”。同样的代码预测误差设0和设15%结果天差地别。写论文或者做工程验证时一定要把预测误差、模型不确定性这些真实场景因素包含进去否则你的双层MPC在理想世界里再漂亮放到实际光资源和负荷数据里也未必站得住脚。最后分享一个小技巧滚动优化循环里所有需要反复查询的参数提前做成struct字段循环里直接用不要每次调用都去读取外部文件。这个小改动可能让你的仿真时间直接缩短30%以上尤其当下层MPC跑到几万步时差距非常明显。
返回列表