粒子群の最適化
序文
組み込みソフトウェアの開発プロセスでは、多かれ少なかれ、制御プロセスでの最小電流、電圧、温度、およびいくつかの最適な係数を見つけるなど、最適な値を見つけるプロセスが発生します。最適化アルゴリズムは、最適値を見つけるプロセスを解決するために使用されます。従来の最適化アルゴリズムは、ラウンドで検索する線形単調手段に依存しており、多極値をうまく処理できず、最適値を見つけるのが困難です。複数の極値から局所的な最適値に落ちます。インテリジェントな最適化アルゴリズムの多くは、反復進化を実現するバイオニクスの原理を採用しており、計算量が多く、通常のシングルチップコンピュータの計算能力には限界がありますが、計算量の多い一部の汎用アルゴリズムでは、実装には時間と労力がかかります。粒子群の実装は比較的単純で、他の最適化アルゴリズムに比べて計算量が少なくなります。同時に、特定のインテリジェントなアルゴリズムを備えているという利点があるため、本稿では汎用シングルチップインテリジェント最適化アルゴリズムを実現する粒子群最適化アルゴリズム。
1. 最適化と粒子群最適化の概要
最適化は最適化とも呼ばれますが、その本来の目的は、大量のデータの中から最大の値を見つけ出し、制約を満たす最適な値を見つけることです。制約条件が複数ある場合には、異なる重み係数を用いて制約条件を重畳することも考慮する必要がある。グループではなく複数の値を探している場合、それは多変量最適化問題であり、生成される最適解は最適解セット (条件を満たす複数のグループのセット) である可能性があります。
PSO (Particle Swarm Optimization) と略される Particle Swarm Optimization は、一般的に使用される最適化アルゴリズムで、バイオニック シミュレーションを使用して、最も多くの餌を見つけるために地上で捕食する鳥の動的な状況をシミュレートします。各鳥は粒子としてシミュレートされます, 粒子として, 質量と体積を持たず, 位置と速度の情報のみを持ちます. 継続的な更新と反復により, 粒子は最も近い最適な位置に移動します. 反復の後, 粒子の数が最も多い位置最適な解決策を検討していきます。遺伝的最適化アルゴリズム、アリのコロニー最適化アルゴリズム、BP ニューラル ネットワーク最適化アルゴリズムなど、他の一般的な最適化アルゴリズムも同じ原理を持っていますが、粒子群最適化アルゴリズムは実装が簡単で、計算量が少なく、実装が簡単なので、シングルチップコンピュータでの試用に適しています。
2. 粒子群最適化の基本原理
2.1 モデルの概要
鳥の捕食プロセスは自然な最適化プロセスです。鳥のグループがエリア内で狩りをします。最初の瞬間はランダムに分布します。各鳥は近くの餌の量を認識できます。現時点では、1 羽の鳥が常に近くの餌を見つけます。多くの場合、餌の少ない鳥は、次の瞬間に餌の多い鳥に積極的に近づき、餌の多い鳥の近くに集まり続けると、最終的には現在のエリアで最も餌が多い場所を見つけます。
2.2 理論式
鳥は粒子として抽象化され、鳥の数は粒子の数 n であり、空間内の鳥の位置は m 次元の位置ベクトルX = (x1,x2,x3,…,xm) で表すことができます。空間内の速度ベクトルV =(v1,v2,v3,...,vm) とすると、鳥の近くの餌の量は、鳥がその環境で生き残る程度 (適応度と呼ばれます) とみなすことができます。空間への最初の入口位置から現在位置まで更新して適応する 次数が最大となるときの位置Pi = (pi1, pi2, pi3, ..., pim) を個体極値と呼びます。最大適応度値はグループ極値と呼ばれる極値の極値ですPg = ( pg1, pg2, pg3,..., pgm)
したがって、更新式は次のようになります:
上の式の w は慣性重みであり、大きいほど値、位置は元の位置を維持する傾向があります、 d=1,2,...,mi=1,2,...,n ; k は現在の反復回数; c1 c2 は加速係数、r1 r2 は 0 ~ 1 に分布する乱数です。
上の式から、粒子の位置の更新は、元の位置、個々の極値位置、およびグループの極値位置の 3 つの部分に依存することがわかります。乱数を追加すると、自然のランダム性が模倣されます。一般に、一定回数の反復の後、グループの極値が目的の結果になります。
3. C++ コードの実装
3.1 アルゴリズムのフローチャート
3.2 ソースコード
STM32F407 に基づく C++ パッケージ
ヘッダーファイルは以下の通りです
#ifndef __PUB_PSO
#define __PUB_PSO
#include "stdint.h"
#include "stm32f4xx_rng.h"
const uint32_t NUM=10;//粒子总数
const uint32_t DIM=1;//维度,即变量数目
typedef struct
{
float x[DIM];//当前位置
float f;//当前适应度 性能评估指标
float v[DIM];//当前速度
float bestx[DIM];//当前粒子历史最优位置
float bestf;//当前粒子历史最优适应度 性能评估指标
}PSO_SWARM;
typedef struct
{
float w;//惯性项系数
float c1;//个体寻优项系数
float c2;//集体寻优项系数
float max_gen;//最大进化次数
float (* FUNC_fit) (float*);//适应度函数指针
float xmin[DIM];//位置下限
float xmax[DIM];//位置上限
float gbestx[DIM];//全局最优位置
float gbestf;//全局最优适应度 性能评估指标
}PSO_INITSET;
class pub_pso
{
/*---------DATA-----------*/
public:
float w;//惯性项系数
float c1;//个体寻优项系数
float c2;//集体寻优项系数
float max_gen;//最大进化次数
float (* FUNC_fit) (float*);//适应度函数指针
float xmin[DIM];//位置下限
float xmax[DIM];//位置上限
float gbestx[DIM];//全局最优位置
float gbestf;//全局最优适应度 性能评估指标
PSO_SWARM pso_swarm[NUM];//粒子
private:
/*------------FUNCTION----------*/
public:
pub_pso(){
};
~pub_pso(){
};
void InitValue(void);
void PSOInstall(PSO_INITSET*pso_initset);
void Evolution(void);
void Seekgbest(void);
void Run(void);
private:
};
extern pub_pso pso;
extern "C" void RNG_Init(void);
extern "C" float rand(void);
#endif
ソースファイルは以下の通りです
#include"pub_PSO.h"
#include"stm32f4xx_rcc.h"
void RNG_Init(void)
{
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
RNG_Cmd( ENABLE);
}
pub_pso pso;
float rand(void)
{
int temp;
while(!RNG_GetITStatus( RNG_FLAG_DRDY));
temp=RNG_GetRandomNumber()%(1000-0+1)+0;
return temp;
}
float finit(float *x)
{
return 1;
}
void pub_pso::InitValue(void)
{
for(int each=0;each<NUM;each++)//更新每一个粒子
{
PSO_SWARM *p=&pso_swarm[each];
for (int i = 0; i < DIM; i++)//初始粒子均匀分布
{
p->v[i]=0;
p->x[i]= each*(xmax[i]-xmin[i])/NUM+xmin[i];
}
p->f = FUNC_fit(p->x);//计算适应度值
for (int j = 0; j < DIM; j++)//局部最优初始化
{
p->bestx[j]= p->x[j];
}
p->bestf=p->f;
}
for (int j = 0; j < DIM; j++)//全局最优初始化
{
gbestx[j]= pso_swarm[0].x[j];
}
gbestf=pso_swarm[0].f;
// gbestf=pso_initset->gbestf;//全局最优适应度 性能评估指标
}
void pub_pso::PSOInstall(PSO_INITSET*pso_initset)
{
// w=pso_initset->w;//惯性项系数
c1=pso_initset->c1;//个体寻优项系数
c2=pso_initset->c2;//集体寻优项系数
max_gen=pso_initset->max_gen;//最大进化次数
for (int i = 0; i < DIM; i++)//更新每一个粒子的每一个维度,
{
xmin[i]=pso_initset->xmin[i];//位置下限
xmax[i]=pso_initset->xmax[i];//位置上限
// gbestx[i]=pso_initset->gbestx[i];//全局最优位置
}
}
void pub_pso::Evolution(void)
{
for(int each=0;each<NUM;each++)//更新每一个粒子
{
PSO_SWARM *p=&pso_swarm[each];
for (int i = 0; i < DIM; i++)//更新每一个粒子的每一个维度,
{
p->v[i]=p->v[i]*w + c1 * rand() * (p->bestx[i]-p->x[i])
+ c2 * rand() * (gbestx[i]-p->x[i]);
p->x[i] += p->v[i];
if(p->x[i]<xmin[i])p->x[i]=xmin[i];
if(p->x[i]>xmax[i])p->x[i]=xmax[i];
}
p->f = FUNC_fit(p->x);//计算适应度值
if(p->bestf > p->f)//更新个体最优
{
for (int j = 0; j < DIM; j++)
{
p->bestx[j]= p->x[j];
}
p->bestf=p->f;
}
if(gbestf > (p->f))//更新全局最优 异步更新,后续粒子会使用新的全局最优 速度快容易陷入局部最优
{
for (int j = 0; j < DIM; j++)
{
gbestx[j]= p->x[j];
}
gbestf=p->f;
}
}
}
void pub_pso::Run(void)
{
InitValue();//种群初始化
for(int gen=0;gen<max_gen;gen++)//循环演变
{
w= 0.9f-gen*0.5f/max_gen;//线性变化惯性速度权重
Evolution();//粒子进化一次//寻找全局最优
}
}
float finit(float *x)
上記の関数は、関数の特定のコンテンツを独自に追加する必要があります。これは、後で関数ポインターの形式でインポートできます。乱数を使用する場合は、STM32F4の乱数レジスタを呼び出して取得します。
主な使用法は、初期化後に関数を呼び出して最適化をオンにしvoid pub_pso::Run(void)
、終了後にグループの極値を持ち上げることです。
4. 応用例
1. 最適な値を見つける
上記の関数の最大値を求めます
1. PIDパラメータの最適化
PID パラメータの調整は面倒なプロセスですが、粒子群最適化アルゴリズムを使用することで解決できます。粒子群の位置パラメータとして PID 係数を入力可能 適応度関数は通常誤差性能指数 ITAE で定義される 離散化後、
シングルチップマイコン内で 1 回の誤差内で誤差がなかった累積和として定義できるPIDパラメータを入力してから一定時間経過します。システム応答時間が5秒の場合、ITAE=1エラー(1秒時)+2エラー(2秒時)+3エラー(3秒時)+4エラー(4秒時)+ 5*エラー(5秒時)。
要約する
最適化アルゴリズムと粒子群最適化アルゴリズムを基本原理から紹介し、C++のソースコードと応用例の簡単な説明を掲載しています。
参考文献
1. MATLAB インテリジェント アルゴリズム 30 ケースの分析
2.超簡潔なランダム粒子群最適化 (PSO) プログラム (C/C++)