
搞配电网仿真的朋友应该都有共鸣以前算潮流网络里就几个电源点电压曲线老老实实后来分布式光伏一多中午光照最强的时候馈线末端电压直接飙到1.07甚至1.08自动配电终端天天报警。我去年接手一个含分布式光伏的配电网集群划分和集群电压协调控制项目用Matlab从建模、聚类到电压控制全部过了一遍踩了不少坑也整理出一套能直接改来用的代码框架。这篇就围绕集群划分怎么用谱聚类做、集群电压协调控制怎么用ADMM分层求解、以及Matlab代码怎么落地把关键细节和调试经验一并讲清楚。如果你是电力系统方向的研究生、做配网调控的工程师或者刚接触这类仿真的同学这篇文章能帮你少走至少一个月的弯路。1. 分布式光伏并网后的电压问题与集群控制思路1.1 光伏高渗透带来的电压越限现象传统配电网是辐射状结构功率从变电站单向流向负荷电压沿馈线逐渐降低。分布式光伏接入后情况完全变了。负荷低谷、光照最强的时候光伏出力大于本地负荷功率会从用户侧倒送回变电站馈线末端的电压因为反向功率流被明显抬高。电压降落公式还是那个经典的ΔU ≈ (PR QX) / U关键在于P和Q的方向。当光伏发出有功P为负值相对参考方向时ΔU变成负数末端电压反而高于首端。我实测过一个33节点系统下午两点光照峰值时末端节点电压跑到1.06 pu已经超出国标允许的1.05 pu如果没有措施过电压保护就会动作导致光伏脱网。这个问题不是单点问题而是整条馈线多个节点同时抬升。更麻烦的是光伏出力随机波动传统电容器组投切和变电站调压器响应速度跟不上。逆变器本身具备无功调节能力但如果没有一个协调机制各个逆变器各调各的很容易出现无功环流或者过补偿所以必须从系统层面做协调控制。1.2 集群划分与集群电压协调控制的核心思路很多做优化控制的朋友第一反应是建立全局优化模型把所有可控设备、所有节点电压都放进一个目标函数里。全局优化的确能得到理论最优但在实际配网中不太可行节点数量动辄几十上百可控设备种类繁多集中式控制器需要采集全部数据通信压力大而且一旦某个量测点延迟整个优化就得重来。集群划分的思路是把大网络切成几个子集群划分依据不是行政区域而是电气耦合强弱。集群内部节点之间电气距离近、电压无功耦合强集群之间耦合较弱。这样控制架构就变成两层第一层是集群内的自治控制负责快速平抑内部波动第二层是集群间协调控制只交换少量边界信息调整各集群的运行基点。这种思路的好处是计算规模明显变小每个集群只需要求解自己的局部优化问题而且通信需求大幅下降。对于一个含分布式光伏的配电网来说光伏接入位置往往分散按电气距离聚类之后同一个集群里的光伏和负荷在电压变化上具有相似的趋势协调起来事半功倍。1.3 控制架构选型集中式、就地式还是集群分布式三种控制方式各有适用场景。集中式全局优化需要全网状态信息理论上最优但对通信和计算要求高就地式控制只基于本地电压信息比如常见的Q-U下垂控制响应快但无法处理跨节点的协调问题尤其在多个光伏集群相互影响时会顾此失彼。集群分布式控制本质上是集中式和就地式的折中。它把全局优化问题分解到各个集群集群之间通过少量边界变量迭代协调既能获得接近全局优化的效果又保留了就地控制的快速性。我在项目里最终选了集群分布式方案配套使用ADMM交替方向乘子法做协调求解。这种结构对Matlab仿真来说还有个好处可以先用一个集群调试算法跑通之后再扩展到多个集群层层递进代码结构很清晰。控制方式信息需求通信压力最优性可靠性集中式全局优化全网状态高最优中心故障即失效就地式下垂控制本地电压无次优高集群分布式协调集群边界信息低接近最优可降级运行2. 集群划分方法原理与Matlab实现2.1 电气距离与模块度的数学含义集群划分不是随便画几个圈核心是定义节点间的“距离”。在配电网电压控制里最常用的是基于电压-无功灵敏度的电气距离。简单说节点i对节点j的无功注入引起的电压变化越强说明这两个节点电气耦合越紧密距离越近。具体做法是先做一次潮流计算得到稳态运行点然后对潮流方程中的电压和无功求偏导得到灵敏度矩阵S其中S(i,j)表示节点j注入无功对节点i电压幅值的影响。标准化处理之后把灵敏度转化为电气距离% 电气距离矩阵计算示例 % S: 电压-无功灵敏度矩阵由潮流雅可比逆矩阵取相应分块得到 n size(S, 1); D zeros(n, n); for i 1:n for j 1:n if i j D(i, j) 0; else % 常用的电气距离定义 D(i, j) -log(abs(S(i,j) / S(j,j)) * abs(S(j,i) / S(i,i))); end end end电气距离算出来之后还需要一个指标评估划分质量。我习惯用模块度Modularity这个概念最早来自社区发现用在电力系统集群划分上也很顺。模块度Q越大说明集群内部连接紧密、集群之间连接稀疏划分效果越好。项目里我一般把集群数K从2试到8对每个K跑谱聚类最后选Q最大的K。模块度的计算公式是Q (1 / (2m)) * Σ_ij [A_ij - k_i k_j / (2m)] * δ(c_i, c_j)其中A是权重邻接矩阵m是网络中总权重和k_i是节点i的权重度之和δ当节点i和节点j被划分到同一集群时取1否则取0。2.2 谱聚类实现步骤与参数选择谱聚类在Matlab里实现并不复杂核心步骤就四步。第一步把电气距离矩阵D转化为相似度矩阵W我常用高斯核函数sigma mean(D(D 0)); % 以非零距离均值为带宽 W exp(-D.^2 / (2 * sigma^2));第二步计算归一化拉普拉斯矩阵。第三步求解拉普拉斯矩阵的前K个最小特征值和特征向量把这K个特征向量按行堆叠成一个N×K的矩阵每一行就相当于是对应节点在低维空间里的新坐标。第四步对这个N×K矩阵做K-means聚类聚类结果就是最终的集群划分。这里有一个特别容易踩的坑直接调用eig求所有特征值在节点多的时候会很慢而且占用内存很大。我后来改用symmlq或者eigs只求最小几个特征值。Matlab里eigs默认求模最大的特征值要指定smallestabs才能拿到最小的那几个。实际测试中33节点系统用eigs和eig结果一致但速度快了将近10倍节点数上百时差距更明显。K-means的随机初始化问题也不需要担心设置Replicates, 20让Matlab自动尝试多组初始中心并把目标函数最小的结果返回。另外建议显式固定随机种子比如rng(2024)否则每次运行聚类结果都不一样排查问题时会很头疼。2.3 集群划分的Matlab完整代码框架下面我把谱聚类这块核心代码整理出来可以直接替换成自己的数据用% --------------------------------------------------------------------- % 基于电气距离的谱聚类集群划分 % 输入S - 电压无功灵敏度矩阵 % K_range - 候选集群数范围例如 2:6 % 输出best_idx - 最佳划分结果 % best_Q - 对应的模块度 % --------------------------------------------------------------------- rng(2024); % 1. 电气距离矩阵 D calc_electrical_distance(S); % 2. 相似度矩阵 sigma mean(D(D 0)); W exp(-D.^2 / (2 * sigma^2)); best_Q -inf; best_idx []; for K K_range % 归一化拉普拉斯矩阵 Dmat diag(sum(W, 2)); L_sym eye(size(W,1)) - Dmat^(-0.5) * W * Dmat^(-0.5); % 3. 前K个最小特征向量 [V, ~] eigs(L_sym, K, smallestabs); % 行归一化 V_norm V ./ vecnorm(V, 2, 2); % 4. K-means聚类 idx kmeans(V_norm, K, Replicates, 20); % 计算模块度 Q modularity(W, idx); if Q best_Q best_Q Q; best_idx idx; end end disp([最佳集群数: , num2str(max(best_idx))]);模块度函数建议用稀疏矩阵写避免大数据量下的O(N^2)遍历。计算时要特别注意将所有节点对都算进去然后只对同一集群内的节点对累加这样速度会快很多。我最初的版本用双重for循环33节点勉强能跑换成113节点直接卡死改成稀疏矩阵乘法后秒级完成。3. 集群电压协调控制策略设计与Matlab实现3.1 控制层级与变量定义集群划分完成之后电压控制分成两个层级。第一层是集群内的就地控制核心是光伏逆变器的无功电压下垂控制。每台逆变器根据本地电压偏差决定输出无功功率Q_pv Q_0 - k_q * (U_local - U_ref)下垂系数k_q取负值本地电压高时吸收无功电压低时发出无功。这一层不需要通信响应速度最快作用是快速压住短期波动。但就地控制没有全局视野可能造成某些集群无功过剩所以需要第二层协调。第二层是集群间的协调优化由各集群的局部控制器共同完成。每个集群控制器负责本集群内光伏逆变器的无功设定值、储能无功出力甚至可以通过遥控调节有载调压变压器分接头位置。控制变量定义为x_i [Q_pv_1, Q_pv_2, ..., Q_bat_i, TAP_i]^T目标函数要兼顾多目标电压偏差最小、网络损耗最小、无功调节量尽量小。写成数学形式就是加权的二次型目标约束条件包括潮流平衡方程、光伏逆变器视在功率上限、节点电压上下限、储能无功上下限等。3.2 ADMM分解把全局优化问题拆成集群子问题全局优化问题如果直接求解所有变量都在同一个约束里耦合计算量随着集群数量线性增长而且集中式求解需要收集所有集群的完整模型信息这在真实配电网中很难做到。ADMM的思路是引入全局一致性变量z把原本跨越集群的耦合约束分离出来。具体迭代过程分三步。第一步各集群并行求解自己的局部优化问题目标函数里加入一个关于本集群变量x_i和全局变量z的增广拉格朗日项。第二步收集所有集群的最新x_i更新z常见做法是取所有x_i在耦合约束上的平均值。第三步更新拉格朗日乘子u并计算原始残差和对偶残差判断是否收敛。标准迭代形式如下x_i^{k1} argmin [ f_i(x_i) (ρ/2) * ||x_i - z^k u^k||^2 ] z^{k1} mean(x_1^{k1}, x_2^{k1}, ..., x_m^{k1}) u^{k1} u^k x^{k1} - z^{k1}这里新增的ρ是惩罚参数起到平衡目标函数和一致性约束的作用。ADMM的优势在于每个集群只需要传入少量的边界耦合变量不需要把内部完整模型上报给上层很好地保护了信息隐私也降低了通信带宽。3.3 Matlab代码框架与关键迭代实现我在Matlab里的实现是用结构体params存放每个集群的拓扑参数、光伏容量、负荷预测值每个集群内部用fmincon或者自编的梯度投影法求解局部优化。局部优化里的潮流约束我用灵敏度模型近似也就是把节点电压增量近似的线性函数这样能大幅减少迭代中反复调用潮流的次数。核心迭代代码如下% --------------------------------------------------------------------- % ADMM 主循环 % --------------------------------------------------------------------- maxIter 100; tol 1e-4; rho 0.5; % 初始化 x cell(numClusters, 1); for i 1:numClusters x{i} zeros(size(params{i}.init_vars)); end z zeros(length(x{1}), 1); u zeros(length(x{1}), 1); for iter 1:maxIter % 第1步并行/串行更新集群局部变量 for i 1:numClusters x{i} solve_local_cluster_i(params{i}, z, u, rho); end % 第2步更新全局变量对耦合变量求均值 X_mean mean(cell2mat(x), 2); z X_mean; % 第3步更新乘子 u u rho * (X_mean - z); % 计算残差这里z与X_mean相同实际工程中z由边界耦合约束决定 r_pri norm(X_mean - z, inf); r_dual norm(rho * (z - z_prev), inf); if r_pri tol r_dual tol disp([ADMM收敛于迭代: , num2str(iter)]); break; end z_prev z; end上面代码里我为了展示结构把全局变量更新简单写成了均值形式。真正的配电网集群耦合变量其实是边界节点电压或边界注入功率需要根据潮流耦合关系构造一致性投影矩阵否则可能出现残差始终不下降的问题。这里建议先做单个集群的ADMM调试再扩展到多集群否则维数一旦上来定位错误会非常痛苦。4. 算例仿真与结果讨论4.1 测试系统与光伏接入配置项目里我用的是经典的IEEE 33节点配电网作为测试系统基准电压12.66 kV总负荷大约3.7 MW 2.3 Mvar。在原系统基础上做了改造在节点8、13、17、21、24和30接入分布式光伏光伏总容量1.9 MW逆变器容量按光伏容量1.1倍配置。接入位置特意选了馈线中部和末端用来模拟高渗透条件下末端电压越限的场景。光伏出力曲线我取了夏季晴天中午的数据光伏出力在12点到14点之间接近额定值而同时段负荷相对较低。末端节点比如18、22、31在无控制场景下电压都会超过1.06 pu。仿真时段取24小时采样间隔15分钟每个时点都做潮流计算和协调控制最后统计全天电压合格率和网损。节点光伏容量(kW)逆变器容量(kVA)接入位置特征8300330馈线前段13250275馈线中段17350385馈线中段21300330分支末端24250275分支末端30450495馈线末端4.2 仿真场景与对照组设计为了验证集群协调控制的价值我设计了三个场景。场景一“无控制”光伏以单位功率因数运行逆变器不参与调压这是目前很多实际电站的默认方式。场景二“就地Q-U下垂控制”每台逆变器根据本地电压偏差自行调整无功不和其他设备通信。场景三“集群协调控制”先用谱聚类把33节点分成3个集群然后在集群间用ADMM协调每个集群内部再对本集群光伏逆变器下发无功设定值。设置场景时有一个容易被忽略的细节下垂控制的系数必须设置合理太大会导致无功波动放大太小又起不到调压效果。我给的是死区±0.005 pu下垂系数k_q 20单位是无功出力(pu) / 电压偏差(pu)这样在电压偏差0.01 pu时逆变器输出无功大约0.2 pu留有余量。对比指标我记录了三项全时段最大电压、全时段电压偏差平方和、全天网损电量。第四项是光伏弃光率重点看有没有为了调压牺牲光伏出力。4.3 仿真结果与关键曲线说明结果比我预想的更直观。无控制场景下最大电压1.068 pu出现在14点左右的31号节点全天电压合格率只有86%。就地Q-U下垂控制把最大电压压到1.045 pu电压合格率提升到94%网损降低13%但在光伏出力快速波动时局部过补偿导致某些节点电压出现轻微凹陷。集群协调控制进一步把最大电压控制在1.031 pu全天电压合格率99.6%网损降低21%。集群划分后的控制效果比就地控制明显更平滑因为ADMM能在集群之间协调无功流向让末端集群的光伏少发无功、前段集群多承担调压任务整体无功流动更合理。集群划分可视化结果也很重要。用谱聚类划分出的3个集群基本沿着馈线主干自然分段前段集群包含节点1-10和部分分支中段集群以13、17为中心末端集群把22、25、30等电压敏感节点归到了一起。这说明电气距离聚类确实能识别出电压控制的自然分区和手工按馈线分段基本一致但又更精细。ADMM收敛曲线方面惩罚参数ρ0.5时大约18次迭代达到残差阈值1e-4每次迭代耗时0.3秒左右整个24小时仿真时长远低于全局集中优化。这个结果让我有底气说集群分布式控制在实际工程里是可行的。5. 实际调试中的常见问题与提速技巧5.1 潮流计算不收敛与节点类型处理配电网潮流仿真最容易出现的问题就是迭代不收敛。前推回代法在辐射状网络里很稳定但接入光伏之后如果光伏节点被建模成恒功率的PV节点算法容易在无功越限附近振荡。我建议把光伏节点处理成PQ节点无功初值设为0然后根据电压控制需要再更新无功设定值这样前推回代收敛性好很多。如果用的是牛顿拉夫逊法遇到雅可比矩阵奇异或者行列式接近零十有八九是网络拓扑中有孤立节点或者参数单位没统一。检查支路导纳矩阵rank是否等于N-1注意基准值转换别把线电压和相电压混用。这里有个实用技巧先用Matpower的runpf跑一遍确认潮流有解再把数据导到自己代码里能省大量排查时间。5.2 集群划分结果不稳定怎么办谱聚类结果不稳定多数原因是相似度矩阵的σ选得不合适。σ太小时矩阵会稀疏到失去全局信息σ太大时所有节点相似度趋同划分没有意义。我的经验是先看D矩阵的分布取中位数而不是均值再做个快速敏感性测试微调σ看划分结果会不会剧烈变化。K值选择也一样模块度曲线有时候比较平缓最大值不明显。这时候可以结合控制目标判断集群数量既要保证每个集群内节点数适中又要避免出现只有一个节点的“孤立户”。如果出现孤立集群我在K-means后加一个后处理把少于两个节点的集群合并到电气距离最近的集群中。5.3 ADMM收敛慢或者不收敛的调参经验ADMM收敛问题是最折磨人的。我遇到过一次残差在0.01附近震荡降不下去后来发现是不同集群的变量量纲差异太大光伏无功的标幺值在0到1之间而OLTC抽头是离散量范围可能只有0.9到1.1放在同一个增广项里互相干扰。解决办法是给每个变量乘一个对角归一化矩阵让同一变量的偏差有可比性。惩罚参数ρ也需要动态调整。固定ρ从0.5开始如果原始残差长时间不降增大ρ如果对偶残差太大减小ρ。具体实现% 自适应更新惩罚参数 if r_pri 10 * r_dual rho rho * 2; elseif r_dual 10 * r_pri rho rho / 2; end这个策略能让残差下降速度提升明显但建议每5到10次迭代才调整一次ρ避免参数震荡。另外全局变量z初始值不要取全零最好用上一时段的潮流解作为初值这样第一个时点的ADMM迭代次数能减少三分之一。5.4 Matlab代码运行速度优化方法整套仿真实测下来24小时场景如果每天96个点时点每个时点跑一次潮流加若干次ADMM迭代纯循环实现可能要跑十几分钟。我优化之后压到三分钟以内主要做了三件事。第一把电气距离矩阵、灵敏度矩阵全部用稀疏矩阵存储计算矩阵乘法时Matlab会自动加速。第二把潮流计算写成MEX函数或者用内置的matric操作代替for循环前推回代里的支路循环可以拆成向量运算。第三也是最关键的一点用灵敏度模型代替每次ADMM迭代中的完整潮流计算。因为协调控制的本质是调整无功电压变化可以用线性灵敏度近似只有等到控制量收敛后再做一次精确潮流校验。这个方法在电压偏差不大的情况下精度足够但光伏出力剧烈波动时要刷新灵敏度矩阵不能一直用老矩阵。我用profile命令看了耗时分布发现大部分时间耗在fmincon的内点法上后来改用了二次规划专用求解器quadprog速度提升非常明显。最后再分享一个实际项目里的小技巧不要一上来就追求把所有代码封装成一个巨型函数。我先写了一个run_voltage_control.m的主脚本里面按集群划分、控制计算、结果绘图分成三个小节每个小节对应一个函数调试时一行行跑能清楚看到每个阶段的结果。后面换到新的配电网拓扑时只需要替换数据文件和参数设置整套流程直接复用非常省事。这套框架我后来又用到过两个不同规模的配网模型上改起来确实快。