简介:一份面向MATLAB/Simulink使用者的粒子群算法(PSO)整定PID参数学习资源,帮助解决传统PID参数人工调整繁琐、难以找到最优解的问题。内容从粒子群算法原理、算法步骤到适应度评估均有讲解,并详细展示了基于M文件与Simulink环境的PID参数自整定实现过程,适合需要自动调参的工程师及相关专业学生。资源为PDF文档,共1个文件,大小约529KB,文档内附有代码讲解与仿真思路。已有4895人学习下载,说明其在实际应用中的参考价值。通过这份资料可以掌握PSO的速度与位置更新公式、评价函数设计,以及调节惯性权重和加速常数对优化效果的影响,进而可自行搭建Simulink模型实现PID参数的自动整定。
1. 粒子群算法整定PID:从一个不想查表的午后说起
调PID最磨人的时刻,是你已经对着响应曲线试了十几组参数,超调压下去了调节时间又上来,改了Kp又动Ki,仿佛永远在二维平面上打转。更麻烦的是,被控对象一换,之前的经验全部作废。粒子群算法(PSO)整定PID的思路是反过来的——你只需定义“什么样的响应算好”,算法自己在参数空间里搜索Kp、Ki、Kd的最优组合。这份资源从零开始,用MATLAB的M文件实现了一套完整的PSO优化PID流程,从简单传递函数到双闭环直流调速Simulink模型都覆盖了。适合手里有Simulink模型、想摆脱手动调参、又不想只看表面结论、想弄懂算法内部逻辑的开发者。
2. 粒子群核心算法拆解:速度-位置迭代公式与MATLAB向量化实现
2.1 算法流程四步走
粒子群算法是1995年提出的群体迭代算法,和遗传算法相比,它没有交叉和变异过程,需要整定的参数更少,收敛速度更快。核心逻辑非常直白:一群粒子在参数空间中飞行,每个粒子记住自己见过的最优位置,即个体最优P,整个群体共享一个全局最优位置Pg。每次迭代,粒子的速度由三部分组成:上一时刻的惯性速度、朝向个体最优的拉力、朝向全局最优的拉力。位置则在速度方向上前进一步。这个机制和鸟群觅食的行为模型对应,每只鸟不知道食物在哪,但能通过信息交换逐步汇聚到食物点。
具体到PID整定场景,参数维度N等于3,分别对应Kp、Ki、Kd。每个粒子就是一个三维坐标点,位置范围就是参数搜索范围。以资源包中的PSO函数为例,完整迭代循环可以拆成四个步骤。
第一步是初始化。速度设为零矩阵,位置在参数范围内均匀随机分布。原文用X=(xmax-xmin)*rand(m,dimension)+xmin生成初始位置,这一步保证了粒子覆盖整个搜索空间。P初始等于X,因为第一次迭代还没有历史最优可参考。last_f=f(X)一次性算出所有粒子的初始适应度,min找到全局最优所在的行号,Pg就是这一行对应的坐标。
第二步更新速度v=wv+c1rand*(P-X)+c2rand(ones(m,1)*Pg-X)。这里的rand每次产生的随机数矩阵维度与运算对象一致,相当于每个粒子、每个维度都有独立的随机系数。ones(m,1)*Pg把1行3列的全局最优向量广播成m行3列的矩阵,整个更新过程用矩阵运算完成,全程不需要写for循环。MATLAB的矩阵运算本身集成了并行能力,这是选它做粒子群实现的最大理由。
第三步更新位置并限幅。X=X+v*dt,其中dt是位移仿真间隔。原文取0.3,意味着粒子每一步只走速度向量的百分之三十,搜索更细腻。如果dt取1,速度更新完就直接落到新位置,搜索步长偏大,容易跳过最优区域。速度限幅和位置限幅都用矩阵乘加实现,V=(V>vmax).*vmax+(V>=-vmax & V<=vmax).V+(V<-vmax).(-vmax),这种写法比if分支简洁一个量级。
第四步更新最优。new_f=f(X)得到新一代适应度,find(new_f<last_f)找出比上一代变好的粒子,更新它们的历史最优位置P。new_Pg=X(min_i,:)是这一代的新全局最优,Pg=(new_fmin<fmin)*new_Pg+(new_fmin>=fmin)*Pg保证全局最优只向更优方向移动。这四步循环执行n次,就完成了整个优化过程。
2.2 PSO函数代码逐段讲解
function [Pg,fmin]=PSO(f,dimension,n,m,xmax,xmin,vmax,vmin) % 全局粒子群算法,f为目标函数 % dimension为参数维度,n为迭代代数,m为种群规模 % 位置限幅为[xmin,xmax],速度限幅为[vmin,vmax]这是函数头,返回值是全局最优位置Pg和最优适应度fmin。输入参数中f是一个函数句柄,可以是匿名函数,也可以是function文件,PSO内部通过f(X)批量计算适应度。只要保证输入是一个矩阵、输出是一个列向量,任何目标函数都可以接进来。xmax和xmin既可以是标量也可以是向量,若传入向量如[15,50,2]和[0.2,0,0],则每个维度有各自边界,这对PID场景很重要,因为Kp、Ki、Kd的量纲和合理范围完全不同。
w=1; c1=2; c2=2; % 惯性权重与加速常数 dt=0.3; % 位移仿真间隔 v=zeros(m,dimension); % 初始速度为0 X=(xmax-xmin)*rand(m,dimension)+xmin; % 初始化位置在[xmin,xmax]均匀分布 P=X; % P为每个粒子每代的历史最优位置 last_f=f(X); % 计算初始代适应度,一次性算完整个种群 [fmin,min_i]=min(last_f); Pg=X(min_i,:); % 全局最优位置初始速度设为零是粒子群算法的标准做法,避免一开始粒子乱飞。位置初始化用均匀分布而不是正态分布,好处是对搜索范围无偏。w取1时,粒子完全保留上一时刻速度,搜索范围大但收敛慢;c1=c2=2是最经典的取值,让个体经验和群体经验各占一半。
进入迭代主循环:
for i=1:n % 速度更新:惯性 + 个体认知 + 社会认知 v=w*v+c1*rand*(P-X)+c2*rand*(ones(m,1)*Pg-X); % 速度限幅:防止粒子飞行过快越过最优区域 v=(v>vmax).*vmax+(v>=-vmax & v<=vmax).*v+(v<-vmax).*(-vmax); % 位置更新:沿速度方向前进dt比例的一步 X=X+v*dt; % 位置限幅:保证PID参数始终在合法范围内 X=(X>xmax).*xmax+(X>=xmin & X<=xmax).*X+(X<xmin).*xmin; % 计算新适应度 new_f=f(X); % 更新个体历史最优,只更新变好的粒子 update_j=find(new_f<last_f); P(update_j,:)=X(update_j,:); % 更新全局最优,只保留更优的值 [new_fmin,min_i]=min(new_f); new_Pg=X(min_i,:); Pg=(new_fmin<fmin)*new_Pg+(new_fmin>=fmin)*Pg; last_f=new_f; fmin=min(new_fmin,fmin); end这段代码里两个工程细节值得注意。第一个是速度限幅,vmax=1意味着每步速度不能超过1,否则粒子可能在参数空间里来回穿越,既浪费计算量又容易跳过最优区域。第二个是Pg的更新方式,(new_fmin<fmin)是逻辑标量,参与矩阵乘法时true转换为1、false转换为0,相当于条件选择。这种写法比if分支高效得多,也是MATLAB编程里推荐的做法。
循环结束后函数应该把每代的最优适应度保存到数组里,最后画出来。不过如果你只需要最优解,可以注释掉绘图部分,能明显减少运行时间。资源包中的PSO函数还保留了每隔10代记录一次种群位置的逻辑,用于观察粒子分布变化,这个对理解算法行为很有帮助,但对工程调用来说是额外开销,正式优化时可以删掉。
2.3 惯性权重衰减:一个收敛速度的突破
原文在测试函数中对比了固定w和递减w的效果。测试函数f=(1-x1).^2+(x1.^2-2x2).^2理论极小值在x=(1,0.5)。固定w=1时,粒子群在最优解附近震荡,因为速度过大导致“刹车不住”,连续多代找不到更优解。递减策略为wk=wk-i/n0.7wk,每代衰减当前权重的一定比例。
% 在迭代循环末尾加上这一行 w=w-i/n*0.7*w;这段代码放在循环尾部,随着i增大,w从1逐步衰减到约0.3。效果是粒子初期大范围搜索,后期小范围精细收敛。同样的种群规模和迭代次数下,fmin比固定权重小了很多。对于PID整定这种目标函数多峰的场景,递减权重比固定权重更容易跳出局部最优。
为什么取0.7这个系数?这是经验值。衰减太快,比如0.9,粒子很快就失去了探索能力,可能困在局部最优;衰减太慢,后期还在大幅震荡,浪费迭代次数。我一般先试0.5到0.8区间,观察适应度曲线是否平滑下降。从绘制出的粒子分布图看,递减权重后粒子几乎全部收敛到了中心点,而固定权重时还有一部分粒子在远处徘徊。
3. M文件方式的PID自整定:先让简单系统跑起来
3.1 PID仿真引擎的离散化实现
调PID需要知道参数效果如何,也就是把一组Kp、Ki、Kd代入控制回路看阶跃响应曲线。原文的PID_sim.m函数自己实现了一个PID仿真引擎,没有依赖Simulink。这一步的好处是迭代速度快,适合PSO这种需要大量评分的场景,毕竟Simulink每次启动都有模型编译开销。
function [f_infty,tp,ts,sigma]=PID_sim(kp,ki,kd,debug) % kp,ki,kd为PID参数,Tt为仿真采样周期,total_t为仿真时间 Tt=5e-4; % 仿真采样周期,决定离散化时间粒度 T0=1e-2; % 控制采样周期 Tf=1e-3; % 微分环节滤波器系数 alp=Tf/(Tt+Tf); total_t=1; % 仿真总时长1秒 N=floor(total_t/Tt); % 样本总数,仿真1秒共2000个点 M=numel(kp); % 并行仿真序列数,等于传入的参数组数 kp=reshape(kp,M,1); ki=reshape(ki,M,1); kd=reshape(kd,M,1); sys=tf(0.998,[0.021,1]); % 被控对象传递函数,模拟直流电机转速模型 dsys=c2d(sys,Tt,'z'); % 离散化 [num,den]=tfdata(dsys,'v');这段代码设计的巧妙之处在于输入参数kp、ki、kd可以是列向量,一次调用能并行仿真M组PID参数。每组参数对应一个离散传递函数,循环内部只用矩阵运算更新状态,没有嵌套循环,运行速度远快于逐一仿真的写法。M=numel(kp)获取的是参数组数,也就是说,200个粒子对应200组PID参数,PID_sim一次调用就把200条阶跃响应曲线全部算出来了。
被控对象sys=tf(0.998,[0.021,1])是一个一阶惯性系统,时间常数0.021秒,增益0.998,常用于模拟直流电机的转速响应。如果你的对象是二阶或更高阶,直接改这一行即可,不影响后面的逻辑。
循环体是仿真核心:
r=1500; % 阶跃目标值 y=zeros(M,N); u=zeros(M,N); for k=1:1:N % 系统响应输出,来自离散传递函数的差分形式 y(:,k)=-1*den(2).*y_1+num(2)*u_1+num(1).*u(:,k); % 误差信号 e0=r-y(:,k); % 微分项带一阶滤波,避免纯微分放大噪声 ud=alp.*ud_1+(1-alp)/T0.*kd.*(e0-e_1); % PID控制器输出:比例+积分+微分 u(:,k)=kp.*e0+T0*ki.*Ee+ud; % 累积误差,相当于积分项 Ee=Ee+e0; % 状态更新,供下一步使用 u_1=u(:,k); y_1=y(:,k); e_1=e0; ud_1=ud; endy(:,k)的计算来自离散传递函数的差分形式,den(2)是传递函数分母的第二个系数,num(1)和num(2)是分子系数。控制量u由三部分组成:比例项kpe0、积分项T0ki*Ee、微分项ud。这里微分没有直接用(e0-e_1)/T0,而是乘以滤波系数alp,因为纯微分对测量噪声极其敏感,一阶滤波是工程中常见的处理手段。alp=Tf/(Tt+Tf),当Tf远小于Tt时alp趋近0,微分项主要看当前变化率。
r=1500是阶跃目标的幅值,对应1500转每分的转速设定。这个值会直接影响控制器的输出范围,如果你换到别的物理量,记得同步修改。
3.2 评价函数设计:让算法知道“好”是什么意思
PSO优化PID的关键其实不在算法本身,而在评价函数。搜索的“方向感”完全由评价函数提供。原文给出的评价函数只用了两个指标:调节时间ts和超调量sigma。
function y=PID_access(para) % PID调节性能的指标参数,para每行是一组[kp,ki,kd] kp=para(:,1); ki=para(:,2); kd=para(:,3); [~,~,ts,sigma]=PID_sim(kp,ki,kd,false); y=log(ts/5e-2+1)+log(sigma/1e-2+1); end这个函数的设计有讲究。ts和sigma的数量级差异很大,ts可能是0.1量级,sigma可能是百分之几到几十的量级,直接相加的话大数项的波动会淹没小数项。取对数后再相加,相当于对两个指标做了归一化压缩。5e-2和1e-2是期望的目标值,当ts接近目标值时,log(ts/5e-2+1)的值约为log2,此时该指标的边际调整率最大,偏离目标越远调整率越小。这保证了算法收敛到期望值附近,而不是一味追求某一个指标。
如果你希望调节时间和超调量各占一半的权重,这里就是等权的。但工程需求往往不是等权,比如有的系统宁可超调大一点也要响应快,有的系统则恰恰相反。这就要改评价函数,我们留到最后一章细说。
parameter_cal.m负责从响应曲线中提取指标:
function [f_infty,tp,ts,sigma]=parameter_cal(y,T0,delt_err,debug) % y是系统输出序列,T0是采样时间,delt_err是调节时间的误差精度 M=size(y,1); N=size(y,2); f_infty=y(:,N); % 稳态值取末时刻输出 err=y-f_infty*ones(1,N); % 误差序列 ferr=fliplr(abs(err)); % 倒序并取绝对值 [~,ts_i]=max(ferr>delt_err*f_infty,[],2); ts_i=N*ones(M,1)-ts_i; ts=ts_i*T0; % 调节时间 [fp,tp]=max(y,[],2); % 峰值和峰值时间 tp=tp*T0; tp(abs(fp-f_infty)<1e-5)=NaN; % 无超调时置NaN sigma=(fp-f_infty)./f_infty; % 超调量调节时间的计算用了一个反向搜索技巧:先把误差序列倒过来,找到最后一个越过误差带的位置,再用总长度减回去。这个写法比正向for循环查找高效得多,是矩阵运算的典型风格。delt_err取2e-2,意味着误差带是正负百分之二的稳态值,这是控制理论中调节时间的标准定义。t_s的返回值是采样点数乘以采样周期,换算成实际时间。
超调量sigma的计算相对直白,(峰值-稳态值)/稳态值。对于过阻尼系统,峰值就是稳态值本身,此时tp被置NaN,避免后面计算峰值时间时报错。调试模式下,如果M==1,函数还会打印稳态值、超调量、峰值时间、调节时间,方便单组参数的人工观察。
3.3 主流程串起来:从set_para.m开始
资源包要求从set_para.m开始运行,主流程非常短:
dimension=3; % PID三维参数:kp、ki、kd n=20; % 迭代次数 m=200; % 种群规模 [Pg,fmin]=PSO(dimension,n,m)PSO.m内部每代取出当前Pg,调用PID_sim并绘制响应曲线,同时记录ts和sigma随迭代的变化。从原文的仿真结果看,调节时间逐渐减小,超调量第一代就归零了。这说明评价函数里超调量的贡献很快被满足,后续优化全部集中在调节时间上。也就是说,算法找到了一个超调几乎为零、同时调节时间逐步缩短的参数组合。
这里有个值得学习的工程化技巧,PID_sim的debug参数。PSO迭代过程中传false,不画图不打印,跑完只看最终结果;需要观察单组参数响应时才设true。这种开关式设计避免了迭代过程被绘图阻塞,我自己的仿真代码也沿用这套做法。
4. Simulink复杂系统整定:双闭环直流调速系统实战
4.1 模型搭建与参数声明
简单系统用M文件仿真就够了,一到双闭环直流调速这种带饱和限幅、带电流环和转速环嵌套的系统,M文件手写整个控制逻辑就非常痛苦。Simulink模型的优势在于结构清晰、易于修改,而且能直接复用PSO的搜索逻辑。
资源包要求根据给定的电机参数搭建Simulink模型,命名为double_circle.slx,另存为PSO_double_circle.slx。电机参数包括额定电压800V、额定电流2164A、额定功率1500KW、额定转速44r/min、过载系数1.5、电枢电阻0.1欧姆、主回路电阻0.1014欧姆、电枢电感3.25mH、变流器放大倍数80、系统飞轮惯量8.6e5。这些参数决定了电流环和转速环PI参数的合理范围。
双闭环结构本身值得一提:外环是转速环,负责让转速稳定在期望值并抵抗负载扰动;内环是电流环,负责让电流快速跟随给定值,以获得更好的动态特性。电机启动时电流先达到容许最大值,让电机以最大加速度加速,到达期望转速后电流迅速减小到负载转矩所需电流,转速维持不变。
模型搭建的关键不是画框图,而是让M文件能实时修改Simulink里的参数。做法是把转速调节器ASR的Knp、KnI和电流调节器ACR的Kip、KiI在Simulink中直接命名为工作区变量,M文件里声明global后修改,Simulink仿真时自动读取最新值。
这一步常踩的坑是Simulink中的增益模块默认用数值,改不了。需要双击增益模块,把数值替换成变量名,模型才会从工作区动态取值。另外还要在模型中加To Workspace模块,把转速和电流信号输出到工作区,M文件才能拿到曲线并计算指标。
4.2 PSO与Simulink交互的闭环流程
整套交互流程可以概括为:PSO负责在参数空间搜索,Simulink负责在时间域验证。桥接的载体是全局变量。
global Knp KnI Kip KiI % PSO每代更新这四个全局变量 % 调用sim('PSO_double_circle.slx')运行仿真 % 从仿真输出中提取转速和电流曲线 % 计算评价函数值返回给PSO这里有一个核心的效率问题。Simulink仿真本身有编译开销,每次sim调用都要重新编译模型。如果种群规模200、迭代20次,理论上要跑4000次仿真,每次哪怕只有0.1秒也要400秒。实际做法是每代只取当前全局最优Pg跑一次Simulink仿真,而不是每个粒子都跑,这样总仿真次数降为迭代次数20次,配合M文件预先筛选候选参数,效率高很多。
另一个需要注意的地方是全局变量在工作区和Simulink之间的传递时机。M文件修改了全局变量之后,必须确保Simulink模型确实在下一次仿真时读取了新值。有的情况下Simulink会缓存参数,你需要在sim命令前加set_param或者手动清除模型的编译缓存。我一般会加一行disp(Knp)确认变量确实更新了。
4.3 电流超调与转速超调的联合优化
双闭环系统的评价函数需要同时考虑四个指标:电流超调sigma_i、电流调节时间ts_i、转速超调sigma_n、转速调节时间ts_n。资源的cal_n.m函数就是干这个的,输入仿真曲线,输出四个指标。
function [n_sigma,ts_n,I_sigma,ts_transient_i,n_err]=cal_n(par, ...) % par为仿真得到的转速和电流序列 % 从曲线中提取电流峰值、超调回归时间、转速超调、转速调节时间 % 内部逻辑与parameter_cal类似,但增加了电流平台的判断 end这个函数的具体实现在资源包中,核心逻辑和parameter_cal类似,只是多了对电流平台的判断。电流环的特点是启动瞬间电流冲到过载限幅值,形成一个平台。转速环和电流环的评价优先级不同,电流超调直接关系到过流保护是否动作,转速超调则影响舒适性和稳定性。
原文给出了一组工程设计法计算出的参考参数:[Knp,KnI,Kip,KiI]=[7.3660,1.5658,0.8257,30.2773]。仿真结果为sigma_n=4.07e-4%、ts_n=0.7875、sigma_i=20.38%、ts_i=0.0172。这组参数可以作为PSO的对照组。如果你写好了PSO整定程序,先跑一遍工程参数,再跑一遍PSO结果,对比一下就知道算法是否正常工作。这是我强烈建议所有学习者做的验证步骤。
实际上电流超调百分之二十点三八对于工程设计方法来说已经偏大,但因为它发生在启动瞬间且持续时间极短,对系统危害有限。如果你想用PSO降低电流超调,在评价函数里给电流超调项提高权重就可以,PSO会主动搜索一组能压低电流峰值的参数。这种“按需分配”的能力,是粒子群算法整定PID相比传统查表法最大的价值。
5. 避坑指南:版本、全局变量、迭代卡死与仿真加速
5.1 MATLAB版本引起的中文注释与函数兼容问题
现象:高版本MATLAB打开低版本写的代码,有的函数名变了,有的绘图函数警告,甚至直接报错。
原因:MATLAB的绘图函数和工具箱接口持续在改,比如legend、hold on的行为在不同版本有细微差异。中文注释乱码多半是文件编码问题。
解决:先跑set_para.m,逐行执行定位第一个报错函数,用help查当前版本接口。代码中的中文注释如果出现乱码,把文件编码转为GBK或UTF-8再打开,我一般直接用MATLAB编辑器重新粘贴中文注释,不依赖源文件的编码推断。
5.2 Simulink参数改不进去
现象:M文件里修改了global变量,再sim运行模型,曲线和之前一模一样。
原因:Simulink模型中的增益模块没有引用工作区变量,仍是硬编码数值。或者变量名拼写不一致,比如模型里写的是Knp,M文件里写的是Kp_n。
解决:双击增益模块,确认参数是Knp而不是别的拼写。增加一条验证代码:
Knp=5; sim('PSO_double_circle.slx');跑完看输出曲线是否有变化,没变化就说明模型没读到工作区变量。还有可能是仿真起始时间设置不当,模型结果覆盖了之前的变量,或者To Workspace模块没勾选“保存格式为数组”。
5.3 迭代时间过长,怀疑程序死机
现象:运行PSO主程序后长时间无输出,界面无响应。原文特别提醒:每次迭代都会打印结果,如果运行时间过长,可以观察迭代次数是否有变化。
原因:每次迭代调用sim仿真一两次,单次Simulink仿真可能就要几秒,20次迭代就是几十秒到几分钟的量级。如果内部又误写了每个粒子都仿真一次的循环,总时间会膨胀到不可接受。
解决:在PSO.m的for循环内加一行disp(['iter=',num2str(i)]),每代打印一次。如果某代停留超过预期,检查sim模型是否进入了死循环,或者仿真时间太长。另外把Simulink加速模式设置为“快速加速”也能显著提升仿真速度,但要注意加速模式下全局变量的刷新时机可能不同。
5.4 种群规模与迭代次数的平衡
现象:种群规模很大但结果反而不如小种群好,或者收敛特别慢。
原因:种群规模m=200只是粒子数,如果迭代次数n=20,总共只搜索了4000个位置,但每个位置都要跑一次仿真,计算量全花在评分上。盲目加大m只会拖慢速度,不会提升精度,因为PSO的搜索效率主要由迭代次数决定。
解决:先小规模试跑,m=50、n=10,看评价函数是否单调下降。确定了搜索范围和评价函数没问题之后,再逐步加大m和n。资源包里m=200、n=20的组合是针对PID三维参数验证过的经验值,换场景时不一定保持这个比例。
5.5 评价函数权重失衡导致整定结果偏科
现象:输出超调很小,但调节时间很长,或者反过来,调出来的参数不符合你的真实需求。
原因:评价函数里ts和sigma的权重比例不匹配实际需求。比如你更关心超调,但函数里sigma项权重太低,算法就会牺牲超调来换调节时间。原文评价函数中sigma的期望值设1e-2,但对直流调速系统,工程参数产生的sigma_i达到百分之二十,这已经不是微调能解决的了。
解决:调整期望值常数或显式加权重系数:
y=0.3*log(ts/5e-2+1)+0.7*log(sigma/1e-2+1);权重体现了你的偏好,不必拘泥于原文的等权设计。我一般先跑一版等权重看结果,再按需求调整,比一开始就猜权重更稳妥。
6. 二次开发:把PSO整定扩展到你的模型上
拿到这份资源,最快能落地的改造就是把自己系统的模型换成PSO的评分目标。核心改动有三个地方:被控对象模型、待优化参数列表、评价函数。
被控对象模型:把PID_sim.m里的sys=tf(0.998,[0.021,1])替换成你自己的传递函数,或者把sim调用的slx文件替换成自己的模型。注意保持PID_sim的输入输出接口不变,这样PSO.m一行都不用改。如果你的模型是Simulink工程里已有的,我建议先在M文件环境里用简化模型验证算法,再切换到完整Simulink模型,两边对照起来更容易定位问题。
待优化参数列表:如果你的控制器不是经典PID而是一阶或二阶控制律,比如状态反馈系数[A,B,C]三个参数,只需把dimension改成3,xmax和xmin改成对应系数范围。PSO函数本身与PID无关,它只负责在给定维度上搜索使得评价函数最小的位置。如果你只想整定PI两个参数,把dimension改成2,xmax和xmin长度切成2即可。
评价函数是改造的重头戏。原文只用了调节时间和超调,工程中往往还要考虑控制量u的幅值约束,防止输出饱和。一个常见的扩展是加罚函数:
function y=PID_access(para) kp=para(:,1); ki=para(:,2); kd=para(:,3); [~,~,ts,sigma]=PID_sim(kp,ki,kd,false); u_max=estimate_u_max(kp,ki,kd); % 估算控制量峰值 y=log(ts/5e-2+1)+log(sigma/1e-2+1)+10*(u_max>1); end罚函数写法让控制量越限时评价函数急剧变大,PSO自动避开这组参数。这类罚函数法在处理系统约束时比硬限幅更好用,PSO在搜索中能感知到边界的存在。如果你希望直接在Simulink模型上做,可以再加一个输出端口观察控制量,把u_max从仿真结果中提出来,不一定要像上面这样单独估算。
另外一个实用技巧是把PSO的最终结果作为初值,直接切入Simulink的响应优化器或者MATLAB的优化工具箱做一次精调。PSO的粗搜索能力和梯度优化的细调能力互补,两段式整定在实践中比单独使用任何一个都稳。我试过几次,两段式整定最终的适应度比纯PSO再低百分之十到二十,而且参数分布更合理。
从那以后我每次换一个新被控对象,都强制走一遍这套流程:先在M文件仿真上验证评价函数,再挂到Simulink跑全局搜索,最后用工程参数做对照验证。这个习惯帮我避开了不少把评价函数写错导致整定结果和物理直觉完全对不上的尴尬,希望帮到你。
本文还有配套的精品资源,点击获取