配电网韧性优化:移动储能预布局与动态调度策略
配电系统的“韧性”这个词这几年在电力圈里出现的频率越来越高。简单说它指的是配电网在遭遇极端灾害台风、冰灾、外力破坏时能够提前准备、故障中快速响应、灾后快速恢复的能力。而移动储能因为可以灵活移动位置、在关键时候给关键负荷临时供电几乎天生就是为配电网韧性服务的。我这次要复现的就是一套基于IEEE33节点系统的移动储能预布局与动态调度策略用MATLAB把整个两阶段的优化决策过程完整实现出来。这篇文章会把我踩过的坑、模型的构建逻辑、代码的框架结构、参数怎么调以及怎么从零跑通整套程序全都讲透。如果你正在研究配电网韧性、移动储能优化调度或者导师突然丢给你一个IEEE33节点的算例让你做预布局这篇文章应该能帮你少走很多弯路。我不打算讲太多虚的直接上干货从算例建模、故障场景生成到预布局模型、动态调度模型再到MATLAB代码里的求解器调用和结果分析每一步都拆开来讲。1. 项目整体设计思路为什么预布局必须和动态调度放在一起1.1 配电网韧性评估的基本逻辑要做移动储能的预布局和动态调度第一步不是写代码而是先理解问题本身。配电网韧性评估通常采用“灾前-灾中-灾后”三阶段框架。灾前对应预布局就是说在灾害来临之前移动储能车应该提前停靠在哪些节点灾中对应动态调度指的是灾害发生、网络出现故障后储能车如何根据实际的故障状态动态调整位置和出力灾后则是对故障元件进行修复让网络逐步恢复到正常状态。我这次复现的项目重点放在灾前的预布局和灾中的动态调度上。原因很简单灾前决策需要考虑的是“最坏情况下怎么保命”而灾中决策需要考虑的是“当前情况下怎么最优供电”。这两个决策在时间尺度上不同目标函数也略有不同但必须联合起来建模才符合实际调度需求。如果只做预布局不考虑动态调度那预布局方案很可能在真实故障场景中根本跑不动如果只做动态调度没有预布局给出的初始位置调度程序又没有初始解。所以两阶段模型不是堆砌而是逻辑闭环。1.2 移动储能与固定储能的对比选项很多人会问直接用固定储能不行吗固定储能确实建设简单、运维方便但在台风这种大面积故障场景下固定储能只能对本地负荷供电没办法跑到负荷重要度更高、失电更严重的区域去救急。移动储能车的优势就在于“靠得住、跑得动、送得快”。具体来说移动储能是一个典型的多状态资源它有位置状态、荷电状态SOC、充放电状态还需要考虑移动时间。也就是说决策变量里不仅有连续变量充放电功率、SOC还有二进制变量移动还是不移动、充还是放这个问题的复杂度一下子就上来了。用IEEE33节点系统来研究移动储能是因为这个系统规模不大不小既能体现网络拓扑约束又能用普通电脑在可接受的时间内解出结果非常适合作为算法验证的基准算例。1.3 两阶段模型的总体架构整套策略我把它归成两个关联又独立的优化问题第一阶段预布局。在灾害预警信息发布后已知可能的故障场景集合决策每台移动储能车应该预先停靠在哪一个节点。目标一般是最大化系统在最坏故障场景下的韧性指标比如最小负荷供应率、关键负荷恢复量等。第二阶段动态调度。在故障实际发生且部分元件被隔离后决策储能车在下一时刻移动到哪里、在哪个节点放电、放电功率多大目标通常是在当前场景下最大化恢复供电量同时满足网络安全约束。两个阶段通过储能车的初始位置和SOC状态衔接。预布局给出的位置和SOC就是动态调度的初始条件。这样的嵌套结构在数学上可以写成两阶段随机规划也可以用场景分解的方式逐场景求解。我这次采用的实现方案是在MATLAB中建立混合整数二阶锥规划MISOCP模型再用成熟的求解器求解。这样既能把潮流约束写成凸约束又能保证在可接受时间内收敛。2. IEEE33节点系统与移动储能参数从零搭建能被程序识别的算例2.1 IEEE33节点系统的拓扑和数据准备IEEE33节点系统是一个经典的配电网算例包含33个节点、32条支路额定电压12.66千伏总负荷大约3.7兆瓦左右。系统拓扑中有一个变电站节点作为根节点通过多条主干线和分支线向负荷供电。这套算例在网上有公开的标准数据但一旦要用于移动储能优化必须做一些专门的处理。我建议的第一步是把节点编号、支路编号、支路首端/末端节点、线路电阻和电抗、负荷有功和无功全部整理成表格。许多人的代码跑不通问题往往出在支路方向不统一或者是负荷功率的单位搞错了。MATLAB里处理这类数据我习惯用结构体数组来存比如branch.bus_i、branch.bus_j、branch.r、branch.x再配合一个bus_load数组存节点负荷。后面写潮流约束时直接调用这些字段不容易出错。对于移动储能接入的节点通常是在33个节点中选若干个候选节点。候选节点一般是负荷较大的节点、地理位置在拓扑中处于枢纽位置的节点或者是有重要负荷如医院、通信基站的节点。我这次选了节点8、18、25、33作为候选预布局位置。实际项目中你也可以通过负荷重要度和网络介数指标来筛选候选点。2.2 移动储能的主要参数设定移动储能车MESS的建模参数主要包括储能容量kWh比如我设置为500千瓦时。额定充放电功率kW比如150千瓦。初始荷电状态SOC一般设为0.5到0.8。移动速度与单位移动耗时比如从一个节点移动到另一个节点需要的时间。最大移动次数限制因为灾害场景下道路可能受阻不能假设无限移动。在动态调度模型里移动储能的放电功率不能超过额定功率同时SOC要维持在安全范围内比如0.1到0.9。此外储能车到达某个节点后才能在该节点放电这个“到达才能放电”的约束是通过二进制变量关联位置和功率来实现的。换句话说如果储能车没有在t时刻连接到节点i那么它在节点i的放电功率就必须为0。2.3 MATLAB代码的整体框架我用的是MATLAB R2020版本建模采用YALMIP工具箱这是一个纯粹的建模接口就像翻译器把你的优化问题翻译成求解器能理解的形式底层求解器用的是开源或商业求解器。如果没有YALMIP也可以直接用MATLAB自带的优化工具箱写混合整数规划但代码会冗长很多而且二阶锥约束很难处理。YALMIP的optimize函数封装得很友好调试起来也方便。代码框架大致分四个部分数据输入模块读入IEEE33节点拓扑、负荷、储能参数场景生成模块生成多种故障场景如线路断线、节点失电第一阶模型模块预布局优化第二阶模型模块动态调度优化并以第一阶段结果为初始条件。后面我会详细展开每个模块的具体实现。3. 预布局阶段的关键约束与目标函数怎么让储能车提前停在正确的位置3.1 故障场景集合的生成预布局模型最麻烦的是故障场景。灾害往往是随机的预布局阶段不知道具体哪条线路会断所以必须生成一批有代表性的故障场景然后让优化算法去针对这批场景做决策。我采用的场景生成方式是蒙特卡洛模拟。先设定每个线路元件的故障概率再抽样生成1000个场景然后用聚类算法比如K-means把这些场景缩减到10个有代表性的场景。为什么要聚类因为1000个场景直接代入两阶段优化求解时间会爆炸。10个场景就能兼顾代表性和计算复杂度。每个场景由一组断线支路索引组成比如场景1表示支路5、17、25断开场景2表示支路10、20、30断开。为了实现N-1或N-K故障模拟还可以采用枚举方式对每条支路单独断开形成N-1故障集。但对于韧性研究N-K更贴近真实灾情所以我建议至少生成双故障和三故障的场景。3.2 韧性评估指标的选择预布局模型的目标函数必须和韧性指标挂钩。我见过很多文献用“负荷削减量最小”或者“失电负荷最小”来表达。但纯粹用负荷量指标可能不够全面因为关键负荷医院和普通负荷居民在重要性上是不一样的。我这次选择的是“加权失电损失最小化”即给每个节点负荷一个权重权重越高代表越重要。目标函数写为[ \min \sum_{s \in S} p_s \sum_{i \in N} w_i P^{loss}_{i,s} ]其中(p_s)是场景s的概率(w_i)是节点i的负荷权重(P^{loss}_{i,s})是场景s下节点i的失电功率。这个指标简单直接但能够把预布局导向“优先保重要负荷”。当然你也可以使用“韧性指数”比如AREA指标恢复速率或者负荷恢复百分比。为了让程序更通用我在代码里设计了加权系数数组改起来非常方便。3.3 预布局决策的核心约束预布局阶段需要满足以下关键约束储能数量约束总共只有若干台储能车比如2台每台只能停在一个候选位置。这个约束是[ \sum_{i \in N_{cand}} x_{i}^{mess} N_{mess} ]其中(x_{i}^{mess})为0-1变量表示储能车是否预布在节点i。这里要注意一台储能车不能同时出现在两个位置所以每个候选节点最多一个储能车。拓扑连通约束预布局后的系统在故障场景下部分线路断开需要判断每个负荷节点是否通过未断开的支路与变电站连通。这个约束在预布局模型中通常被隐式处理但在动态调度模型中需要显式建立辐射状拓扑约束。我这里采用了一种简化方式用matpower或自建潮流函数计算每个场景下的潮流如果潮流不收敛说明存在孤岛或雅可比奇异。不过这种数值方法不够严谨更可靠的还是用图论中生成树的约束。我建议在代码里实现一个DFS函数判断节点是否连通作为预布局阶段的可行域检查。网络安全约束即便在灾害中已经恢复供电的区域也要满足节点电压约束如0.95~1.05 p.u.和线路容量约束。由于预布局模型通常不细算每个时刻的潮流所以可以用线性化的DistFlow方程近似。在实际代码中我对每个代表场景建立潮流约束然后在约束里加入储能放电功率变量形成场景耦合的混合整数规划问题。3.4 预布局模型的求解方法与代码结构预布局模型在YALMIP里实现时我习惯先定义主决策变量X_mess二进制数组长度等于候选节点数再定义场景相关的辅助变量比如每个场景下的放电功率、切负荷量、电压幅值等。由于场景之间通过(X_mess)耦合最终生成的是一个大规模混合整数规划。用求解器直接求解时如果场景数超过15个计算时间会飙到几分钟以上这还算可以接受。为了提高求解效率我采用了Benders分解的简化版本先只求解主问题不含场景潮流约束得到储能车位置后再对每个场景做校验子问题如果有不可行或更差的解再添加割约束回主问题。这个逻辑其实不复杂却能把求解时间从半小时压缩到三分钟。这一步非常关键因为做课题的时候你不可能每次都等一个小时。4. 动态调度模型储能车在故障中如何“跑位”与“出力”4.1 时间离散化与动态调度流程动态调度发生在灾中典型的时间步长是1小时总调度时长为24小时。故障在某个时刻发生比如t2小时之后配电系统进入故障运行状态。移动储能系统在每个时间步需要决策要不要移动、移动到哪个节点、在哪个节点放电、放电功率多大。在MATLAB代码里我建立了一个逐小时滚动优化的循环。每个时间步采集当前网络状态哪些支路已经断开、哪些负荷已经失电、当前储能车位置和SOC然后求解一个单时段优化模型得到本时段的调度指令。滚动优化的好处是能应对故障变化但坏处是需要反复求解计算开销大。另一种方式是多时段联立优化把24小时所有决策一次性求解这样的结果全局最优但模型规模会爆炸。我这次的动态调度采用的是“实时滚动多时段预测”的折中在每个时刻预测未来4个小时的故障场景优化未来4小时的决策只执行第1小时的结果。这么做接近模型预测控制MPC的思路鲁棒性比一次性全局优化强很多。4.2 移动储能运行约束的数学表达动态调度的核心约束分几组储能车位置约束储能车在任一时刻只能位于一个节点且从一个节点移动到另一个节点需要时间。若移动时间为1小时则t时刻储能车在节点it1时刻如果想在节点j放电必须满足t时刻到t1时刻的移动关系。这个约束通过二进制变量(y_{i,t}^{mess})表示位置并限制移动距离与时间的关系。充放电功率约束每台储能车在节点上作为电源时放电功率(P_{i,t}^{dis})要小于额定功率乘以位置变量[ 0 \le P_{i,t}^{dis} \le P_{rate} \cdot y_{i,t}^{mess} ]SOC动态方程[ SOC_{t1} SOC_t - \frac{P_{dis,t} \cdot \Delta t}{E_{cap}} \frac{P_{ch,t} \cdot \Delta t}{E_{cap}} ]灾害中移动储能主要作为电源放电但也不排除在安全区域用剩余电量充电。不过由于配电网自身故障实际上充电机会很少我主要考虑放电。线路潮流与电压约束动态调度中每个时段的潮流计算需要考虑故障支路。我将IEEE33节点系统的DistFlow线性化约束写入模型中即对于一个辐射状网络节点潮流满足[ P_{j} P_{i} - r_{ij} \frac{P_{ij}^2 Q_{ij}^2}{V_i^2} - P_{load,j} ]线性化处理后变为关于电压和功率的线性约束。在YALMIP里我把这类约束建模为二阶锥[ V_j^2 V_i^2 - 2(r_{ij}P_{ij} x_{ij}Q_{ij}) (r_{ij}^2x_{ij}^2)\frac{P_{ij}^2Q_{ij}^2}{V_i^2} ]然后用cone()函数表示二阶锥约束。这个细节是代码能否被求解器高效处理的关键。很多初学者写成非线性函数导致求解器报错或者根本算不动。4.3 负荷恢复与切负荷的建模动态调度中并不是所有负荷都能恢复。网络故障导致某些区域与变电站解列如果移动储能车容量不够就必须切负荷。在每个节点负荷的恢复量不能超过该节点的实际负荷需求。[ 0 \le P_{i,t}^{rec} \le P_{i,t}^{load} ]同时系统功率平衡要求所有恢复负荷加上网络损耗等于变电站注入功率加储能放电功率。在实际代码里我用了一个节点电压幅值平方的变量(u_i)来替换原方程中的二次项这样二阶锥约束自然满足求解器处理得更快。4.4 动态调度的目标函数动态调度的目标是在每个时间段内最大化加权恢复供电量[ \max \sum_{i \in N} w_i P_{i,t}^{rec} ]如果考虑多时段还要加入储能SOC的惩罚项防止储能车在早期把所有电量放光。所谓“贪心调度”在长时间灾害中是非常危险的可能出现前期恢复了重要负荷后期却无电可用的尴尬局面。所以在目标函数中加入剩余电量比例的正则项[ \max \sum_t \sum_i w_i P_{i,t}^{rec} \lambda \sum_t SOC_t ]系数(\lambda)一般设为一个很小的值比如0.001作用是让算法在同样恢复效果下倾向于保留更多的电量。我试验过这个正则项确实能显著提升后期负荷恢复水平。4.5 动态调度代码实现实例这里给出一个关键代码片段基于YALMIP展示如何构造单时段动态调度模型% 决策变量 P_dis sdpvar(n_mess, n_node, 1); % 储能放电功率 P_load sdpvar(n_node, 1); % 负荷恢复量 u sdpvar(n_node, 1); % 电压幅值平方 y_pos binvar(n_mess, n_node); % 位置选择 % 约束每台储能车只能在一个节点 for m 1:n_mess Constraints [Constraints, sum(y_pos(m,:)) 1]; end % 约束储能放电功率限制 for m 1:n_mess for i 1:n_node Constraints [Constraints, P_dis(m,i) P_rate * y_pos(m,i)]; Constraints [Constraints, P_dis(m,i) 0]; end end % 潮流约束DistFlow线性化 % ... 省略具体支路循环 % 目标函数加权恢复负荷最大化 Objective -sum(weight .* P_load); % 因为优化是min所以取负 % 求解 ops sdpsettings(solver, cplex, verbose, 2); optimize(Constraints, Objective, ops);这段代码是框架级别的实际运行需要补充潮流约束和场景参数。在完整代码里我还会加入移动时间约束确保储能车从上一时刻的位置只能移动到相邻可达节点。5. 常见问题与排查技巧复现这套程序的避坑指南5.1 潮流不收敛总是在某些场景下报错这是复现过程中最常遇到的问题。原因一般是构建的辐射状网络中出现了孤岛而孤岛内部没有平衡节点导致潮流方程无解。解决方法是在每个故障场景中先运行一次连通性检查把不与变电站相连的负荷节点标记为失电节点然后把这些节点的恢复功率直接设为0不参与潮流计算。只有与变电站通过未断线路相连的节点才需要写入潮流约束。另外DistFlow线性化需要注意支路的r和x数值。IEEE33系统电阻电抗都在0.1到1欧姆量级如果直接用国际单位数值差异巨大。我建议把电压、功率都换算到标幺值系统电压基准12.66kV功率基准1MVA这样模型数值稳定性会好很多。5.2 求解时间过长几小时都算不完如果求解器长时间不退出问题很可能出在三个方面。第一二进制变量过多。预布局阶段候选节点数和储能数量直接决定二进制变量个数如果能事先筛掉明显不合理的候选节点规模能减少一半。第二二阶锥约束太密集。每个节点每个时段都加二阶锥约束求解器内点法迭代会很慢。解决方法是在不太关键的时段省略电压约束只保留功率平衡约束。第三求解器参数没有调好。建议将mipgap设置为0.01即允许1%的误差而不是等到精确最优解。工程上1%的差异对结果影响很小但求解时间能降低80%以上。5.3 结果不合理储能车来回乱跑或者SOC突变出现这种结果一般是模型缺少移动时间约束。例如储能车从节点5到节点20不考虑路程耗时那么算法会让它每个时段都在不同节点充电放电完全不现实。解决办法是在位置变量之间添加递推关系如果上一时刻在i节点本时刻在j节点且i不等于j那么本时段必须被标记为“移动时段”移动时段不能放电。这样一来储能车在移动过程中无法恢复负荷调度程序就会权衡“跑去支援”还是“就地保电”。SOC突变往往是因为充放电效率设置错误或者时间步长与容量单位不匹配。比如如果容量500kWh时间步长1小时放电150kW一小时SOC应该下降0.3但如果代码里写成SOC SOC - P/Ecap且没有乘以时间步长就会导致SOC下降太快。检查这个公式是调试SOC曲线的第一优先级。5.4 代码中容易忽略的边界条件储能车初始位置必须在预布局方案中指定的候选节点中一致性。多个储能车不允许同时在同一节点接入需要添加互斥约束。故障线路恢复后动态调度中要考虑网络拓扑发生变化比如某个时刻线路被修复后续潮流约束要跟着更新。加权系数如果差异太大优化会完全忽略低权重负荷导致某些节点负荷一直无法恢复。可以设置一个最低恢复比例约束比如每个负荷节点至少恢复20%的负荷。5.5 代码复现的环境和平台建议我建议在MATLAB 2020以上版本运行YALMIP更新到最新的R2021版本并安装一个可用的求解器。如果求解器授权不好解决可以先使用开源的CBC求解器这是开源的验证小规模模型但大规模二阶锥问题可能需要更专业求解器。另外模型中的二阶锥约束需要在YALMIP中明确用cone定义否则求解器识别不了。6. 结果分析与扩展方案从一套代码到一个可用的决策工具预布局和动态调度的最终输出结果应该包括储能车的预布局节点位置、每个时段的SOC曲线、各节点的负荷恢复情况、以及系统整体韧性指标提升效果。以IEEE33节点为例假设有两台500kWh移动储能车在5个典型故障场景下通过预布局和动态调度关键负荷的平均恢复率可以从0提升到65%左右这个数字跟很多文献的结果是吻合的。这套代码还可以继续扩展。比如加入修复时间随机性让故障恢复时间服从某种概率分布进而做鲁棒优化。也可以考虑交通网络约束因为移动储能车上路行驶需要避开积水路段或断桥。更实际的是把移动储能和固定储能、柴油发电机联合调度形成多维韧性资源池。以上扩展方向在代码里都有相应的接口只要你把决策变量和约束条件按我前面讲的模块化思路加进去就能逐步搭建一个覆盖“预测-预布局-调度-评估”的完整框架。最后分享一个小技巧在调试整个代码时不要一上来就运行24小时动态调度。先固定预布局方案只优化单时段调度验证潮流和SOC逻辑正确再增加时域滚动。这样定位错误会快很多。我实际调试时把每个阶段的中间结果用save存成mat文件后面阶段直接读取避免重复计算同时也方便对照检查。我个人在复现这个项目时最大的体会是移动储能调度问题的难点并不在优化算法本身而是如何把“位置-电量-潮流-时间”这四类约束拼装得正确无误。每一步都像搭积木少一块积木整个模型就会塌。但只要按照“预布局定初值、动态调度做滚动、潮流约束管安全、SOC约束管电量”的逻辑来组织代码任何规模类似的配电网系统都能套用。希望这篇专栏能帮你把这块硬骨头啃下来如果你在复现中遇到其他奇怪的报错也可以顺着这个框架逐步排查。