灰狼优化算法GWO整定单区域负荷频率控制PID参数:Simulink仿真实践

发布时间:2026/9/16 3:02:30
灰狼优化算法GWO整定单区域负荷频率控制PID参数:Simulink仿真实践
干电力系统仿真这行的估计都绕不开“负荷频率控制LFC”这道坎。我最初入坑这个方向就是拿着“基于灰狼优化算法GWO整定单区域负荷频率控制PID参数”这个题目在Matlab和Simulink里反复搭模型、跑仿真、调参数一度被各种奇奇怪怪的报错和收敛问题折腾到怀疑人生。后来把整套逻辑理顺之后发现其实核心就三件事把被控对象模型搭对、把优化目标函数写清楚、把GWO和Simulink的数据通道接好。这篇文章我就按自己实际跑通的经验把整套流程从模型原理、Simulink搭建、GWO代码实现到结果分析完整写一遍给正在做毕业设计或者想入门智能优化算法整定PID的同学一个能直接“抄作业”的参考。我默认你有基本的Matlab和Simulink使用基础至少知道怎么拖模块、怎么运行仿真。整篇文章不会讲太虚的理论重点放在可复现的步骤和容易踩的坑上。1. 项目背景与整体方案选型1.1 单区域LFC到底在解决什么问题电力系统的频率是衡量发电和用电平衡的核心指标负荷变化会导致频率波动。单区域负荷频率控制的本质就是用调速器、汽轮机和发电机转子构成的闭环系统在负荷扰动出现后通过调节原动机出力让频率偏差Δf尽快恢复到零。单区域模型是LFC研究里最基础的入门砖它把整个电力系统简化为一个等值发电机忽略联络线功率交换。这样处理的好处是把控制问题聚焦在“频率偏差抑制”这一个核心目标上方便我们先把控制算法跑通。Simulink里搭建单区域LFC模型也是大多数论文和毕设的标准操作因为结构清晰、参数直观还能方便扩展到两区域甚至多区域。在这个模型里PID控制器承担的角色是系统的二次调频它根据频率偏差实时输出调节指令改变调速器的阀门开度从而改变汽轮机机械功率最终抵消负荷扰动的影响。可以说PID参数整定得好不好直接决定频率恢复的速度和超调量。1.2 传统PID整定方法为什么会力不从心很多人第一反应是PID参数直接用Matlab的自动整定工具不就行了或者用经典的Ziegler-Nichols公式算一算。这些方法对简单过程控制对象确实有效但用到LFC模型上就有些吃力。原因在于单区域LFC被控对象是多个惯性环节串联还带有负荷扰动输入。ZN法本质上是基于系统的临界增益和临界周期做近似对高阶对象的整定精度不够整定出来的参数往往是“能稳定但不是最优”频率偏差的恢复时间较长超调量也不理想。手动试凑法就更看经验和运气了面对5个传递函数系数加PID三个参数纯靠试凑想找到一个接近最优的参数组合效率实在太低。智能优化算法解决的就是这个“黑箱寻优”问题。我们不依赖被控对象的精确数学模型直接以PID参数为优化变量以频率偏差的动态性能指标为目标函数让算法自己去找最优参数。这也是为什么近年来灰狼优化算法、粒子群算法、遗传算法在LFC整定方向大量出现。1.3 为什么选择灰狼优化算法(GWO)灰狼优化算法是Mirjalili在2014年提出的一种群体智能算法它在PID整定场景下有几个非常实用的优点。第一是控制参数少GWO主要只需要设置种群规模和迭代次数不像遗传算法要考虑交叉率、变异率也不像粒子群要调惯性权重、个体学习因子和社会学习因子。参数少意味着调试成本低算法更容易收敛。第二是算法结构简单核心就是包围、追捕、攻击三个数学步骤写代码也就几十行非常适合和Simulink结合做循环优化。第三是全局搜索能力比较均衡GWO的搜索机制基于狼群等级制度和猎物包围策略既能保持种群多样性又能在后期快速收敛实测下来在LFC这类中等维度优化问题上表现稳定。密钥和授权信息先放一边我们直接进入正题先把Simulink模型搭好这是后面所有优化的基础。2. 单区域LFC的Simulink模型搭建2.1 传递函数模型和典型参数选择单区域LFC的线性化模型通常由三个主要环节组成调速器、汽轮机和发电机-负荷环节。如果按经典文献的简化模型它们的传递函数分别是调速器Gg(s) 1 / (Tg·s 1)汽轮机Gt(s) 1 / (Tt·s 1)发电机-负荷Gp(s) Kp / (Tp·s 1)其中Tg是调速器时间常数Tt是汽轮机时间常数Tp是发电机-负荷时间常数Kp是发电机增益。此外还有一个重要的反馈通道也就是调差系数R速度调节系数它反映了一次调频的作用。不同文献给出的参数差异比较大我用的是经过验证的常用参考值实际建模时可以根据自己的场景修改参数数值说明Tg0.2 s调速器时间常数Tt0.5 s汽轮机时间常数Tp20 s发电机-负荷时间常数Kp100发电机增益R0.05调差系数单位Hz/MW系统整体是闭环结构负荷扰动ΔPL作为输入频率偏差Δf作为输出。控制器输出的调节信号叠加到调速器输入端同时频率偏差通过1/R反馈到求和点模拟一次调频的自动作用。2.2 Simulink模块连接与信号走向在Simulink里新建一个模型我习惯命名为LFC_GWO.slx。需要的模块主要有Step模块作为负荷扰动输入Step time设置为1秒幅值设为0.01表示1%的负荷扰动求和模块用来做信号叠加传递函数模块Transfer Fcn分别表示调速器、汽轮机和发电机-负荷Gain模块增益值为1/RPID Controller模块输出到调速器前Clock、Abs、Integrator、To Workspace模块用于计算ITAE指标信号走向是这样的频率偏差Δf经过1/R增益后与参考值0比较产生控制偏差这个偏差送入PID控制器PID输出作为调节信号和负荷扰动一起进入调速器和汽轮机最后由发电机-负荷环节得到新的频率偏差。这里有个细节需要注意PID控制器模块在较新版本Matlab中默认支持抗积分饱和anti-windup可以保持默认设置但如果出现积分饱和导致的振荡可以把限制器打开或者改成conditional clamping。ITAE计算部分我的做法是用Clock模块输出时间t乘以|Δf|取绝对值后的信号再通过积分器对时间积分最后用To Workspace模块存到工作区变量ITAE中。注意To Workspace的Save format要选Array或Structure with time方便后续脚本读取。2.3 把PID参数变成工作区变量这一步是整个联合仿真最关键的地方。要让GWO算法能够反复修改PID参数就不能在PID Controller模块里写死参数而是要把参数名设置为工作区变量。具体做法是双击PID Controller模块在参数P、I、D的输入框中不要填数字而是分别填Kp、Ki、Kd。这样每次运行仿真前只要先用assignin函数把Kp、Ki、Kd这几个变量写入Matlab基础工作区Simulink在仿真时就会自动读取这些变量的值。为了让优化流程闭环模型里PID输入端的参考值通常设成0测量信号接实际频率偏差这样得到的偏差e就是−Δf适合ITAE计算时的绝对值取数。模型搭完后先手动设一组初始PID参数比如Kp1、Ki0.5、Kd0.2运行一次仿真检查模型是否正确收敛频率偏差曲线是否在扰动后能够逐渐回稳。这一步一定要做不要直接上优化算法否则模型本身有问题会让优化过程非常痛苦。3. GWO优化PID参数的核心实现3.1 灰狼优化算法的数学原理灰狼优化算法的灵感来自灰狼群体的等级制度和狩猎行为。算法把搜索空间中的每个解看成一只“狼”最优解称为α狼第二优解称为β狼第三优解称为δ狼其余解统称为ω狼。α、β、δ引导整个狼群向猎物位置靠近。在数学上包围猎物和位置更新的核心公式是距离向量D |C·Xp(t) − X(t)|位置更新X(t1) Xp(t) − A·D其中Xp是猎物位置或当前最优狼的位置X是灰狼位置A和C是系数向量。系数A和C由以下公式计算A 2a·r1 − aC 2r2a从2线性衰减到0r1和r2是[0,1]范围内的随机数。a的衰减意味着迭代前期狼群大步搜索后期小步逼近这正好符合优化过程“先全局探索后局部开发”的需求。每次迭代中α、β、δ三只头狼分别按照上述公式对每个ω狼的位置进行修正最终ω狼的新位置取三者的平均值X1 Xα − A1·DαX2 Xβ − A2·DβX3 Xδ − A3·DδX(t1) (X1 X2 X3) / 33.2 GWO主循环代码实现下面给出我调试通过的GWO主程序代码这个代码是完整可运行的只要把模型名和变量名对应上基本不需要大改。function [Best_pos, Best_fit, Convergence] GWO_LFC(SearchAgents, Max_iter, dim, lb, ub) % 初始化狼群位置 Positions rand(SearchAgents, dim) .* (ub - lb) lb; Fitness zeros(SearchAgents, 1); % 评估初始适应度 for i 1:SearchAgents Fitness(i) LFC_Fitness(Positions(i, :)); end % 初始化α、β、δ狼 [Best_fit, sortIdx] sort(Fitness); Alpha_pos Positions(sortIdx(1), :); Alpha_score Fitness(sortIdx(1)); Beta_pos Positions(sortIdx(2), :); Beta_score Fitness(sortIdx(2)); Delta_pos Positions(sortIdx(3), :); Delta_score Fitness(sortIdx(3)); Convergence zeros(1, Max_iter); for t 1:Max_iter a 2 - 2 * t / Max_iter; for i 1:SearchAgents for j 1:dim % 利用α狼更新 r1 rand(); r2 rand(); A1 2 * a * r1 - a; C1 2 * r2; D_alpha abs(C1 * Alpha_pos(j) - Positions(i, j)); X1 Alpha_pos(j) - A1 * D_alpha; % 利用β狼更新 r1 rand(); r2 rand(); A2 2 * a * r1 - a; C2 2 * r2; D_beta abs(C2 * Beta_pos(j) - Positions(i, j)); X2 Beta_pos(j) - A2 * D_beta; % 利用δ狼更新 r1 rand(); r2 rand(); A3 2 * a * r1 - a; C3 2 * r2; D_delta abs(C3 * Delta_pos(j) - Positions(i, j)); X3 Delta_pos(j) - A3 * D_delta; Positions(i, j) (X1 X2 X3) / 3; % 边界检查 if Positions(i, j) ub(j) Positions(i, j) ub(j); elseif Positions(i, j) lb(j) Positions(i, j) lb(j); end end % 重新评估适应度 Fitness(i) LFC_Fitness(Positions(i, :)); end % 更新α、β、δ狼 allFit [Fitness, (1:SearchAgents)]; sortedFit sortrows(allFit, 1); if sortedFit(1,1) Alpha_score Alpha_score sortedFit(1,1); Alpha_pos Positions(sortedFit(1,2), :); end if sortedFit(2,1) Beta_score Beta_score sortedFit(2,1); Beta_pos Positions(sortedFit(2,2), :); end if sortedFit(3,1) Delta_score Delta_score sortedFit(3,1); Delta_pos Positions(sortedFit(3,2), :); end Convergence(t) Alpha_score; fprintf(迭代次数: %d, 最优适应度: %.6f\n, t, Alpha_score); end Best_pos Alpha_pos; Best_fit Alpha_score; end这个代码写得很直观我在实际跑通前也经历过几轮调整主要问题集中在适应度函数和Simulink的数据交互下面重点讲这部分。3.3 适应度函数和ITAE指标计算适应度函数是连接GWO和Simulink的桥梁。它接收一组PID参数调用Simulink仿真然后把仿真结果转化为一个数值指标返回给优化算法。在LFC中最常用的指标是ITAE时间乘以绝对误差积分公式为ITAE ∫₀ᵀ t·|Δf(t)| dtITAE相比ISE、IAE的优势在于它对时间加权后期的小幅偏差也会被放大因此优化出来的系统既能快速响应又不容易出现长时间的拖尾稳态误差。这一点对频率控制特别合适因为频率偏差哪怕很小只要持续时间长对电力系统也是不利的。适应度函数代码如下function ITAE LFC_Fitness(x) Kp x(1); Ki x(2); Kd x(3); % 将PID参数传给Simulink模型中的变量 assignin(base, Kp, Kp); assignin(base, Ki, Ki); assignin(base, Kd, Kd); % 运行仿真 try simOut sim(LFC_GWO.slx, StopTime, 20); ITAE_value simOut.ITAE.Data; ITAE ITAE_value(end); catch % 仿真报错时返回一个很大的惩罚值 ITAE 1e6; end if isnan(ITAE) || isinf(ITAE) ITAE 1e6; end end这里有几个非常容易出错的地方我逐一说明。第一sim函数的调用方式。在较旧的Matlab版本中直接写[t,x,y] sim(模型名)比较常见。但新版Simulink推荐用simOut sim(模型名, StopTime, 20)返回一个SimulationOutput对象然后通过simOut.变量名.Data读取数据。如果你用的是To Workspace模块注意块命名必须唯一数据保存格式会影响读取方式。第二为什么用try-catch。我调试时经常遇到的情况是GWO在边界附近生成的参数过大会导致仿真发散而Simulink仿真发散时Matlab会直接报错中断脚本。如果不加try-catch整个优化循环就会停下来。加了之后一旦仿真报错就返回一个很大的适应度值引导算法自动淘汰这些参数。第三ITAE读取的Data格式。如果To Workspace模块的Save format选了Array那么读取时用simOut.ITAE(end)就行。选Structure with time时需要simOut.ITAE.Data。我建议统一用Array格式简单直接。3.4 搜索空间和算法参数设置GWO的搜索空间设置很关键直接决定收敛速度和结果质量。我采用的三维变量是Kp、Ki、Kd而不是Kp、Ti、Td。原因很简单Simulink的PID Controller模块直接填入P、I、D参数时I参数就是KiD参数就是Kd和GWO搜索变量一一对应。如果非要用Ti和Td就得在模块里写KiKp/Ti、KdKp*Td这样变量之间存在耦合关系搜索效果会差一些问题排查也麻烦。搜索范围我用的是Kp ∈ [0, 10]Ki ∈ [0, 5]Kd ∈ [0, 2]这个范围是我多次测试后得到的合理区间既能覆盖大多数LFC模型的PID参数范围又不会因为边界过宽导致大量仿真发散。如果你改动了模型参数导致最优值偏移可以观察收敛结果是否落在边界附近如果是就说明边界需要扩大。GWO算法本身的参数设置比较简单种群数量20~30最大迭代次数30~50搜索维度3种群数量不建议太大因为每次适应度计算都要跑一次Simulink仿真种群翻倍仿真时间也接近翻倍。我实测下来25只狼跑40次迭代总仿真次数是1000次在普通笔记本上大概需要10到20分钟如果模型复杂或者仿真时间太长可以考虑用快速加速器模式Rapid Accelerator来提速。4. 仿真结果分析与参数对比4.1 收敛过程和最优参数结果运行GWO优化程序后会看到每一代的收敛值。我这里给出一次具有代表性的运行结果最优参数收敛为Kp 1.823Ki 0.456Kd 0.347对应的ITAE值大约在0.052左右。收敛曲线呈现典型的GWO特征迭代前10代适应度快速下降说明狼群从随机初始位置迅速向最优区域聚集后面30代下降速度变慢逐步做局部精细搜索。这里需要提醒一下GWO属于随机优化算法每次运行结果会有小幅波动。如果你发现两次运行最优参数差异很大通常说明迭代次数不够或者搜索范围设置不合理。同一参数范围下多跑几次取适应度最好的结果是论文写作和工程调试中的常见做法。4.2 GWO整定参数和传统整定方法对比为了说明优化效果我用传统的Ziegler-Nichols整定方法得到一组对比参数同时在相同Simulink模型下做相同负荷扰动的仿真对比结果如下整定方法KpKiKdITAE超调量(%)调节时间(s)ZN法0.8500.3020.1430.09715.211.8手动试凑1.2000.3500.2000.0718.69.2GWO优化1.8230.4560.3470.0524.36.5从数据可以看出GWO整定的参数在ITAE、超调量和调节时间三个指标上都明显优于ZN法和手动试凑法。特别是超调量从15.2%降到4.3%频率偏差的最大幅值大幅减小这对于电力系统频率质量来说意义很大。调节时间从11.8秒缩短到6.5秒意味着系统抗扰动恢复能力显著提升。频率偏差响应曲线的对比趋势是GWO整定情况下负荷扰动发生后频率偏差更早达到峰值且峰值明显更小回落过程几乎无振荡。手动试凑的参数虽然也能稳住但会经历一到两次明显振荡这在真实电力系统里往往伴随着机械部件磨损和系统稳定性隐患。4.3 不同负荷扰动幅值下的鲁棒性表现优化定参的下一步是验证鲁棒性。我分别把负荷扰动幅值设为0.01、0.02和0.05保持PID参数不变观察系统响应。结果比较理想扰动增大时频率偏差峰值相应增大但系统始终保持稳定没有出现发散。这主要得益于ITAE指标训练的控制器对动态过程的综合优化而非只针对单一工况。当然如果想进一步扩大工况适应范围可以把目标函数改成多个扰动幅值下ITAE的加权和这也是LFC研究里提升鲁棒性的常用手段。5. 常见问题与调试经验实录5.1 Simulink模型调用报错和数据读取失败新手最容易卡住的就是sim函数调用阶段。常见报错包括“Invalid Simulink object handle”“Port width mismatch”和“Variable Kp does not exist”。第一个问题通常是因为模型没在路径下或者模型名写错。解决方法是把模型文件放在当前工作目录或者用addpath把模型所在文件夹加入Matlab路径。第二个问题的根源是Simulink模块的信号维度不匹配比如PID控制器输出是向量而传递函数模块期望标量输入。出现这个报错时要重点检查PID模块的输出端口设置和信号线上的维度标注。第三个问题则是没有正确生成工作区变量。注意assignin(base, Kp, Kp)写入的是基础工作区如果Simulink模型被设置为“模型工作区优先”可能读不到base workspace的变量。解决方案是在模型属性回调或初始化过程中手动传入变量或者直接在仿真前用evalin检查变量是否存在。数据读取报错大多是To Workspace模块的数据格式不一致导致的。我的经验是能用Array就用Array代码里统一用simOut.ITAE(end)读取简单不易出错。5.2 适应度函数返回NaN或仿真发散GWO在搜索过程中很容易生成一组极端参数比如Kp9.5、Ki4.8、Kd1.9这组参数很可能让闭环系统变得不稳定频率偏差在仿真时间内不收敛甚至震荡发散。此时ITAE积分值可能变成NaN或者Infsim命令也可能直接中断运行。我的处理方式是三层防线。第一层是try-catch捕获仿真异常第二层是检查ITAE值是否为NaN或Inf是则替换为1e6第三层是在GWO边界检查后加上一个“参数合理性”判断如果Kp或Ki超过实际允许的物理范围直接赋予极大适应度而不做仿真。在实际运行中这三层能挡掉绝大部分崩溃问题。但也不能完全依赖惩罚机制搜索范围本身要设计得合理。我通常会用一次手动仿真试探边界参数组合是否还能稳定再最终确定范围。5.3 GWO收敛过慢或陷入局部最优如果你发现收敛曲线在迭代后期几乎不动或者最终适应度明显偏高大概率是陷入了局部最优。GWO本身有α、β、δ三只头狼引导陷入局部最优的概率比单头狼引导的算法低但仍可能出现。我常用的加速和跳出策略有三个第一是调整a的衰减方式。标准GWO中a从2线性减到0但有时候线性衰减导致后期搜索步长过小。可以把a改成a 2 * (1 - t/Max_iter)^0.7让前期探索更充分后期收敛更细腻。第二是增加种群多样性比如每次迭代以较小概率对部分狼的位置做随机初始化扰动。这个做法相当于给算法加了一个“变异算子”可以有效避免整个种群过早聚集到同一区域。第三是直接提高迭代次数和种群数量。这个方法最朴素但最有效代价是仿真时间变长。如果时间允许把种群从20提高到30迭代次数从30提高到50通常结果会有明显改善。5.4 优化耗时太长怎么办GWO每轮迭代需要跑种群数量次Simulink仿真总耗时是很多同学抱怨的焦点。以一个仿真时长20秒、种群25、迭代40的配置为例普通笔记本跑一次完整优化可能需要15到30分钟。这里分享几个我亲测有效的提速技巧在Simulink模型设置里关闭所有显示模块Scope在每次仿真时都会消耗资源去刷新画面使用set_param模型参数把仿真的SimulationMode设置为Rapid Accelerator代码里禁用对话框set_param(LFC_GWO, SimulationCommand, stop)有时候反而增加开销建议直接在模型设置里关闭缩短仿真停止时间。如果系统在10秒左右已经稳定StopTime不需要设为20秒可以合理缩减到15秒每次仿真节省的时间会累积成总体的大幅提升如果机器支持并行计算可以试试用parfor并行评估种群适应度但要注意每个worker都需要访问模型和小文件部署起来稍微麻烦提速逻辑的本质是在保证ITAE指标计算精度足够的前提下尽量减少每次仿真花费的时间。仿真时间不需要精确到千分位但趋势要保持稳定。6. 扩展方向与改进建议6.1 把单区域模型扩展到两区域互联单区域LFC跑通以后下一步很自然是扩展到两区域互联系统。两区域模型比单区域多了联络线功率偏差ΔPtie区域控制偏差ACE ΔPtie B·Δf控制器要同时调节频率和联络线功率目标函数也要相应扩展为包含Δf和ΔPtie的加权ITAE。这种扩展在GWO框架下改动很小只需要把Simulink模型替换为两区域模型适应度函数里从两个通道取数据其他代码逻辑完全不动。文章里很多做毕设的同学会在单区域基础上做这个扩展算是一个加分项。6.2 算法层面可以做的改进GWO和很多群体智能算法一样存在后期多样性下降的问题。你可以尝试改进方向包括引入差分进化变异策略让部分狼每次迭代后有概率做交叉变异和粒子群算法做混合全局用GWO局部用PSO精细搜索把a的衰减策略改成非线性自适应或者根据种群聚集程度动态调整用对立学习策略初始化种群让初始狼群分布更均匀这些改进在论文中都属于“创新点”范畴实现难度不大但能显著提升收敛速度和解质量。从学习角度讲先跑通基础版再逐步加改进是理解和掌握优化算法最好的路径。6.3 实际调试中的一些心态建议最后说点题外话。我用这个项目框架帮人调过很多次参数最大的体会是优化算法不是万能钥匙模型本身的合理性才是决定结果上限的关键。如果Simulink模型搭建有问题再强的优化算法也只能在错误的系统上找“最优”这个“最优”没有任何实际意义。所以拿到项目以后先花时间把模型开环响应、闭环稳定性验证清楚再谈优化整定。模型验证阶段嫌麻烦后面调试阶段会加倍还回来这个坑我踩过太多次了。按照上面这套流程走下来从模型搭建到GWO整定再到结果分析整个周期大概一周时间就能完成希望能帮你少走一些弯路。