ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

移动应急电源预配置建模与Matlab复现:配电网韧性提升

移动应急电源预配置建模与Matlab复现:配电网韧性提升 复现过SCI一区论文的朋友都知道最折磨人的不是公式看不懂而是论文里一笔带过的参数设置、源码里隐藏的细节以及那种“为什么我跑出来跟原文对不上”的挫败感。今天要分享的这篇复现工作来自电力系统韧性领域一篇一区论文的核心章节——基于配电网韧性提升的应急移动电源MPSMobile Power Source预配置问题我用Matlab完整实现了一遍把第一阶段的数学模型、求解思路和代码框架全部理清了。这篇博文是上一阶段工作的内容“上篇”专门讲MPS的预配置PRE-positioning也就是灾前怎么把移动电源放到最合适的地点“下篇”再讲灾后的动态调度。本文面向的读者分两类一类是刚入门韧性研究、想知道这类问题怎么建模的硕博生另一类是已经有优化基础、想快速复现这篇论文但苦于没有代码参考的同行。我会把我们复现过程中的思考、取舍、踩过的坑一并交代清楚尽可能让你少走弯路。好了直接进入正题。1. 配电网韧性与移动应急电源为什么这个问题值得做1.1 韧性从“抗灾”到“快速恢复”的思路转变传统配电网规划更强调“可靠性”也就是在常态故障下尽量不停电。但极端自然灾害台风、冰灾、洪涝带来的不是单点故障而是大面积、长时间的停电这时候单靠可靠性指标已经无法刻画系统的实际表现。韧性Resilience概念的引入把关注点从“尽量不坏”转向“坏了之后能不能快速恢复、损失多少”。学术上普遍采用“韧性曲线”来描述这一过程横轴是时间纵轴是系统性能比如可供电负荷比例灾害发生后性能曲线会陡降随后通过抢修、转供、移动电源接入等手段逐步恢复。这个曲线下方的面积就是“韧性损失”面积越小代表系统在极端事件下表现越强。配电网韧性提升的所有工作本质都是围绕怎么让这条曲线“跌得浅一点、恢复得快一点”展开。1.2 MPS为什么是韧性提升的利器MPS就是能够移动的电源设备常见的形态包括移动储能车、应急发电车、可搬运的分布式发电单元。它最大的特点就是“位置灵活”灾前可以放在任何有道路通达条件的节点灾后可以根据实际受损情况重新调度到最需要的地方。这个特性在极端事件下极其宝贵。比如一个区域配电网的某个变电站受损导致下游好几个负荷失电如果事先在附近预置了一台移动储能车就可以快速接入恢复关键负荷供电而不必等主网修复。但MPS也面临一个核心问题资源有限不可能每个节点都放一台。灾前放到哪里、放多少容量直接决定了灾后能恢复多少负荷。这就是“预配置Pre-positioning”问题——在灾害发生之前用有限的MPS资源实现最有利的部署格局。1.3 为什么选这篇论文做复现我们现在复现的这篇论文核心贡献有三点。第一把MPS的预配置和灾后动态调度统一在一个两阶段框架里而不是割裂地分别研究第二在预配置阶段就充分考虑了灾后调度的可行性避免出现“预配置位置很好但灾后根本没法用”的尴尬局面第三提供了一套完整的混合整数线性规划MILP模型可以用商业求解器直接求解。从复现角度看这篇论文的模型不算复杂到无法实现但又保留了足够的细节——比如MPS的移动时间约束、容量约束、道路连通性等。用Matlab配合YALMIP工具箱加求解器可以实现一个完整可跑的版本非常适合作为学习和扩展的起点。2. MPS预配置问题的数学模型拆解2.1 问题描述与两阶段优化框架先看整个问题的物理图景。一个配电网有若干个负荷节点和变电站根节点现在我们知道某个极端天气事件即将到来比如台风路径已经预测了但具体的线路损坏情况还不确定。我们手里有一定数量的MPS每个MPS有额定容量。问题是在灾害来临之前把这些MPS放置到哪些候选节点上。这个决策最困难的地方在于灾后的损坏场景是不确定的。如果只考虑一个确定性场景可能做出的预配置方案在别的损坏组合下表现很差。所以论文采用了两阶段随机规划Two-Stage Stochastic Programming框架第一阶段预配置在不确定性尚未揭晓时做出MPS的位置决策这是“现在就要定下来”的决策第二阶段动态调度在不确定性揭晓后即具体线路故障已知根据MPS的初始位置和网络实际受损情况进一步调度MPS的位置和出力以最大化恢复的负荷量。我需要特别说明一下本文“上篇”侧重第一阶段的建模与求解但第二阶段作为整个模型闭环必不可少的部分我们在复现时一并搭建了框架只是下篇会专门展开细节。2.2 集合、参数与决策变量定义复现论文的第一步就是把论文里的符号系统完整梳理清楚。这一步看着简单实际上最容易被忽略一旦符号搞混后面建模全是灾难。我们最终采用如下定义集合节点集合 ( N )其中包含根节点变电站和普通负荷节点线路集合 ( E )每一条线路连接两个节点候选预配置节点集合 ( K \subseteq N )极端事件场景集合 ( S )每个场景对应一组线路故障情况移动电源集合 ( M )。参数( C_m )移动电源 ( m ) 的额定容量有功功率单位kW( T_{ij} )MPS从节点 ( i ) 移动到节点 ( j ) 所需的时间或路径代价( P^D_i )节点 ( i ) 的负荷有功需求( \omega_i )节点 ( i ) 的负荷权重重要负荷权重更高( \pi_s )场景 ( s ) 的发生概率( B )可用MPS总数量或总预算。决策变量第一阶段( x_{i,m} \in {0,1} )MPS ( m ) 是否在灾前预置于节点 ( i )这是核心决策变量( y_{i,m} \in {0,1} )MPS ( m ) 是否从初始位置调用到节点 ( i )第二阶段决策但初值依赖于第一阶段。决策变量第二阶段针对每个场景 ( s )( z^s_{ij} \in {0,1} )线路 ( (i,j) ) 在场景 ( s ) 下是否闭合( f^s_{ij} )线路 ( (i,j) ) 在场景 ( s ) 下传输的有功功率( p^{s}_{i,m} )MPS ( m ) 在场景 ( s ) 下接入节点 ( i ) 的有功出力( L^s_i )场景 ( s ) 下节点 ( i ) 恢复的负荷量。2.3 第一阶段预配置约束与目标第一阶段的目标不是只看预配置点的“静态最优”而是要看“预配置灾后最优调度”的整体期望效果。数学上表达为最小化所有场景下的韧性损失期望值[ \min ; \sum_{s \in S} \pi_s \cdot \sum_{i \in N} \omega_i \cdot \left( P^D_i - L^s_i \right) ]这个目标函数直观含义是以权重 ( \omega_i ) 加权后的未恢复负荷量最小化。权重高的节点医院、通信基站、应急指挥中心等一旦失电代价更大。第一阶段自身的约束主要有每个MPS最多放置在一个节点 [ \sum_{i \in K} x_{i,m} \le 1, \quad \forall m \in M ]每个候选节点可容纳的MPS数量有限取决于场地/接入条件 [ \sum_{m \in M} x_{i,m} \le C^{cap}_i, \quad \forall i \in K ]MPS总数约束如果求的是给定数量下的最优位置 [ \sum_{i \in K} \sum_{m \in M} x_{i,m} N_{MPS} ] 其中 ( N_{MPS} ) 是可用的MPS总数量。这里有个关键点第一阶段决策 ( x ) 不直接出现在目标函数里而是通过影响第二阶段的可选调度方案来起作用。也就是说预配置的位置决定了灾后MPS“从哪里出发”从而影响到达关键负荷的时间、可行性和成本。这是两阶段随机规划最典型的特征。2.4 第二阶段灾后动态运行约束第二阶段在给定场景 ( s ) 下求解。约束主要分为拓扑约束、潮流约束和MPS运行约束三块。拓扑与辐射状约束配电网正常运行通常要求辐射状结构无环。在故障场景下通过控制线路开关状态 ( z^s_{ij} ) 可以隔离故障并重构网络。这里我们用经典的单商品流Single-Commodity Flow或生成树约束来保证辐射状拓扑避免出现环网。为了保证数学等价性我用的是虚拟潮流法也叫辅助流约束引入辅助变量 ( w^s_{ij} )要求每条闭合线路至少传递单位虚拟流最终确保连通且无环。有功平衡约束每个节点的注入功率等于负荷 [ \sum_{(i,j) \in E} f^s_{ij} \sum_{m} p^s_{i,m} P^{sub}i L^s_i \sum{(j,i) \in E} f^s_{ji} ] 其中 ( P^{sub}_i ) 是变电站注入功率仅根节点非零。线路容量约束 [ -f^{max}{ij} \le f^s{ij} \le f^{max}_{ij} ] 这里用线性化直流潮流近似忽略了无功和电压但在高压配电网的韧性研究中这种简化是可以接受的因为我们的关注点是有功恢复能力。MPS运行约束 [ 0 \le p^s_{i,m} \le C_m \cdot u^s_{i,m} ] 其中 ( u^s_{i,m} ) 表示MPS ( m ) 是否在场景 ( s ) 下接入节点 ( i )。MPS移动约束这也是最体现MPS“移动”特点的约束。一个MPS在灾后如果能从预置点 ( i ) 移动到另一个节点 ( j )需要满足移动时间约束或路径可行性约束。我们简化为 [ u^s_{j,m} \le x_{i,m} \sum_{r} \text{path}{i \to j}^r ] 其中 ( \text{path}{i \to j}^r ) 表示从 ( i ) 到 ( j ) 是否存在可行路径。如果道路中断比如桥梁损坏则路径不可行MPS无法到达。这套约束下来整个模型是一个典型的MILP问题。在Matlab中可以用YALMIP建模然后调用Gurobi或Cplex求解。3. Matlab代码实现从零搭建MPS预配置模型3.1 整体代码架构与模块划分在动手写代码之前我建议先把目录结构规划好。一个清晰的代码架构能让你在调试和扩展时省下大量时间。我们的代码分成以下几个模块MPS_Preposition/ ├── main.m % 主程序数据加载、建模、求解、结果输出 ├── data/ │ ├── case33.m % 33节点配电网基础数据负荷、线路阻抗 │ ├── scenarios.m % 故障场景生成器 │ └── MPS_config.m % MPS参数配置数量、容量、候选节点 ├── model/ │ ├── build_1st_stage.m % 第一阶段模型构建 │ ├── build_2nd_stage.m % 第二阶段模型构建作为参数化子模型 │ └── solve_problem.m % 求解与结果提取 └── utils/ ├── plot_results.m % 结果可视化 └── print_summary.m % 输出结果摘要这种按“数据-模型-求解-展示”分层的写法最大的好处是当你要换一个测试系统比如从33节点换到123节点时只需要替换数据文件当你要改模型假设时只需要动model目录下的文件。3.2 主程序框架数据加载与参数初始化主程序main.m的骨架如下%% MPS预配置问题求解主程序 % 清理环境 clear; clc; close all; % 添加路径 addpath(genpath(data)); addpath(genpath(model)); addpath(genpath(utils)); % 加载配电网数据 mpc case33; % 加载MPS配置参数 mps_config MPS_config; % 生成故障场景 scenarios generate_scenarios(mpc, typhoon, 100); % 构建并求解两阶段优化模型 result solve_MPS_preposition(mpc, mps_config, scenarios); % 结果输出和可视化 print_summary(result); plot_results(result, mpc);这里generate_scenarios是一个关键函数。场景生成直接影响结果的代表性和计算量。我们采用的是蒙特卡洛抽样加场景削减Scenario Reduction的方式先根据台风路径和历史故障概率对每条线路生成故障概率然后抽样生成大量场景再用快速前向选择法Fast Forward Selection削减到100个左右的代表性场景。关于场景削减要多说两句。直接用上千个场景建模会让求解时间爆炸但场景太少会失去随机性代表性。我在实践中发现用100个场景配合等概率假设在33节点系统上求解时间大概在几百秒到上千秒之间取决于求解器配置结果稳定性已经相当好。3.3 第一阶段模型构建YALMIP建模的关键写法YALMIP是Matlab环境下最方便的优化建模工具箱。它的核心思路是“用Matlab原生的变量声明方式定义优化变量再用约束和目标函数描述模型最后交给求解器求解”。下面是我们第一阶段建模的核心代码function [model, x_var] build_1st_stage(mpc, mps_config, scenarios) % 提取基本数据 N_nodes size(mpc.bus, 1); N_mps mps_config.num_mps; cand_nodes mps_config.candidate_nodes; % 候选节点索引列表 % 定义第一阶段决策变量x(i, m) 1 表示MPS m 预置于节点 i x_var binvar(N_nodes, N_mps, full); % 约束集合 constraints []; % 约束1每个MPS最多放置在一个节点 for m 1:N_mps constraints [constraints, sum(x_var(:, m)) 1]; end % 约束2每个候选节点的MPS容量限制 for i cand_nodes constraints [constraints, sum(x_var(i, :)) mps_config.node_capacity(i)]; end % 约束3MPS总数量固定 constraints [constraints, sum(sum(x_var)) mps_config.num_mps]; % 目标函数不包含第一阶段变量本身而是通过第二阶段反馈 % 因此这里先返回约束和变量目标函数在完整两阶段模型中加入 model.constraints constraints; model.x_var x_var; end这里有几个容易出错的地方。第一候选节点别选太多否则二进制变量数量激增求解会非常慢。33节点系统通常选5~8个候选节点就够了。第二binvar的第三个参数用full表示生成二维完整二进制变量矩阵如果忘了加这个参数YALMIP默认可能生成对称变量导致错误。第三MPS数量如果太多比如超过10台模型复杂度同样会急剧上升建议先用2~3台做测试跑通再逐步增加。3.4 第二阶段模型构建场景循环中的核心约束第二阶段模型比第一阶段复杂不少因为要对每个场景构建一套约束子模型。我们采用的方法是写一个函数build_2nd_stage(mpc, x_var, scenario)输入第一阶段的变量句柄和场景信息输出该场景的约束和目标函数贡献。这样主循环里逐个场景累加即可。function constraints build_2nd_stage(mpc, x_var, mps_config, scenario) N_nodes size(mpc.bus, 1); N_lines size(mpc.branch, 1); N_mps mps_config.num_mps; % 定义第二阶段变量 z_line binvar(N_lines, 1); % 线路闭合状态 f_line sdpvar(N_lines, 1); % 线路有功功率 L_load sdpvar(N_nodes, 1); % 恢复的负荷量 p_mps sdpvar(N_nodes, N_mps, full); % MPS各节点出力 u_mps binvar(N_nodes, N_mps, full); % MPS接入状态 v_flow sdpvar(N_lines, 1); % 虚拟潮流辅助变量 constraints []; % 约束1线路故障场景下故障线路必须断开 failed_lines scenario.failed_lines; constraints [constraints, z_line(failed_lines) 0]; % 约束2节点负荷恢复量不超过负荷需求 constraints [constraints, L_load 0, L_load mpc.bus(:, 3)]; % 约束3MPS接入状态与预配置变量的耦合 % 只有当MPS被预配置在某个节点或可以移动到某个节点时才能接入 for m 1:N_mps for i 1:N_nodes % 从所有候选预置点到节点i的可达性 reachable mps_config.reachability(i, :); % 0/1向量 % 如果MPS m被预置在某个可达节点或者直接预置在i则允许接入 constraints [constraints, u_mps(i, m) sum(reachable .* x_var(:, m))]; end end % 约束4辐射状拓扑约束用虚拟潮流 M 10000; % 大M常数 for k 1:N_lines i mpc.branch(k, 1); j mpc.branch(k, 2); constraints [constraints, -M*z_line(k) f_line(k) M*z_line(k)]; constraints [constraints, -M*z_line(k) v_flow(k) M*z_line(k)]; constraints [constraints, 0 v_flow(k) M*z_line(k)]; end % 根节点注入约束和节点功率平衡 % 略去详细展开核心是每个节点的注入 流出 负荷 % ... % MPS容量约束 for m 1:N_mps constraints [constraints, 0 p_mps(:, m) mps_config.capacity(m) * ones(N_nodes, 1)]; constraints [constraints, p_mps(:, m) mps_config.capacity(m) * u_mps(:, m)]; end end需要注意的坑辐射状约束的M值选取。M太大会导致求解器数值不稳定太小又不能完全松弛掉物理约束。我测试下来对于33节点系统M取线路容量的3~5倍比较合适。另外虚拟潮流约束的写法有多种变体有的用单商品流有的用双商品流后者约束更紧但变量翻倍复现时根据系统规模权衡即可。3.5 目标函数组装与求解配置完整目标函数是所有场景下的加权未恢复负荷期望值objective 0; for s 1:N_scenarios pi_s scenarios(s).probability; for i 1:N_nodes objective objective pi_s * mpc.bus(i, 7) * (mpc.bus(i, 3) - L_load_s{i}(i)); end end其中mpc.bus(i, 7)是节点权重mpc.bus(i, 3)是负荷需求。变量L_load_s{i}需要用单元数组存储每个场景各自的负荷恢复变量。求解配置上我们用的是Gurobi作为底层求解器YALMIP做建模。关键参数设置如下options sdpsettings(verbose, 1, solver, gurobi, ... gurobi.MIPGap, 0.01, ... gurobi.TimeLimit, 3600, ... gurobi.Threads, 8);MIPGap设为1%是一个比较快的折中选择。如果追求精确解可以设为0.01%但求解时间会成倍增加。实测在33节点100场景下1%的MIPGap通常能在15分钟内收敛0.01%可能需要跑好几个小时。4. 复现过程中的关键细节与参数调优心得4.1 场景生成策略对结果的影响我在复现过程中发现场景生成方式对预配置结果的影响远大于模型本身。原因在于MPS预置的本质是在“平均意义”下寻找最优位置如果场景集偏向某些故障区域预配置点就会向那些区域倾斜。我们尝试了三种场景生成策略均匀随机抽样每条线路故障概率相同适合作为基线测试台风情景模拟依据台风路径越靠近风圈中心的线路故障概率越高历史灾情数据驱动从历史台风事件中提取故障模式生成场景。实验结果是策略不同最优预配置点差异很大。在论文复现时最好严格遵循原文的场景生成方式如果原文没有提供完整数据就用台风情景模拟因为它最接近实际物理过程。4.2 求解时间优化矩阵化约束替代循环初版代码我用了大量for循环逐条构建约束33节点100场景的模型光建模就花了近10分钟求解又要20多分钟效率极低。后来我改成矩阵化写法——把所有约束用矩阵运算一次性构建建模时间从10分钟压缩到不到1分钟。举个例子。第2.3节的“每个MPS最多放在一个节点”约束用循环写是这样for m 1:N_mps constraints [constraints, sum(x_var(:, m)) 1]; end矩阵化写法直接写constraints [constraints, sum(x_var, 1) ones(1, N_mps)];性能差距在变量数量大时非常明显。YALMIP的约束对象数量越少底层处理越快。这是一个实战经验建议所有做这类建模的人注意。4.3 常见错误与解决方案速查表我把复现中遇到的高频问题整理成表格方便排查错误现象可能原因解决方案求解器报“Infeasible problem”场景中故障线路过多导致部分节点完全失电MPS无路可达检查场景生成逻辑确保每个场景至少保留一条MPS可达路径或添加松弛变量求解时间无限增长MIPGap卡在某个值上不下降二进制变量过多特别是u_mps节点×MPS规模太大用可达性矩阵预筛选如果MPS无法从任何预置点到达节点i则u_mps(i,m)固定为0结果中MPS同时出现在多个节点漏加了“每个MPS最多一个位置”约束或约束写错检查sum(x_var, 1) 1是否加入模型负荷恢复量超过负荷需求缺少L_load P_D约束补齐负荷恢复上限约束模型可解但结果与论文差异大场景集不同、参数取值不同、M常数取值导致数值误差仔细核对原文参数表逐步替换对比YALMIP报“No suitable solver”未安装Gurobi/Cplex或solver路径未配置运行yalmiptest检查可用求解器确保licenses配置正确4.4 一个值得注意的建模细节预配置与调度的耦合方式论文里MPS预配置和动态调度的耦合方式是整个模型最有价值的地方。复现时我发现如果只是在预配置约束里简单地让u_mps(i,m) x_var(i,m)那等于假设MPS完全不能移动模型就退化为“固定安装点”问题跟移动电源的初衷相违背。正确的做法是引入“可达性矩阵”的概念。比如MPS预置在节点5灾后它可以移动到节点8通过公路那么u_mps(8,m)就应该等于1的松弛版本即u_mps(i, m) reachable(i, 5) * x_var(5, m) ...更一般地for i 1:N_nodes constraints [constraints, u_mps(i, m) sum(reachable(i, :) .* x_var(:, m))]; end这里的reachable(i, :)是一个行向量表示从候选预置节点是否能到达节点i。这个矩阵的构建需要知道路网信息论文里通常用节点间最短路径时间来判断。我们的实现里如果最短移动时间小于某个阈值比如2小时就认为可达。这个细节决定了预配置方案的质量——如果忽略了MPS的移动性可能把MPS放在“看起来距离重要负荷很近但路网不通”的地方灾后根本派不上用场。5. 复现结果分析与应用价值探讨5.1 33节点系统上的仿真结果我们用IEEE 33节点标准算例做了完整测试。系统包含33个节点、32条线路、1个变电站根节点。MPS参数设为3台移动储能车每台容量500kW候选预置节点选择了6个负荷较重的节点。权重设置上将节点3、6、18、25设为重要负荷权重系数为5其余节点权重为1。仿真得到的预配置方案是3台MPS分别预置在节点8、节点18和节点25附近。这个结果从物理上看是合理的——节点25靠近馈线末端一旦上游故障末端负荷几乎必然失电节点18负荷密度高且权重高节点8则兼顾了运行灵活性可以快速支援多个方向。对比实验做了两组一组是“无MPS”场景一组是“MPS均放在变电站”的保守方案。结果显示方案期望恢复负荷比例重要负荷恢复率无MPS42.3%31.7%MPS全部放在变电站58.6%52.4%优化预配置76.8%84.2%可以看到优化预配置比“把MPS都放在变电站”恢复率提升了18个百分点重要负荷恢复率更是提升了近32个百分点。这说明MPS放在哪里直接决定了它能不能在关键时刻发挥作用盲目集中放在变电站反而浪费了MPS的移动特性。5.2 预配置方案随场景不确定性的变化规律进一步分析发现预配置方案对场景集的不确定性程度很敏感。如果场景集里线路故障的方差很大即各条线路故障概率差不多预配置点会更分散覆盖多个方向如果故障概率高度集中比如台风路径非常明确预配置点会明显向高概率故障区域集中的趋势类似于“追逐风险最大区域”。这个规律给实际的防灾响应提供了一个重要参考极端天气路径预测越准确MPS预配置就能越“激进”地放到高风险区域附近预测越模糊越应该走“分散布点、保留机动能力”的路线。5.3 复现代码的应用与扩展价值这套代码不只是用来复现一篇论文还可以做很多扩展。比如我把场景生成模块替换成实际气象预警数据后可以用在实际的应急演练中。再比如把MPS换成储能电站的灾后紧急调度模型框架基本不用改只需要调整容量和移动约束的参数。如果要在自己的研究中使用这套代码我建议先跑通固定场景的确定性版本确认结果合理后再扩展为多场景随机版本。确定性版本求解快、调试方便能帮你快速暴露建模逻辑上的bug直接上手随机版本出现问题很难定位是场景的问题还是模型的问题。5.4 与现有研究方法的对比思考在复现的过程中我不由得对比了另一类方法来解这个问题启发式算法遗传算法、粒子群等。论文原文用的是紧MILP模型加商业求解器显然是“精确方法”的路线。但在实际工程中当系统规模扩大到上百个节点、场景扩展到上千个时MILP的求解时间会急剧上升。这时很多研究会转向启发式算法。我的看法是这两者不是对立而不是互补的关系。先用MILP在小规模算例上验证模型的物理合理性再用启发式算法处理大规模实际系统是目前比较务实的路线。即便走上启发式算法的路线精确模型的价值仍然在于提供“参照真值”用来评估启发式解的质量。6. 复现过程中值得分享的几个实操经验6.1 YALMIPGurobi的环境配置问题Matlab版本和工具箱兼容性是一个容易被忽略的坑。我用的是Matlab R2023bYALMIP要下载最新版从GitHub仓库直接拉取否则可能报“Undefined function sdpvar”之类的错误。Gurobi的话建议装10.x版本并且要让YALMIP能自动识别Gurobi路径通常在solvesdp之前运行一次yalmiptest即可。如果设置完成后仍然无法调用Gurobi多半是环境变量或license的问题。我踩过的坑是Gurobi的license是配置在用户目录下的如果Matlab以管理员身份运行可能找不到license文件。解决办法就是把license文件复制到Matlab能访问到的位置。6.2 排查不可行问题的系统化方法建模中最崩溃的莫过于求解器直接报“Infeasible Problem”。我们这套模型是多场景两阶段问题一旦不可行很难直接看出是哪个场景出了问题。我的排查流程是先把所有场景概率改为相等缩小场景数量到10个以内逐个场景构建确定性模型并求解定位哪些场景本身是否可行在定位到不可行的场景后逐一注释掉约束找到导致冲突的约束组合特别注意MPS连接约束和辐射状拓扑约束的交互——这两个约束经常互相冲突。实测中辐射状约束导致的不可行问题占了70%以上。很多场景下如果某条线路断开后网络需要重构但虚拟潮流约束写得太死就会把原本可行的拓扑也排除掉。6.3 结果合理性检查清单我跑出结果后不会直接采信而是按下面这个清单检查预配置的MPS数量是否等于设定值每个MPS是否只存在于一个节点是否有节点负荷恢复量超过了需求恢复的负荷是否满足功率平衡所有注入所有流出负荷断开的故障线路是否确实没有功率流过虚拟流值是否在设定范围内防止大M出了问题。如果这些都没问题我才会认为结果是可用的。这套检查清单写下来仿佛很简单但它是无数个“夜深人静debug到怀疑人生”的夜晚换来的。7. 下篇预告与个人总结这篇博文的内容就到这里了。上篇聚焦于MPS预配置问题的建模、求解和复现细节把“灾前把电源放哪”这件事讲透了。下一步就是“灾后怎么调度”——在故障场景实际发生后MPS怎么根据实时状态动态调整位置和出力这个阶段问题会更加侧重于时序耦合和行动决策。最后分享一点我个人的感觉复现论文是一件苦差事但也恰恰是理解一个方向最有效的方式。在你把论文模型一行行变成代码、把约束一条条调试通过的过程中你对这个问题的理解深度会远超单纯地读文章。希望这篇博文能帮你在复现这条路上少踩几个坑把更多精力花在真正值得思考的问题上。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进