FPGAはPID制御アルゴリズムを実装(シミュレーションを含む)

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 ツアーに関連リソースがアップロードされます。

おすすめ

転載: blog.csdn.net/weixin_44678052/article/details/130547375