☰
配电网韧性之MPS预配置:两阶段随机规划建模与Matlab实现
2026/10/8 4:24:24 网站建设 项目流程

配电网韧性研究这几年最热门的方向之一,就是应急移动电源(MPS)在灾害前后如何发挥最大价值。而MPS预配置,作为整个“预配置+动态调度”体系的第一步,恰恰是最容易被初学者轻视、却最影响复现结果的一环。我翻了不少SCI一区论文,也自己动手用Matlab复现过类似的模型,发现很多人卡住的地方并不是动态调度,而是第一步预配置就没弄明白:MPS应该提前停在哪、为什么停在那、这个决策和灾后的调度是什么关系。这篇先把(上)写透——只讲MPS预配置的建模思路和Matlab实现,动态调度细节留到(下)再展开,这样两篇合起来正好构成一个完整的两阶段随机规划复现闭环。

先说这系列文章的适用对象:正在复现配电网韧性相关论文的研究生、想用Matlab做灾害场景模拟的工程师、以及需要给移动储能电站做前期规划方案的同行。这篇文章不会只丢一个“论文模型”给你,而是会拆清楚模型每一层约束背后的物理含义,再给出可以落地运行的Matlab代码框架。看完之后,你至少能回答三个问题:预配置为什么是两阶段问题里的第一阶段?预配置目标函数到底在优化什么?怎么用Matlab把预配置模型搭出来并求出合理的方案。

1. 研究问题拆解:配电网韧性提升与MPS预配置到底解决什么问题

1.1 配电网韧性:从“停电”到“快速止血”

传统配电网可靠性研究关注的是一般性故障:某条线路跳闸、某台配变过载,这类故障持续时间短、影响范围可控,常规保护与调度就能应付。但配电网韧性(Resilience)面对的完全是另一类问题——极端灾害场景下,多条馈线可能同时跳闸,变电站出线甚至母线都会失压,整个配电网可能陷入大面积停电。台风的狂风暴雨、冬季冰灾的线路覆冰、地震造成的杆塔倒伏,都属于典型的“高影响-低概率”事件,不可能用平时那套可靠性指标去评估。

学界描述配电网韧性时,最常用的工具是韧性曲线:横轴是时间,纵轴是系统剩余供电能力或恢复负荷比例。一场极端事件发生后,曲线会先快速跌落,然后随着故障隔离、应急供电、抢修恢复逐步回升。韧性研究的核心目标,就是要把这条曲线的“跌得慢一些、谷底浅一些、回升早一些”给做出来。MPS预配置就是典型的事前措施:在灾害发生前的预测预警期,把有限的移动电源布置到合理节点,为灾后快速建立应急供电走廊做好物理准备。

这里有必要定义一下MPS。在不少论文里,MPS写作Mobile Power Source,也可以理解为移动储能车(MES)、移动柴油发电车,或者广义的“可移动能量源”。它可以自己带电量,也可以从变电站或健康馈线取电后转运到失电区域。MPS的数量、容量、移动速度都是有限资源,所以预配置不可能覆盖所有负荷,只能针对重点区域做布局。

1.2 MPS预配置与动态调度:两阶段问题的时间分工

从时间维度看,一场典型极端天气过程可以粗略分成三个阶段:预测预警期(灾害发生前几小时到几天)、灾害发展期(几小时)、恢复期(几小时到几天)。MPS预配置发生在预测预警期,动态调度发生在灾害发生与恢复期。

预配置解决的是“车提前停在哪”的问题。动态调度解决的是“灾后车怎么走、接在哪、功率怎么出”的问题。这两个决策在数学上正好构成了两阶段随机规划的骨架:预配置位置是第一阶段决策变量,也叫here-and-now变量,必须在灾害场景真实发生之前确定;移动路径、接入位置、充放电功率、负荷恢复量都是第二阶段决策变量,也叫wait-and-see变量,需要等具体的故障场景信息暴露后再决定。

这里有一个初学者极容易踩的坑:既然灾后还要动态调度,那预配置是不是随便选个点就行?答案是完全可以反过来理解——预配置位置决定了动态调度的初始终端集合,也就决定了灾后调度的可行域上限。如果预配置点选在一段极易被台风刮断的馈线末端,灾后这条路一断,车就被困在孤岛里,连出车的机会都没有。如果预配置点太分散,灾后移动距离拉长,车辆在路上白白消耗恢复窗口。所以预配置是在“拓扑位置可达性”和“负荷需求空间分布”之间做风险对冲,跟“就近原则”完全是两回事。

1.3 为什么“预配置”值得单独开一篇

从代码复现的角度讲,很多论文把预配置和动态调度一起塞进一个两阶段模型,拿到手的第一步就是变量爆炸——根本分不清哪个变量是一阶段的,哪个变量是每个场景一套的二阶段变量。我最初复现时也花了很久才理顺。这篇先把预配置单独拆出来,目标很明确:把阶段一彻底吃透。目标函数长什么样、约束怎么建、为什么这么建、Matlab里对应代码如何组织,都在这一篇里交代清楚。把预配置这个模块整明白,再看动态调度那一篇,就是水到渠成的事。

2. 数学建模精读:预配置阶段的目标函数与约束体系

2.1 目标函数:在不确定性场景下最小化加权负荷损失

预配置优化的标准数学框架是两阶段随机规划。记第一阶段预配置决策为向量x,第二阶段在场景s下的调度决策为y_s,目标函数可以写成:

min C_place(x) + Σ_s ω_s · Q(x, s)

其中C_place(x)是预配置本身的动作代价(比如车辆从驻地出发到达预配置点的移动成本,如果为便于简化也可以直接设为常数或0),ω_s是场景s的发生概率,Q(x, s)是在预配置方案x已经确定、场景s的故障线路已知的前提下,灾后动态调度所能实现的最小加权失负荷量。

Q(x, s)的内部形式是:

Q(x, s) = min Σ_t Σ_n w_n · L_curt(n, t, s)

这里的w_n是节点负荷重要性权重,L_curt是未恢复(被削减)的负荷量。权重设置非常关键,医院、通信基站、消防设施这类敏感负荷权重可以设为10甚至更高,普通居民负荷权重就是1。韧性提升和传统经济调度的目标差异就在这里——它追求的不是电价最低或者网损最小,而是关键负荷的连续供电时间最长、累计失电量最小。

理解这个目标函数,需要抓住一点:预配置不是针对某一个确定的灾难场景做优化,而是对所有可能场景的期望表现负责。这个“期望值”恰恰是两阶段随机规划区别于确定性选址的核心。比如某节点在单一场景下可能是最优位置,但它在其他几个高概率场景里完全不可达,那么它的期望得分就很低,大概率不会被选中。

2.2 第一阶段约束:预配置的唯一性与离散性

预配置阶段的约束看起来很简单,只有三类:

  • 每个MPS只能预配置在一个节点:Σ_n x_v,n = 1,对每辆车v成立。
  • 每个节点最多停靠一辆MPS:Σ_v x_v,n ≤ 1,对每个节点n成立。
  • MPS可用总数限制:Σ_v Σ_n x_v,n = N_mps。

这三条约束保证了预配置方案是一个“一对一”的离散匹配关系,本质上是组合优化里的匹配问题。第二类约束(每个节点最多一辆)很容易被初学者漏掉。漏掉之后,模型可能会把两辆车都放在同一个变电站节点上,虽然目标函数值可能好看,但物理上完全不合理——同一个节点多放一辆车并不会带来更多供电能力,只会浪费资源。为了在空间上形成覆盖,这个约束必须加上。

这里我提一个经验性的补充解释:为什么预配置阶段不做移动时间约束?因为预配置发生在灾害之前,车辆从驻地到预配置点有充足的时间窗口,通常以小时计,完全可以在目标函数里用固定成本处理,或者干脆令其为0,只保留位置决策。把移动时间约束放在第二阶段,才是符合物理规律的。

2.3 场景内约束:移动、容量、潮流三类缺一不可

预配置方案的质量,必须通过第二阶段的场景内约束来检验。因为历史原因,配电网韧性论文里动态调度的约束体系相对统一,主要分成三类。

第一类是移动约束。车辆v在时段t的接入位置Z_v,t必须满足空间可达性约束。设预配置节点为n0,那么灾后初始时刻(t=1)车辆必须出现在n0。如果后续要转移到另一个节点n1,必须满足:从n0到n1的移动时间要小于等于(t-1)个时段的累计时长。实际操作中,一般会提前计算一个可达性矩阵reach_time(i,j),表示从节点i到节点j的最短移动时间,然后写成整数约束。

第二类是容量与功率约束。每辆MPS的电量SOC_v,t要在上下限之间,充放电功率不能超过额定功率,且充电与放电不能同时进行。这个“不能同时”在数学上是非凸约束,通常用大M法线性化:p_ch ≤ M·γ、p_dch ≤ M·(1-γ),其中γ是0-1辅助变量。还需要注意充放电效率,实际SOC变化是:

SOC_v,t+1 = SOC_v,t + η_ch·p_ch - p_dch / η_dch

效率系数如果取0.95左右,仿真结果才能贴近真实储能设备的特性。

第三类是潮流约束。配电网在恢复过程中通常要把网络盘活,所以用的是支路潮流模型。为了可计算性,绝大多数论文都用线性化的DistFlow方程:

V_j(t) = V_i(t) - 2·(r_ij·P_ij(t) + x_ij·Q_ij(t))

P_ij(t) = Σ_k P_jk(t) + P_j_load(t) - P_j_MPS(t) - P_j_DG(t)

其中P_j_MPS(t)是MPS注入该节点的功率,P_j_DG是分布式电源出力。这里需要特别提醒:如果只是做选址预配置,可以先用直流潮流或忽略电压约束的版本做一个快速判断;但如果要把结果写进论文,必须回到带电压约束的DistFlow模型,否则优化方案可能在弱网场景下过于乐观——因为实际配电网节点电压偏差是会限制MPS实际可输出功率的。

2.4 线性化处理与模型简化:能省则省

两阶段随机规划天然是混合整数线性规划(MILP),求解规模本身就很大。建模时要注意把一切可以线性化的环节都做掉:

  • 充放电互斥条件,用大M法。
  • 目标函数里min-max结构,通过把min放到外层、内层Q(x,s)作为各场景最小失负荷量,不需要额外线性化。
  • 潮流方程直接在DistFlow线性化版本下构建,不做非线性交流潮流。
  • 如果有联络线开关变量,也需要加0-1整数变量,但这类变量数量过多会严重影响求解速度。

实操经验是:能用连续变量表达的,绝不用整数变量;能用线性约束表达的,绝不用非线性约束。预配置本身是整数变量,避不开;但第二阶段的移动路径选择、MPS接入位置也是整数变量,这一块如果能压缩就需要尽量压缩。比如移动路径中关于“车辆不得越过故障线路”的空间拓扑约束,可以通过预计算可达集合并用0-1系数矩阵参与约束,避免引入路径级联变量。

3. Matlab代码实现:核心模块搭建与求解策略

3.1 整体代码架构:数据、场景、模型、结果四层分离

复现这类模型,我最推荐的方式是把代码拆成几个独立脚本,不要全都堆在一个main文件里。原因很简单:两阶段随机规划的调试周期长,中间任何一层出错都会导致结果莫名其妙,模块化之后才能逐层定位问题。一个典型的目录结构是:

  • main.m:算例配置和运行骨架。
  • case_ieee33.m:拓扑、线路参数、节点负荷、MPS参数。
  • scenario_generation.m:蒙特卡洛生成故障场景并做场景削减。
  • mps_pre_config_model.m:YALMIP建模、求解、返回预配置位置和期望指标。
  • plot_resilience.m:输出韧性曲线和对比图。

main.m只需做三件事:加载数据、生成场景、调用模型脚本。具体业务逻辑全部放到子函数里。

3.2 场景生成模块:蒙特卡洛抽样与场景削减

配电网韧性研究里,灾害场景的生成是决定结果可信度的底座。最常用的方法是按线路故障概率做蒙特卡洛抽样。比如给每条线路设定一个故障概率p_break,然后对每条线路独立采样一个0-1变量,1代表故障。这样做S次,就得到S个场景。场景数据结构建议用struct数组,每个元素存故障线路索引、故障时段范围、以及发生概率。

% 场景生成:按独立故障概率抽样 S = 200; % 初始场景数 K = 12; % 削减后的代表场景数 prob_line = 0.06; % 每条线路故障概率(示例值) scenario_list = struct('broken', cell(1,S), 'prob', 0); for s = 1:S is_break = rand(num_line, 1) < prob_line; scenario_list(s).broken = find(is_break == 1); scenario_list(s).prob = 1 / S; end % 用k-means做场景削减,减少代表性场景数量 [scenario_red, ~] = reduce_scenario(scenario_list, K);

我习惯先抽200个场景,然后削减到10~15个代表场景,再用削减后的场景做两阶段优化。削减算法不复杂:把每个场景的故障线路集合编码成一个one-hot向量,做k-means聚类,取每个聚类中心最接近的真实场景作为代表,该代表的概率等于簇内所有场景概率之和。这步做完,求解规模能降一个数量级,而且对预配置结论影响很小。

3.3 YALMIP建模:变量定义、约束组装、目标函数

Matlab里做这类优化,我基本离不开YALMIP工具箱。用YALMIP有两个好处:一是变量定义直观,二是不用关心底层求解器的接口细节。核心建模逻辑如下:

% 载入数据 data = load_case_ieee33(); N = data.num_node; M = data.num_line; V = 3; % 3辆MPS T = 24; % 24时段 % ---------- 第一阶段变量 ---------- x_place = binvar(V, N); % 每辆车是否停在节点n % ---------- 第二阶段变量(每个代表场景一套) ---------- for k = 1:K z{k} = binvar(V, N, T); % 时段t车辆接入节点 p_dch{k} = sdpvar(V, T); % 放电功率 p_ch{k} = sdpvar(V, T); % 充电功率 soc{k} = sdpvar(V, T); % 荷电状态 L_rec{k} = sdpvar(N, T); % 恢复的负荷量 end Constraints = []; % 每辆车只能选一个预配置节点 Constraints = [Constraints, sum(x_place, 2) == ones(V,1)]; % 每个节点最多停一辆 Constraints = [Constraints, sum(x_place, 1) <= ones(1,N)];

第二阶段约束的关键是“预配置位置与灾后初始接入位置”的耦合。用x_place直接约束z的第1个时段:

% 场景k中,车辆在t=1必须在预配置节点上 for k = 1:K Constraints = [Constraints, sum(z{k}(:, :, 1), 3) == x_place]; end

这一段是整篇代码最容易出错的地方。必须注意维度匹配:z是一个(V,N,T)的三维数组,sum(z(:,:,1),3)会得到(V,N)矩阵,让它等于x_place,就保证了“车停在哪就必须从哪出发”。如果漏掉这条约束,预配置变量和场景内调度变量就完全脱节了,算出来的结果毫无意义。

目标函数要按场景概率加权:

Objective = 0; for k = 1:K L_curt_k = data.L_demand - L_rec{k}; % 失负荷矩阵 (N,T) loss_k = sum(sum(data.w .* L_curt_k)); % 加权失负荷 Objective = Objective + scenario_red(k).prob * loss_k; end ops = sdpsettings('solver', 'cplex', 'verbose', 2, 'miprelgap', 0.01); result = optimize(Constraints, Objective, ops); x_best = value(x_place);

如果Cplex或Gurobi没装,YALMIP自带的内置求解器也能跑小规模问题,但要求解MILP还是建议装一个商用求解器,学术许可证通常是免费申请的。我实测过,同一模型在Cplex和Gurobi下求解速度差别明显,预配置问题在IEEE 33节点系统上,Gurobi往往比Cplex快20%到50%。

3.4 求解策略:当大规模MILP跑不动时的替代方案

两阶段随机规划全变量展开后,变量数量会非常大。如果不想一上来就碰大规模优化,有一个非常实用的替代方案:枚举预配置组合 + 固定第一阶段后的子问题求解。

当节点数较少、MPS数量也不多时,比如IEEE 33节点系统、3辆MPS,预配置的组合数量是C(33,3)=5456。这个数字虽然看起来不小,但每组合只需要解一个第二阶段的确定性等价问题,完全可以用parfor并行跑完。这样得到的预配置方案是全局最优的,因为枚举覆盖了所有可行组合。代码框架大致是:

combos = nchoosek(1:N, V); % 5456行,每行一个三节点组合 n_combo = size(combos, 1); obj_each = zeros(n_combo, 1); parfor c = 1:n_combo x_fixed = zeros(V, N); for v = 1:V x_fixed(v, combos(c, v)) = 1; end % 用写的子问题函数求期望失负荷 [loss, ~] = eval_subproblem(x_fixed, scenario_red, data, params); obj_each(c) = loss; end [min_loss, idx_best] = min(obj_each); best_combo = combos(idx_best, :);

这个“枚举+子问题验证”的思路,本质上就是把两阶段问题的第一阶段摘出来做粗暴搜索,第二阶段用线性规划(少数整数变量)快速求出期望最优值。它最大的好处是:不需要处理复杂的分解算法,也不用担心大规模MILP求解器跑一天还没收敛,代码调试极其友好。当节点规模升级到100以上、MPS数量到5以上时,再用Benders分解或L-shaped方法也不迟。

4. 实验设计与结果可视化

4.1 算例配置:以IEEE 33节点系统为默认测试床

做配电网韧性仿真的默认算例,几乎绕不开IEEE 33节点系统。它是8节点系统的经典扩展版,12.66kV,33个节点,32条支路,5个联络开关,总负荷约3.7MW。在做应急移动电源研究时,我习惯在原始拓扑基础上做如下配置:

  • 节点负荷采用一天24小时的归一化曲线,峰值负荷按各节点原始额定值乘以1.2倍放大,给“削峰填谷”留空间。
  • 3辆MPS,每辆额定功率100kW,容量300kWh,SOC运行范围0.1~0.9,初始SOC设为0.5。
  • 车辆平均移动速度取20km/h,节点间移动时间按地理距离折算,向上取整到1小时。
  • 场景的故障线路集从10条易损线路中抽取,每条线路故障概率设为0.1,模拟台风路径覆盖区域。
  • 联络开关在故障发生后允许闭合,以形成额外转供路径。

这些参数是我复现同类论文时整理的一组“接近实际、又方便计算”的值。如果你只是为了对论文结果,先按原论文参数跑;如果是为了验证自己代码逻辑,用上面这组默认值就足够。

4.2 对比方案设计:无MPS、随机预配置、优化预配置、事后最优

有了预配置模型之后,如何证明它的价值?光看优化结果不够,必须做对比实验。我常用的对比方案有四种:

  • 无MPS:完全不做应急移动电源参与,反映系统基础韧性水平。
  • 随机预配置:在33个节点里随机选3个位置放MPS,重复做20次取平均值,代表“没有规划、凭经验放”的结果。
  • 优化预配置:用两阶段随机规划求出的方案。
  • 事后最优:假设故障场景已知,再回代求解最优预配置位置,这是理论上的“上帝视角”上界,只用来衡量预配置优化的极限增益。

评价指标用两个就够了:累计加权失负荷量(相当于失电能量损失,单位kWh)和恢复比例曲线下面积(恢复比例对时间积分,越接近1说明韧性越好)。

4.3 韧性曲线绘制与解读

绘制韧性曲线时,我习惯将纵轴定义为“系统恢复供电比例”,即当前时段恢复负荷除以全部负荷。代码很简单:

figure; plot(t_hour, ratio_opt, 'b-', 'LineWidth', 1.6); hold on; plot(t_hour, ratio_random, 'g--', 'LineWidth', 1.4); plot(t_hour, ratio_no_mps, 'r:', 'LineWidth', 1.6); xlabel('时间/h'); ylabel('恢复供电比例'); legend('优化预配置', '随机预配置', '无MPS', 'Location', 'southeast'); grid on;

真正有价值的是读曲线时的判断逻辑。通常优化预配置方案会在灾后早期(第2到第4小时窗口)就把恢复比例拉起来,而随机预配置可能会在前期“干瞪眼”一两小时,因为车辆要么离故障点太远,要么所在区域本身就失电。这种差异反映的不只是调度能力,更是“预配置位置”决定的时间窗口优势。所以预配置优化的核心收益往往不体现在最终稳态(稳态时大家都恢复),而是体现在恢复过程的“响应速度”上。

5. 常见问题与踩坑清单

5.1 建模阶段的高频错误

两阶段变量层次混淆是最常见的问题。新手容易把预配置变量写成每个场景一套,导致第一阶段变量变成了场景相关,模型结果不可解释。记住:所有与场景下标k相关的变量都是第二阶段变量,第一阶段变量必须不带k。

目标函数漏乘场景概率也很常见。如果只对每个场景求和而不加权,高概率场景和低概率场景的影响就一样了,预配置方案会严重偏向那些概率极低但破坏极大的场景,得到的方案“看起来很保守,实际很浪费”。

负荷权重w设置不统一是复现论文对不上号的一大原因。很多论文对权重默认全部取1,但实际应用里一定是有差别的。我在复现时建议在说明文档里明确写出:哪些节点是医院/应急负荷,权重多少;哪些节点是普通负荷,权重多少。否则你跑出的韧性与原论文有差异,先不怀疑代码,先检查权重表。

5.2 求解性能优化与数值问题

如果初始场景数取300个,又做了k-means削减到15个,整体规模合理,Cplex求解通常几十秒到几分钟不等。但如果场景削减没做好,或者MPS数量和时段数偏大,MILP求解时间就可能呈指数增长。遇到这种情况,先检查是不是整数变量太多了。

大M系数也容易踩坑。取值过大(比如10^8)会造成数值病态,求解器可能给出满足容差但物理意义错误的解;取值过小(比如只是功率上限的2倍)又可能约束不够松。我习惯把M设为“相关变量理论最大值的10倍”,比如放电功率上限100kW,M取1000就够,再往上没必要。

还有一个容易被忽视的点是求解器的整数容忍度设置。Cplex默认的整型变量容忍度有时候太紧,导致求解很慢。我一般会把miprelgap设为0.01,把IntFeasTol放到1e-5级别,求解速度能提升不少,而结果差距通常小于千分之一。做科研复现完全可以接受。

5.3 复现时容易忽略的细节

移动时间约束的参数设定直接影响动态调度的可行性。我最初复现时忽略了这个约束,直接把车辆从一个节点瞬间转移到另一个节点,结果预配置方案特别激进——车辆可以任意飞到任何地方,导致模型给出“某车初始配置在A节点,灾后瞬间出现在B节点”这种物理不合理的调度。后来加上reach_time矩阵约束后,预配置方案立刻就变得更保守、更贴近实际。

联络开关的状态设置也是一个隐藏变量。IEEE 33系统的5个联络开关默认是断开的,但如果允许故障后闭合联络开关,相当于给恢复过程增加了很多转供路径,系统的韧性基线会大幅抬高。这也意味着MPS预配置的“增量价值”会变小,因为网架自己就能依靠联络线恢复不少负荷。论文里两种假设都存在,你复现时必须看清原论文是“固定开环”还是“允许动态重构”,否则结果差异会非常大。

场景故障线路的设定方式也需要看仔细。有的论文假设所有线路都有相等故障概率,有的论文只对特定区域线路设定故障概率。我在复现时更倾向于用“故障场景由线路故障概率抽样生成”的方式,因为它可以灵活模拟台风范围,也让预配置模型真正面对不确定性。如果想要复现一篇具体论文,建议先核对它用的场景生成方式,再决定自己怎么抽。

我自己的体会是,MPS预配置这个阶段看似只是“放几个点”,但它几乎决定了后面所有内容的上限。预配置放得准,灾后调度哪怕用最朴素的最短路优先策略,韧性指标也不会差;预配置放得偏,后面调度模型再漂亮,也只能在给定的初始点上小修小补。所以复现这类论文,我强烈建议你在预配置阶段多花时间:先吃透两阶段结构,再理解约束背后的物理动机,最后才动手写Matlab代码。顺序反了,就会在一个个数值怪癖里反复横跳。接下来准备写(下)的时候,我会把动态调度部分遇到的两个有意思的问题也整理出来,算是给这个系列的收尾。

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

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

立即咨询