“配电网N-1扩展规划”这七个字,我最初接到这个题目时,第一反应是:无非就是在现有网架上多架几条线路,保证故障时能转供电不就行了吗?等到真正动手在Matlab里把整套逻辑实现出来,才发现问题远没有这么简单。N-1不是简单的“双回路”概念,扩展规划也不是拍脑袋加线路,而是一个涉及拓扑决策、潮流计算、故障场景枚举、可靠性校验的组合优化问题。
这篇文章就把我做配电网N-1扩展规划研究的完整思路梳理一遍:从N-1校验的本质含义、扩展规划的数学模型建立,到Matlab代码的整体架构、辐射状约束与N-1转供判断的核心实现,最后用一个IEEE 33节点系统做完整算例验证。内容适合电气工程方向的研究生、准备做配电网规划方向课题的本科生,以及刚接触配电网络规划的一线工程师参考。我会把每一步背后的“为什么”也讲清楚——为什么辐射状约束要单独处理、为什么N-1校验不能直接甩给优化器、为什么配电网潮流计算首选前推回代法,这些都是文档里不常写但实际做项目一定会遇到的东西。
1. N-1到底在配电网规划里校验什么:概念拆解与常见误区
1.1 输电网N-1与配电网N-1根本不是一回事
很多从电力系统分析课程里学过N-1准则的人,会把输电网的思维直接搬到配电网里来,这是第一个坑。
输电网的N-1校验,侧重的是某条线路或某台变压器退出后,系统还能不能保持安全稳定运行,不引起其他元件过载、电压越限甚至连锁跳闸。输电网是环网结构、闭环运行,N-1分析的核心是潮流重分布后系统是否越限。
配电网不一样。配电网绝大多数是“闭环设计、开环运行”,正常运行状态下是一个辐射状网络,约等于一棵树。一条馈线主干线故障跳闸后,下游所有负荷都会失电——这是辐射状网络的天生短板。所以配电网N-1校验的真正含义是:某个元件故障退出后,能不能通过分段开关、联络开关的操作,把失电区域的负荷转移到相邻馈线或其他电源点,转移之后各线路不过载、各节点电压不越限。
换句话说,输电网N-1校验的是“系统是否稳定”,配电网N-1校验的是“负荷能否通过转供恢复供电”。这一字之差,落到代码实现上就是完全不同的逻辑:前者要解一个全系统的潮流重分布问题,后者要在故障场景里做转供路径搜索与负荷再分配。
1.2 三个特别容易踩的误区
第一个误区:“N-1不就是双回路供电嘛”。双回路、手拉手接线只是满足N-1的常见网架形式之一,但不是充分条件。两条手拉手馈线,如果联络点附近已经在重载运行,故障转供后照样会过载,N-1照样过不了。规划的目标不是画一个“手拉手”拓扑,而是让转供后的运行状态落在安全边界内。
第二个误区:“N-1校验就是每条线路断开跑一次潮流”。实际上,N-1校验要考虑故障后网络如何重构——哪些分段开关需要分闸、哪些联络开关需要合闸、失电负荷如何重新分配。不先做开关策略和转供路径搜索,直接跑潮流肯定会得到大量误判为“失负荷”的结果。
第三个误区:“N-1扩展规划就是在原网络上多选几条线路”。扩展规划真正的难点在于:新线路的建设位置、建设时序和建设容量是耦合的,新增一条线路不仅改变正常运行方式,还会改变N-1故障场景下的转供能力。一个看起来网损很小、投资很省的方案,可能在某个元件故障后完全无法转供,直接被判为不可行。这就是规划层和校验层必须闭环的原因。
把这个概念吃透,后面的数学模型和代码实现才有意义。不少毕业论文里N-1只是作为一句话约束带过,真正落到算法上根本没法算,这就是没有理解配电网N-1的机理。
2. 数学模型:把“投资最小、故障不失负荷”写成优化问题
2.1 决策变量、目标函数与成本拆解
配电网扩展规划是一个典型的混合整数规划问题。决策变量最核心的就是新建线路的0-1变量:
[ x_{ij} = \begin{cases} 1 & \text{在走廊(i,j)上新建线路} \ 0 & \text{不新建} \end{cases} ]
如果有分布式电源、储能或变电站扩容,还会有各自的安装位置和容量决策变量。但作为起步版本,先把线路决策做扎实是最重要的。
目标函数我习惯写成三部分相加:
[ \min ; C = C_{inv} + C_{loss} + C_{eens} ]
- (C_{inv}):新建线路的投资等年值,通常用等年值法把一次性建设成本折算到每年,加上运行维护成本。
- (C_{loss}):正常运行方式下的网络损耗成本,按年损耗电量乘以电价计算。
- (C_{eens}):缺供电量成本,即N-1故障场景下失负荷电量乘以单位缺电成本。这部分的本质是把“可靠性”货币化。
单位缺电成本怎么定?可以用当地销售电价,也可以查文献里推荐的停电损失折算值(一般取电价的几倍到十几倍)。规划项目里这个参数直接影响优化结果的偏向:缺电成本取高了,算法会倾向于多建线路、把网架铺得比较满;取低了,算法会尽量省钱、容忍一定失负荷。实际做项目时建议至少算三组不同缺电成本下的方案,给决策者一个敏感性区间,而不是只给一个“最优值”。
2.2 五类约束条件缺一不可
约束条件归纳下来是五件套:
第一,辐射状运行约束。配电网正常运行时必须是辐射状,不允许合环。数学上可以表达为:支路数量等于节点数减去连通分量数,且网络连通。后面我会专门讲这个在Matlab里怎么实现。
第二,潮流约束。每个节点的有功无功注入等于负荷加流出功率,这是任何规划方案必须满足的物理约束,用前推回代法或Newton法求解都可以。
第三,节点电压约束。N-0正常方式和N-1故障转供后,各节点电压都要在允许范围内,典型是0.95 p.u.到1.05 p.u.。
第四,支路载流量约束。所有线路的电流或视在功率不能超过导线长期允许载流量,N-1转供后的短时过载是否允许需要规划时界定清楚。我在实际项目里一般取额定载流量的1.0~1.2倍作为N-1工况的短期上限,具体看当地导则。
第五,N-1校验约束。这是最特殊的约束——它不是一个显式代数约束,而是一个“故障场景枚举+转供可行性判断”的验证过程。任何一个元件开断后,如果能通过转供恢复全部负荷且不越限,判为通过;否则判为不通过,方案进入不可行集。
2.3 为什么N-1校验约束不能直接丢给求解器
初学者最容易踩的坑就是想把N-1校验写成一个约束公式,直接塞进Yalmip或Gurobi里让求解器处理。想法很美好,实际很痛苦。
原因有三点。第一,N-1校验本质是枚举所有单重故障场景,每一个场景内还包含一组开关操作策略,这些策略是离散的逻辑判断(哪些分段开关断开、哪些联络开关闭合),不是简单的代数关系。第二,负荷转供后网络拓扑发生变化,潮流方程的结构跟着变,这引入了大量0-1变量和双线性项,模型变成高度非线性的MINLP,通用求解器在大规模节点系统上基本跑不动。第三,配电系统的三相不平衡、恒功率负荷模型等实际因素,会让这个约束进一步偏离可解析表达的范围。
我的处理思路是把问题拆成两层:
- 上层是规划决策层,用智能优化算法搜索候选网架方案。
- 下层是校验层,对每个候选方案做正常运行潮流分析和N-1故障转供校验。
上层算法只负责生成和演化方案,下层校验负责判定方案是否可行并计算目标函数值。分层解耦以后,N-1校验变成一个独立的迭代过程,可以单独优化、单独加速,代码结构也干净得多。
3. 转供搜索与N-1校验:整个程序里最难写的一环
3.1 故障开断后到底发生了什么
要写对N-1校验代码,脑子里必须有一个清晰的故障场景演变过程。以一条馈线主干线某处故障为例:
首先,故障点上游的分段开关或变电站出口断路器跳闸,故障段被隔离。然后,失电区域是故障点下游的所有节点和负荷。接下来,运行人员或配网自动化系统执行转供操作:合上某个联络开关,让失电区域通过联络线从另一条馈线取电。如果失电区域的拓扑比较复杂,可能需要按“先恢复主干、再恢复分支”的顺序逐级合闸。
转供完成后,失电区域的负荷接入相邻馈线,这些馈线的潮流会明显增加。如果某条馈线或某段线路的载流量超过上限,或者某个节点电压越限,就说明单靠这个联络路径无法满足N-1,需要增大网架联络强度或增加新线路。
拿城市配电来类比:一个小区的供水管爆了,物业把备用阀门打开,让隔壁小区的水管往里供水。如果隔壁水管本身已经用掉八成容量,备用阀门一开就超压爆管,那这个“备份方案”就是不合格的。配电网N-1转供干的就是这事。
3.2 转供搜索的实现思路
在Matlab里实现转供搜索,我用的是一种偏工程化的方法,分四步:
第一步,枚举故障元件。对网络中的每一条线路(或变电站出线开关)逐一设为开断状态,生成故障后网络。
第二步,判断失电范围。从电源节点开始做广度优先搜索,能遍历到的节点就是有电节点,遍历不到的节点集合就是失电区域。这一步很关键,因为失电区域才是需要转供的对象。
第三步,寻找可行的转供路径。查看失电区域里有哪些节点连接着联络开关(这些联络开关的另一端在正常带电区域内)。如果存在至少一个带电联络开关,说明失电负荷有潜在的转供通道。如果有多个,就涉及转供通道的优选问题。
第四步,转供后运行状态校验。将失电区域通过选定的联络路径并入带电网络,重新跑一次配电网潮流,检查所有线路电流和节点电压是否越限。若都不越限,N-1校验通过;若存在越限,可以尝试调整联络开关组合,或者直接判定该故障场景下存在失负荷。
如果失电区域完全找不到带电联络开关,那就直接记为失负荷,失负荷量就是该区域的总负荷值。
这里有一个工程细节:转供路径选择本质上也是一个优化问题。为了降低复杂度,我的做法是先用启发式规则筛选——优先选择联络线另一端负载率低、电气距离近的路径,然后跑潮流验证。如果验证不通过再换下一候选路径。这个“启发式筛选+潮流验证”的组合在实践里效率很高,而且不容易漏判。
3.3 前推回代潮流为什么是首选
N-1校验的内循环要跑大量潮流计算,一次计算几毫秒,一百个方案校验下来也要不少时间。所以潮流算法一定要选对。
配电网的特点是辐射状结构、R/X比高(电阻和电抗比值经常大于1,输电网里一般远小于1)、节点数量多但规模不大。牛顿-拉夫逊法在这种网络上经常因为雅可比矩阵条件数差而收敛慢。前推回代法(Backward/Forward Sweep)天然适配辐射状网络:先假设全网电压为额定值,从末端节点向电源节点推算支路电流和功率损耗,然后从电源节点向末端节点回推更新电压,反复迭代直到电压误差小于设定阈值。
这个方法的实现逻辑和树形网络完全吻合,每轮计算是O(n)复杂度,而且不需要求导和矩阵求逆,数值稳定性好得多。在Matlab里写一个前推回代函数,核心循环不超过三十行,用向量化还能再快一个数量级。
4. Matlab代码框架:模块划分与关键函数实现
4.1 数据组织方式
写配电网规划代码,第一步不是写算法,而是把数据模型整理清楚。我用三个结构体来组织所有数据:
busData:节点数据,字段包括节点编号、有功负荷、无功负荷、节点类型(电源节点/负荷节点/联络节点)。branchData:现有支路数据,字段包括首端节点、末端节点、电阻、电抗、容量上限、是否正常闭合。candidateData:候选新建走廊数据,字段包括两端节点、可选导线型号(决定阻抗和容量)、建设成本。
用一张表来理解:
| 数据对象 | 关键字段 | 作用 |
|---|---|---|
| busData | 节点编号、P_load、Q_load | 定义系统负荷分布 |
| branchData | from、to、R、X、capacity | 定义现有拓扑与电气参数 |
| candidateData | from、to、R、X、cost | 定义新建线路的决策空间 |
候选走廊的编号顺序必须固定,因为后面遗传算法粒子编码的长度和每一位的含义都依赖这个顺序。我在做项目时在这里吃过亏——中途调整了候选走廊表顺序,结果优化结果全部错位,排查了整整一天。建议在一开始就确定候选走廊清单,后续不要改动,最好把编号注释写到代码文件头部。
4.2 模块划分与主循环流程
整个代码我从功能上拆成六个模块:
- 数据准备模块:读入系统数据和候选走廊,生成基础数据文件。
- 初始化模块:在Matlab里通过
rng固定随机种子,生成初始种群,每个个体是一段0/1向量,对应候选走廊是否建设。 - 拓扑校验模块:检查每个个体的辐射状约束是否满足。
- 潮流计算模块:前推回代法,输出节点电压、支路电流和网损。
- N-1校验模块:枚举故障场景、做转供搜索、统计失负荷量。
- 优化主循环模块:用粒子群或遗传算法迭代寻优,更新个体位置和全局最优。
主循环用伪代码可以写成这样:
% 优化主循环(遗传算法示意) for gen = 1:maxGen for i = 1:popSize % 个体i:新建线路决策向量 x = pop(i,:); % 拓扑校验:不满足辐射状则直接罚函数 if ~checkRadial(x, branchData, candidateData) fitness(i) = inf; continue; end % 正常方式潮流计算 [loss, vmax, vmin] = runPowerFlow(x); % N-1校验:返回失负荷量 [eens, n1Pass] = doN1Check(x); % 目标函数 fitness(i) = investCost(x) + lossCost(loss) + eensCost(eens); end % 选择、交叉、变异 pop = evolve(pop, fitness); end这个流程里,doN1Check是最耗时的函数,也是整个程序能不能跑出结果的关键。
4.3 辐射状约束的图论实现
辐射状约束在代码里可以用图论的结论实现,简单可靠:一个连通网络是树(辐射状)的充要条件是“边数等于节点数减一”。
function isValid = checkRadial(x, branchData, candidateData) % 合并现有支路和候选新建支路 allBranches = [branchData; candidateData(x==1, :)]; nBranch = height(allBranches); nBus = max(max(allBranches.from), max(allBranches.to)); % 条件1:边数 = 节点数 - 1 if nBranch ~= nBus - 1 isValid = false; return; end % 条件2:全图连通 G = graph(allBranches.from, allBranches.to, nBus); isValid = numel(unique(conncomp(G))) == 1; end这段代码用到了Matlab的图对象和conncomp函数,第一个条件排除了“有环不辐射”的网络,第二个条件排除了“节点孤岛”的情况。两个条件合起来就是严格的树形拓扑。
我最初写这个函数时只检查了连通性,忘了边数条件,结果算法老是生成带环的方案。环状结构在配电网正常运行方式下是不允许的,前推回代也会因为遇到环而算错。后来把两个条件写全,潮流结果才稳定下来。
4.4 N-1校验主循环的代码结构
N-1校验模块的骨架,我用这样的结构:
function [eens, failList] = doN1Check(x) % 构建完整网络:现有支路 + 新建支路 network = buildNetwork(x); % 找出所有需要校验的元件(线路) branchesToCheck = network.branches; nCheck = length(branchesToCheck); totalEens = 0; failList = []; for k = 1:nCheck % 第k条支路开断 faultNetwork = openBranch(network, k); % 判断失电区域 [lostArea, hasPower] = findLostArea(faultNetwork); if all(hasPower) % 没有失电区域,直接通过 continue; end % 尝试转供:寻找带电联络路径 restorePlan = searchRestoration(faultNetwork, lostArea); if isempty(restorePlan) % 无法转供,全失电区域计入失负荷 totalEens = totalEens + sumLoad(lostArea); failList = [failList, k]; else % 执行转供并校验是否越限 [ok, overLoad] = checkAfterRestoration(restorePlan); if ~ok totalEens = totalEens + overLoad; % 按实际转供缺口计 failList = [failList, k]; end end end eens = totalEens; end代码里的findLostArea用图的广度优先遍历实现,searchRestoration在失电区域与带电区域之间搜索联络开关。这种逐条开断、搜索转供、校验越限的做法,每一个故障场景的处理逻辑都和实际运行方式对应,结果可信度高。
5. 算例验证:以IEEE 33节点系统为例
5.1 场景设定与候选走廊生成
我用IEEE 33节点标准测试系统做了算例验证。这个系统基准电压12.66 kV,33个节点,32条正常运行支路,5条联络开关支路,总负荷约3.7 MW + 2.3 Mvar。原始参数在很多公开资料里都能查到,作为Matlab验证算例非常合适。
为了把“扩展规划”做起来,我做了两步改造:
第一步,把原始负荷普遍乘以1.8,模拟5到8年后的负荷增长。这样做的原因是,原有网架在重载下很多支路接近满载甚至过载,扩展规划才有发挥空间。
第二步,在原有32条支路基础上,额外设置了12条候选新建走廊,分布在馈线末端、联络薄弱区域和大负荷集中区域。每条候选走廊的造价按导线截面和长度折算成等年值。
优化算法参数设置为:种群规模100,最大迭代代数60,交叉概率0.85,变异概率0.1。缺电成本取1元/kWh。
5.2 规划结果与N-1校验对比
跑完程序后,我整理了优化前后对照表:
| 指标 | 无扩展方案 | N-1扩展规划方案 |
|---|---|---|
| 新增线路数 | 0 | 5 |
| 总投资等年值(万元/年) | 0 | 325 |
| 年网损(MWh) | 2860 | 1480 |
| 正常方式最低电压(p.u.) | 0.91 | 0.97 |
| N-1校验通过率 | 32/37 | 37/37 |
| 缺供电量(MWh/年) | 约90 | 0 |
这个表非常直观。原始网架在负荷增长后,正常运行最低电压只有0.91 p.u.,明显越下限;N-1通过率只有32/37,也就是有5条支路故障后无法通过转供全部恢复负荷。而扩展规划方案虽然新增了5条线路、每年多花325万投资,但网损减半、最低电压恢复到0.97 p.u.,N-1全部通过,缺电成本直接降为0。
如果把缺电成本调高到5元/kWh,优化出来的方案会新增6到7条线路,总成本反而增加不明显——因为缺电成本占了主导。这种敏感性分析在论文里很有说服力,也方便工程上做决策。
5.3 结果怎么解读
从算法角度看,这个算例说明两件事:第一,N-1校验约束确实在改变最优解的结构,不在目标函数里引入可靠性成本、不对方案做N-1验证,很难找到一个既能满足安全准则又经济合理的网架;第二,分层优化框架在33节点规模下收敛速度很快,单次完整运行(100个个体×60代,每代含37次N-1校验)在普通台式机上大约5到10分钟,完全在可接受范围内。
从代码角度看,输出结果建议把新增线路列表、各故障场景的转供路径、恢复到失负荷区域的操作序列都打印出来,方便和论文里的网络拓扑图对应。单纯打印一个目标函数值,后期分析会非常痛苦。
6. 实测中的计算瓶颈、DG接入与工程落地建议
6.1 N-1校验的计算量到底有多大
先把计算量摊开算一笔账:假设候选方案100个、每个方案校验37条支路,每个故障场景需要做一次转供路径搜索和一次潮流计算,那么一代就是3700次潮流计算,60代就是22万次。前推回代法每次求解按几毫秒计算,总时间大约10到20分钟。看起来可行,但如果把网络规模扩大到100节点以上,候选支路数量翻倍、校验元件数量翻倍,计算量直接涨4倍,优化一晚上都可能出不来结果。
我实测中的经验是三个加速手段组合使用。第一,预筛选——在跑N-1之前先做连通性预判,不满足辐射状约束或者连通性太差的个体直接淘汰,完全不进入N-1校验。第二,只校验关键元件——对馈线末端的短分支、轻载线路可以跳过N-1校验,重点只校验收敛馈线出口、长主干线和大负荷分支,这样校验元件数量能砍掉三分之一以上,风险可控。第三,借用Matlab并行计算,parfor替换for,把每个个体的N-1校验分到不同worker上。加上这三板斧,100节点规模的计算时间能压缩到原来的五分之一左右。
6.2 DG接入后的N-1校验新问题
现在做配电网规划,分布式电源基本躲不开。DG接入对N-1校验的影响是把双刃剑:好的方面,DG可以在孤岛模式下维持部分失电区域供电,减少失负荷量;麻烦的方面,DG的出力随机性和停运概率让N-1场景枚举变得更加复杂。比如,一个分布式光伏接入在馈线末端,在晴天午间故障时它可以带起局部孤岛,但到了夜间或阴雨天它出不了力,孤岛根本维持不了。
我在实际程序里对DG的处理方式是分层处理:规划阶段默认DG不参与孤岛运行,故障后失电区域里如果含DG,可以考虑DG与主网并联转供、由主网和DG共同供电的场景,但要同时校验故障发生在DG并网线路上以及DG本身停机两种情况。对于更精细的可靠性评估,最好用序贯蒙特卡洛模拟去统计全年的故障场景,而不是只做单一N-1枚举——那是另一个工作量量级的项目,但规划阶段的N-1校验可以先把主网架的联络能力做扎实。
6.3 从论文代码到工程落地的距离
最后聊聊工程落地。论文里的IEEE节点系统,线路参数整齐、负荷数据精确、假设条件单一,代码跑通很容易。但真实配电网项目里,你要面对的是几十个变电站、几百条馈线的存量网络,负荷数据大量缺失或者口径不一致,还有不同年份的改造约束。
我的建议是:代码框架保持分层解耦的设计,但数据接入层要做得灵活。最好的做法是把系统数据独立成Excel或数据库表,节点表、支路表、候选走廊表、负荷表完全由数据驱动,主程序里不要写死任何节点数或线路数。这样无论是IEEE 33节点算例,还是某个实际区域电网的1000节点模型,只需要换数据表就能跑。
另外,N-1校验结果不要只输出通过/不通过,要把“哪些线路故障会失电、失电多少、转供路径是什么”全部输出到报表。实际规划论证会上,决策者问得最多的不是“你用了什么算法”,而是“3号馈线故障怎么倒负荷、倒过去会不会过载”。代码能把这些问题回答清楚,才真正有工程价值。
6.4 一个小经验:先搭框架,再填算法
我自己写这类规划代码最大的体会是:不要一上来就陷入粒子群参数调优、遗传算子设计这些细节里。先把数据模型、拓扑校验、潮流计算、N-1校验这些底层模块写好,用一个小算例(比如改到十几节点的系统)验证每个模块的输出合理,再上完整算法和完整算例。底层模块不正确,上层算法再花哨都白搭。
我在第一次完整跑通程序的时候,就遇到一个非常隐蔽的bug:辐射状检查对于“现有网络本身包含联络开关但处于打开状态”的情况判断错误,导致初始种群大量个体被罚函数判为不可行,最优解一直搜索不出来。这个问题后来通过在构建网络对象时把打开的联络开关从活动支路集合中剔除才解决。这类细节没有实际调试经历,靠看代码很难发现,但一旦遇到,解决问题的过程本身就是对配电网规划理解加深的过程。
如果读者正在复现配电网N-1扩展规划这个课题,建议按照“数据准备 → 潮流基础 → 辐射状校验 → 单故障转供逻辑 → 完整N-1校验 → 优化算法封装”这个顺序逐步推进。先把潮流和故障转供逻辑用固定网架验证准确,再让优化算法去搜索网架方案,每一步都能看到明确的结果,调试起来也轻松得多。这套框架跑通之后,无论是扩展到多时段规划、考虑储能配置还是计及DG不确定性,都是在这个骨架上做增量开发了。