多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

模型预测控制在微电网调度优化中的应用与Matlab实战

模型预测控制在微电网调度优化中的应用与Matlab实战 开题报告里的“基于模型预测控制MPC的微电网调度优化的研究Matlab代码实现”我前前后后带过好几届学生做也在实际园区微网项目里用MPC跑过日内调度。说实话这个方向现在火是有原因的微电网里光伏、风电、负荷全在波动储能SOC、柴油机爬坡、联络线功率上限这些约束又互相牵扯传统查表规则早就力不从心。MPC恰好就是干这个的——用预测模型往前看一段时域滚动求解带约束的优化问题再把第一步控制量下发执行如此循环。这篇文章我不讲虚的直接从调度问题的本质、MPC建模、Matlab代码实现一路写到调试排坑把我实际做过的经验全部摊开。这个内容适合几类人看一是做微电网调度方向毕业设计的硕士生二是想把MPC从公式变成可跑代码的工程师三是刚接触预测控制、想知道这玩意到底怎么落到微电网场景的研究者。只要你手头有Matlab装了优化工具箱或者YALMIP跟着下面的思路走一天之内把开环仿真跑通没有太大问题。1. 为什么微电网调度选择MPC而不是其他方法1.1 微电网调度到底在优化什么很多人一开始就把问题想窄了以为微电网调度就是“每个时刻让功率平衡就行”。实际上它是个典型的多时段耦合动态优化问题储能SOC今天充了多少直接决定明天还能放出多少柴油机从20%出力升到80%出力爬坡时间可能要好几分钟大电网购电电价在不同时段差一大截。任一时段的决策都会通过储能状态、爬坡速率这些“状态量”影响后续时段的可行域。我用一句话概括这个问题的本质在满足供需平衡和设备物理约束的前提下确定未来若干个控制周期内储能充放电功率、柴油机出力、联络线购售电策略使得总运行成本最低同时保证系统安全。这句话看着简单但要同时满足“带约束”“多时段耦合”“运行成本”“安全性”就已经排除了大部分传统方法。基于规则的调度比如“光伏多了就充电、负荷高了就放电”实现简单、鲁棒性强但完全不考虑电价差异和运行成本经济性很差而且规则的人工经验太重微电网拓扑一变规则就作废。实时经济调度的思路更短视只算当前时刻最优完全不考虑储能后效实际跑起来容易出现“现在拼命放电、下一小时SOC见底”的尴尬局面。启发式算法如遗传算法、粒子群做离线全局搜索很猛但计算太慢天气一变你没法在线重新滚动。MPC的思路上来就把这些痛点掐住了。我还记得第一次给学生讲MPC时的类比开车从A到B不是出发前一次性规划好整条路线然后闭眼开而是每几百米重新看一眼路况把未来几十秒或几分钟的路径重新算一遍只执行当前这一步。MPC调度微电网就是这个逻辑预测模型相当于导航地图滚动优化相当于重新规划反馈校正相当于利用实时量测修正偏差。1.2 MPC的三要素如何落到调度上MPC的核心三要素是预测模型、滚动优化、反馈校正这三条分别对应着微电网调度中的具体环节。预测模型。微电网里的预测模型分两块一是设备本身的数学模型比如储能SOC演化方程、柴油机出力上下限、爬坡约束这些是物理层面确定性的二是外界扰动的预测序列也就是未来一段时间的光伏出力预测、负荷预测、电价序列。光伏和负荷预测精度不可能100%准但MPC的优势就在于它不要求预测完全准确只要趋势大体对滚动机制会自动修正。滚动优化。在每个采样时刻控制器以当前状态为起点求解未来N个时域的优化问题得到一串最优控制序列但只执行序列里的第一个控制量。下个时刻新量测进来状态更新再把整个优化问题重新解一遍。注意这里的时间窗在往前“滚动”每一步都在用最新信息刷新决策。我见过的调度程序只要时间窗滚动起来即使预测数据有一定误差实际运行也不会太离谱。反馈校正。公式上体现为每步优化前用当前时刻的真实SOC、真实负荷去修正状态初值如果模型里有不确定项还可以引入状态估计器把模型预测值和实测值之间的偏差补偿回去。这一点是MPC区别于开环最优控制的分水岭。1.3 几种调度方案的对比为了让你直观理解选型逻辑我列个实际对比表这个表也是我之前给学生做开题报告时的底稿方案是否考虑多时段耦合是否处理约束在线计算量对预测误差的适应能力典型适用场景规则调度否部分处理极低弱简单并网/离网控制实时经济调度否能处理当前时刻低中电价响应、需求响应启发式算法GA/PSO是能处理高离线尚可弱需重新寻优容量规划、日前离线优化模型预测控制是能处理中等强日内滚动调度、多时间尺度协调从这张表能看出来MPC的定位很明确它不强调一次性算出“全天最优”而是强调“每个时刻都能做出目前信息下最优的决策”。在微电网这种预测不确定性较强的场景里这种滚动决策带来的鲁棒性价值远大于理论上的全局最优。我个人做项目时的经验是MPC跑出来的累计运行成本往往比规则调度低5%到15%前提是模型没建错、权重没乱调。2. 微电网设备建模与MPC关键参数设计2.1 设备模型怎么写做MPC调度第一步永远不是写控制器而是把微电网里每个设备的数学模型写清楚。我按常见拓扑一个个过。储能电池。最核心的是SOC演化方程离散形式写成SOC(k1) SOC(k) Pb(k) * Ts / E其中Pb(k)为储能功率正为充电、负为放电单位kWTs为采样周期单位hE为储能额定容量单位kWh。如果严格区分充放电效率这个方程会变成分段或带0-1变量的问题后面我再说。初学者先用线性效率近似比如统一取0.95把主逻辑跑通再去加复杂度。储能的约束有两个SOC范围约束一般取0.2到0.9充放电功率上下限约束取决于PCS变流器容量。注意很多同学会漏掉“SOC不能突变”这一条导致优化结果里储能功率在相邻时段疯狂跳变这在工程上是绝对不允许的。柴油发电机/燃气轮机。出力约束是下限加爬坡约束。出力下限固定比如最低稳定出力占额定30%上限是额定功率。爬坡约束指的是相邻两个控制周期之间出力变化不能超过一定速率比如每15分钟最多爬50kW。MPC里这类约束写成相邻决策变量差值的上下限非常好处理。柴油机的启停状态如果是0-1变量那就是混合整数模型会让求解难度上一个台阶初学阶段建议先不考虑启停。光伏和负荷。一般不把它们当控制变量而是当作预测扰动输入直接代入功率平衡方程。光伏发电受天气影响大可以采用“预测曲线误差修正”的方式预测曲线来自历史数据、气象预报或AI预测模块MPC代码里直接读入就行。负荷也是同理居民负荷、工业负荷预测序列作为已知输入。与大电网的联络线。常见的简化模型是联络线功率上下限约束以及购电电价、售电价。允许向电网卖电时目标函数里要区分购电和售电成本这部分优化变量逻辑会复杂一点因为需要判断正负。我建议新手先做“只买不卖”的并网模型把MPC本身跑顺再扩展为双向功率流动。2.2 目标函数里的每一项都对应什么MPC调度优化的目标函数本质上就是运行成本的数学表达。最常见的形式是J Σ (C_buy * Pgrid * Ts) Σ (C_fuel * Pdiesel * Ts) Σ 电池老化惩罚 Σ 权重惩罚项第一项是向大电网购电的成本C_buy在不同时段取值不同——这就是峰谷电价带来的优化空间。第二项是柴油机燃料成本一般是出力的二次函数工程上经常线性化处理。第三项电池老化惩罚常用表达式是跟充放电深度相关的也可以用充放电功率平方项代替目的就是让储能别总在极限状态下工作。最后一类是软约束对应的惩罚项用于放宽原本可能冲突的约束。我自己调参的一条铁律所有项的物理量纲必须统一。电价单位是元/kWh而功率平方项的单位是kW^2直接加一起就会出问题。平方项前的权重系数通常要除以某个基准值才能和其他项同一个数量级。一个更稳妥的做法是先只保留购电成本和燃料成本把其他惩罚项全部设成0跑通整体逻辑后再一项一项加惩罚并观察效果。一上来就把五个权重全部配上结果只会是每个都不对。我之前遇到过一位同学一直觉得MPC算出的结果“很奇怪”储能总在电价低的时候不充电、电价高的时候反而放电——后来发现是老化惩罚权重太大把电价套利空间吃掉了。这种问题不用怀疑什么算法理论先检查权重大概率是目标项量级不匹配。2.3 预测时域、控制时域、采样时间怎么选三个参数直接决定MPC的效果和求解速度。我按实操经验逐个说。采样时间Ts。对微电网日内调度常用15分钟或1小时。15分钟粒度能捕捉负荷和光伏的快速变化但一天就有96个时点优化问题规模大1小时粒度模型小但对负荷突变响应偏慢储能策略毛糙。我实际项目里如果只做有功调度、不涉及电压/频率快速响应15分钟足够如果做日内计划和日前计划两级协调日前用1小时步长、日内用15分钟步长各干各的最合适。注意分布式光伏波动剧烈时采样时间太长会把峰值都平滑掉调度策略就失去意义了。预测时域Np。Np要覆盖系统动态的主要变化周期。对日内调度场景一天是最典型周期所以Np取到9615分钟间隔覆盖全天是理论上的“完全预测”。但这会导致每个控制周期的优化问题规模巨大在线计算吃力。实际项目中我常用Np24也就是往前看6小时。6小时足以覆盖一个上午或下午的光伏/负荷变化趋势也不至于让计算负担压垮控制器。在离线仿真里可以试一次Np96看看“上帝视角”能省多少钱你往往会发现滚动优化和离线优化的结果差距没那么大——这是MPC的魅力。控制时域Nc。控制时域表示未来有多少步控制变量被当作决策变量自由优化Nc之后保持最后一步不变。工程上Nc设定为3到10步就够用不用等于Np。原因是减少决策变量能显著加快求解速度而性能损失很小。我常用的组合是Ts15minNp24Nc5这样储能功率决策变量只有5个连同一个Np的联络线功率QP规模大约300个决策变量以内用quadprog或OSQP基本秒级求解完全够在线滚动。还有一点关于稳定性标准的线性MPC如果约束和权重设计不当可能出现终端状态跑飞。我在调度场景里通常给SOC加一个终端约束比如终止SOC要回到初始值附近或者加终端惩罚项这样既保证了日间调度策略的可持续性也在客观上让优化结果更合理。不要直接拿来就用终端约束设太死也可能让无解风险变大建议加“软终端约束”配合松弛变量。3. 用Matlab实现MPC调度的两条路线与核心代码3.1 实现路线怎么选Matlab里做MPC有两条常见路线我分别说清楚你自己选合适的。第一条是MATLAB MPC Toolbox自带mpc对象和nlmpc对象配置好状态空间模型后交给Simulink或mpcmove就能跑预测控制。好处是封装度高几行代码就能搭出经典MPC坏处是目标函数和约束的定制性受限比如你要写复杂的阶梯电价、电池老化成本、启停逻辑自定义起来非常别扭。第二条是YALMIP 求解器quadprog、OSQP、Gurobi等。YALMIP是一个建模工具箱可以把优化问题写成符号表达式然后自动调求解器。这种方式对研究型代码友好几乎任何目标函数和约束都能表达可视化调参直观也是我给学生推荐的主力路线。代价是你得自己写“滚动优化”的循环但这对理解MPC机制反而有好处。不同Matlab版本下YALMIP的安装路径略有差异新版可以在附加功能管理器里直接搜或从GitHub拉源码添加到路径设置好求解器路径即可。我测试过R2022b和较新的R2026b环境核心代码不受版本影响只要YALMIP和求解器能正常调用就行。3.2 核心调度代码与逐段说明下面给一段可以直接跑通主逻辑的YALMIP代码实现“光伏储能购电”并网微电网的滚动优化调度。为便于理解我做了简化不考虑柴油机储能效率近似线性只允许购电。%% 参数设置 Ts 15/60; % 采样周期单位h15分钟 E 500; % 储能容量kWh SOC_init 0.5; % 初始SOC SOC_min 0.2; SOC_max 0.9; Pmax 100; % 储能最大充放电功率kW Pgrid_max 300; % 联络线最大购电功率kW Np 24; % 预测时域 %% 模拟预测数据实际使用时换成预测模块输出 load_pred 50 30*sin(2*pi*(1:Np)/12); % 负荷预测kW pv_pred 40*max(0, sin(pi*(1:Np)/12)); % 光伏预测kW price 0.6 0.3*((1:Np)8 (1:Np)20);% 分时电价元/kWh %% 决策变量 SOC sdpvar(1, Np1); % SOC轨迹多一步存末端 Pb sdpvar(1, Np); % 储能功率正为充电kW Pgrid sdpvar(1, Np); % 购电功率kW Constraints []; for k 1:Np % 储能SOC动态 Constraints [Constraints, SOC(k1) SOC(k) Pb(k)*Ts/E]; % SOC与功率约束 Constraints [Constraints, SOC_min SOC(k1) SOC_max]; Constraints [Constraints, -Pmax Pb(k) Pmax]; % 功率平衡购电光伏负荷充电Pb0为负荷 Constraints [Constraints, Pgrid(k) pv_pred(k) load_pred(k) Pb(k)]; % 联络线约束 Constraints [Constraints, 0 Pgrid(k) Pgrid_max]; end % 末端SOC约束 Constraints [Constraints, abs(SOC(Np1) - SOC_init) 0.05]; %% 目标函数购电成本 储能功率平滑惩罚 Objective sum(price .* Pgrid) * Ts 0.1*sum(Pb.^2)*Ts; %% 求解 ops sdpsettings(solver, quadprog, verbose, 0); sol optimize(Constraints, Objective, ops); %% 取值 SOC_opt value(SOC); Pb_opt value(Pb); Pgrid_opt value(Pgrid);这段代码的每一行背后都有讲究。第一SOC动态里的Pb*Ts/E因为Ts单位是小时所以充电电量单位是kWh除以容量E得到SOC增量单位制统一清爽。如果Ts你写成分钟那么这里就算不对了我踩过这个坑。第二功率平衡写成Pgrid pv load Pb意思是光伏和购电共同承担负荷和充电功率。这个等式如果不加优化结果就会出现“既充电又弃光”或“既放电又购电”的荒唐解。别笑我见过不少初版代码里忘了这个约束结果MPC一边从电网高价买电、一边给电池充电看起来成本还低——那完全是把能量守恒丢了。第三末端SOC约束abs(SOC(Np1)-SOC_init) 0.05这个约束的意思是在预测窗口结束时储能回到初始电量附近。实际调度中通常要求每天循环能持续所以这约束很重要。不过要注意如果你的Np只有24步6小时这个约束可能限制储能利用效率当预测时域覆盖全天时它才是完全合理的。我建议初学阶段设一个宽松的偏差范围比如0.05到0.1避免无解。第四目标函数的0.1*sum(Pb.^2)*Ts是功率平方惩罚目的是让储能充放电曲线更平滑不要出现频繁冲击。这个0.1是我常用初值实际得根据购电成本量级调整反正原则就是让它只起平滑作用、不要压制电价套利。3.3 仿真闭环中容易被忽略的细节上述代码只是单次优化真正的MPC仿真需要把它放到滚动循环里。伪逻辑如下初始化真实SOC for 每个时刻t 根据最新预测序列和当前SOC求解优化问题 只取Pb_opt(1)下发执行 通过设备模型更新真实SOC加入扰动 下一时刻预测序列刷新重复。实操中容易翻车的是以下几点我逐个说。每个周期必须用当前真实量测更新状态初值而不是沿用上一轮优化算出的预测SOC。我见过有同学的代码把上一轮squeeze(value(SOC(2)))当成下一轮初值结果是开环控制预测误差越滚越大到后面SOC全飘了。正确做法是每个周期从外部“量测模型”获取当前SOC作为初值。预测序列要滚动更新。循环内部load_pred和pv_pred不能是固定数组的第1到24个点而应该是从当前时刻t开始的第t1到t24个点。很多离线代码出bug就是因为预测序列没有滚动切片导致仿真和单次优化没区别。我建议写成load_pred load_profile(t1:tNp)这种形式越简单越不容易错。数据单位全程统一。这是个老生常谈但永远有人踩的坑。功率用kW、能量用kWh、时间用h这个体系从头贯穿到尾。如果计算SOC时不小心把15分钟写成15SOC直接飞掉而且目标函数里的电量也差4倍最后结果看起来好像也对实际成本全算错了。我习惯在代码开头写一大段注释标明单位每次调试前先过一遍单位。别急着上Simulink。研究阶段先用m脚本把滚动优化逻辑跑通画SOC和功率曲线确认合理再考虑Simulink联合仿真。Matlab与Simulink联调虽然直观但问题定位链路长一旦报错你很难分清是MPC代码问题还是信号线接错。直接m脚本循环输出好调试跑通了再迁移。4. 常见问题与调试实录4.1 求解失败、实时性不够、曲线抖振我踩过的坑这一节全是真金白银的排坑记录每个问题我都见过不止一次。求解器报“infeasible problem”无解。这是MPC调试里最常见的拦路虎。原因通常是三类一是约束之间互相冲突比如SOC上下限、功率上下限和能量守恒方程组合起来根本没有可行解二是预测时域太长加上终端约束太死后半程的负荷预测把可行域堵死了三是某个数值出了问题比如SOC初值0.5但预测序列里光伏和负荷的差值远超过储能容量允许范围。处理方法先把约束全部放开只保留能量守恒和简单功率上下限确认问题能解再逐步加回约束看哪一步开始无解。同时强烈建议在SOC约束、末端SOC约束里引入松弛变量soft constraint允许小幅度越界但付出惩罚代价这样模型对预测异常有包容力。每个周期求解时间太长实时性达不到。我碰到过用Gurobi解一个带整数变量的MIQP单步耗时几十秒完全无法滚动。解决路径几条把整数变量去掉先做连续MPC把预测时域Np从48砍到24甚至16把不必要的高阶多项式目标降为线性或二次使用optimizer对象预编译优化问题避免每次循环重复调用sdpvar和optimize。YALMIP的optimizer相当于把问题固定下来只更新参数速度能提升一个数量级。调度曲线抖振严重。储能功率逻辑上在每分钟内频繁反转这在实际设备上会要命。原因往往是没有控制量变化率约束也没有在目标函数里加平滑惩罚。处理办法是我前面代码里的Pb.^2惩罚或者干脆加显式变化率约束-Delta_max Pb(k1)-Pb(k) Delta_max。但要注意Delta_max设太小会牺牲经济性储能无法快速参与电价套利一般先设成最大功率的20%到30%观察效果再调。SOC老是顶在边界上。如果优化结果总让SOC贴着0.2或0.9跑说明目标函数里储能的使用“免费”系统可劲用电池省钱。这种情况我一般分两步处理一是给SOC目标值加软约束让SOC在优化中向0.5附近靠拢二是给SOC距离边界的偏差加惩罚项比如w * sum((SOC - 0.5*SOC_max).^2)。另外SOC的上下限本身不要设到物理极限留5%到10%的安全裕量这样控制器的解才不会总游走在边界上实际运行也更安全。预测误差一大MPC效果还不如规则调度。这通常不是算法问题而是反馈校正环节没做。MPC的鲁棒性依赖每步用新量测修正状态如果SOC模型误差大又没引入状态估计或补偿项预测误差就会持续累积。我建议先把储能SOC方程尽力和实际设备标定一致再考虑加一个简单的偏差修正SOC_used SOC_measured biasbias来自历史预测误差的滚动平均。这个朴素方法对大多数项目够用别一上来就上卡尔曼滤波项目周期不允许。4.2 问题速查表与操作建议下面这张表是我给学生做调试时用的速查表基本能覆盖80%的MPC调度代码问题问题表现排查方向推荐处理求解器报无解约束冲突、预测序列异常、末端约束过紧加松弛变量逐步放开约束定位单步求解时间过长决策变量多、整数变量多、求解器配置差缩Np/Nc去整数化用optimizer预编译储能功率抖振缺乏平滑惩罚或变化率约束加Pb平方惩罚或变化率约束SOC总顶边界储能使用成本太低、权重不匹配加SOC软约束和边界惩罚滚动后误差累积开环控制、状态未用新量测更新每步重新用当前量测做状态初值成本比规则调度还高目标函数项量纲不统一、权重失衡先只留电费项调通后再逐项加预测序列没滚动切片错误、固定数组检查load_pred(t1:tNp)切片逻辑最后一条操作建议先把单次优化跑通再闭环滚动。单次优化只做一次看SOC轨迹在预测时域内是否合理、功率平衡是否满足、目标函数值和手算对照是否正确。这一步逻辑通了再加循环。很多同学一上来就写完整仿真循环出了问题根本分不清是控制器逻辑错还是仿真接口错。另外强烈建议每轮仿真保存三张图调度功率曲线图、SOC轨迹对比图、累计成本对比图MPC vs 规则调度。这三张图既是论文的核心支撑也是你判断代码是否正确的第一依据。曲线长得怪一定是代码有错而不是算法不行。我个人实际做下来最大的感受是MPC调度优化的核心难点从来不在MPC公式本身而在模型细节与参数是否经得起推敲。SOC方程单位处理好、约束之间不自相矛盾、目标函数权重有的放矢、滚动循环正确更新状态这套代码基本就能交付了。至于终端约束、不确定性建模、随机MPC都是后续可以继续丰富的内容。有项目经验的同学会发现先把基础版本跑稳比什么都重要。
返回列表