結論

PID制御は、目標値と今の値のずれ(偏差)を「今の大きさ(P)」「たまった量(I)」「変化の速さ(D)」の3つで見て、操作量を決めるフィードバック制御です。P だけだとずれが残り、I がそのずれを消し、D が行き過ぎを抑えます。

この記事でわかること

  • P・PI・PID の応答を時間ごとの値と、行き過ぎ・整定時間の数値で比較
  • 積分ワインドアップを再現し、対策で行き過ぎが20.0%→0.5%になった結果
  • ジーグラー・ニコルス法のゲインの検証と、Python・C の実装

2026年10月29日更新|Python 3.13・NumPy 2.5・SciPy 1.18・gcc 13.3 で計算確認

PID制御は、温度・速度・位置・圧力などを目標値に合わせ続けるしくみです。センサーで測った値を目標値と比べ、ずれから操作量(ヒーターの出力やモーターの電圧)を計算し、その結果をまた測ります。この「測る→比べる→直す」の輪がフィードバック制御です。

flowchart TD
    R[目標値 r] --> C((比較))
    C -->|偏差 e = r − y| PID[PID 制御器<br>P+I+D]
    PID -->|操作量 u| G[制御対象<br>ヒーター・モーター]
    G --> Y[出力 y]
    Y --> S[センサー]
    S -->|測定値| C

よく調べられることの答えを先にまとめます。

知りたいこと 答え 詳しい節
PID制御とは 偏差の比例・積分・微分の和で操作量を決めるフィードバック制御 PID制御とは
P・I・D の役割をわかりやすく P は今、I は過去、D は未来(変化の向き)を見る P・I・D の役割
P だけでは足りない理由 定常偏差が残る。Kp=10 でも目標の9.1%足りなかった P 制御と定常偏差
P・PI・PID の違い 同じ Kp で行き過ぎ 37.1%・44.7%・14.4%、PID だけが速く落ち着く P・PI・PID の応答比較
ゲインの調整方法 限界感度法で出発点を決め、行き過ぎを見て下げる ジーグラー・ニコルス法の検証
積分ワインドアップとは 出力が上限に張りついている間に I がたまり、大きく行き過ぎる 積分ワインドアップ
D がうまく働かない ノイズを拾う。不完全微分と測定値微分で抑える 微分のノイズと微分キック
プログラムの書き方 位置形の離散 PID。Python と C で同じ結果 PID制御のプログラム

確認環境:Ubuntu 24.04.5 LTS の上で、作業場所に作った venv に NumPy 2.5.4・SciPy 1.18.1(Python 3.13.18)を入れ、制御対象を伝達関数で作り、scipy.signal.cont2discrete(零次ホールド)で 0.01 秒ごとの式に直して、離散の PID 制御器と組み合わせて計算しました。主な制御対象は一次遅れの 1/(5s+1) と、一次遅れが3つつながった 1/(s+1)^3 です。行き過ぎ量・立ち上がり時間・整定時間・定常偏差・IAE はすべてこのシミュレーションで計算した値です。C の実装は gcc 13.3.0 でコンパイルし、Python と出力を突き合わせました。グラフ画像は使わず、時間ごとの値を表で示します。ジーグラー・ニコルス法の係数は Wikipedia(英語版「Ziegler–Nichols method」と日本語版「PID制御」)、比例帯の定義は理化工業の技術解説、離散化の方法は SciPy の公式ドキュメントで確かめました。実機(ヒーター・モーター)は動かしていません。図は mermaid 11.16.0 で描画を確かめています(確認日 2026年10月29日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「PID制御とは?わかりやすく|P・I・Dの役割と調整をシミュレーションで検証」

PID制御とは(フィードバック制御のしくみ)

この節では、PID制御が何をしていて、どこで使われているのかが分かります。

PID制御は、目標値 r と測定値 y の差(偏差 e = r − y)から、操作量 u を毎回計算し直す制御です。 P は Proportional(比例)、I は Integral(積分)、D は Derivative(微分)の頭文字です。偏差が大きければ強く、小さければ弱く操作し、ずれが残っていればじわじわ足し、急に近づいているならブレーキをかけます。

Wikipedia(日本語版)は、PID制御を古典制御理論で体系化された、産業界で主に使われている制御方式と説明しています。計算が軽く、制御対象の詳しい数式モデルが無くてもゲイン(係数)の調整で使えることが、広く使われる理由です。

用語の整理

用語 意味 エアコンの例
目標値(SV・r) こうしたい値 設定温度 26℃
測定値・制御量(PV・y) 今の値 室温センサーの値
偏差(e) 目標値 − 測定値 26℃ − 28℃ = −2℃
操作量(MV・u) 制御器が出す指令 コンプレッサーの回転数
外乱 外から入る乱れ 窓を開けた・人が増えた
定常偏差(オフセット) 十分に時間がたっても残るずれ ずっと 26.5℃ のまま
行き過ぎ量(オーバーシュート) 目標を越えた分の割合 一度 25℃ まで冷えすぎる

身近な例(エアコン・ドローン・クルーズコントロール)

ここで挙げる例は、一般的な説明の範囲です。製品ごとの実際の制御方式は、各社の資料で確かめる必要があります。

1

エアコン・給湯器

室温や湯温を測り、設定温度との差でコンプレッサーや燃焼量を変える。温度は変化が遅く、PI 制御が多く使われる。

温度制御

2

ドローンの姿勢

ジャイロで傾きと回転の速さを測り、各モーターの回転数を変えて水平を保つ。D が揺れを抑える。

姿勢・角度の制御

3

自動車の速度

設定速度との差でアクセル量を変える。上り坂は外乱で、I が坂の分を補う。

速度制御

4

ライントレースロボット

線からのずれでハンドルを切る。P だけだとカーブで線から外れ続け、I で補正する。

位置の制御

P・I・Dの役割(比例・積分・微分をわかりやすく)

この節では、P・I・D がそれぞれ何を見て、どんな働きをするのかが分かります。

P は「今の偏差」、I は「これまでの偏差の合計」、D は「偏差の変化の速さ」に、それぞれ係数(ゲイン)を掛けて足し合わせます。 過去(I)・現在(P)・未来(D)と覚えると、役割を取り違えにくくなります。

flowchart LR
    E[偏差 e] --> P[P:今<br>e × Kp]
    E --> I[I:過去<br>e の積分 × Ki]
    E --> D[D:未来<br>e の傾き × Kd]
    P --> U((操作量 u))
    I --> U
    D --> U

P比例動作:ずれの大きさに比例

偏差が大きいほど強く操作する。速く近づくが、Kp を上げすぎると振動し、P だけではずれが残る(定常偏差)。

I積分動作:ずれをためて足す

小さなずれでも、残っている限り操作量を増やし続ける。定常偏差を0にするが、効かせすぎると行き過ぎと振動が増える。

D微分動作:変化の速さで先回り

目標に急に近づいているとブレーキをかける。行き過ぎを減らすが、測定のノイズを大きくしてしまう。

ゲインの増減と応答の傾向です。右の2列は、この記事のシミュレーション(制御対象 1/(s+1)^3)で確かめた範囲です。

ゲイン 上げると速さは 上げると行き過ぎは 定常偏差 手元の結果
Kp(比例) 速くなる 増える 減るが0にならない Kp 1→6 で立ち上がり 1.87→0.79秒、行き過ぎ 14.0→73.7%
Ki(積分) 速くなる 増える 0になる Ki 0.2→1.5 で行き過ぎ 0→69.7%
Kd(微分) 少し遅くなる 減る(上げすぎると戻る) 影響しない Kd 0→2 で行き過ぎ 44.7→14.4%、Kd 4 で 15.3%

PID制御の式と伝達関数(ラプラス変換は入口だけ)

この節では、PID制御の式の読み方と、カタログや教科書で出てくる「並列形」「標準形」「比例帯」の関係が分かります。

時間の式では u(t) = Kp·e(t) + Ki·∫e(t)dt + Kd·de(t)/dt です。 1項目が P、2項目が I(偏差を0から今まで積分した値)、3項目が D(偏差の時間あたりの変化)です。

制御工学では、この式をラプラス変換して C(s) = Kp + Ki/s + Kd·s という伝達関数で書きます。s を掛けると微分、s で割ると積分という読み方で十分に追えます。ラプラス変換そのものは、同時期に公開する記事「ラプラス変換とは|変換表・逆変換・微分方程式の解き方をSymPyで検算」で扱います。

並列形と標準形

書き方 式 設定する値
並列形 Kp + Ki/s + Kd·s Kp・Ki・Kd
標準形(理想形) Kp·(1 + 1/(Ti·s) + Td·s) Kp・積分時間 Ti・微分時間 Td
換算 Ki = Kp/Ti、Kd = Kp·Td Ti を大きくすると I は弱くなる

積分時間 Ti は大きいほど I が弱く、微分時間 Td は大きいほど D が強くなります。 並列形の Ki と向きが逆なので、温度調節計の説明書と Python のコードを行き来するときに取り違えやすい点です。ジーグラー・ニコルス法の表も標準形(Kp・Ti・Td)で書かれています。

比例帯(PB)

温度調節計では、Kp の代わりに比例帯(Proportional Band)を設定することが多くあります。理化工業の技術解説では PB = 100/Kp(%)としています。比例帯を狭くすると Kp が大きくなり、広くすると小さくなります。たとえば Kp = 2 は比例帯 50%、Kp = 5 は比例帯 20% です。

P制御と定常偏差(オフセット):Pだけでは目標に届かない理由

この節では、P だけの制御でずれが残る理由と、その大きさを数値で確かめた結果が分かります。

P だけの制御は、偏差が0になると操作量も0になります。 ヒーターなら、目標温度に届いた瞬間に出力が0になって冷め始めるので、出力と熱の逃げがつり合う「少し手前」で止まります。これが定常偏差(オフセット、残留偏差)です。

一次遅れの制御対象 1/(5s+1)(時定数5秒)に、目標値 1.0 を与えて30秒計算しました。理論では、ゲイン1の対象に P 制御をかけると、最終値は Kp/(1+Kp)、定常偏差は 1/(1+Kp) です。

Kp 最終値 定常偏差(計算) 理論 1/(1+Kp) 立ち上がり時間
1 0.5000 0.5000 0.5000 5.49秒
2 0.6667 0.3333 0.3333 3.65秒
5 0.8333 0.1667 0.1667 1.82秒
10 0.9091 0.0909 0.0909 0.99秒

立ち上がり時間は、最終値の10%から90%になるまでの時間です。Kp を10にしても目標の9.1%が足りず、Kp を上げるほど速くはなりますが、ずれは0になりませんでした。 計算の値は理論値と小数第4位まで一致しています。

Kp を上げると振動する(三次遅れの対象)

一次遅れの対象は、Kp をいくら上げても振動しません。実際の装置には、ヒーター→金属板→センサーのように遅れが重なるため、一次遅れが3つつながった 1/(s+1)^3 でも計算しました(60秒)。

Kp 最終値 行き過ぎ量 立ち上がり時間 整定時間(±2%)
0.5 0.333 5.3% 2.49秒 7.16秒
1 0.500 14.0% 1.87秒 8.43秒
2 0.667 30.1% 1.35秒 10.09秒
4 0.800 54.7% 0.97秒 18.94秒
6 0.854 73.7% 0.79秒 42.83秒
8.1 発散 — — —

行き過ぎ量と整定時間は、最終値を基準にしています。定常偏差を小さくしようと Kp を上げると、行き過ぎと振動が増え、ある値を超えると振動が大きくなり続けます(発散)。 P だけでは「ずれを消す」と「振動させない」を両立できないため、I と D を足します。

P・PI・PIDの応答比較(時間ごとの値の表)

この節では、同じ Kp で P・PI・PID を比べたとき、目標値への近づき方がどう違うのかが、時間ごとの値で分かります。

制御対象 1/(s+1)^3、目標値 1.0、Kp = 2.5 をそろえ、PI は Ki = 1.0、PID はさらに Kd = 2.0 を足しました。 微分には不完全微分(N = 10)を使っています(後の節で説明します)。

0.286P の定常偏差最終値 0.714 で止まった
44.7%PI の行き過ぎ量偏差は0になるが揺れる
9.01秒PID の整定時間PI の 21.02秒の半分以下
時刻(秒) P(Kp=2.5) PI(+Ki=1.0) PID(+Kd=2.0)
00.0000.0000.000
10.1970.2200.208
1.50.4510.5340.476
20.7090.8960.748
2.50.8971.2100.956
30.9761.4021.080
3.50.9531.4431.134
40.8631.3501.144
50.6590.9691.116
60.6050.7151.085
80.7541.0251.037
100.7151.1051.010
120.7020.8991.001
150.7171.0590.999
200.7151.0141.000
300.7140.9961.000
制御 立ち上がり時間 行き過ぎ量 整定時間(±2%) 定常偏差
P 1.21秒 37.1%(最終値 0.714 基準) 11.86秒 0.286
PI 1.28秒 44.7% 21.02秒 0.000
PID 1.61秒 14.4% 9.01秒 0.000
  • P:3秒で 0.976 まで上がったあと、0.714 に落ち着きました。目標の 1.0 には届きません。
  • PI:I がずれをためて押し上げるので、最終値は 1.000 になりました。その代わり 3.5秒で 1.443 まで行き過ぎ、10秒・15秒でもまだ 1.105・1.059 と揺れています。
  • PID:D が上がる勢いにブレーキをかけ、最大 1.144 で止まりました。立ち上がりは PI より 0.33秒遅いものの、12秒の時点で 1.001 に落ち着いています。

偏差の絶対値を時間で足した IAE(小さいほどよい)は、PI が 3.499、PID が 2.089 でした。P は偏差が残り続けるため、IAE は計算する時間に比例して大きくなります。

外乱が入ったとき(目標値の変更と外乱の2つの場面)

理化工業の技術解説は、一般的な制御の大部分は「目標値の変更」と「外乱(坂道など)」への対応だと説明しています。ここまでは目標値の変更を見てきたので、外乱を確かめます。30秒の時点で、操作量に −0.3 の外乱(窓を開けて熱が逃げ始めた、上り坂に入った)を加え、80秒まで計算しました。

制御 外乱の前 最も下がった値 80秒の値 元の±0.02に戻るまで
P(Kp=2.5) 0.714 0.597 0.629 戻らない
PI(2.5 / 1.0) 0.996 0.897 1.000 9.23秒
PID(2.5 / 1.0 / 2.0) 1.000 0.921 1.000 6.09秒

P は外乱のぶんだけ新しいずれが加わり、0.629 で止まりました。 理論値 (2.5 − 0.3)/(1 + 2.5) = 0.6286 と一致します。PI と PID は I が外乱を打ち消して 1.000 に戻り、D のある PID は落ち込みが浅く(0.921)、戻りも速くなりました。上り坂でも速度が落ちたままにならないのは、I の働きです。

ゲインを変えると応答はどう変わるか(Kp・Ki・Kdの比較)

この節では、Ki と Kd を1つずつ変えたときの応答の数値と、「ゲインは大きいほどよい」とは言えない理由が分かります。

Ki を変える(PI、Kp = 1.5)

Ki 立ち上がり時間 行き過ぎ量 整定時間(±2%) IAE
0.213.91秒0.0%32.00秒4.980
0.42.10秒5.0%15.03秒2.607
0.61.84秒20.0%12.08秒2.567
1.01.56秒46.7%20.05秒3.987
1.51.39秒69.7%60秒で落ち着かない11.061

Ki が小さすぎると、ずれがなかなか消えず(0.2 で整定まで 32.00秒)、大きすぎると振動します(1.5 では120秒計算して整定 71.69秒・行き過ぎ 75.1%)。 IAE が最も小さかったのは 0.4〜0.6 の間でした。

Kd を変える(PID、Kp = 2.5・Ki = 1.0)

Kd 立ち上がり時間 行き過ぎ量 整定時間(±2%) IAE
0(PI)1.28秒44.7%21.02秒3.499
11.42秒26.6%7.53秒2.095
21.61秒14.4%9.01秒2.089
31.91秒13.7%10.93秒2.331
42.40秒15.3%12.33秒2.670

Kd を 0→2 にすると行き過ぎが 44.7%→14.4% に減りました。Kd を 4 まで上げると、立ち上がりが 2.40秒に遅れ、行き過ぎも 15.3% に戻りました。 D は「足すほどよい」ものではなく、効かせすぎると動きが鈍くなります。

操作量の上限を考えないと、ゲインはいくらでも上がる

Kp・Ki・Kd を総当たりで変え、「行き過ぎ 5% 以下・定常偏差 0」のうち IAE が最小の組を探しました。

探した範囲 見つかった Kp / Ki / Kd 行き過ぎ・整定時間 操作量の最大
Kp 1〜5、Kd 0〜4 5.0 / 0.8 / 3.75 0.9%・4.45秒(IAE 1.290) 5.05
Kp 2〜10、Kd 1〜8 10.0 / 1.0 / 7.0 4.1%・5.36秒(IAE 1.098) 10.03

どちらも探した範囲の端(いちばん大きい Kp)が選ばれ、操作量の最大は 5.05 から 10.03 に増えました。 目標を保つのに要る操作量は 1.0 なので、10倍の力を出せる装置が前提です。計算の上では操作量に上限が無いため、ゲインを上げるほど成績がよくなります。実際の装置には出力の上限・ノイズ・モデルの誤差があり、ゲインを決めるのはそれらです。上限があると何が起きるかは、積分ワインドアップの節で確かめます。

オンオフ制御との違い(ハンチングを数値で)

この節では、PID制御とよく比べられるオンオフ制御で、どれくらい揺れが残るのかが分かります。

オンオフ制御は、目標より低ければ全開、高ければ停止の2択です。 仕組みは簡単ですが、遅れのある対象では目標の上下を行ったり来たりする揺れ(ハンチング)が止まりません。同じ 1/(s+1)^3 で、全開時の出力 2.0、切り替えのすきま(ヒステリシス)を変えて計算し、30〜60秒の値を見ました。

制御 30〜60秒の範囲 振れ幅 切り替え回数(30秒)
オンオフ(すきま 0) 0.833〜1.167 0.334 16回
オンオフ(すきま ±0.02) 0.804〜1.196 0.393 15回
オンオフ(すきま ±0.1) 0.713〜1.287 0.574 12回
PID(2.5 / 1.0 / 2.0) 1.000 0.000 —(連続で変化)

オンオフ制御は、すきまを0にしても ±0.17 ほどの揺れが残りました。 すきまを広げると切り替え回数(リレーやコンプレッサーの負担)は減りますが、揺れは大きくなります。全開の出力を 1.2 に下げると、30〜60秒の平均が 0.939(すきま 0)と目標より低くなりました。PID制御は操作量を連続で変えられるため、揺れも定常偏差も残りません。

温度を一定に保ちたい

オンオフ目標を越えたら止め、下回ったら全開。揺れが残り、切り替えのたびに装置に負担がかかる
→
PID偏差に応じて出力を連続で変える。目標に近づくと出力を絞り、ずれが残れば足す

オンオフ制御で済むのは、多少の揺れが問題にならない用途(冷蔵庫・電気ポットの保温など)

積分ワインドアップとは(再現と対策)

この節では、積分ワインドアップがどんな条件で起き、対策でどれだけ変わるのかが、時間ごとの値で分かります。

積分ワインドアップは、操作量が上限に張りついて偏差が減らない間も I が偏差をため続け、偏差が消えたあとも操作量が下がらず、大きく行き過ぎる現象です。 実際の装置には出力の上限(ヒーターは100%まで、モーターは最大電圧まで)があるので、計算でも上限を付けて確かめます。

flowchart TD
    A[操作量が上限に張りつく] --> B{偏差が残る}
    B -->|対策なし| C[積分項がたまり続ける]
    C --> D[偏差が消えても<br>上限のまま]
    D --> E[大きな行き過ぎ]
    B -->|対策あり| F[積分を止める・戻す]
    F --> G[すぐ目標値に落ち着く]

再現:窓が開いている20秒間

制御対象 1/(s+1)^3、PID(2.5 / 1.0 / 2.0)、操作量は 0〜1.2 に制限します。最初の20秒は −0.5 の外乱(窓が開いて熱が逃げ続ける)があり、出力を上限の 1.2 にしても目標 1.0 に届かず 0.7 止まりです。20秒で窓を閉めます。

時刻(秒) 対策なし y(積分項) 積分の停止 y(積分項) バックカリキュレーション y(積分項)
100.698(5.10)0.698(0.45)0.698(0.75)
20 直前0.700(8.10)0.700(0.45)0.700(0.75)
220.862(8.60)0.852(0.87)0.861(1.00)
230.988(8.67)0.939(0.97)0.968(1.08)
241.081(8.63)0.979(1.01)1.014(1.08)
251.138(8.52)0.995(1.02)1.021(1.07)
271.185(8.19)1.005(1.02)1.015(1.03)
301.199(7.60)1.002(1.00)1.003(1.00)
401.200(5.60)1.000(1.00)1.000(1.00)
501.200(3.60)1.000(1.00)1.000(1.00)

対策なしでは、20秒の時点で積分項が 8.10 までたまっていました。 目標を保つのに要る操作量は 1.0 なので、8倍以上ためこんだことになります。窓を閉めたあとも、たまった分を吐き出すまで操作量は上限の 1.2 のままで、y は 1.200 に張りついたまま50秒を過ぎました。

方式 20秒以降の最大 行き過ぎ量 ±2%に戻るまで
対策なし 1.200 20.0% 45.39秒
積分の停止(クランプ) 1.005 0.5% 4.03秒
バックカリキュレーション(Kb=1) 1.021 2.1% 5.58秒
速度形(変化分を足す) 1.006 0.6% 3.79秒

ワインドアップ対策の方法

  • 積分の停止(条件付き積分・クランプ):出力が飽和していて、偏差が飽和をさらに深める向きのときは積分しない。実装が最も簡単で、手元では行き過ぎが最も小さくなりました。
  • バックカリキュレーション:飽和した分(制限後の出力 − 制限前の出力)に係数 Kb を掛けて積分に戻し、積分項を引き戻す。Kb で戻す速さを調整できます。
  • 速度形:毎回「操作量の変化分」を計算して足し、足した結果を上限で切る。たまる場所が無いので、ワインドアップが起きにくい形です。

窓の場面ではなく、目標値を 0→1 に変えただけでも、上限 1.2 なら差が出ました。対策なしは行き過ぎ 19.6%・整定 15.40秒、積分の停止は 1.2%・5.80秒、バックカリキュレーションは 2.5%・8.60秒です(上限なしの同じ PID は 14.4%・9.01秒)。上限がある装置では、上限なしで調整したゲインのままだと応答が変わります。

微分のノイズと微分キック(不完全微分・PI-D・I-PD)

この節では、D を使うときに起きる2つの問題(ノイズの増幅と、目標値を変えた瞬間の跳ね)と、その対策の効果が分かります。

測定ノイズを D が増やす

測定値に標準偏差 0.01 のノイズ(センサーの読みのばらつき)を足し、20〜40秒の操作量のばらつきを比べました。PID は 2.5 / 1.0 / 2.0、刻みは 0.01秒です。

微分の取り方 操作量の標準偏差 操作量の最大 行き過ぎ量
D なし(PI) 0.0289 2.99 44.9%
D そのまま(フィルターなし) 2.8555 11.02 15.9%
不完全微分 N = 10 0.2530 3.37 14.4%
不完全微分 N = 5 0.1441 3.09 13.2%

D をそのまま計算すると、操作量のばらつきは PI の約99倍(0.0289→2.8555)になりました。 0.01 の読みのぶれを 0.01秒で割るため、Kd = 2 では、D 項だけで標準偏差 2.9 前後の指令が毎回出ます。不完全微分は、微分に一次遅れのフィルター(時定数 Td/N)を掛けて、速すぎる変化を通さない方法です。N = 10 で約11分の1、N = 5 で約20分の1に下がり、応答(行き過ぎ量)はほぼ変わりませんでした。

目標値を変えた瞬間の微分キック

1秒の時点で目標値を 0→1 に変えたとき、その瞬間の操作量です。

方式 変えた瞬間の操作量 行き過ぎ量 整定時間(±2%)
D を偏差で取る・フィルターなし 202.50 2.4% 3.20秒
D を偏差で取る・N = 10 24.72 3.9% 3.15秒
D を測定値で取る(PI-D) 2.50 14.4% 9.01秒
P も D も測定値で取る(I-PD) 0.00 0.7% 7.51秒

偏差で微分すると、目標値が1刻みで 1.0 跳ねるため、D 項は Kd × 1.0 / 0.01 = 200 になりました。 刻みを 0.001秒にすると 2002.50(D 項 2000)になりました。表の上2行は行き過ぎが小さく見えますが、操作量に上限が無い計算だからで、実際の装置では上限で切られ、モーターや弁に衝撃を与えます。

  • PI-D(微分先行形):D を測定値 y の変化で取る。目標値の段差では跳ねず、外乱への応答は元の PID と同じ。
  • I-PD(比例・微分先行形):P も測定値で取る。目標値を変えても操作量は I からゆっくり立ち上がり、行き過ぎは 0.7% になった。その代わり立ち上がり時間は 4.23秒と遅い。

目標値への追従と外乱への強さを別々に調整できる、こうした形を2自由度 PID と呼びます。

ジーグラー・ニコルス法でゲインを求めて検証する(限界感度法・ステップ応答法)

この節では、ジーグラー・ニコルス法の手順と、求めたゲインを実際に入れたときの応答の数値が分かります。

ジーグラー・ニコルス法は、1942年に J. G. Ziegler と N. B. Nichols が発表した、実験でゲインを決める方法です。 限界感度法とステップ応答法の2つがあり、どちらも「最初の目安」を出す方法です。

flowchart TD
    S[開始:P だけ] --> K[Kp を少しずつ上げる]
    K --> Q{一定の振れ幅で<br>振動し続ける?}
    Q -->|いいえ| K
    Q -->|はい| M[Ku と周期 Pu を記録]
    M --> T[表で Kp・Ti・Td を計算]
    T --> F[行き過ぎを見て<br>Kp を下げ Td を調整]

限界感度法:Ku と Pu を求める

P だけで Kp を上げ、振れ幅が増えも減りもしない Kp(限界ゲイン Ku)と、そのときの振動の周期 Pu を求めます。1/(s+1)^3 なら手計算でも求まり、閉ループの特性方程式 s³ + 3s² + 3s + 1 + Kp = 0 に Kp = 8 を入れると、NumPy の np.roots で根は次のようになりました。

閉ループの極 Kp=8: [-3.00000000e+00+0.j  -8.32667268e-17+1.73205081j  -8.32667268e-17-1.73205081j]

実部がほぼ0の根 ±1.732j(= √3)があるので、Ku = 8、周期は 2π/√3 = 3.628 秒です。次に、計算機の上で人が行う手順(Kp を変えて振れ幅を見る)を二分法でまねて、0.01秒刻みのシミュレーションから Ku と Pu を求めました。

求め方 Ku Pu
理論(連続時間) 8 3.628秒
シミュレーション(刻み 0.001秒) 7.988 —
シミュレーション(刻み 0.01秒) 7.882 3.652秒
シミュレーション(刻み 0.1秒) 6.985 —
シミュレーション(刻み 0.3秒) 5.671 —

計算の刻み(サンプリング周期)が粗いほど、限界ゲインは下がりました。 0.3秒刻みでは理論の約7割です。マイコンで制御するときは、制御周期そのものが遅れになり、振動しやすくなります。以下は 0.01秒刻みで求めた Ku = 7.8822、Pu = 3.652秒を使います。

限界感度法の表と、入れてみた結果

係数は Wikipedia 英語版「Ziegler–Nichols method」の表です。古典的な ZN 以外に、行き過ぎを抑える変形も載っているので、すべて計算しました(80秒)。

規則 Kp / Ti / Td 行き過ぎ量 整定時間(±2%) IAE
P(0.5Ku) 3.941 / — / — 54.1% 17.14秒 定常偏差 0.202
PI(0.45Ku・Pu/1.2) 3.547 / 3.043 / — 55.5% 30.84秒 4.785
PID 古典(0.6Ku・0.5Pu・0.125Pu) 4.729 / 1.826 / 0.457 51.9% 9.70秒 2.205
Pessen(0.7Ku・0.4Pu・0.15Pu) 5.518 / 1.461 / 0.548 57.8% 8.67秒 2.098
some overshoot(Ku/3・0.5Pu・Pu/3) 2.627 / 1.826 / 1.217 22.0% 12.78秒 2.496
no overshoot(0.2Ku・0.5Pu・Pu/3) 1.576 / 1.826 / 1.217 19.0% 10.34秒 2.840
  • 古典的な ZN の PID は、行き過ぎ 51.9% と大きくなりました。 1つ目の山(2.64秒・+0.519)と2つ目の山(6.97秒・+0.072)の比は 0.138 です。ZN 法は「1/4 減衰」(次の山が前の山の約1/4)をねらった方法と説明されることが多く、行き過ぎの小ささより速さを優先した値です。
  • 「no overshoot」という名前の規則でも、この対象では 19.0% 行き過ぎました。 名前どおりになるとは限らず、規則で出した値は出発点として扱います。
  • PI は整定に 30.84秒かかり、同じ表の PID(9.70秒)より大幅に遅くなりました。遅れの重なった対象では、D が効きます。

ステップ応答法(過渡応答法)

制御器を付けずに操作量を 1 にしたときの応答(開ループのステップ応答)から、変曲点の接線を引いて、むだ時間 L と傾き R を読み取ります。1/(s+1)^3 のステップ応答は次のとおりでした。

時刻(秒) 出力 時刻(秒) 出力
0.50.014440.7619
10.080350.8753
2(変曲点)0.323360.9380
30.5768100.9972

変曲点は t = 2.00秒、最大の傾き R = 0.2707、接線から読んだむだ時間 L = 0.805秒、時定数 T = 3.695秒です。ZN のステップ応答法の係数(P は Kp = 1/(R·L)、PI は 0.9/(R·L)・Ti = L/0.3(約3.3L)、PID は 1.2/(R·L)・Ti = 2L・Td = 0.5L)で計算しました。

制御 Kp / Ti / Td 行き過ぎ量 整定時間(±2%)
P 4.587 / — / — 60.6% 22.61秒(定常偏差 0.179)
PI 4.128 / 2.685 / — 69.1% 60.27秒
PID 5.504 / 1.611 / 0.403 65.2% 13.28秒

ステップ応答法は、限界感度法より強めの値になり、行き過ぎは PID で 65.2% でした。 ステップ応答法は、制御対象を「むだ時間+一次遅れ」とみなして近似するため、その近似がずれると値もずれます。どちらの方法も、出た値から Kp を下げ、Td を上げる方向に詰めるのが基本です。

Wikipedia(日本語版)は、ほかに CHR 法(Chien・Hrones・Reswick、1952年)を挙げています。目標値追従と外乱抑制、行き過ぎ 0% と 20% の組み合わせで係数が分かれる方法です。むだ時間が長い対象には、スミス補償などの別の方法が使われます。

PID制御のプログラム(PythonとCの離散PID)

この節では、マイコンやパソコンで動かす離散 PID の書き方と、Python と C で同じ結果になることの確かめ方が分かります。

コンピューターは一定の周期 dt ごとに計算するので、積分は「偏差 × dt を足していく」、微分は「前回との差 ÷ dt」に置き換えます。 操作量そのものを毎回計算する形を位置形、変化分を足していく形を速度形(増分形)と呼びます。次の Python のクラスは位置形に、ここまでの対策(不完全微分・測定値の微分・積分の停止)を入れたものです。

class PID:
    """位置形の離散PID(不完全微分・測定値微分・積分の停止つき)"""
    def __init__(self, kp, ki, kd, dt, umin, umax, n=10.0):
        self.kp, self.ki, self.kd, self.dt = kp, ki, kd, dt
        self.umin, self.umax = umin, umax
        self.tf = (kd / kp) / n if kp > 0 and kd > 0 else 0.0  # 微分のフィルター時定数
        self.i = 0.0       # 積分項
        self.d = 0.0       # フィルター後の微分項
        self.y_prev = None

    def update(self, r, y):
        e = r - y
        if self.y_prev is None:
            self.y_prev = y
        a = self.tf / (self.tf + self.dt)
        # 微分は測定値で取る(目標値が変わっても跳ねない)
        self.d = a * self.d - (1 - a) * self.kd * (y - self.y_prev) / self.dt
        self.y_prev = y
        v = self.kp * e + self.i + self.d
        u = min(max(v, self.umin), self.umax)
        # 飽和していて、積分がさらに飽和を深める向きなら積分を止める
        if v == u or (e > 0) != (v > u):
            self.i += self.ki * e * self.dt
        return u


def plant_step(x, u, dt):
    """1/(s+1)^3 を一次遅れ3段でオイラー法"""
    x[0] += dt * (u - x[0])
    x[1] += dt * (x[0] - x[1])
    x[2] += dt * (x[1] - x[2])
    return x[2]


if __name__ == "__main__":
    dt = 0.01
    pid = PID(2.5, 1.0, 2.0, dt, 0.0, 1.2)
    x = [0.0, 0.0, 0.0]
    y = 0.0
    for k in range(int(20 / dt) + 1):
        u = pid.update(1.0, y)
        if k % 200 == 0:
            print(f"t={k*dt:5.2f} y={y:.6f} u={u:.6f}")
        y = plant_step(x, u, dt)

同じ処理を C で書いたものです。構造体に状態を持たせ、pid_update を制御周期ごとに呼びます。

#include <stdio.h>

typedef struct {
    double kp, ki, kd, dt, umin, umax, tf;
    double i, d, y_prev;
    int first;
} PID;

void pid_init(PID *p, double kp, double ki, double kd, double dt,
              double umin, double umax, double n) {
    p->kp = kp; p->ki = ki; p->kd = kd; p->dt = dt;
    p->umin = umin; p->umax = umax;
    p->tf = (kp > 0 && kd > 0) ? (kd / kp) / n : 0.0;
    p->i = 0.0; p->d = 0.0; p->y_prev = 0.0; p->first = 1;
}

double pid_update(PID *p, double r, double y) {
    double e = r - y;
    if (p->first) { p->y_prev = y; p->first = 0; }
    double a = p->tf / (p->tf + p->dt);
    p->d = a * p->d - (1 - a) * p->kd * (y - p->y_prev) / p->dt;
    p->y_prev = y;
    double v = p->kp * e + p->i + p->d;
    double u = v < p->umin ? p->umin : (v > p->umax ? p->umax : v);
    if (v == u || ((e > 0) != (v > u)))
        p->i += p->ki * e * p->dt;
    return u;
}

int main(void) {
    const double dt = 0.01;
    PID pid;
    pid_init(&pid, 2.5, 1.0, 2.0, dt, 0.0, 1.2, 10.0);
    double x[3] = {0, 0, 0}, y = 0.0;
    for (int k = 0; k <= (int)(20 / dt); k++) {
        double u = pid_update(&pid, 1.0, y);
        if (k % 200 == 0) printf("t=%5.2f y=%.6f u=%.6f\n", k * dt, y, u);
        x[0] += dt * (u - x[0]);
        x[1] += dt * (x[0] - x[1]);
        x[2] += dt * (x[1] - x[2]);
        y = x[2];
    }
    return 0;
}

gcc -O2 -Wall -Wextra -o pid pid.c は警告なしで通りました。2つの出力を並べ、diff で比べた結果です。

$ python3 pid.py > py.out; ./pid > c.out; diff py.out c.out && echo SAME
SAME
$ cat c.out
t= 0.00 y=0.000000 u=1.200000
t= 2.00 y=0.394336 u=1.112234
t= 4.00 y=0.859486 u=1.013078
t= 6.00 y=0.986697 u=1.018456
t= 8.00 y=1.011862 u=1.003941
t=10.00 y=1.008610 u=1.000843
t=12.00 y=1.003515 u=0.999823
t=14.00 y=1.000941 u=0.999809
t=16.00 y=1.000092 u=0.999907
t=18.00 y=0.999931 u=0.999971
t=20.00 y=0.999947 u=0.999995

Python と C の出力は、小数第6位まで11行すべて一致しました。 最初の 0秒で操作量が上限の 1.2 に張りつき、積分が止まっているので、行き過ぎは最大でも 1.0121(8.33秒)に収まりました。Python で調整して C に移すときは、このように同じ制御対象・同じ刻みで出力を突き合わせると、移植の誤りに気づけます。

位置形と速度形

速度形は Δu = Kp·(e[k] − e[k−1]) + Ki·dt·e[k−1] + Kd·(e[k] − 2e[k−1] + e[k−2])/dt を前回の u に足します。上限が無い条件で位置形と速度形の y を比べると、差の最大は 4.4e-16 で、浮動小数点の丸め誤差の範囲で同じでした。上限がある窓の場面では、前の節の表のとおり速度形のほうが行き過ぎが小さくなります。浮動小数点の丸めの考え方は、関連記事「浮動小数点の落とし穴8選|0.1+0.2・丸め・金額計算」で扱っています。

制御周期(サンプリング周期)の影響

同じ PID(2.5 / 1.0 / 2.0)のまま、制御周期だけを変えました。制御対象の計算は零次ホールドで正確に離散化しています。

制御周期 行き過ぎ量 整定時間(±2%) IAE
0.01秒14.4%9.01秒2.089
0.05秒14.6%9.05秒2.112
0.1秒15.0%9.10秒2.143
0.2秒16.2%9.20秒2.212
0.3秒18.0%9.30秒2.285
0.5秒24.2%9.00秒2.483

制御周期が 0.5秒になると、行き過ぎが 14.4%→24.2% に増えました。 この対象の時定数は1秒です。制御周期は、対象の速さ(時定数や振動の周期)より十分に短くする必要があり、周期を変えたらゲインも見直します。NumPy の配列の扱いは関連記事「NumPyの使い方 基本一覧|配列の作成・演算・形状変更」で扱っています。

PIDゲインの調整手順(シミュレーションから実機へ)

この節では、ここまでの結果をもとにした、ゲイン調整の進め方が分かります。

1

操作量の上限・下限と制御周期を決める

ヒーターの最大出力、モーターの最大電圧、マイコンの計算周期を先に決める。上限があるならワインドアップ対策を最初から入れる。

上限 1.2 で行き過ぎ 14.4%→19.6% に変わった

2

開ループのステップ応答を取る

制御器を外し、操作量を一定量だけ変えて出力の時間変化を記録する。むだ時間・時定数・ゲインが分かり、モデルも作れる。

安全な範囲の小さな変化で

3

ジーグラー・ニコルス法で出発点を決める

限界感度法かステップ応答法でゲインを出す。持続振動させられない装置ならステップ応答法を使う。

ZN の PID は行き過ぎ 51.9%

4

Kp を下げ、Td(Kd)で行き過ぎを抑える

行き過ぎが大きければ Kp を下げ、Kd を少しずつ上げる。Kd は上げすぎると遅くなるので、行き過ぎ量と立ち上がり時間を見ながら止める。

Kd 0→2 で 44.7%→14.4%

5

Ki(Ti)で定常偏差の消え方を合わせる

ずれの消え方が遅ければ Ki を上げ(Ti を下げ)、揺れるなら下げる。

Ki 0.4〜0.6 で IAE が最小

6

外乱とノイズで確かめる

目標値の変更だけでなく、外乱を入れたときの戻り方と、ノイズを入れたときの操作量のばらつきを見る。D のフィルター N を決める。

N=10 で操作量のばらつき約11分の1

温度調節計などの製品には、オートチューニング(AT)の機能が付いているものが多くあります。リレーで意図的に振動させて Ku と Pu を測る方式が知られていますが、各製品の具体的な方式は、その製品の取扱説明書で確かめます。

実機に入れる前のチェック

  • 1偏差の符号が正しいか冷房は「温度が高いほど出力を上げる」。符号が逆だと正のフィードバックになり、出力が上限に張りつく
  • 2操作量に上限・下限があり、ワインドアップ対策があるか窓の場面で、対策なしは ±2% に戻るまで 45.39秒、対策ありは 4.03秒
  • 3D にフィルターがあり、測定値で微分しているかフィルターなしでは目標値を変えた瞬間に操作量 202.50
  • 4制御周期がシミュレーションと同じか0.01秒→0.5秒で行き過ぎが 14.4%→24.2%
  • 5手動と自動の切り替えで操作量が跳ねないか切り替えの瞬間に積分項を今の操作量に合わせる(バンプレス切り替え)

よくあるつまずきとエラー(原文つき)と判断表

この節では、PID制御をシミュレーションや実装で試すときによく出る症状と原因、P・PI・PID のどれを選ぶかの目安が分かります。

症状・エラー原文 原因 直し方
目標の少し手前で止まる P だけ(定常偏差) I を足す
目標の上下をずっと揺れる Kp・Ki が大きすぎる、またはオンオフ制御 Kp・Ki を下げる、D を足す
出力が上限のまま下がらず、大きく行き過ぎる 積分ワインドアップ 積分の停止・バックカリキュレーション・速度形
操作量がガタガタ動く D がノイズを拾っている 不完全微分(N=5〜10)、センサーのフィルター
目標値を変えた瞬間に操作量が跳ねる 偏差で微分している(微分キック) 測定値で微分する(PI-D)
RuntimeWarning: invalid value encountered in matmul のあと y が nan ゲインが大きすぎて発散(Kp=20 で300秒後に約2e47) Kp を限界ゲインより下げる
ValueError: Improper transfer function. `num` is longer than `den`. SciPy の伝達関数で分子の次数が分母より高い(理想微分 Kd·s を単独で入れた) 不完全微分 Kd·s/(Tf·s+1) にする
ZeroDivisionError: float division by zero 刻み dt を0にした(微分で割る) 制御周期を正しく渡す
ModuleNotFoundError: No module named 'scipy' venv に SciPy を入れていない venv を有効にして pip install numpy scipy

venv の作り方は関連記事「Python venvの使い方|仮想環境の作成・有効化・削除をOS別にコピペ」で扱っています。

P・PI・PD・PID のどれを選ぶか(判断表)

状況 向く方式 理由
多少の揺れでよい・装置を安くしたい オンオフ センサーとスイッチだけで作れる
少しのずれが残ってよい・単純にしたい P 調整する値が1つ
温度・流量など、変化が遅くノイズがある PI 定常偏差を消し、D のノイズ問題を避けられる
位置決め(後段に積分の性質がある) PD 対象が積分の性質を持てば P でも偏差が残りにくい
遅れが重なり、速く落ち着かせたい PID 手元で整定時間が PI の 21.02秒→9.01秒
目標値を頻繁に変える PI-D・I-PD 微分キック・P の跳ねを避けられる
むだ時間が時定数より長い PID 以外も検討 スミス補償・モデル予測制御など

よくある質問

Q. PID制御とは何ですか?わかりやすく教えてください。 A. 目標値と今の値のずれ(偏差)を、今の大きさ(P)・これまでの合計(I)・変化の速さ(D)の3つで見て、操作量を決める制御です。車の運転なら、速度が足りないぶん踏み込む(P)、上り坂で足りない状態が続けばさらに踏む(I)、目標速度に急に近づいたらゆるめる(D)、という動きです。

Q. P・I・D の役割を一言でいうと? A. P は「速く近づける」、I は「最後のずれを消す」、D は「行き過ぎを抑える」です。

Q. P制御だけでは使えないのですか? A. 用途によっては使えますが、定常偏差が残ります。一次遅れの対象で Kp = 10 にしても、目標の9.1%が足りませんでした。ずれを0にしたいなら I を足します。

Q. PI 制御と PID 制御はどちらがよいですか? A. 温度のように変化が遅く、センサーにノイズがある対象では PI が多く使われます。遅れが重なる対象で速く落ち着かせたいなら PID です。手元の三次遅れの対象では、PI の整定時間 21.02秒が PID で 9.01秒になりました。

Q. ゲインの決め方(調整方法)は? A. ジーグラー・ニコルス法(限界感度法・ステップ応答法)で出発点を決め、行き過ぎを見ながら Kp を下げ Kd を足す方法が基本です。シミュレーションできるなら、モデルを作って計算で詰めてから実機で確かめます。

Q. 積分ワインドアップとは何ですか? A. 操作量が上限に張りついている間に積分項がたまり続け、偏差が消えても操作量が下がらずに大きく行き過ぎる現象です。手元の例では、積分項が必要量の8倍以上の 8.10 までたまり、行き過ぎ 20.0% が45秒以上続きました。積分の停止で 0.5% になりました。

Q. 微分制御(D)を入れると不安定になるのはなぜですか? A. D は変化の速さを見るため、センサーのノイズを大きくしてしまうからです。標準偏差 0.01 のノイズで、フィルターなしの D は操作量のばらつきを PI の約99倍にしました。不完全微分と測定値での微分で抑えます。

Q. 比例帯とは何ですか? A. 温度調節計で使われる、P の強さの表し方です。PB = 100/Kp(%)で、比例帯が狭いほど P が強くなります。

Q. 積分時間・微分時間とは何ですか? A. 標準形 Kp·(1 + 1/(Ti·s) + Td·s) の Ti と Td です。Ti は大きいほど I が弱く、Td は大きいほど D が強くなります。並列形の Ki・Kd とは Ki = Kp/Ti、Kd = Kp·Td の関係です。

Q. PID制御をプログラムで書くには? A. 一定周期で「偏差を計算→積分に偏差×dt を足す→微分は前回との差÷dt→3つを足して上限で切る」を繰り返します。この記事の Python と C のコードは、同じ入力で出力が小数第6位まで一致しました。

Q. PID制御にラプラス変換の知識は要りますか? A. 動かして調整するだけなら、時間の式と離散化したコードで進められます。安定性を式で調べる、周波数特性を見る、といった段階で伝達関数とラプラス変換が要ります。

まとめ

  • PID制御は、偏差の比例(P・今)・積分(I・過去)・微分(D・未来)の和で操作量を決めるフィードバック制御。
  • P だけでは定常偏差が残る(一次遅れで Kp=10 でも 0.0909)。同じ Kp=2.5 で、P・PI・PID の行き過ぎは 37.1%・44.7%・14.4%、整定時間は PID が 9.01秒で最も短かった。
  • 出力に上限があると積分ワインドアップが起きる。窓の場面で行き過ぎ 20.0%・戻るまで 45.39秒が、積分の停止で 0.5%・4.03秒になった。
  • D はノイズに弱く、微分キックも起こす。不完全微分(N=10)でばらつきは約11分の1、測定値で微分すると目標値の変更で跳ねなくなった。
  • ジーグラー・ニコルス法は出発点。Ku=7.882・Pu=3.652秒から求めた PID は行き過ぎ 51.9% で、ここから Kp を下げ Kd を調整する。Python と C の実装は同じ出力になった。

計算結果をグラフにしたいときは関連記事「matplotlibの使い方と日本語文字化け対策|OS別・Colab・3.12対応」で、ステップ応答の記録からモデルの係数を当てはめるときの考え方は関連記事「最小二乗法とは|公式・手計算の例とPythonでの求め方を実例で解説」で扱っています。

参考・出典

確認日はいずれも 2026年10月29日です。

  • Wikipedia「PID制御」:https://ja.wikipedia.org/wiki/PID%E5%88%B6%E5%BE%A1
  • Wikipedia「Ziegler–Nichols method」:https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method
  • Ziegler, J. G., Nichols, N. B.「Optimum Settings for Automatic Controllers」Transactions of the ASME, 64, pp.759–768(1942)
  • 理化工業「PID制御の仕組み」:https://www.rkcinst.co.jp/technical_commentary/658221/
  • 理化工業「PID制御とは」:https://www.rkcinst.co.jp/technical_commentary/13090/
  • SciPy「scipy.signal.cont2discrete」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.cont2discrete.html
  • NumPy「numpy.roots」:https://numpy.org/doc/stable/reference/generated/numpy.roots.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「PID制御とは?わかりやすく|P・I・Dの役割と調整をシミュレーションで検証」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ
参加受付中

AI駆動開発、 無料セミナー