1. はじめに
PID制御アルゴリズムは皆さんもよくご存じだと思いますが、バランスカーはこれによってバランスを取られており、フライトコントロールのバランスアルゴリズムもそれに基づいており、FOCにおける閉ループ制御にも使われています。シンプルなだけでなく、使いやすさも兼ね備えています。次に、この記事ではアルゴリズムの原理を簡単に紹介し、それを実現するために FPGA を使用する方法を説明します (C 言語の実装プロセスは非常に簡単です)。
2. PIDアルゴリズム
PID は、比例、積分、微分の 3 つの英語の頭文字から取られています。アルゴリズムがこれら 3 つの部分で構成されていることを意味します。
1.P比
演算プロセスは、期待値から現在値を減算し、p 係数を乗算してフィードバック値を取得します。比率の役割は主に、期待値を現在の値と等しくすることです。
2.Iポイント
誤差値は継続的に蓄積され、I 係数が乗算されてフィードバック値が得られます。積分の機能は主に静的誤差を除去することですが、現在値が期待値に近い場合、この時点では比率の影響は非常に小さく、0に近い場合があり、誤差値は隣接する 2 つの時間の誤差もほぼ 0、D 微分もあまり機能しません このときシステムの外部抵抗と PD フィードバック値がオフセットしている場合、現在値を作るにはこの誤差値を累積し続ける必要があります期待値と等しい。
3.D 微分
現在のエラー値が最後の操作のエラー値から減算され、d 係数が乗算されてフィードバック値が得られます。微分機能の主な機能は、システムの衝撃を軽減し、システムの変化の方向と逆方向のフィードバックを適用して、システムのこの方向の変化を抑制することです。
PID アルゴリズムには主に加算、減算、乗算の 3 つの演算が含まれることがわかります。これら 3 種類の演算も FPGA 上で実装するのが非常に簡単です。
3. FPGA実装
まず、PID の 3 つの係数はすべて浮動小数点数であることに注意してください。実装の便宜上、浮動小数点数は 100 倍に拡大されてから切り上げられます。次に、フィードバック結果を 100 分の 1 に減らします。
1.Pレシオの実現
実装コードは次のとおりです。完了するまでに必要な時間は 2 クロック サイクルだけです。ここでは 100 倍のズームアウト操作を左にシフトすることで実現していますが、実際には 102 倍のズームアウトとなり、結果にはあまり影響しません。I積分とD微分の計算サイクル数と同じになるように、ビート演算を行います。
//P -------------------------------------------------
always@(posedge clk or negedge rst_n)
begin
if( rst_n == 1'b0)
Kp_fb <= 1'b0;
else if( pid_en == 1'b1)
Kp_fb <= ( desired_value - current_value ) * Kp;
else
Kp_fb <= Kp_fb;
end
always@(posedge clk or negedge rst_n)
begin
if( rst_n == 1'b0)
Kp_fb_reduce <= 'd0;
else if( cal_delay_0 == 1'b1)
Kp_fb_reduce <= (Kp_fb >>> 7) + (Kp_fb >>> 9); // /102.4
else
Kp_fb_reduce <= Kp_fb_reduce;
end
always@(posedge clk or negedge rst_n)
begin
if( rst_n == 1'b0)
Kp_fb_reduce_d0 <= 'd0;
else if( cal_delay_1 == 1'b1)
Kp_fb_reduce_d0 <= Kp_fb_reduce;
else
Kp_fb_reduce_d0 <= Kp_fb_reduce;
end
//----------------------------------------------------------------------------
2. Iポイントの実施
実装コードは以下の通りで、P比率よりも若干アシストを強めています。ここでは積分制限の問題を考えていますが、積分値が蓄積し続けるとシステムが不安定になる可能性があるため、ここでは3000に設定しています。
//I --------------------------------------------------------
always@(posedge clk or negedge rst_n)
begin
if( rst_n == 1'b0)
Ki_integral <= 'd0;
else if( pid_en == 1'b1)
if( Ki_integral > $signed('d3000) && ( desired_value - current_value ) > $signed('d0) )
Ki_integral <= Ki_integral;
else if( Ki_integral < $signed(-'d3000) && ( desired_value - current_value ) < $signed('d0) )
Ki_integral <= Ki_integral;
else
Ki_integral <= Ki_integral + ( desired_value - current_value );
else
Ki_integral <= Ki_integral;
end
always@(posedge clk or negedge rst_n)
begin
if( rst_n == 1'b0 )
Ki_fb <= 'd0;
else if( cal_delay_1 == 1'b1 )
Ki_fb <= Ki_integral * Ki;
else
Ki_fb <= Ki_fb;
end
always@(posedge clk or negedge rst_n)
begin
if( rst_n == 1'b0 )
Ki_fb_reduce <= 'd0;
else if( cal_delay_2 == 1'b1)
Ki_fb_reduce <= (Ki_fb >>> 7) + (Ki_fb >>> 9); // /102.4
else
Ki_fb_reduce <= Ki_fb_reduce;
end
//------------------------------------------------------------------------------
3.D 差分実現
D 微分演算は次のように実現されます。公式に従ってください。
//D ---------------------------
always@(posedge clk or negedge rst_n)
begin
if( rst_n == 1'b0)
Kd_error <= 'd0;
else if( pid_en == 1'b1)
Kd_error <= ( desired_value - current_value );
else
Kd_error <= Kd_error;
end
always@(posedge clk or negedge rst_n)
begin
if( rst_n == 1'b0)
Kd_fb <= 'd0;
else if( cal_delay_0 == 1'b1)
Kd_fb <= (Kd_error - Kd_last_error) * Kd;
else
Kd_fb <= Kd_fb;
end
always@(posedge clk or negedge rst_n)
begin
if( rst_n == 1'b0)
Kd_last_error <= 'd0;
else if( cal_delay_0 == 1'b1)
Kd_last_error <= Kd_error;
else
Kd_last_error <= Kd_last_error;
end
always@(posedge clk or negedge rst_n)
begin
if( rst_n == 1'b0)
Kd_fb_reduce <= 'd0;
else if( cal_delay_1 == 1'b1)
Kd_fb_reduce <= (Kd_fb >>> 7) + (Kd_fb >>> 9); // /102.4
else
Kd_fb_reduce <= Kd_fb_reduce;
end
//--------------------------------
4. シミュレーション検証
テストコードは次のとおりです。現在値を 500 に初期化し、PID 出力の期待値とフィードバック値に従って現在値を調整します。
always@(posedge clk or negedge rst_n) begin
if( rst_n == 1'b0)
current_value <= 'd500;
else if( pid_ack == 1'b1)
current_value <= current_value + out;
else
current_value <= current_value;
end
PID_Control PID_Control_i(
.clk ( clk),
.rst_n ( rst_n),
.pid_en ( 1'b1),
.pid_ack ( pid_ack),
.desired_value ( desired_value),
.current_value ( current_value),
.Kp ( 'd10),
.Ki ( 'd1),
.Kd ( 'd10),
.out ( out)
);
シミュレーション波形は以下の通りです
これは D を 0 に設定した場合です。システムの振動がわかります。
ようこそ━( `∀´ )ノ亻! WeChat 公式アカウントをフォローすると、 FPGA ツアーに関連リソースがアップロードされます。