
简介面向电力系统最优潮流计算问题这份资料基于人工鱼群算法提供完整Matlab实现。内容覆盖鱼群算法的觅食、聚群、追尾等核心步骤并配有节点数据、线路参数等输入文本方便读者直接运行验证。程序采用参数化编程注释详细变量命名清晰适合自动化、电气工程及相关专业学生用于课程设计、期末大作业或毕业设计也便于初学者快速上手并理解群智能优化算法在潮流计算中的应用思路。资源包共11个文件以7个m脚本为主体包含主程序与功能函数模块另有3个txt数据文件和1张示意图整体仅9KB轻量易用。目前已有67人学习下载脚本可直接替换数据运行可根据实际电网参数快速得到最优潮流结果也可作为二次开发基础用于改进算法或扩展目标函数。1. 人工鱼群算法求解最优潮流为什么是这组Matlab文件最优潮流OPF是一个带等式和不等式约束的非线性规划问题传统内点法和简化梯度法的收敛性严重依赖初值选取海森矩阵近似稍有偏差就会发散。人工鱼群算法AFSA不计算梯度靠模拟鱼群觅食、聚群、追尾、随机四种行为在解空间搜索反而能在目标函数非凸、约束边界强的情况下找到可用的可行解。这组Matlab代码把算法拆成 prey.m、follow.m、swarm.m 三个核心行为函数用 builtnet.m 构建节点导纳矩阵再用 dcflow.m 做快速潮流校验最终由 guihua.m 串联整个优化流程。对做课程设计的学生来说替换数据文件即可跑通对做配电网规划或电力市场出清的一线工程师真正值得看的是鱼群行为参数与潮流计算模块之间的接缝设计。2. 从OPF约束到人工鱼群位置编码数学模型与算法映射2.1 OPF的数学形式与变量拆分最优潮流问题的目标函数通常取发电成本最小用二次函数拟合每台机组的费用曲线min F sum( a_i * P_gi^2 b_i * P_gi c_i )其中 P_gi 是第 i 台发电机的有功出力a_i、b_i、c_i 为成本系数。等式约束是节点功率平衡方程即每个节点的注入有功和无功必须等于负荷加上与相邻节点交换的功率不等式约束则覆盖发电机有功/无功上下限、节点电压幅值上下限、线路传输容量上限。如果直接用 fmincon 这类梯度化工具求解必须提供雅可比矩阵和海森矩阵或者至少准备一套可靠的有限差分。而人工鱼群算法只需要一个“食物浓度”函数能够比较任意两个解的优劣即可。因此第一步是把 OPF 的决策变量拆成两组控制变量发电机有功出力、机端电压幅值、变压器变比、无功补偿容量。这部分直接编码到人工鱼的位置向量里。状态变量负荷节点电压幅值、所有节点相角。这部分由潮流计算方程隐式求出不需要鱼群算法去搜索。实际编码时一条鱼的位置 X [P_g1, P_g2, ..., V_g1, V_g2, ...]维度等于控制变量个数。鱼个体在解空间移动每一步都意味着一次发电机出力调整或电压调整。这种拆分方式让鱼群算法只处理少数几十个变量而把几十上百个节点电压的耦合关系交给潮流求解器避免解空间维数爆炸。2.2 鱼群行为到优化变量的映射食物浓度函数食物浓度函数是连接鱼群算法与OPF的桥梁。常见做法是在目标函数基础上叠加惩罚项把越限的电压、线路潮流转换成巨大的惩罚值这样即使个体落在不可行区域也能获得“往回走”的梯度方向。核心逻辑可以写成下面这个函数function cost opf_fitness(x, net) % x: 控制变量向量前net.nG个为有功出力其余为机端电压 net.Pg x(1:net.nG); net.Vg x(net.nG1:end); [V, theta, Pg, Qg] powerflow_solve(net); % 内部调用牛顿-拉夫逊潮流 f sum(net.a .* Pg.^2 net.b .* Pg net.c); penalty 0; % 电压越限惩罚 if any(V net.Vmin) || any(V net.Vmax) dv min(V - net.Vmin, 0) max(V - net.Vmax, 0); penalty penalty 1e4 * sum(dv.^2); end cost f penalty; end这段代码里 powerflow_solve 是潮流求解函数可以由 dcflow.m 的线性直流潮流替换也可以换成交流牛顿-拉夫逊。惩罚系数 1e4 是经验值太小会让鱼群认为电压越限无所谓太大则会把可行边界附近的最优解全部压死。我一般先把系数设为成本量级的一千倍再根据残差曲线微调。食物浓度函数在人工鱼群中定义为 fitness -cost或者用 1/(costeps)。鱼群算法内部只做比较运算不需要知道真实成本数值所以取相反数即可。需要注意的是每条鱼每次评价食物浓度都要跑一次潮流如果潮流计算是交流迭代整体计算量会非常可观这就是后面要把 dcflow.m 拆出来做快速筛选的原因。2.3 为什么选人工鱼群而不是遗传算法同一套工程问题用遗传算法GA、粒子群PSO和人工鱼群AFSA都能解但行为特性差别明显。下面这个表格展示了在中等规模OPF算例上的典型差异算法是否依赖梯度局部极值逃逸能力参数数量后期收敛速度对约束惩罚的敏感度内点法是无少快高遗传算法 GA否中中中中粒子群 PSO否低少较快中人工鱼群 AFSA否高中慢低遗传算法的交叉、变异需要对编码方式做精心设计如果控制变量里同时含有有功出力和电压幅值不同量纲会相互干扰。粒子群收敛快但容易早熟在多峰OPF问题上经常停在局部最优。人工鱼群通过聚群和追尾两种行为维持全局搜索又用觅食行为做局部扰动逃逸能力最强。代价是后期收敛速度明显下降鱼群在最优解附近反复震荡。对于课程设计常用的IEEE 30节点或57节点系统这种速度完全可以接受对于更大规模系统就需要用到第5章的混合策略。3. 拆开prey.m/follow.m/swarm.m行为函数与dcflow/builtnet的配合3.1 觅食、追尾、聚群在Matlab里怎么落盘prey.m 是人工鱼群的基石行为。每条鱼在视野范围内随机试探 try_number 次如果找到食物浓度更高的位置就移动一步否则随机移动。项目里把这个行为单独拎出来是为了让 swarm.m 和 follow.m 在判断失败时都可以回退调用它。优先实现觅食能保证任何情况下鱼群都不会静止function newX prey(X, i, visual, step, try_number, fitness) x X(i,:); for k 1:try_number x_next x visual * (rand(size(x)) * 2 - 1); if fitness(x_next) fitness(x) d x_next - x; nd norm(d); if nd 0 newX x step * d / nd; else newX x; end return; end end newX x step * (rand(size(x)) * 2 - 1); end注意这里 fitness 是函数句柄由 guihua.m 在初始化时传入确保 prey.m 可以复用不同算例。try_number 建议取值 510过大会让每次迭代的潮流计算次数爆炸过小则觅食行为退化成纯随机游走。步长 step 取视野 visual 的 1/5 到 1/3 比较合理太大容易越过最优解太小则前期收敛过慢。follow.m 负责追尾行为也就是向视野内食物浓度最高的同伴靠拢。与遗传算法的精英保留不同AFSA 追尾是有条件的如果最优同伴周围鱼群太密集拥挤度因子会否决这次移动。简化代码如下function newX follow(X, i, visual, step, delta, fitness) n size(X, 1); x X(i,:); best_fit -inf; best_j i; for j 1:n if j i, continue; end if norm(X(j,:) - x) visual fitness(X(j,:)) best_fit best_fit fitness(X(j,:)); best_j j; end end if best_j ~ i best_fit fitness(x) spread sum(exp(-sum((X - X(best_j,:)).^2, 2) / (visual^2))); if spread delta * n d X(best_j,:) - x; nd norm(d); if nd 0 newX x step * d / nd; return; end end end newX prey(X, i, visual, step, 1, fitness); end拥挤度判断用的是统计视野内同伴数量的方式也可以写成“视野内同伴数 / 总数 delta”。delta 通常取 0.60.9越小代表对拥挤越敏感鱼群越容易分散去探索新区域。swarm.m 聚群行为的思路类似先计算视野内所有同伴的中心位置如果中心位置食物浓度高于当前位置并且中心区域不拥挤就向中心移动。这个行为让鱼群保持聚集性避免变成多个孤立个体。这里不再展开代码核心就是把 follow.m 中的“最优同伴”替换成“同伴中心”即可。3.2 潮流计算与网络构建dcflow.m、builtnet.m、liantong.mdcflow.m 实现的是直流潮流忽略了无功和电压幅值变化只解有功分布。常见做法是用节点导纳矩阵的虚部 B 构建线性方程 P B * theta其中 theta 为节点相角。直流潮流在人工鱼群迭代中承担两件事一是快速预估每条鱼的网络损耗和有功越限情况二是为交流潮流提供初始相角。因为直流潮流只需解一次稀疏线性方程速度比交流牛顿-拉夫逊快一到两个数量级适合放在觅食试探的内层循环里。builtnet.m 负责从支路参数表构建节点导纳矩阵。典型输入是 five 列或六列数据起始节点、终止节点、电阻、电抗、对地导纳。核心循环如下function Ybus builtnet(branch) n max(max(branch(:,1:2))); Ybus zeros(n); for k 1:size(branch,1) f branch(k,1); t branch(k,2); z branch(k,3) 1j * branch(k,4); y 1 / z; Ybus(f,f) Ybus(f,f) y 1j * branch(k,5) / 2; Ybus(t,t) Ybus(t,t) y 1j * branch(k,5) / 2; Ybus(f,t) Ybus(f,t) - y; Ybus(t,f) Ybus(t,f) - y; end end这段代码把每条支路的串联导纳加到自导纳把负互导纳填入互导纳位置。注意对地导纳被平分到两端节点这是电力系统分析的标准约定。liantong.m 的作用是检查网络是否连通防止数据里存在孤立节点导致导纳矩阵奇异。在 guihua.m 中建议先调用 liantong.m如果返回不连通就直接报错而不是等到潮流计算发散后再回头排查。3.3 数据文件读取与Pi.txt/yjzl.txt/dxzl.txt格式项目根目录下的 Pi.txt、yjzl.txt、dxzl.txt 分别保存节点注入功率、支路数据、负荷数据。这些文件用空白符分隔但可能带表头或注释行所以不能直接 load。兼容做法是raw importdata(Pi.txt, , 1); % 跳过第一行表头 Pi raw.data; yjzl dlmread(yjzl.txt, \t); % 如果Tab分隔 dxzl load(dxzl.txt); % 纯数据文件直接loadload 适合纯数据文本遇到非数值字符会报错importdata 能自动处理表头但如果表头里含有中文某些版本Matlab会识别异常建议先打开文件自己看一眼前两行。dxzl.txt 这种纯数据文件最安全直接 load 即可。数据读取错误是新手拿到工程后第一个会踩的坑。常见情况是 dlmread 默认逗号分隔而文件里是空格或tab导致读进来全为一个超宽矩阵。我一般会写一小段断言检查矩阵维度是否和 builtnet.m 使用的节点数匹配不匹配就停止运行并打印预期维度和实际维度。4. guihua.m主流程与人工鱼群参数整定换数据前先改这几个地方4.1 从数据到最优解的调用链guihua.m 是整个工程的入口它的调用链决定了工程的可扩展性。标准流程是加载数据 → builtnet.m 构建导纳矩阵 → liantong.m 验证连通性 → 初始化鱼群位置 → 进入迭代循环 → 每个个体按一定概率执行觅食、追尾、聚群 → 用 dcflow.m 做快速潮流评价 → 更新历史最优 → 输出结果。主循环里最关键的是行为调度策略不能每一条鱼都同时执行所有行为否则计算量会翻三倍。常见做法是给聚群和追尾分配概率例如 p_follow 0.6p_swarm 0.4如果对应行为失败则回退到觅食。下面是一个可运行的主循环骨架% 初始化鱼群bounds为每条鱼各维度的上下界 pop rand(n, dim) .* (bounds(:,2) - bounds(:,1)) bounds(:,1); best_fitness -inf; for gen 1:maxgen for i 1:n if rand 0.6 new follow(pop, i, visual, step, delta, opf_fitness); else new swarm(pop, i, visual, step, delta, opf_fitness); end if opf_fitness(new) opf_fitness(pop(i,:)) pop(i,:) new; else pop(i,:) prey(pop, i, visual, step, try_number, opf_fitness); end end [fval, idx] max(arrayfun((i) opf_fitness(pop(i,:)), 1:n)); if fval best_fitness best_fitness fval; best_x pop(idx,:); end step step_max - (step_max - step_min) * gen / maxgen; end这段代码先执行较激进的聚群或追尾如果新的位置没有变得更好就退回局部觅食。step 随迭代线性从 step_max 降到 step_min前期大步长探索后期小步长精修。注意 opf_fitness 内嵌了潮流计算所以这里的 arrayfun 循环在鱼群数量增多时会成为瓶颈如果换成 parfor 并行需要保证 opf_fitness 对 net 结构体的处理是只读的。4.2 关键参数与整定经验人工鱼群算法最需要调的是五个参数种群规模 n、视野 visual、步长 step、拥挤度因子 delta、尝试次数 try_number。下面是我在IEEE 30节点系统上常用的范围参数推荐范围说明种群规模 n2050小于20容易陷入局部最优大于50计算成本陡增视野 visual搜索空间对角线长度的1/101/5太小则交互不足太大则行为趋近随机搜索步长 stepvisual 的1/51/3必须小于视野否则跳过最优区域拥挤度因子 delta0.60.9越大聚集性越强越小越容易分散探索尝试次数 try_number510每次尝试都要调用潮流计算不宜过大实际调参时我习惯先固定 visual:step 3:1然后整体缩放。如果成本曲线持续震荡无法收敛说明 step 太大如果前期下降平缓说明 visual 太小。拥挤度因子对结果影响最微妙delta 取 0.9 时鱼群聚集性强容易快速收敛但可能早熟取 0.6 时鱼群分散性强不易早熟但后期收尾慢。建议在课程设计里先用标准测试函数如 Rastrigin验证参数再挂到 OPF 上避免被潮流计算的高频波动干扰判断。4.3 新手替换数据时最容易错的三个点第一节点编号必须从 1 开始连续编号。builtnet.m 用 max(max(branch(:,1:2))) 决定导纳矩阵维度如果节点编号是 5、8、12 这种稀疏编号导纳矩阵会被放大成 12 维实际只有 3 个节点参与计算直流潮流结果完全错误。第二功率数据必须统一成标幺值。Pi.txt 里的有功注入如果写的是实际兆瓦值而直流潮流的导纳矩阵用的是标幺值解出的相角会小一两个数量级鱼群算法会误以为这些解都很好最后得到一组没有任何工程意义的控制变量。第三控制变量顺序必须与 guihua.m 里 bounds 矩阵的行序一致。比如 bounds 第一行定义第一个发电机的有功范围那 pop 第 1 列对应的就必须是同一台发电机的有功出力。如果数据里机组顺序和 bounds 定义顺序不一致最优解即便收敛了也对应错位。提示替换数据后先做一次固定初值的直流潮流测试把算出的节点相角与已知参考值比较确认网络构建无误后再加鱼群算法能省下大量排错时间。5. 进阶用潮流残差验证AFSA结果并用内点法收尾5.1 先验证再信结果人工鱼群算法收敛后不能只看成本曲线下降就认为找到了可行解。由于 fitness 函数里带惩罚项鱼群可能在惩罚系数不够大时停留在轻微越限的位置。验证方法是在最优解处重新做一次严格交流潮流检查节点注入功率残差[V, theta] powerflow_solve(net, best_x); S_calc V .* conj(Ybus * V) / baseMVA; res net.Spec .* exp(1j*net.Pinj) - S_calc; % 节点注入功率残差 if max(abs(res)) 1e-6 warning(结果未通过潮流残差校验检查惩罚系数); end如果残差过大优先增大 opf_fitness 里的惩罚系数而不是增加迭代代数。惩罚系数的物理意义是“对越限的容忍度”IEEEE 30节点系统上 1e4 通常够用但换成高阻抗支路居多的系统后电压越限的平方量级会放大需要相应调高到 1e5 或 1e6。5.2 AFSA与fmincon混合策略因为人工鱼群后期收敛速度极慢把鱼群找出的较优解作为内点法的初值是一种实用策略。内点法对初值敏感但靠近全局最优点时收敛极快。代码上只需要把鱼群最优解作为 x0 传入约束优化函数options optimoptions(fmincon, Algorithm, interior-point, ... Display, off, MaxIterations, 200); [x_refine, fval_refine] fmincon(opf_fitness, best_x, ... [], [], [], [], lb, ub, opf_con, options);这里 opf_con 返回等式约束节点潮流方程和不等式约束电压、线路容量作用域只在最终精炼阶段。混合策略在IEEE 30节点上通常能把成本再压低 0.5%1%并且严格满足所有约束。调参技巧是先固定 visual 与 step 的比值为 3:1然后整体缩放这两个参数比单独调整其中一个更快每次只改一个参数并记录成本曲线才能看出每次改动的影响。本文还有配套的精品资源点击获取