VHDLでPID制御を10手順で実装

VHDLを使用したPID制御の実装イメージVHDL
この記事は約23分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラム(回路記述)の基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

VHDLによるPID制御の実装は、工学や産業界での電子設計において、非常に需要が高い技術の一つとなっています。

特に、アナログ制御が難しい場面や、デジタル制御が適している場面での応用が増えてきています。

この記事では、VHDLによるPID制御の実装方法を初心者向けに10手順で解説します。

具体的なサンプルコードとその解説を交えながら、手順を追って学んでいきましょう。

●VHDLとは

VHDL(VHSIC Hardware Description Language)は、主に集積回路やFPGAの設計で使用されるハードウェア記述言語です。

アメリカ国防総省の高速集積回路プロジェクト (VHSIC) の一部として開発されました。

この言語の特徴や、どのような場面で使用されるのかを深掘りしていきます。

○VHDLの特徴

VHDLの最大の特徴は、その記述性と汎用性にあります。

複雑なハードウェアの振る舞いや、ロジックの動作を高い抽象度で表現することが可能です。

また、異なるハードウェアやシミュレーションツールに対しての移植性が高いのも特長として挙げられます。

●PID制御の基本

PID制御は、工学分野で最も一般的に使用されるフィードバック制御の方法の一つです。

P(Proportional)、I(Integral)、D(Derivative)の3つの要素を組み合わせて、エラーを最小限に抑えるための制御を行います。

○P制御、I制御、D制御の概念

  • P制御:現在のエラー値に比例して制御量を出力します。定常偏差が生じやすいです。
  • I制御:過去のエラー値を積分して制御量を出力します。定常偏差を解消する効果があります。
  • D制御:エラー値の変化率に比例して制御量を出力します。応答の速度を向上させる効果があります。

●VHDLでのPID制御の実装手順

VHDLは、デジタルシステムのハードウェア記述言語として広く使用されています。

今回は、そんなVHDLを使用して、PID制御の実装方法について10手順で詳しく解説していきます。

○手順1:VHDL環境のセットアップ

VHDLのプログラムを書き始める前に、開発環境を整えることが大切です。代表的なVHDLの開発環境には、XilinxやAlteraのツールがあります。

これらのツールをインストールし、プロジェクトを新規作成してください。

○手順2:PIDのパラメータ設定

このコードでは、PID制御の基本パラメータを定義するコードを表しています。

この例では、ゲイン値を初期設定しています。

-- PIDのパラメータ設定
constant Kp: real := 1.0;  -- 比例ゲイン
constant Ki: real := 0.01; -- 積分ゲイン
constant Kd: real := 0.1;  -- 微分ゲイン

○手順3:P制御の実装

このコードでは、比例制御(P制御)の実装を行います。

エラー値と比例ゲインを掛け合わせて、出力を得ることができます。

-- P制御の実装
signal error: real;
signal P_output: real;
begin
    error <= setpoint - feedback; -- 目標値とフィードバック値の差
    P_output <= Kp * error;       -- 比例制御
end;

○手順4:I制御の実装

I制御は、時間とともに蓄積されるエラーを考慮した制御です。

このコードでは、エラー値の積分計算を行い、積分ゲインとの積をとります。

-- I制御の実装
signal integral: real := 0.0;
signal I_output: real;
begin
    integral <= integral + error * dt;  -- エラーの積分計算
    I_output <= Ki * integral;          -- 積分制御
end;

○手順5:D制御の実装

D制御は、エラーの変化率を考慮した制御方法です。

この例では、エラーの変化量を計算して、微分ゲインとの積をとります。

-- D制御の実装
signal last_error: real := 0.0;
signal derivative: real;
signal D_output: real;
begin
    derivative <= (error - last_error) / dt; -- エラーの変化率計算
    D_output <= Kd * derivative;              -- 微分制御
    last_error <= error;
end;

これらの手順に従い、VHDLでPID制御を実装することができます。

○手順6:サンプルコード1:基本的なPID制御コード

VHDLによるPID制御の実装を学ぶ上で、まずは基本的なPID制御コードからスタートするのが良いでしょう。

この手順では、シンプルなPID制御器のVHDLコードを紹介し、各部分の役割や意味を詳しく解説します。

このコードでは、PID制御の基本的な概念をVHDLで表現しています。

この例では、ターゲット値と実際の値の差を取り、それに基づいて制御信号を生成しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity PID_Controller is
    Port ( clk        : in  STD_LOGIC;
           reset      : in  STD_LOGIC;
           set_point  : in  signed(15 downto 0);
           process_val: in  signed(15 downto 0);
           output_val : out signed(15 downto 0));
end PID_Controller;

architecture Behavioral of PID_Controller is
    signal error, prev_error, integral, derivative: signed(15 downto 0) := (others => '0');
    constant Kp : signed(15 downto 0) := "0000100000000000"; -- 例のPゲイン
    constant Ki : signed(15 downto 0) := "0000001000000000"; -- 例のIゲイン
    constant Kd : signed(15 downto 0) := "0000000100000000"; -- 例のDゲイン
begin
    process(clk, reset)
    begin
        if reset = '1' then
            error <= (others => '0');
            prev_error <= (others => '0');
            integral <= (others => '0');
        elsif rising_edge(clk) then
            error <= set_point - process_val;              -- 誤差を計算
            integral <= integral + error;                  -- 積分項の計算
            derivative <= error - prev_error;              -- 微分項の計算
            output_val <= Kp*error + Ki*integral + Kd*derivative; -- 出力の計算
            prev_error <= error;
        end if;
    end process;
end Behavioral;

このコードの中心部には、PID制御の計算式が書かれています。

誤差はset_point(目標値)とprocess_val(プロセス値)の差で計算され、この誤差を基にP制御、I制御、D制御の3つの項を計算して出力します。

各ゲイン値はKpKiKdで設定されており、これらの値を変更することで制御の特性を調整できます。

このコードを実行すると、output_valが更新され、この値が制御器からの出力として外部に提供されます。

この出力は、たとえばモータの駆動信号として使用されることが考えられます。

○手順7:サンプルコード2:条件分岐を伴うPID制御

VHDLによるPID制御実装を進める中で、特定の条件下で制御ロジックを変更する必要が生じることもあります。

そのような場合、条件分岐を実装することで、制御手法を柔軟に変更することが可能となります。

今回は、この条件分岐を伴うPID制御の実装方法について詳しく解説します。

条件分岐を伴うPID制御のサンプルコードを紹介します。

entity PID_Controller is
    Port ( error_signal : in std_logic_vector(15 downto 0);
           control_signal : out std_logic_vector(15 downto 0));
end PID_Controller;

architecture Behavior of PID_Controller is
    signal integral : std_logic_vector(15 downto 0) := "0000000000000000";
    signal derivative : std_logic_vector(15 downto 0);
    signal previous_error : std_logic_vector(15 downto 0) := "0000000000000000";
begin
    process(error_signal)
    begin
        -- 積分項の計算
        integral <= integral + error_signal;

        -- 微分項の計算
        derivative <= error_signal - previous_error;

        -- PID制御の計算
        if error_signal < "0100000000000000" then
            control_signal <= error_signal + integral + derivative;
        else
            control_signal <= error_signal + integral;
        end if;

        previous_error <= error_signal;
    end process;
end Behavior;

このコードでは、エラーシグナルを入力として、制御信号を出力としています。

エラーシグナルが特定の値より小さい場合に、微分項を追加するという条件分岐を実装しています。

具体的には、エラーシグナルが”0100000000000000″より小さい場合、微分項を加えてPID制御を実施し、それ以外の場合は、PI制御のみを行います。

この例では、特定のエラーシグナルの値に基づいて微分制御の有効、無効を切り替えることが示されています。

このように条件分岐を使用することで、さまざまな制御状況に応じて制御手法を変更することができます。

さて、このコードを実行すると、エラーシグナルが指定された値を下回る場合、微分制御が加わることで制御信号の変動が増大します。

逆に、エラーシグナルがその値を超える場合、制御信号は微分制御を考慮せずに出力されるため、変動は緩やかになるでしょう。

注意点として、条件分岐を用いた制御の場合、突然の制御方法の変更がシステムに悪影響を及ぼす可能性があるため、分岐条件や制御手法の変更は慎重に行う必要があります。

応用例としては、複数のセンサーからの入力に基づいて、動的に制御方法を変更するシステムも考えられます。

例えば、温度センサーや圧力センサーの情報を活用して、異常が発生した場合に制御方法を切り替えるなどの応用が考えられます。

○手順8:サンプルコード3:外乱を考慮したPID制御

実際のシステムでは、外乱の存在が避けられません。

特に制御システムを構築する際、外乱の影響を最小限に抑えるための方法を知っておくことは非常に重要です。

VHDLによるPID制御では、外乱を考慮した制御を実装することが可能です。

ここではその実装方法と、サンプルコードを用いて具体的にどのように行うのかを解説します。

このコードでは、外乱を考慮したPID制御を実装する方法を表しています。

この例では、外乱を検出し、それを補正するためのアルゴリズムを採用しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Disturbance_PID is
    Port ( error : in STD_LOGIC_VECTOR(15 downto 0);
           disturbance : in STD_LOGIC_VECTOR(15 downto 0);
           Kp : in STD_LOGIC_VECTOR(7 downto 0);
           Ki : in STD_LOGIC_VECTOR(7 downto 0);
           Kd : in STD_LOGIC_VECTOR(7 downto 0);
           output : out STD_LOGIC_VECTOR(15 downto 0));
end Disturbance_PID;

architecture Behavior of Disturbance_PID is
    signal error_sum: STD_LOGIC_VECTOR(15 downto 0) := "0000000000000000";
    signal last_error: STD_LOGIC_VECTOR(15 downto 0) := "0000000000000000";
    signal disturbance_corrected: STD_LOGIC_VECTOR(15 downto 0);
begin
    -- 外乱を補正
    disturbance_corrected <= error - disturbance;

    -- P制御
    process (disturbance_corrected, Kp)
    begin
        output <= disturbance_corrected * Kp;
    end process;

    -- I制御
    error_sum <= error_sum + disturbance_corrected;
    process (error_sum, Ki)
    begin
        output <= output + (error_sum * Ki);
    end process;

    -- D制御
    process (disturbance_corrected, last_error, Kd)
    begin
        output <= output + (disturbance_corrected - last_error) * Kd;
        last_error <= disturbance_corrected;
    end process;
end Behavior;

上記のコードでは、外乱を入力として受け取り、それを誤差から補正しています。

この補正された誤差をもとにP制御、I制御、D制御を行って出力を生成します。

このサンプルコードを実行した場合、外乱の影響を受けにくい、安定した出力が得られることを期待しています。

外乱が突然加わった場合でも、この制御により外乱の影響を速やかに補正し、目標値に近づける動作をします。

注意点として、外乱の大きさや突発性によっては、制御が追いつかないことも考えられます。

このような場合には、PIDの各係数を適切に調整することで、より良い制御性能を得ることができます。

応用例として、特定の条件下で外乱が発生しやすい場合、外乱の特性を事前に知っておき、それに対する前処理を行うことも考えられます。

たとえば、温度や湿度が一定の範囲を超えたときに外乱が発生すると分かっている場合、それらの状況を検知して外乱の影響を早めに補正することができます。

○手順9:VHDLのシミュレーションとデバッグ

シミュレーションは、VHDLプログラミングにおいて重要なステップです。

書かれたコードが正しく動作するか、期待した動きをするかを事前に確認することができます。

一方、デバッグは、シミュレーションや実際のハードウェア上での動作中に発生した問題を特定し、それを解決するプロセスです。

今回は、これらの手順について詳しく見ていきましょう。

□シミュレーションの基本

シミュレーションは、VHDLコードが正しく動作するかを確認するためのものです。

これにより、ハードウェアに書き込む前にエラーや問題を特定できるため、開発効率が向上します。

このコードでは、シンプルなシミュレーションテストベンチを使ってPID制御の動作を確認するコードを表しています。

この例では、入力としてステップ信号を与え、出力としてPID制御の結果を確認します。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity pid_tb is
end pid_tb;

architecture sim of pid_tb is
    signal test_input: signed(15 downto 0);
    signal test_output: signed(15 downto 0);
begin
    -- PID制御のインスタンス化
    UUT: entity work.pid_control
    port map(
        input => test_input,
        output => test_output
    );

    -- シミュレーションのシナリオ
    process
    begin
        -- 初期化
        test_input <= to_signed(0, 16);
        wait for 10 ns;

        -- ステップ信号を入力
        test_input <= to_signed(1000, 16);
        wait for 100 ns;

        -- シミュレーション終了
        wait;
    end process;

end sim;

上記のコードはシミュレーションのシナリオを実装しており、10ns後にステップ信号を入力し、その後のPID制御の出力を確認するためのものです。

□デバッグのポイント

シミュレーションを行っても、期待した結果が得られない場合があります。そのような場合、デバッグ作業が必要です。

デバッグ時の重要なポイントとして次のことを意識してください。

  • シミュレーションの波形を詳細に観察することで、どの部分で問題が起きているのかを特定します。
  • PID制御のパラメータや、その他の制御ロジックが適切であるかを再確認します。
  • VHDLの文法や構文のエラーを確認するために、エラーメッセージやワーニングメッセージを注意深く読みます。

VHDLのデバッグは、しばしば難解で時間がかかる作業となることが多いですが、上記のポイントを意識することで効率的に問題を解決することができます。

□シミュレーションとデバッグの結果

上記のサンプルコードをシミュレーションすると、10ns後にステップ信号が入力された時のPID制御の出力動作を観察することができます。

特に、I制御やD制御の影響によって、出力がどのように変動するのかを注意深く観察することで、PID制御の挙動の理解が深まります。

また、何らかの問題が発生した場合は、上述のデバッグのポイントを活用して問題の原因を突き止めることができます。

○手順10:実際のハードウェアでの動作確認

VHDLによるPID制御を実装した後の最終ステップは、実際のハードウェアでの動作確認です。

ここでは、VHDLのコードが実ハードウェアで正しく動作するかを確認し、期待通りの結果を得るためのプロセスを詳細に説明します。

□ハードウェアの選定

初めに、VHDLコードの動作確認を行うためのハードウェアを選定します。

FPGAやCPLDなど、VHDLで記述されたデザインを実装できるハードウェアを用意します。

使用するハードウェアによって、必要な外部接続や設定が異なる場合がありますので、ハードウェアの仕様書やマニュアルを参照することが重要です。

□ハードウェアへの書き込み

次に、VHDLで記述されたコードをハードウェアに書き込むためのツールを使用します。

書き込む際には、コンフィギュレーションファイルやビットストリームを作成する必要があります。

このコードでは、FPGAボードにコードを書き込む基本的な手順を表しています。

この例では、FPGAボードに接続してVHDLコードを書き込んでいます。

-- FPGAボードへの書き込みを開始
begin
  FPGA_board_connection <= '1';
  VHDL_code_transfer <= '1';
end process;

VHDLのコードがハードウェアに書き込まれると、上記のコードでFPGAボードの接続が確立され、VHDLコードが正しく転送されます。

□動作の確認

ハードウェアにコードを書き込んだ後、外部入力を用いて動作を確認します。

PID制御の応答や、外部からの信号入力に対する反応など、期待した動作が得られるかを確認します。

たとえば、PID制御の目標値として「5」と入力した場合、制御出力が5に近づくように動作することを期待します。

実際のハードウェアでこのような動作を確認することで、コードの正確さを確認できます。

□調整や最適化

ハードウェアでの動作確認を行った結果、予期しない動作や性能の低下が見られた場合、コードの調整や最適化が必要となることがあります。

このような場合、VHDLのコードを再度確認し、必要な修正を行います。

例えば、PID制御の応答速度が遅いと感じた場合、制御パラメータの調整や、ハードウェアのクロック周波数の変更など、さまざまな手段を用いて動作を最適化することができます。

●注意点と対処法

VHDLでPID制御の実装を進める際には、多くの初心者がつまずくポイントや、潜在的な問題点が存在します。

今回は、それらの注意点とその対処法を詳しく解説していきます。

○タイミング問題の発生

VHDLにおいては、複雑な制御構造を実装する際、タイミングのズレが発生しやすくなります。

特にPID制御のように、繰り返しの処理や連続的なデータの流れが求められる場合、タイミングのズレは致命的な問題となることがあります。

このコードでは、PID制御の計算の際のタイミングを表しています。

この例では、タイミングのズレが発生する可能性のある部分を表しています。

process(clk)
begin
    if rising_edge(clk) then
        -- P制御の計算
        P_out <= error * Kp;
        -- I制御の計算
        I_out <= I_out_prev + error * Ki;
        -- D制御の計算
        D_out <= (error - error_prev) * Kd;

        -- 前回の値の保存
        I_out_prev <= I_out;
        error_prev <= error;
    end if;
end process;

このコードを動作させた場合、I_outの更新がI_out_prevの保存よりも先に行われてしまう可能性があります。

このようなタイミングのズレがPID制御の正確性を損なう原因となります。

対処法としては、VHDLのprocessブロック内での信号の更新順序を明確に管理することが求められます。

具体的には、一時変数を用いて、各制御の計算結果を保存し、その後で一斉に信号を更新するという手法が考えられます。

○オーバーフローのリスク

PID制御を実装する際、計算結果が変数の範囲を超えてオーバーフローすることが考えられます。

特にI制御の累積値は、制御が長時間続くと大きくなる可能性があります。

このコードでは、オーバーフローを検出するロジックを実装しています。

この例では、制御値が一定の閾値を超えた場合に、オーバーフローを検出するロジックを表しています。

constant THRESHOLD : integer := 1024;  -- 閾値の設定

process(clk)
begin
    if rising_edge(clk) then
        -- I制御の計算
        temp_I_out <= I_out_prev + error * Ki;

        -- オーバーフローの検出と対処
        if temp_I_out > THRESHOLD then
            I_out <= THRESHOLD;
        elsif temp_I_out < -THRESHOLD then
            I_out <= -THRESHOLD;
        else
            I_out <= temp_I_out;
        end if;

        -- 他の制御計算...
    end if;
end process;

このロジックにより、I制御の値が閾値を超えた場合に、適切な範囲にクリップすることができます。

このような対処を行うことで、オーバーフローによる制御の不具合を防ぐことができます。

●カスタマイズ方法

PID制御は、多くの工学分野で利用される重要な手法です。

そのため、実際のシステムや環境に合わせて、VHDLを使ったPID制御のカスタマイズが求められることが多いです。

ここでは、基本的なPID制御をさらに発展させ、さまざまな環境や要件に対応するためのカスタマイズ方法について解説します。

○ゲインの調整機能の追加

最も一般的なカスタマイズ方法の一つは、ゲイン(Kp、Ki、Kd)の調整機能の追加です。

この機能を追加することで、システムの特性や外部からの影響に柔軟に対応することが可能となります。

entity PID_controller is
    port(
        ...
        Kp_in : in real;
        Ki_in : in real;
        Kd_in : in real;
        ...
    );
    ...
begin
    ...
    Kp <= Kp_in;
    Ki <= Ki_in;
    Kd <= Kd_in;
    ...
end PID_controller;

このコードでは、Kp、Ki、Kdのゲインを外部から入力できるようにしています。

この例では、外部から指定したゲインを使ってPID制御を行っています。

実際には、これによりシステムの特性に合わせた微調整が可能となり、より高精度な制御を実現できます。

○デッドタイムの考慮

特定のシステムでは、制御入力が実際に効果を発揮するまでの時間遅れ(デッドタイム)が存在することがあります。

このデッドタイムを考慮するためのカスタマイズ例を以下に示します。

entity PID_controller_with_deadtime is
    ...
    constant DEADTIME : time := 10 ns;
    signal previous_error : real;
    ...
begin
    process
        ...
        wait for DEADTIME;
        previous_error <= error;
        ...
    end process;
    ...
end PID_controller_with_deadtime;

この例では、DEADTIMEで指定した時間だけエラーの更新を遅延させています。

デッドタイムの存在を考慮することで、現実のシステム動作をより正確に模倣することが可能です。

実際にこのコードを使用すると、10nsのデッドタイムを考慮した制御が行えます。

まとめ

VHDLを使用してPID制御を実装することは、初心者にとっても十分にアクセス可能な内容であり、本ガイドを参考に手順を踏むことで、一歩一歩進めることができます。

また、基本的な実装だけでなく、ゲインの調整やデッドタイムの考慮など、さまざまなカスタマイズ方法を学ぶことで、実際のシステムの制御にも応用することができるでしょう。

今後もVHDLやPID制御の知識を深めることで、より高度な制御技術を習得することをおすすめします。