我用权重线性递减的PSO-PID算法寻找最优的PID值,其参数设置如下:
Wmax=0.9; % 最大权重
Wmin=0.4; % 惯性因子 线性惯性权重 最小权重
c1 = 2; % 个体学习因子1
c2 = 2; % 社会学习因子2
Dim = 3; % 维数
SwarmSize = 100; % 粒子群规模
ObjFun = @PSO_PIDdiscrete1; % 待优化函数句柄
MaxIter = 300; % 最大迭代次数
MinFitness = 0.00001; % 最小适应值
Vmax = 1; %速度更新限制范围
Vmin = -1;
Xmax = [10 100 10]; %位置更新限制范围
Xmin = [0 0 0];
仿真出来的结果如下面三张图所示:
Kp值随迭代次数变化曲线
Ki值随迭代次数变化曲线
Kd值随迭代次数变化曲线
明明我设置的X可变化范围那么大(代码最后两行),为什么每一次迭代它们三个的随机取值变化范围那么小?可以看下面三张图:
Kp粒子取值
Ki粒子取值
Kd粒子取值
后面一两百代已经收敛了,不变化了我能理解,为了不让算法陷入局部最优,我用了权重线性递减的方法。
我的问题是怎么让它的PID随机取值变化范围变大?
需要改V速度的取值范围吗?但是它每一次的Vstep也没有超过[-1,1]这个范围。
请看到的大佬不吝赐教,这对我会有很大的帮助!
谢谢大家!
2024.01.20 19:20第一次更新
我怀疑是不是速度的上下限设置的太小了,所以导致所有的粒子不能飞太远,也就导致其随机取值范围变小了,于是我进行了以下尝试,改变速度的范围大小:
Vmax = 10; %速度更新限制范围
Vmin = -10;
然后为了尽快验证我的猜想,减短仿真时间,用100个粒子只跑了100代,100代曲线后面也变化不大,这是-10~10跑出来的结果:
我简直震惊啊!全部都是0,还运行了我8459.246000s≈2.3h 。我觉得应该是这个范围(-10~10)太大了。
于是我再改:
Vmax = 2; %速度更新限制范围
Vmin = -2;
这是速度范围-2~2的迭代结果:
比之前要好,但是也是很快就固定到一个值然后再也没有变动过,应该是陷入了局部最优。或者这个速度范围还是取大了? 尤其是PSO整定的最优PID值分别取[0.123057559866944 ;0 ;0]肯定是不对的。因为知道肯定不对,我也就没有把这些值带回到simulink模型进行验证了。
我还要再试一下,把速度范围改回去效果会不会好一点?(尽管每一次都是随机初始化的,每一次仿真寻优都会有不同的结果)请期待我下一次更新!!!
现在已经不是每一次随机初始化的PID的变化不大的问题了,而是为什么很短的迭代次数内就像已经找到最佳的组合一样,每一次都生成相同的PID值了,慢慢来吧!
2024.01.21 9:50第二次更新
不好的消息,最佳PID参数全部都是0,和第一次的仿真条件一模一样(除了迭代次数),但是达不到第一次的效果了。
Vmax = 1; %速度更新限制范围
Vmin = -1;
这是速度-1~1跑出来的结果:
不应该啊,难道是速度初始化有问题吗?都是利用rand函数随机生成的,应该不会出什么岔子。
%% 粒子群初始化
Range = ones(SwarmSize,1)*(Ub-Lb); % 初始化范围
Swarm = rand(SwarmSize,Dim).*Range + ones(SwarmSize,1)*Lb % 初始化粒子群
VStep = rand(SwarmSize,Dim)*(Vmax-Vmin) + Vmin % 初始化速度
fSwarm = zeros(SwarmSize,1); % 初始化粒子群适应值
但我想不出还有什么地方会出错,我下一步要用均匀分布的方式随机生成初始化粒子,请期待我下一次更新!
%% 粒子群均匀随机生成初始化
Range = ones(SwarmSize,1)*(Ub-Lb); % 初始化范围
for i = 1:SwarmSize
for j = 1:Dim
Swarm(i, j) = unifrnd(Lb(j), Ub(j)); % 使用均匀分布随机生成位置
VStep(i, j) = unifrnd(Vmin, Vmax); % 使用均匀分布随机生成速度
end
end
fSwarm = zeros(SwarmSize,1); % 初始化粒子群适应值
2024.01.21 10:39第三次更新
好像找到原因了,应该是Simulink模型的反馈速度我多加了一个负号,之前那个模型是没有的。
为了验证我的猜想,是不是这里出错,我将这个-1的Gain模块去除,20个粒子迭代20代试一试,这是跑出来的结果:
可以清晰地看到每一张图片都有明显变化趋势,不像之前两次迭代出来的值都是0,那么这就验证了我的猜想,确实是Simulink模型出了一点小错误。也不是速度初始化的问题,之后对比rand初始化速度和均匀随机分布初始化速度我会另外出一篇文章,敬请期待!
那么回到本篇文章问题本身,是不是改变速度边界可以使得迭代PID值变化范围变大,下一次我将更新正确的模型,速度范围边界为-5~5的迭代结果。
2024.01.21 15:05第四次更新
这是速度-5~5跑出来的结果:
我觉得和第一次得出来的结果(最开始贴出来的三张图)没有什么大的区别,我计算了它们的取值范围区间(Max-Min),其计算结果如下:
Kp | Ki | Kd | |
第一次 | 0.4616 | 1.2448 | 1.6516 |
这一次 | 0 | 1.1781 | 0.5379 |
如果单看变化范围,这一次的变化范围甚至还没有第一次变化得大呢,这还是在加大了速度的边界范围的前提下,所以不是单纯改变速度的边界范围就能改变最优PID粒子的取值范围的。
让我们来梳理一下,最终的PID粒子取值是靠Swarm这个变量决定的,而Swarm初始化的公式如下:
%% 粒子群初始化
Range = ones(SwarmSize,1)*(Ub-Lb); % 初始化范围,因为它有多维参数
Swarm = rand(SwarmSize,Dim).*Range + ones(SwarmSize,1)*Lb % 初始化粒子群,初始位置满足(-Ub,Ub)内均匀分布
VStep = rand(SwarmSize,Dim)*(Vmax-Vmin) + Vmin % 初始化速度,初始速度满足(-Vmax,Vmax)内均匀分布
粒子群更新位置公式如下(就不考虑其位置会超出边界了,仿真那么多次还没有一次超出的):
%% 位置更新
Swarm(j,:)=Swarm(j,:)+VStep(j,:);
这样我们就能稍微发现点问题了:
1)Swarm初始化大小和Range有关,而Range和PID取值位置边界有关,但是我们最初设置的PID参数取值范围,Kp和Kd是0~10,而Ki是0~100,为了更好地观察这个PID粒子取值与位置边界、速度边界的关系,接下来我把位置边界都设置成0~50(Ki也没有超过20);
2)如果想让Swarm的PID取值变化更加明显,可以从Vmin速度最小值设置入手,如果Vmin设置为0,那么Vstep只会取正值,PID值只会在初始化值的基础上增加,但这样是一种非常极端的做法,接下来不妨把Vmin的取值取得比较小一点;
又或者是,确实人家那么多粒子也取到了其他变化范围比较大的点,但是一代那么多粒子表现得比较好的值,一代代这么迭代下就就是变化范围这么小,所以不是它变化范围小,而是最终它的效果不好,所以没有表现出来,我也就只能这么解释了。再做最后一次仿真验证吧。
2024.01.22 9:15第五次更新
这一次仿真主要就是改变了以下参数,向前的速度比较大,而向后的速度设置得较小一点,以及位置的边界都设置得一样:
Vmax = 5; %速度更新限制范围
Vmin = -1;
Ub = [50 50 50]; %位置更新限制范围
Lb = [0 0 0];
以下是仿真出来的结果:
说实话得出来的结果是大差不差的,唯一一个改变的点是这次仿真进行了 32745.980857s≈9.1h,时间远超前面几次仿真(我还在电脑面前傻傻地等以为只要仿真3小时差不多了,时间沉没成本啊!)
得到的较优PID值带回到Simulink模型后发现反馈曲线是这样子的:
也就是说得到的较优PID值是不能用的。
所以结论是这个改变速度边界大小还是不能明显改变每次PID迭代的变化范围!暂且就这样吧!
总结
1)改变速度范围边界对迭代的PID值变化范围影响不大,如果你将向前的速度(Vmax)和向后的速度(Vmin)变化边界设置得差距比较大(比如一个5,一个-1),那么会大大增加matlab仿真的时间;
2)如果想要得到一个比较精确的适合自己模型的PID值,需要提前知道PID值大概在哪个区间,再在这个区间进行迭代寻优的效果比较好,不然得出来的值带进去效果也不好。
All in all,
所以只解决了一个问题,排除了改变速度边界可以明显影响PID随机取值变化范围;
最本质的问题还是没有解决:怎么让它的PID随机取值变化范围变大?
欢迎各位在评论区积极讨论!!!
2024.7.28 20:52第六次更新
仔细想来,为什么在后期PID迭代曲线几乎没有什么变化,可能有两种说法:
1)迭代次数不够多,没有找到最优解就要迭代次数结束了;
2)陷入了局部最优解,这就是这个范围内最好的迭代结果了。
我也不去纠结“怎么让其迭代曲线变化大”的结果了。