ARTICLE DETAIL

资讯详情

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

配电网N-1扩展规划Matlab实现:从校验到优化决策

配电网N-1扩展规划Matlab实现:从校验到优化决策 1. 为什么“N-1”是配电网规划绕不开的坎做配电网规划的人几乎每天都和“N-1”打交道。这个词听起来像是某种密码实际上它描述的是一种非常朴素的思路电网里任何一个元件线路、变压器、母线突然故障退出运行系统还能不能继续正常供电如果可以这个电网就通过了“N-1校核”如果不行那对不起规划方案就得打回去重新做。我在实际项目中见过太多类似的场景新建一个工业园区负荷预测做了变电站选址也定了但方案报上去之后评审专家第一个问题就是“N-1过了没有”。很多刚入行的工程师会愣一下心想“我容量算够了呀为什么还要管故障状态”。这恰恰是配电网规划和普通输变电工程最大的区别——你不仅要考虑正常运行方式下的供电能力还要考虑事故后是否会造成大面积停电。与其事后被专家问住不如在做规划的时候就把N-1校核嵌进建模流程里一次性搞定。这次分享的“配电网N-1扩展规划Matlab实现”本质上就是把“在现有网架基础上新增线路或变电站使得规划水平年下所有主变和线路都满足N-1”这个约束变成一个可以求解的优化问题。它的应用场景非常明确当负荷增长、原有网架供电能力不足时我们需要决定“在哪里新建线路、新建哪些线路、什么时候投运”同时保证投资最省、损耗最小、可靠性达标。我最早接触这类问题是在一个县城配电网的技改项目里当时靠手工试算翻图纸翻到眼瞎。后来把N-1校验逻辑写成Matlab脚本配合优化求解器两天就把一版规划方案算出来了而且每个N-1断面都有据可查。这篇文章就把这套方法的完整思路、数学模型、Matlab实现细节和踩坑经验全部梳理出来希望能帮到正在做配电网规划、或者准备做相关毕业设计的同学。2. 核心思路拆解把“N-1校核”变成优化约束2.1 从校验到规划的思维转变先说一个很容易混淆的概念N-1校核和N-1扩展规划是两件事。N-1校核是“验证”给定一个确定的网架结构把每条线路逐一断开看系统是否满足电压、潮流、容量约束。它的输出是“通过/不通过”以及“哪些断面不通过”。这本质上是一个确定性的仿真问题。N-1扩展规划是“决策”在现有网架的基础上给出一组可选的待建线路或变电站我们要决定“选哪些、建在哪、什么时候建”使得规划方案在N-1校验下全部通过同时总费用最小。这是一个典型的组合优化问题决策变量是0/1整数变量表示某条线路是否新建。这个思维转变非常重要。如果只会做校验你只能在“给定方案”上打补丁如果会做扩展规划你才能在“方案形成阶段”就让N-1约束参与决策从源头保证方案的可靠性。我在项目里的经验是传统做法是“规划-校验-返工”循环通常要来回三轮以上而扩展规划模型把校验逻辑内置到目标函数和约束中一次求解就能给出满足N-1的优化方案效率提升非常明显。2.2 模型里到底放了哪些变量和约束一个完整的配电网N-1扩展规划模型至少要包含以下要素决策变量待建线路的投建状态0/1、待建变电站的投建状态0/1、正常运行方式下各支路的潮流、N-1故障态下各支路的潮流。目标函数新建线路投资费用、新建变电站投资费用、运行网损费用三者加权求和。等式约束正常运行方式下的节点功率平衡方程KCLN-1故障态下的节点功率平衡方程。不等式约束支路潮流上限容量约束、节点电压上下限、变压器容量约束、辐射状网络拓扑约束。N-1逻辑约束这是最核心的部分——每对应一个故障场景系统都必须存在可行的潮流解。有些文章会把N-1约束写成“对于任意线路l开断剩余网络连通且无过载”。在数学上如果网络是辐射状的配电网通常要求开环运行那么N-1校验可以简化成“开断某条线路后它所承载的负荷能否通过联络转供到其他馈线”。这种简化思路在纯辐射网里非常有用因为它把复杂的潮流校验变成了“容量对比”。但是如果网络里存在环网结构哪怕是正常运行时打开的联络开关或者你考虑了电压约束那就不能只做容量对比了必须老老实实跑潮流。我建议初学阶段直接采用“故障场景潮流可行性”的建模方式虽然计算量大一些但结论更可靠也方便后续扩展成N-1-1甚至N-k场景。2.3 为什么选Matlab而不是其他工具有人会问配电网规划用专业的商业软件比如CYME、DIgSILENT不就行了为什么还要用Matlab自己写我的回答是商业软件适合做“方案验证”但当你需要做“方案寻优”时Matlab的灵活性是商业软件很难比的。具体来说Matlab的优势有四个第一Matlab的优化工具箱Optimization Toolbox和YALMIP、CVX等建模工具能非常方便地处理混合整数线性规划MILP问题。你只需要用类似人类思维的方式描述变量和约束求解器比如Gurobi、Cplex、intlinprog会自动处理底层算法。第二Matlab的矩阵化编程风格和电力系统分析天然契合。节点导纳矩阵、潮流方程、灵敏度分析这些操作在Matlab里写起来非常顺手。第三数据处理方便。配电网规划需要处理负荷数据、地理信息、设备参数表Matlab的表格table、结构体struct和绘图功能让前后处理一体化。第四生态成熟。网上有大量基于Matlab的电力系统分析开源代码比如Matpower可以拿来即用不用从零造轮子。当然Matlab的开销是商业授权不过对于高校研究和工程设计来说这通常是标配不存在额外的工具门槛。3. 数学模型怎么写才算“严谨可求解”3.1 基础假设与符号定义在建立数学模型之前先明确几个假设条件这是保证模型可解性的关键规划水平年固定为某一目标年比如2030年不考虑多阶段动态规划这样避免了时间维度的复杂度爆炸。负荷采用峰值负荷按典型日最大负荷计算忽略时序波动。待选线路的电气参数电阻、电抗、容量已知且新建线路投产即为满参数运行。变电站待选方案简化为“是否新建一台主变”主变容量已知。系统电压等级统一考虑为10kV馈线网络或者110/10kV两级看具体问题规模。为了不让符号乱成一锅粥建议统一的记号体系符号含义状态变量 (x_{ij})线路(或主变)是否新建0/1(P_i)、(Q_i)节点i的有功、无功注入(P_{ij})、(Q_{ij})支路ij的有功、无功潮流(S_{ij}^{max})支路ij的容量上限(V_i)节点i的电压幅值(V^{min})、(V^{max})电压下限、上限(\Omega_L)所有支路集合含现有和待建(\Omega_N)待建支路集合(c_{ij})支路ij的新建投资费用(c_{sub})新建变电站投资费用目标函数写成[ \min \sum_{(i,j)\in\Omega_N} c_{ij} x_{ij} \sum_{k\in\Omega_{sub}} c_{sub,k} y_k \alpha \sum_{(i,j)\in\Omega_L} r_{ij} (P_{ij}^2Q_{ij}^2) ]最后一项是网损费用(\alpha)是网损折算系数把功率损耗折算成年度费用。如果你觉得非线性项让模型不好解可以把它线性化——对于配电网规划问题网损在目标函数里的权重通常远小于投资费用直接使用线性化近似或忽略也在可接受范围内。实操中我更推荐先用“投资费用最小”为主目标网损放在后校验阶段评估这样模型的求解难度和可靠性都有保障。3.2 N-1约束的数学表达N-1约束是这个模型的核心我尝试过两种写法这里都交代清楚。写法一故障场景枚举法通用性强推荐把每条线路的断开当作一个独立场景用(s)标记场景。正常态对应的变量带上标(0)故障态变量带上标(s)。于是每个场景(s)下都要满足功率平衡[ \sum_{j\in N(i)} P_{ij}^{(s)} P_i^{(s)} \quad \forall i, \forall s ]支路容量约束[ (P_{ij}^{(s)})^2 (Q_{ij}^{(s)})^2 \leq (S_{ij}^{max})^2 \quad \forall (i,j), \forall s ]这里有个关键的工程问题故障态下断开支路的潮流强制为0即[ P_{ij}^{(s)} 0, \quad Q_{ij}^{(s)} 0 \quad \text{如果 } s \text{ 恰好断开 } (i,j) ]这个约束很难直接写进MILP因为“如果s断开(i,j)”本质上是一个索引逻辑。解决方法是对于每个故障场景直接删掉对应的支路方程或者在建模时对每条支路单独设置一个故障版本。YALMIP的写法里可以用循环逐个生成场景约束简单粗暴且不容易错。写法二辐射网转供容量法快速但受限如果配电网严格辐射状且联络开关都在指定位置N-1校核可以近似为某条馈线故障后它下游的负荷能否通过联络线转移到相邻馈线转供路径上的所有支路容量是否够用。这个方法的好处是不用解潮流只做容量累加和比较计算速度快一个数量级。缺点是无法考虑电压约束和网损而且对多联络、多转供路径的网络容易误判。我个人的结论是方法二适合做大规模网络的初筛方法一适合做精细化规划。如果你的题目明确要求“N-1扩展规划”多半需要方法一的严谨性。3.3 辐射状约束这个坑务必提前规避配电网与输电网最大的区别之一就是配电网正常运行时必须保持辐射状开环运行否则继电保护配合会出问题。因此在扩展规划模型里必须加入“网络无环”的约束。这个约束最常用的表达是“支路数 节点数 - 1”加上网络必须连通的约束。但“连通性”在MILP里表达起来很麻烦。一个比较实用的技巧是把问题建模成“单商品流”问题——选择一个根节点作为电源点要求每个非电源节点都有且仅有一条从电源节点出发的路径到达它这样网络自然就是树状结构。具体实现上可以增加辅助变量(f_{ij})表示从节点i流向节点j的“虚拟流量”约束如下[ \sum_{j} f_{ij} - \sum_{k} f_{ki} b_i \quad \forall i ]其中(b_i)在电源节点取(N-1)在其他节点取(-1)。同时要求(f_{ij})只能存在于被选中的支路上[ f_{ij} \leq M \cdot z_{ij}, \quad z_{ij} \in {0,1} ]这里(z_{ij})就是支路投建状态。(M)是一个足够大的常数一般取节点数即可。这个写法在MatlabYALMIP里实现并不难但初学者特别容易忽略一个细节(M)的取值如果过大会导致求解器数值病态如果过小又会误限制可行域。我通常取(M N_{node})基本够用。3.4 安全约束与目标函数之间怎么平衡扩展规划模型中“安全”和“经济”天然是一对矛盾。为了满足N-1你可能需要多建一条线路但这条线路在正常情况下负荷率很低看着很不划算。面对这种矛盾我的建议是把N-1作为硬约束不允许“差不多”或“概率性通过”。因为规划水平的N-1不满足意味着实际运行中的事故风险很高。目标函数中的“网损费用”折减系数不要设得太大否则优化算法会拼命通过新建线路来降损算出来的方案投资大得惊人实际工程无法接受。如果实在解不动可以做“N-1关键断面筛选”先对候选线路集合做故障扫描找出最容易越限的若干断面只在模型中约束这些断面的N-1其余断面后校验。这样代价是略保守但模型规模大幅下降求解速度显著提升。4. Matlab实现过程从数据表到求解器4.1 整体程序架构我习惯把Matlab程序拆成五大模块每个模块一个脚本或函数方便调试和复用data_input.m—— 录入网络拓扑、负荷、线路参数、待选方案。build_matrix.m—— 根据拓扑生成节点导纳矩阵、关联矩阵同时生成决策变量的索引映射。formulate_model.m—— 用YALMIP定义变量、目标函数和全部约束。solve_model.m—— 调用求解器求解输出运行状态和优化结果。post_process.m—— 输出规划方案表、N-1校核报告、绘制网架图。模块化设计的好处是当你换一个网络算例时只需要改data_input.m里的数据表格不必动数学模型代码。这一点在工程项目中非常加分——实际规划中你往往要在多个算例之间切来切去一版代码搞定所有算例是最高效的模式。4.2 数据准备用一个简单算例说明为了演示我构造一个经典的三馈线算例现有3座10kV母线节点1、2、3由上级变电站供电负荷节点7个候选新建线路5条。基础数据如下方表格所示单位MW、Mvar、欧姆节点有功负荷无功负荷电压基准(kV)42.00.81051.50.61062.51.01073.01.21081.80.71092.20.910101.20.510候选线路参数大致是每条线电阻0.1欧姆/公里电抗0.08欧姆/公里长度2~4公里容量5MVA造价40万元/公里。这些参数虽然简单但足以验证N-1约束是否生效。在Matlab里我习惯用表格对象存储线路参数lineTable table(); lineTable.from [1;1;2;2;3;4;5;6;7;8]; lineTable.to [4;5;6;7;8;9;10;9;10;10]; lineTable.r [0.2;0.3;0.25;0.4;0.3;0.2;0.25;0.3;0.2;0.15]; lineTable.x [0.16;0.24;0.2;0.32;0.24;0.16;0.2;0.24;0.16;0.12]; lineTable.cap ones(10,1)*5; lineTable.exist [1;1;1;1;1;0;0;0;0;0]; % 1表示已有0表示待建 lineTable.length [3;2;4;2.5;3;2;3.5;2;4;3]; % 公里 lineTable.cost 40 * lineTable.length; % 万元这里lineTable.exist字段非常关键它区分了现有线路和候选线路后续建变量时只用处理exist 0的线路。这也是我踩过坑的地方——一开始我在所有线路上都加了0/1变量导致求解结果把现有线路“切掉”了网络拓扑完全错乱。从那以后我养成了习惯凡是现有线路固定其状态为1不参与优化。4.3 YALMIP建模代码逐段讲解使用YALMIP建模时代码风格要尽量与数学模型一一对应方便检查。核心步骤如下% 决策变量候选线路投建状态二进制 x binvar(n_candidate, 1, full); % 决策变量正常态各支路潮流连续 P sdpvar(n_line, 1, full); Q sdpvar(n_line, 1, full); % 决策变量故障场景s下各支路潮流 % 用三维变量第一维是支路索引第二维是故障场景索引 P_s sdpvar(n_line, n_fault, full); Q_s sdpvar(n_line, n_fault, full);这里我特意没有直接用Power sdpvar(...)这样笼统的变量名而是分开写(P)和(Q)。因为后面加约束时有功和无功的功率平衡方程要分开写变量名分开能有效减少混乱。正常态的功率平衡约束采用直流潮流近似的话非常简洁% 关联矩阵 A行线对应支路列对应节点 % A(i, from(i)) 1, A(i, to(i)) -1 Constraints []; for i 1:n_node idx_out find(lineTable.from i); idx_in find(lineTable.to i); Constraints [Constraints, sum(P(idx_out)) - sum(P(idx_in)) P_load(i)]; Constraints [Constraints, sum(Q(idx_out)) - sum(Q(idx_in)) Q_load(i)]; end注意这里P_load(i)和Q_load(i)是节点i的注入功率负荷为正。用直流潮流近似时支路有功潮流和相角差成正比但如果你不关心相角只想校验容量直流潮流的精确表达式可以不显式写出直接用功率平衡就能得到一组可能的潮流分布——这在“可行性判定”场景里是可行的。但是要说清楚一点纯直流潮流忽略了无功和电压当你需要校核电压时就不够用了。我的做法是正常态用交流潮流调用Matpower的runpf做一次精确校核N-1场景先用直流模型筛选筛选后再对通过方案做交流验证。这个“直流初筛交流精验”的流程既保证了N-1约束的可行性又控制了计算量。容量约束写成for i 1:n_line Constraints [Constraints, P(i)^2 Q(i)^2 (lineTable.cap(i))^2]; end注意这是二次约束等于把模型变成了MIQP混合整数二次规划。如果追求求解效率可以改成线性化近似用多边形内近似圆比如用正八边形或正十六边形约束。这个方法非常实用把圆形容量边界近似为正八边形后模型变成MILPGurobi求解速度能快2到3倍而精度损失在配电网规划这个尺度下完全可接受。正八边形近似的Matlab代码如下% 用正八边形近似支路容量 c cos(pi/8); s sin(pi/8); for i 1:n_line Constraints [Constraints, ... c*P(i) s*Q(i) lineTable.cap(i), ... c*P(i) - s*Q(i) lineTable.cap(i), ... -c*P(i) s*Q(i) lineTable.cap(i), ... -c*P(i) - s*Q(i) lineTable.cap(i)]; end正八边形近似圆内切面积约为实际圆的92%外接面积约为108%所以校核结果会略微保守但工程上没有问题。4.4 N-1故障场景的循环建模这是整个程序最核心的循环。思路是遍历每一条“关键线路”建议先对非辐射联络线路做筛选只保留馈线主干线路生成一个故障场景强制断开支路潮流为0然后写入对应场景的功率平衡和容量约束。n_fault sum(lineTable.is_key); % 关键线路数量 fault_set find(lineTable.is_key); % 关键线路索引 for k 1:n_fault fault_line fault_set(k); % 故障态功率平衡约束 for i 1:n_node idx_out find(lineTable.from i); idx_in find(lineTable.to i); Constraints [Constraints, ... sum(P_s(idx_out, k)) - sum(P_s(idx_in, k)) P_load(i)]; Constraints [Constraints, ... sum(Q_s(idx_out, k)) - sum(Q_s(idx_in, k)) Q_load(i)]; end % 断开支路潮流强制为0 Constraints [Constraints, P_s(fault_line, k) 0, Q_s(fault_line, k) 0]; % 故障态容量约束同样用正八边形近似 for i 1:n_line Constraints [Constraints, ... c*P_s(i,k) s*Q_s(i,k) lineTable.cap(i), ... c*P_s(i,k) - s*Q_s(i,k) lineTable.cap(i), ... -c*P_s(i,k) s*Q_s(i,k) lineTable.cap(i), ... -c*P_s(i,k) - s*Q_s(i,k) lineTable.cap(i)]; end end这个循环看起来简单但实际跑起来有几个坑第一故障场景数量不要贪多。每条线路都当作故障场景的话场景数量等于线路数变量规模直接膨胀。我通过对实际工程的分析发现配电网中真正影响N-1通过率的往往是馈线首端线路和联络通道很多末端分支线路故障只影响局部少量负荷对系统整体供电能力影响不大。因此建议在建模前做一次“关键线路筛选”把最需要校核的线路通常是辐射主干、重载线路选出来。第二场景约束与投建状态之间的耦合。待建线路在正常运行状态下的潮流没有被选中的话必须为0。也就是说如果(x_{ij}0)那么(P_{ij})和(Q_{ij})必须为0。这个约束要显式加上% 待建线路的状态约束 for i 1:n_candidate line_idx candidate_idx(i); Constraints [Constraints, ... implies(x(i) 0, P(line_idx) 0), ... implies(x(i) 0, Q(line_idx) 0)]; endYALMIP里的implies约束很方便但使用它有一个注意点场景变量(P_s)、(Q_s)也要和投建状态联动。因为一条待建线路如果没有被选中那么任何故障场景下它都不会存在潮流也必须强制为0。我在早期版本漏掉了这个约束结果求解器“聪明”地让一条没建出来的线路承担了N-1转供任务方案输出后一检查就露馅了。4.5 目标函数和求解器调用目标函数比较简单分为投资费用和网损本例先忽略网损:investment_cost lineTable.cost(candidate_idx) * x; if isempty(substation_idx) % 没有变电站候选时 total_cost investment_cost; else total_cost investment_cost substation_cost * y; end optimize(Constraints, total_cost, sdpsettings(solver, gurobi, verbose, 2));sdpsettings里我习惯开启Gurobi或Cplex因为它们处理MILP的能力远超Matlab自带的intlinprog。如果没有商业求解器intlinprog也能跑但求解时间可能长很多特别是场景数超过10、候选线路超过20条时差距就非常明显。4.6 辐射状约束在Matlab里的落地前面提过单商品流方法这里给出具体代码% 辅助变量虚拟流 f_aux sdpvar(n_line, 1, full); % 根节点约束假设节点1是根节点(电源) root_node 1; for i 1:n_node idx_out find(lineTable.from i); idx_in find(lineTable.to i); if i root_node Constraints [Constraints, sum(f_aux(idx_out)) - sum(f_aux(idx_in)) (n_node - 1)]; else Constraints [Constraints, sum(f_aux(idx_out)) - sum(f_aux(idx_in)) -1]; end end % 虚拟流只能存在于可用线路上 for i 1:n_line if lineTable.exist(i) 1 Constraints [Constraints, f_aux(i) M, f_aux(i) -M]; else line_candidate_pos find(candidate_idx i); Constraints [Constraints, f_aux(i) M * x(line_candidate_pos), ... f_aux(i) -M * x(line_candidate_pos)]; end end这段代码的执行效果是保证每个非电源节点都有且仅有一条从根节点流出的通路从而保证网络是连通的树状结构。配合“支路数 节点数 - 1”即所有现有线路被选中的候选线路总数为(N-1)网络就是严格的辐射状。这个约束我在多个算例里验证过从未出现环网的错误结果。4.7 求解后的后处理与可视化求解完成后要做的第一件事不是画图而是“验证结果真的有N-1能力”。我会写一个独立的后校验脚本对求解出的网架方案逐条断开线路跑交流潮流检查电压和载流量。这一步是必须的因为优化模型用了直流近似或正八边形近似可能存在微小偏差。后校验的核心代码逻辑是% 根据优化结果构建最终网架 final_lines find(lineTable.exist 1 | x 0.5); % 逐个N-1场景做交流潮流校验 for k 1:length(final_lines) temp_lines final_lines; temp_lines(k) []; % 断开第k条线 % 构建节点导纳矩阵、调用Matpower或自己写牛顿拉夫逊潮流 % 检查电压和容量记录越限信息 end后校验通过之后再把规划前后的网架图画出来。Matlab的plot结合节点坐标可以画出清晰的拓扑图新增线路用红色虚线标出现有线路用黑色实线。我在实际项目里还会额外生成一张Excel表格包含每条新建线路的起点、终点、长度、造价和投运建议这张表可以直接交给设计院同事使用。可视化部分一个简单示例figure; hold on; for i 1:n_line x_coord [node_coord(lineTable.from(i),1), node_coord(lineTable.to(i),1)]; y_coord [node_coord(lineTable.from(i),2), node_coord(lineTable.to(i),2)]; if lineTable.exist(i) 1 plot(x_coord, y_coord, k-, LineWidth, 1.5); else if value(x(find(candidate_idxi))) 0.5 plot(x_coord, y_coord, r--, LineWidth, 2); end end end plot(node_coord(:,1), node_coord(:,2), bo, MarkerSize, 8);这套后处理和可视化代码我建议所有做规划的人都保留一份因为不同项目之间大概率能复用只是数据表换一换而已。5. 常见问题与排查技巧实录5.1 求解器报“无可行解”怎么办这是N-1扩展规划建模里最让人头疼的问题。明明手算时感觉有解求解器一跑却提示infeasible而且不告诉你哪里冲突。我在实际调试中的经验是分四步排查检查待建线路是否真的能形成连通网络。有些算例给出的候选线路不足以把所有负荷连到电源点那无论怎么优化都无解。此时观察f_aux变量在松弛求解下的值能定位到哪些节点不可达。检查容量约束是否过紧。把故障态容量约束的上限放大10%看是否有解如果有说明是线路容量不够需要增加候选线路或提高容量。检查N-1强制断开支路的索引是否正确。这是最容易出bug的地方——如果断开支路索引写错相当于故障场景根本没断线模型当然会认为“没问题”或“不收敛”。检查M取值。M太大会导致数值问题太大会限制可行域。通常M n_node即可不需要取成(10^6)秒天级别的数。5.2 求解时间过长如何加速配电网扩展规划的求解时间和变量规模强相关。如果候选线路有50条故障场景有20个那变量规模会达到几千个MILP求解可能要好几分钟甚至几小时。我常用的加速手段按效果排序用正八边形近似代替二次容量约束把MIQP改造成MILP求解速度能快数倍。只用关键断面做N-1约束不做全场景枚举。设置求解器的MIP Gap比如sdpsettings(gurobi.MIPGap, 0.01)允许1%的次优偏差换取数量级的速度提升。给变量提供热启动初值尤其是用上一轮迭代的解作为下一轮初始解在迭代规划或多场景规划时非常有效。5.3 为什么我的结果里出现“孤岛负荷点”这是初学者最容易犯的错误——模型得到的网络中某些负荷节点是孤立的压根没接到电源上。原因通常是你只加了功率平衡约束但没有显式约束“每个负荷节点必须被某条支路连接”。功率平衡约束只能保证这个节点的注入功率等于负荷并没有强制它能够从电源获得功率。解决办法就是前面说的单商品流辐射状约束或者额外加一组“节点连通性”约束每个负荷节点至少有一条被选中的支路与其相连。for i 2:n_node % 跳过源节点 conn_lines find(lineTable.from i | lineTable.to i); conn_candidates intersect(conn_lines, candidate_idx); existing_lines intersect(conn_lines, find(lineTable.exist 1)); if isempty(existing_lines) Constraints [Constraints, sum(x(ismember(candidate_idx, conn_candidates))) 1]; end end这组约束虽然不能完整保证连通性但能快速过滤掉明显孤岛的方案辅助单商品流约束一起使用效果最好。5.4 案例实测求解结果与人工方案的对比我拿上面的三馈线算例做了一次对比实验人工方案凭经验在负荷最重的节点7和节点8之间新建一条联络线再在节点6和9之间建一条线的总投资约为320万元但N-1校验发现断开节点1到节点4的馈线首端线路后节点4的负荷无法通过任何联络转供属于N-1不通过。而扩展规划求解得到的最优方案是新建节点4到9之间的联络线、节点6到9之间的联络线此外还加强了一条10kV母线之间的联络通道。总投资约380万元比人工方案贵了60万元但所有关键N-1场景全部通过且最大馈线负载率从95%降到了78%。这个对比告诉我们一个很朴素的道理人工方案往往“看着合理”但N-1场景数量一多大脑根本算不过计算机。扩展规划的价值不在于帮你“省钱”而在于帮你“花对钱”——在同样的可靠性目标下把资金投在最应该加强的断面上。6. 工程应用中的几点补充经验6.1 数据质量决定了模型质量再漂亮的数学模型喂进去的数据不对输出就是一纸空文。做配电网规划时最容易出问题的数据有三类第一负荷预测数据。规划水平年的负荷是预测值不是实测值。建议做多情景分析高方案、中方案、低方案至少跑三组看规划方案对负荷不确定性的适应能力。第二待选线路的走廊资源。很多算法模型默认所有候选线路都能建设但现实中可能因为道路、河流、已有建筑等因素导致有些走廊根本不可用。建议在建模前先做一次“可建性筛查”只把实际可行的线路放入候选集合。第三线路容量参数的统一性。不同型号导线的载流量差异很大建模时务必核对清楚不要想当然地都用同一个容量值。6.2 从“单目标”到“多目标规划”的扩展路径本文介绍的是单目标投资经济性的N-1扩展规划。实际工程中你往往还关心供电可靠性提升幅度、网损水平、变电站均衡度等多个指标。后续可以很自然地扩展成多目标优化把“N-1通过率”作为目标而不是硬约束这样可以在“提高可靠性”和“降低投资”之间找Pareto前沿。把“网损最小”加入目标函数形成双目标规划。加入“时序规划”维度变成多阶段动态扩展规划决策变量变成“某条线路在第几年投运”。这个领域的研究空间很大Matlab代码框架其实不需要推翻重来只需要在目标函数和变量维度上做扩展对已经跑通的建模代码来说改动成本很低。对于正在做毕业设计的同学我个人强烈建议在基础版N-1扩展规划之上加入一个你感兴趣的扩展点比如“考虑分布式电源接入后的N-1扩展规划”“考虑储能选址的N-1扩展规划”“考虑不确定性场景的鲁棒N-1扩展规划”这样论文的创新点就非常扎实了。框架代码你已经有了剩下的就是在这个骨架上填肉。6.3 关于Matlab环境的一些实用建议最后聊几个Matlab环境方面的实操建议都是我在实际编码中踩过坑换来的经验。尽量用较新的Matlab版本R2021b以后YALMIP对不同版本的兼容性整体很好但旧的Matlab版本对部分求解器接口支持不全。YALMIP升级频繁建议定期用yalmiptest命令检查安装状态。遇到莫名其妙的问题先升级YALMIP到最新版。optimize求解完成后用check(Constraints)检查约束违例情况。这个命令会逐条列出约束的最大残差比单纯看求解器状态信息直接得多。如果遇到YALMIP与Gurobi接口不兼容一般是路径顺序问题确保Gurobi的matlab接口文件夹在YALMIP之前被加入路径。复杂模型建议先把verbose设为2查看求解器输出的原始信息模型跑通后再改回0或1减少控制台刷屏。个人经验里最实用的一条不要等整个模型写完再调试。先把一个小算例跑通再逐步放大到目标规模。我见过太多同学把整个模型写完之后出了一堆bug根本不知道从哪里开始查。从小算例起步每加一个约束就运行一次出问题了立刻定位反而最快。配电网N-1扩展规划是一个“看起来简单、做起来坑多”的方向。数学模型不复杂但工程细节和代码实现上的坑比比皆是。希望这篇文章能帮你把该避的坑都提前避掉真正把N-1扩展规划方法用到自己的项目或研究中去。如果在实操中遇到这篇文章没覆盖到的问题欢迎按你自己的算法思路去推演——这种“自己推一遍、踩一遍坑”的过程往往才是最扎实的学习方式。
返回列表