人工鱼群算法求解最优潮流:Matlab实现与参数整定
2026/9/14 12:01:11 网站建设 项目流程

简介:面向电力系统最优潮流计算问题,这份资料基于人工鱼群算法提供完整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.nG+1: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/(cost+eps)。鱼群算法内部只做比较运算,不需要知道真实成本数值,所以取相反数即可。需要注意的是,每条鱼每次评价食物浓度都要跑一次潮流,如果潮流计算是交流迭代,整体计算量会非常可观,这就是后面要把 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 建议取值 5~10,过大会让每次迭代的潮流计算次数爆炸,过小则觅食行为退化成纯随机游走。步长 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.6~0.9,越小代表对拥挤越敏感,鱼群越容易分散去探索新区域。

swarm.m 聚群行为的思路类似:先计算视野内所有同伴的中心位置,如果中心位置食物浓度高于当前位置,并且中心区域不拥挤,就向中心移动。这个行为让鱼群保持聚集性,避免变成多个孤立个体。这里不再展开代码,核心就是把 follow.m 中的“最优同伴”替换成“同伴中心”即可。

3.2 潮流计算与网络构建:dcflow.m、builtnet.m、liantong.m

dcflow.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'); % 纯数据文件直接load

load 适合纯数据文本,遇到非数值字符会报错;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.6,p_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节点系统上常用的范围:

参数推荐范围说明
种群规模 n20~50小于20容易陷入局部最优,大于50计算成本陡增
视野 visual搜索空间对角线长度的1/10~1/5太小则交互不足,太大则行为趋近随机搜索
步长 stepvisual 的1/5~1/3必须小于视野,否则跳过最优区域
拥挤度因子 delta0.6~0.9越大聚集性越强,越小越容易分散探索
尝试次数 try_number5~10每次尝试都要调用潮流计算,不宜过大

实际调参时,我习惯先固定 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,然后整体缩放这两个参数,比单独调整其中一个更快;每次只改一个参数并记录成本曲线,才能看出每次改动的影响。

本文还有配套的精品资源,点击获取

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

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

立即咨询