可制御性と可観測性の理論と判定

自動車を運転するとき、アクセルとハンドルで速度と方向を制御できます。しかし、もし車輪がスリップして空転している状態なら、いくらアクセルを踏んでも速度を自由に変えることはできません。つまり、入力(アクセル)から状態(速度)への「到達可能性」が失われています。これが可制御性の問題です。

同様に、カーナビのGPSが壊れたら、速度計だけで現在の正確な位置を知ることはできません。出力(速度)から状態(位置)を推定できなくなっています。これが可観測性の問題です。

制御器を設計する前に、まず「この系は制御可能なのか?」「この系の状態は推定可能なのか?」という根本的な問いに答える必要があります。可制御性(controllability)と可観測性(observability)は、状態空間モデルの最も基本的な構造的性質であり、制御系設計の出発点です。

可制御性と可観測性を理解すると、以下のような応用が開けます。

  • 制御器設計の可否判断: 状態フィードバックで任意の極配置が可能かどうかを事前に判定できる
  • オブザーバ設計の可否判断: 出力から全状態を推定できるかどうかを判定できる
  • システム構造の理解: カルマンの分解定理により、システムを4つの部分空間に分解し、最小実現を求められる
  • 最小実現: 入出力関係を表す最小次数のモデルを構成できる

本記事の内容

  • 可制御性の定義と3つの判定法
  • 可観測性の定義と判定法
  • 可制御性と可観測性の双対性
  • カルマンの標準分解定理
  • PBH判定法(固有値ベース)
  • Pythonでの判定と可視化

前提知識

この記事を読む前に、以下の記事を読んでおくと理解が深まります。

可制御性とは

直感的理解 — 全ての方向に「到達」できるか

可制御性とは、「適切な入力を設計することで、システムの状態を任意の初期点から任意の目標点へ有限時間で移動できるか」を問う概念です。

もう少し具体的なイメージで考えましょう。平面上を移動するロボットを考えます。

  • 前進と左右旋回ができるロボット: 平面上の任意の位置に到達可能 → 可制御
  • 前進しかできないロボット: 直線上にしか動けない → 状態空間全体は不可制御
  • 前進と回転ができるが、速度が制御できないロボット: 位置は自由だが速度は制御できない → 部分的に不可制御

「状態空間の全ての方向に入力の影響が及ぶか」が可制御性の本質です。

数学的定義

連続時間線形時不変系

$$ \dot{\bm{x}} = \bm{A}\bm{x} + \bm{B}\bm{u} $$

が可制御(controllable)であるとは、任意の初期状態 $\bm{x}_0 \in \mathbb{R}^n$ と任意の目標状態 $\bm{x}_f \in \mathbb{R}^n$ に対して、有限時間 $t_f > 0$ と入力 $\bm{u}(t)$($0 \leq t \leq t_f$)が存在して

$$ \bm{x}(0) = \bm{x}_0 \to \bm{x}(t_f) = \bm{x}_f $$

が実現できることを言います。

線形系では $\bm{x}_0 = \bm{0}$ からの到達可能性のみを考えれば十分です。なぜなら、$\bm{x}_0 \neq \bm{0}$ の場合は $\bm{z} = \bm{x} – e^{\bm{A}t}\bm{x}_0$ への座標変換で $\bm{z}(0) = \bm{0}$ に帰着できるからです。

判定法1: 可制御性行列のランク条件

定理(カルマンの可制御性条件): システム $(\bm{A}, \bm{B})$ が可制御であるための必要十分条件は、可制御性行列

$$ \begin{equation} \mathcal{C} = \begin{bmatrix} \bm{B} & \bm{AB} & \bm{A}^2\bm{B} & \cdots & \bm{A}^{n-1}\bm{B} \end{bmatrix} \in \mathbb{R}^{n \times nm} \end{equation} $$

がフルランク($\text{rank}(\mathcal{C}) = n$)であること。

ケーリー・ハミルトンの定理により、$\bm{A}^k$($k \geq n$)は $\bm{I}, \bm{A}, \ldots, \bm{A}^{n-1}$ の線形結合で表せるため、$\bm{A}^k\bm{B}$ は $\mathcal{C}$ の列の線形結合です。したがって、$\bm{A}^{n-1}\bm{B}$ までの列で十分です。

ランク条件の直感

$\bm{B}$ は入力 $\bm{u}$ が直接状態に影響する方向を表します。$\bm{AB}$ は、$\bm{B}$ 方向の入力がシステムダイナミクス $\bm{A}$ によって1ステップ後に伝搬する方向です。$\bm{A}^2\bm{B}$ は2ステップ後の伝搬方向です。

これらの方向ベクトルが集まって $n$ 次元空間全体を張る(ランクが $n$)なら、入力を適切な時系列で印加することで、任意の方向に状態を移動できます。逆に、これらのベクトルが張る空間が $n$ 次元未満なら、入力の影響が及ばない方向が存在し、その方向には制御できません。

判定法2: 可制御性グラム行列

可制御性は可制御性グラム行列でも判定できます。

$$ \begin{equation} \bm{W}_c(t_f) = \int_0^{t_f} e^{\bm{A}\tau}\bm{B}\bm{B}^T e^{\bm{A}^T\tau} \, d\tau \end{equation} $$

定理: $\bm{W}_c(t_f) > 0$(正定値)$\iff$ $(\bm{A}, \bm{B})$ が可制御。

グラム行列は「入力がどれだけ各方向に影響を及ぼせるか」を定量的に表す行列です。$\bm{W}_c$ の固有値が大きい方向は少ないエネルギーで状態を変化させやすく、固有値が小さい方向は多くのエネルギーが必要です。

さらに、初期状態 $\bm{x}_0 = \bm{0}$ から目標状態 $\bm{x}_f$ に移動するための最小エネルギー入力は

$$ \bm{u}^*(t) = \bm{B}^T e^{\bm{A}^T(t_f – t)} \bm{W}_c(t_f)^{-1} \bm{x}_f $$

で与えられ、そのエネルギーは

$$ \int_0^{t_f} \|\bm{u}^*(t)\|^2 dt = \bm{x}_f^T \bm{W}_c(t_f)^{-1} \bm{x}_f $$

です。$\bm{W}_c$ の固有値が小さい方向に移動するほど大きなエネルギーが必要であることが定量的にわかります。

判定法3: PBH判定法

定理(Popov-Belevitch-Hautus; PBH判定): $(\bm{A}, \bm{B})$ が可制御 $\iff$ 全ての $\lambda \in \mathbb{C}$ に対して

$$ \text{rank}[\lambda\bm{I} – \bm{A}, \; \bm{B}] = n $$

等価的に、$\text{rank}[\lambda\bm{I} – \bm{A}, \; \bm{B}] < n$ となる $\lambda$ が存在しないこと。もし $\lambda_0$ でランク落ちするなら、$\lambda_0$ は不可制御固有値です。

PBH条件は各固有値について「その固有モードが入力で励振できるか」を判定します。$\lambda_0$ が $\bm{A}$ の固有値で、対応する左固有ベクトル $\bm{v}^T$($\bm{v}^T\bm{A} = \lambda_0\bm{v}^T$)が $\bm{v}^T\bm{B} = \bm{0}$ を満たすとき、その固有モードは入力と直交しており制御できません。

可制御性の3つの判定法が揃ったところで、次に双対的な概念である可観測性を見ていきます。

可観測性とは

直感的理解 — 出力から全状態がわかるか

可観測性とは、「出力の観測データから、システムの初期状態を一意に特定できるか」を問う概念です。

暗い部屋の中に、ばねで吊られたボールがあるとします。箱の振動を外からセンサで測定できるなら、ボールの動き(位置と速度)を推定できるかもしれません。しかし、もし測定している量がボールの運動と全く関係のない量なら、ボールの状態を知ることは不可能です。

数学的定義

システム

$$ \dot{\bm{x}} = \bm{A}\bm{x}, \quad \bm{y} = \bm{C}\bm{x} $$

が可観測(observable)であるとは、出力 $\bm{y}(t)$($0 \leq t \leq t_f$)の観測から初期状態 $\bm{x}(0)$ を一意に決定できることを言います。

等価的に、$\bm{y}(t) \equiv \bm{0}$($0 \leq t \leq t_f$)ならば $\bm{x}(0) = \bm{0}$ であることが可観測性の定義です。つまり、「ゼロ出力に対応する初期状態はゼロのみ」です。

可観測性行列によるランク判定

定理: システム $(\bm{A}, \bm{C})$ が可観測であるための必要十分条件は、可観測性行列

$$ \begin{equation} \mathcal{O} = \begin{bmatrix} \bm{C} \\ \bm{CA} \\ \bm{CA}^2 \\ \vdots \\ \bm{CA}^{n-1} \end{bmatrix} \in \mathbb{R}^{np \times n} \end{equation} $$

がフルランク($\text{rank}(\mathcal{O}) = n$)であること。

$\bm{C}$ は出力で直接観測できる状態成分、$\bm{CA}$ は $\bm{A}$ のダイナミクスを通じて1ステップ後に出力に現れる状態成分です。これらが $n$ 次元全体を張れば、時系列の出力データから全ての初期状態を復元できます。

可観測性グラム行列

$$ \begin{equation} \bm{W}_o(t_f) = \int_0^{t_f} e^{\bm{A}^T\tau}\bm{C}^T\bm{C} e^{\bm{A}\tau} \, d\tau \end{equation} $$

$\bm{W}_o(t_f) > 0$(正定値)$\iff$ $(\bm{A}, \bm{C})$ が可観測。

グラム行列の固有値が大きい方向の状態は出力で容易に区別でき、固有値が小さい方向の状態は出力への影響が小さく推定が困難です。

PBH判定法(可観測性版)

$(\bm{A}, \bm{C})$ が可観測 $\iff$ 全ての $\lambda \in \mathbb{C}$ に対して

$$ \text{rank}\begin{bmatrix} \lambda\bm{I} – \bm{A} \\ \bm{C} \end{bmatrix} = n $$

可制御性と可観測性の判定法を見てきました。この2つの概念の間に深い関係があることが、次に述べる双対性です。

可制御性と可観測性の双対性

双対性定理

可制御性と可観測性の間には美しい双対性(duality)があります。

定理(双対性): $(\bm{A}, \bm{B})$ が可制御 $\iff$ $(\bm{A}^T, \bm{B}^T)$ が可観測。

証明は単純です。可制御性行列

$$ \mathcal{C} = [\bm{B}, \bm{AB}, \ldots, \bm{A}^{n-1}\bm{B}] $$

の転置は

$$ \mathcal{C}^T = \begin{bmatrix} \bm{B}^T \\ \bm{B}^T\bm{A}^T \\ \vdots \\ \bm{B}^T(\bm{A}^T)^{n-1} \end{bmatrix} $$

であり、これは $(\bm{A}^T, \bm{B}^T)$ を $(\hat{\bm{A}}, \hat{\bm{C}})$ と見なしたときの可観測性行列そのものです。$\text{rank}(\mathcal{C}) = \text{rank}(\mathcal{C}^T)$ より、双対性が成立します。

双対性の設計への影響

この双対性は、制御系設計に深い影響を与えます。

制御器設計 オブザーバ設計
$\bm{A} – \bm{BK}$ $\bm{A} – \bm{LC}$
可制御性が必要 可観測性が必要
ゲイン $\bm{K}$ を設計 ゲイン $\bm{L}$ を設計

オブザーバの設計問題は、転置系の状態フィードバック設計問題に帰着できます。具体的には、$(\bm{A}^T, \bm{C}^T)$ に対する極配置で $\bm{L}^T$ を求め、転置して $\bm{L}$ を得ます。

この対称構造のおかげで、状態フィードバックの設計手法(極配置法、LQR等)をそのままオブザーバの設計に転用できます。

カルマンの標準分解

4つの部分空間

可制御性と可観測性を組み合わせると、状態空間は4つの部分空間に分解できます。これがカルマンの標準分解(Kalman canonical decomposition)です。

適切な座標変換 $\bm{T}$ により、システムは以下の4つのブロックに分解されます。

$$ \bar{\bm{A}} = \begin{bmatrix} \bm{A}_{co} & 0 & \bm{A}_{13} & 0 \\ \bm{A}_{21} & \bm{A}_{c\bar{o}} & \bm{A}_{23} & \bm{A}_{24} \\ 0 & 0 & \bm{A}_{\bar{c}o} & 0 \\ 0 & 0 & \bm{A}_{43} & \bm{A}_{\bar{c}\bar{o}} \end{bmatrix} $$

$$ \bar{\bm{B}} = \begin{bmatrix} \bm{B}_{co} \\ \bm{B}_{c\bar{o}} \\ \bm{0} \\ \bm{0} \end{bmatrix}, \quad \bar{\bm{C}} = \begin{bmatrix} \bm{C}_{co} & \bm{0} & \bm{C}_{\bar{c}o} & \bm{0} \end{bmatrix} $$

部分空間 意味 入出力への影響
$co$ 可制御かつ可観測 入出力伝達関数に寄与
$c\bar{o}$ 可制御だが不可観測 制御可能だが出力に見えない
$\bar{c}o$ 不可制御だが可観測 出力に見えるが制御できない
$\bar{c}\bar{o}$ 不可制御かつ不可観測 入出力に全く寄与しない

最小実現

入出力伝達関数 $G(s) = \bm{C}(s\bm{I} – \bm{A})^{-1}\bm{B}$ に寄与するのは $co$(可制御かつ可観測)の部分空間のみです。

最小実現とは、同じ伝達関数を持つ最小次数の状態空間モデルであり、$co$ ブロックのみで構成されます。最小実現は可制御かつ可観測です。

逆に、可制御かつ可観測な実現は最小実現である(次数が最小)ことが示されます。

伝達関数の極と零点の消去

伝達関数を求めるとき、不可制御な固有値や不可観測な固有値は極と零点の消去により消えます。

たとえば、状態空間モデル

$$ \bm{A} = \begin{bmatrix} -1 & 0 \\ 0 & -2 \end{bmatrix}, \quad \bm{B} = \begin{bmatrix} 1 \\ 0 \end{bmatrix}, \quad \bm{C} = \begin{bmatrix} 1 & 1 \end{bmatrix} $$

の伝達関数は

$$ G(s) = \bm{C}(s\bm{I} – \bm{A})^{-1}\bm{B} = \frac{1}{s+1} $$

$s = -2$ の極が消えています。これは状態 $x_2$ が不可制御($\bm{B}$ の第2成分がゼロ)だからです。入力が $x_2$ に影響しないため、$x_2$ のダイナミクス($s = -2$の極)は伝達関数に現れません。

具体例による理解の深化

例1: 対角系の可制御性

対角行列 $\bm{A} = \text{diag}(\lambda_1, \ldots, \lambda_n)$ のシステムは、可制御性が直感的に理解しやすいです。

$$ \bm{A} = \begin{bmatrix} \lambda_1 & & \\ & \ddots & \\ & & \lambda_n \end{bmatrix}, \quad \bm{B} = \begin{bmatrix} b_1 \\ \vdots \\ b_n \end{bmatrix} $$

可制御性行列は

$$ \mathcal{C} = \begin{bmatrix} b_1 & \lambda_1 b_1 & \cdots & \lambda_1^{n-1} b_1 \\ \vdots & \vdots & & \vdots \\ b_n & \lambda_n b_n & \cdots & \lambda_n^{n-1} b_n \end{bmatrix} $$

これがフルランクであるための条件は

  1. 全ての $b_i \neq 0$(各モードが入力に結合している)
  2. 全ての $\lambda_i$ が異なる(固有値が重複しない)

条件1は「入力ベクトル $\bm{B}$ の全成分がゼロでない」ということで、直感的に「全てのモードに入力が結合している」ことを意味します。条件2は、固有値が重複する場合は追加のチェックが必要であることを示しています。

例2: 物理系の可制御性

質量-ばね-ダンパー系を考えます。

$$ m\ddot{q} + c\dot{q} + kq = u $$

状態 $\bm{x} = [q, \dot{q}]^T$ で書くと

$$ \bm{A} = \begin{bmatrix} 0 & 1 \\ -k/m & -c/m \end{bmatrix}, \quad \bm{B} = \begin{bmatrix} 0 \\ 1/m \end{bmatrix} $$

可制御性行列は

$$ \mathcal{C} = [\bm{B}, \bm{AB}] = \begin{bmatrix} 0 & 1/m \\ 1/m & -c/m^2 \end{bmatrix} $$

$\det(\mathcal{C}) = -1/m^2 \neq 0$ なのでフルランクであり、可制御です。

物理的に考えても、外力 $u$ でばね系の位置と速度を自由に制御できることは直感に合います。ただし、もし入力が位置に直接作用する($\bm{B} = [1, 0]^T$)なら、状態空間の全体を直接動かせるため別の意味で可制御ですが、力として作用する方が物理的に自然です。

Pythonでの実装と検証

可制御性・可観測性の判定

import numpy as np
import matplotlib.pyplot as plt
import control as ctrl

# 例1: 可制御かつ可観測
A1 = np.array([[0, 1], [-2, -3]])
B1 = np.array([[0], [1]])
C1 = np.array([[1, 0]])
D1 = np.array([[0]])

# 例2: 不可制御(対角系で一方のモードが入力に結合しない)
A2 = np.array([[-1, 0], [0, -2]])
B2 = np.array([[1], [0]])
C2 = np.array([[1, 1]])
D2 = np.array([[0]])

# 例3: 不可観測(一方のモードが出力に現れない)
A3 = np.array([[-1, 0], [0, -2]])
B3 = np.array([[1], [1]])
C3 = np.array([[1, 0]])
D3 = np.array([[0]])

# 例4: 可制御かつ可観測(結合系)
A4 = np.array([[-1, 1], [0, -2]])
B4 = np.array([[0], [1]])
C4 = np.array([[1, 0]])
D4 = np.array([[0]])

systems = [
    ("1: Controllable & Observable", A1, B1, C1, D1),
    ("2: Not Controllable", A2, B2, C2, D2),
    ("3: Not Observable", A3, B3, C3, D3),
    ("4: Coupled system (C & O)", A4, B4, C4, D4),
]

for name, A, B, C, D in systems:
    n = A.shape[0]
    ctrb_mat = ctrl.ctrb(A, B)
    obsv_mat = ctrl.obsv(A, C)
    rank_c = np.linalg.matrix_rank(ctrb_mat)
    rank_o = np.linalg.matrix_rank(obsv_mat)

    print(f"\n=== {name} ===")
    print(f"A = {A.tolist()}")
    print(f"B = {B.flatten().tolist()}")
    print(f"C = {C.flatten().tolist()}")
    print(f"Controllability matrix rank: {rank_c}/{n}"
          f" -> {'Controllable' if rank_c == n else 'NOT'}")
    print(f"Observability matrix rank: {rank_o}/{n}"
          f" -> {'Observable' if rank_o == n else 'NOT'}")
    print(f"Eigenvalues: {np.linalg.eigvals(A)}")

    # 伝達関数(極零消去の確認)
    sys = ctrl.StateSpace(A, B, C, D)
    tf = ctrl.tf(sys)
    print(f"Transfer function: {tf}")
# 可視化: ステップ応答と極零マップ
fig, axes = plt.subplots(2, 4, figsize=(18, 8))

for idx, (name, A, B, C, D) in enumerate(systems):
    sys = ctrl.StateSpace(A, B, C, D)
    n = A.shape[0]
    rank_c = np.linalg.matrix_rank(ctrl.ctrb(A, B))
    rank_o = np.linalg.matrix_rank(ctrl.obsv(A, C))

    # ステップ応答
    ax = axes[0, idx]
    t = np.linspace(0, 5, 300)
    t_out, y_out = ctrl.step_response(sys, T=t)
    ax.plot(t_out, y_out, linewidth=2.5, color="steelblue")
    ax.set_xlabel("Time [s]", fontsize=10)
    ax.set_ylabel("Output", fontsize=10)
    c_str = "C" if rank_c == n else "NC"
    o_str = "O" if rank_o == n else "NO"
    ax.set_title(f"Ex {idx+1}: {c_str}, {o_str}\nStep Response",
                 fontsize=10)
    ax.grid(True, alpha=0.3)

    # 極零マップ
    ax = axes[1, idx]
    # 状態空間の極
    ss_poles = np.linalg.eigvals(A)
    ax.scatter(ss_poles.real, ss_poles.imag, marker="x",
               s=150, color="red", linewidths=2,
               label="SS poles", zorder=5)

    # 伝達関数の極と零点
    tf_sys = ctrl.tf(sys)
    tf_poles = np.array(tf_sys.poles())
    tf_zeros = np.array(tf_sys.zeros())
    if len(tf_poles) > 0:
        ax.scatter(tf_poles.real, tf_poles.imag, marker="o",
                   s=100, color="steelblue", facecolors="none",
                   linewidths=2, label="TF poles", zorder=5)
    if len(tf_zeros) > 0:
        ax.scatter(tf_zeros.real, tf_zeros.imag, marker="s",
                   s=80, color="green", facecolors="none",
                   linewidths=2, label="TF zeros", zorder=5)

    ax.axvline(0, color="black", linewidth=0.5, alpha=0.5)
    ax.axhline(0, color="black", linewidth=0.5, alpha=0.5)
    ax.set_xlabel("Real", fontsize=10)
    ax.set_ylabel("Imag", fontsize=10)
    ax.set_title(f"Pole-Zero Map", fontsize=10)
    ax.legend(fontsize=7, loc="upper left")
    ax.grid(True, alpha=0.3)
    ax.set_xlim([-4, 1])
    ax.set_ylim([-2, 2])

plt.tight_layout()
plt.savefig("controllability_observability.png",
            dpi=150, bbox_inches="tight")
plt.show()

この結果から、可制御性・可観測性と入出力の関係が具体的に理解できます。

  1. 例1(可制御かつ可観測): 全状態が入力で制御でき、出力で観測できます。状態空間の極が全て伝達関数の極として現れ、極零消去は起きていません。状態フィードバック制御とオブザーバの設計が可能です

  2. 例2(不可制御): $x_2$ のモード($\lambda = -2$)が入力に結合していないため、伝達関数では $s = -2$ の極が消去されています(極零消去)。ステップ応答は1次系のように見えますが、実際には内部の $x_2$ は制御不能なモードを持っています

  3. 例3(不可観測): $x_2$ のモード($\lambda = -2$)が出力に現れないため、やはり伝達関数で極零消去が起きています。外から見ると1次系ですが、内部に観測できないダイナミクスが隠れています

  4. 例4(結合系で可制御かつ可観測): 入力は直接 $x_2$ にしか作用しませんが、$\bm{A}$ の非対角要素により $x_2 \to x_1$ へ影響が伝搬するため可制御です。同様に出力は $x_1$ のみですが、ダイナミクスを通じて $x_2$ の情報も出力に現れるため可観測です

グラム行列と制御エネルギーの可視化

import numpy as np
import matplotlib.pyplot as plt
from scipy.linalg import solve_lyapunov
from scipy.integrate import solve_ivp

# 安定な可制御システム
A = np.array([[-1, 0.5], [0, -3]])
B = np.array([[1], [0.5]])

# 可制御性グラム行列(定常値): A*Wc + Wc*A^T + B*B^T = 0
Wc = solve_lyapunov(A, -B @ B.T)
print(f"可制御性グラム行列 Wc =\n{Wc}")
eig_vals, eig_vecs = np.linalg.eig(Wc)
print(f"Wcの固有値: {eig_vals}")
print(f"Wcの固有ベクトル:\n{eig_vecs}")

fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# (a) 可制御性楕円体
ax = axes[0]
theta = np.linspace(0, 2*np.pi, 200)
# 単位エネルギーで到達可能な領域: x^T Wc^{-1} x <= 1
Wc_inv = np.linalg.inv(Wc)
L_chol = np.linalg.cholesky(Wc)
circle = np.array([np.cos(theta), np.sin(theta)])
ellipse = L_chol @ circle
ax.fill(ellipse[0], ellipse[1], alpha=0.2, color="steelblue",
        label="Reachable (unit energy)")

# 固有ベクトル方向
for i in range(2):
    scale = np.sqrt(eig_vals[i])
    vec = eig_vecs[:, i] * scale
    ax.arrow(0, 0, vec[0], vec[1], head_width=0.03,
             head_length=0.02, fc='red', ec='red', linewidth=2)
    ax.text(vec[0]*1.2, vec[1]*1.2,
            f"$\\lambda_{i+1}={eig_vals[i]:.3f}$",
            fontsize=10, color="red")

ax.set_xlabel("$x_1$", fontsize=12)
ax.set_ylabel("$x_2$", fontsize=12)
ax.set_title("Controllability ellipsoid\n"
             "(reachable with unit energy)", fontsize=12)
ax.set_aspect("equal")
ax.grid(True, alpha=0.3)
ax.legend(fontsize=10)

# (b) 最小エネルギー入力のシミュレーション
ax = axes[1]
tf = 3.0
x_targets = [np.array([0.5, 0]), np.array([0, 0.5]),
             np.array([0.3, 0.3])]
colors = ["steelblue", "firebrick", "forestgreen"]

for x_f, color in zip(x_targets, colors):
    # 最小エネルギー入力: u*(t) = B^T exp(A^T(tf-t)) Wc^{-1} xf
    def min_energy_sys(t, state):
        x = state[:2]
        t_remain = tf - t
        exp_AT = np.eye(2)
        # 近似的にmatrix exponentialを計算
        for k in range(1, 20):
            exp_AT += np.linalg.matrix_power(A.T * t_remain, k) / np.math.factorial(k)
        u = B.T @ exp_AT @ Wc_inv @ x_f
        dx = A @ x.reshape(-1, 1) + B @ u.reshape(-1, 1)
        return dx.flatten()

    sol = solve_ivp(min_energy_sys, [0, tf], [0, 0],
                    t_eval=np.linspace(0, tf, 200), max_step=0.01)
    ax.plot(sol.y[0], sol.y[1], linewidth=2, color=color,
            label=f"$x_f$=({x_f[0]},{x_f[1]})")
    ax.plot(x_f[0], x_f[1], 'o', color=color, markersize=8)
    ax.plot(0, 0, 'k*', markersize=10)

ax.set_xlabel("$x_1$", fontsize=12)
ax.set_ylabel("$x_2$", fontsize=12)
ax.set_title("Minimum energy trajectories\n"
             "(from origin to targets)", fontsize=12)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)
ax.set_aspect("equal")

plt.tight_layout()
plt.savefig("controllability_gramian.png",
            dpi=150, bbox_inches="tight")
plt.show()

グラム行列の可視化から、可制御性の定量的な意味が読み取れます。

  1. 左図(可制御性楕円体): 単位エネルギーの入力で原点から到達可能な状態の集合が楕円体として描かれています。楕円の長軸方向(グラム行列の大きな固有値に対応)は少ないエネルギーで到達しやすく、短軸方向は多くのエネルギーが必要です。この楕円が潰れて線になると、不可制御な方向が存在することを意味します

  2. 右図(最小エネルギー軌跡): 原点から3つの目標点への最小エネルギー軌跡を示しています。楕円の長軸方向に近い目標(エネルギーが少なくて済む方向)への軌跡は直線的ですが、短軸方向に近い目標への軌跡は間接的な経路を取ります

まとめ

本記事では、可制御性と可観測性の理論と判定法を解説しました。

  • 可制御性: 入力で全ての状態に到達できるか。3つの判定法がある(ランク条件、グラム行列、PBH判定)
  • 可観測性: 出力から全ての状態を推定できるか。可制御性と双対的な構造を持つ
  • 双対性: $(\bm{A}, \bm{B})$ の可制御性と $(\bm{A}^T, \bm{B}^T)$ の可観測性は同値。制御器設計とオブザーバ設計は「転置」の関係
  • カルマンの標準分解: 状態空間を4つの部分空間(co, $c\bar{o}$, $\bar{c}o$, $\bar{c}\bar{o}$)に分解。伝達関数に寄与するのは $co$ 部分のみ
  • グラム行列: 可制御性の「程度」を定量化し、制御エネルギーの方向依存性を示す

次のステップとして、以下の記事も参考にしてください。