問題概要#

External Reactionsを使用して推力を定義した機体で、JSBSim組み込みのトリム計算機能(FGTrim)が失敗します。トリム計算が収束せず、安定した飛行状態を得ることができません。

原因#

JSBSim組み込みのFGTrim機能は、エンジン/プロペラ推進系を前提として設計されています。External Reactionsは外部力として扱われ、FGTrimの制御変数として認識されません。

詳細な原因#

  1. FGTrimの前提: スロットル(fcs/throttle-cmd-norm)を調整してトリムを探索
  2. External Reactionsの仕組み: 外部力として直接作用、スロットル制御に応答しない
  3. 制御ループの不整合: FGTrimがスロットルを変更しても、External Reactionsの推力は変化しない

この問題はJSBSim公式Issue #1010で既知の制限として記録されています。

なぜExternal Reactionsを使用するのか#

External Reactionsは以下の理由で使用されます:

  • 簡易的な推力モデル: エンジン/プロペラの詳細モデルが不要
  • 開発初期段階: 概算推力で素早くシミュレーション開始
  • 特殊な推進系: 電動モーター、ロケット等の簡易モデル化

解決方法#

回避策: 手動トリム探索の実装#

FGTrimの代わりに、scipy.optimizeを使用した最適化ベースのトリム探索を実装します。

実装例:

from scipy.optimize import minimize
import jsbsim

def trim_objective(x, fdm, target_speed_kts):
    """
    トリム目的関数

    Args:
        x: [throttle, elevator_deg]
        fdm: JSBSim FGFDMExec instance
        target_speed_kts: 目標速度 (knots)

    Returns:
        トリム誤差(0に近いほど良い)
    """
    throttle, elevator_deg = x

    # 制御入力を設定
    fdm['fcs/throttle-cmd-norm'] = throttle
    fdm['fcs/elevator-cmd-norm'] = elevator_deg / 20.0  # ±20°正規化

    # シミュレーション実行
    fdm.run()

    # 加速度を取得(トリム状態では0になるべき)
    udot = fdm['accelerations/udot-ft_sec2']  # 前方加速度
    wdot = fdm['accelerations/wdot-ft_sec2']  # 垂直加速度
    qdot = fdm['accelerations/qdot-rad_sec2']  # ピッチ角速度
    hdot = fdm['velocities/h-dot-fps']         # 上昇率

    # 目的関数: 加速度と上昇率の二乗和を最小化
    return udot**2 + wdot**2 + (qdot*10)**2 + (hdot*5)**2

# トリム探索実行
fdm = jsbsim.FGFDMExec('.')
fdm.load_model('RC_UAV_200g')
fdm.run_ic()

result = minimize(
    trim_objective,
    x0=[0.2, -2.0],           # 初期値: スロットル20%, エレベーター-2°
    args=(fdm, 20.0),         # 目標速度20knots
    method='Nelder-Mead',     # 最適化手法
    options={'maxiter': 100}
)

print(f"トリム解: スロットル={result.x[0]:.3f}, エレベーター={result.x[1]:.2f}°")

重み付けの調整#

目的関数の重み(qdot*10, hdot*5)は、機体特性に応じて調整します:

  • ピッチ安定性重視: qdotの重みを大きく(例: *20
  • 高度維持重視: hdotの重みを大きく(例: *10
  • 速度安定性重視: udotの重みを大きく(例: *2

予防策#

1. プロジェクト初期段階から手動トリム探索を計画#

External Reactionsを使用する場合は、プロジェクト初期段階から手動トリム探索実装を計画に含めます。

計画例:

  • Phase 1: External Reactionsで簡易推力モデル作成
  • Phase 2: 手動トリム探索実装(scipy.optimize使用)
  • Phase 3: トリム解を初期条件として設定

2. FGTrim依存の設計を避ける#

External Reactionsを使用する場合、FGTrimに依存した設計を避けます。

避けるべき設計:

  • ❌ FGTrimで自動的にトリム解を得る前提
  • ❌ FGTrimの結果をそのまま初期条件に使用
  • ❌ FGTrimエラーを無視して進行

推奨設計:

  • ✅ 手動トリム探索を標準ワークフローに組み込む
  • ✅ トリム解をファイルに保存して再利用
  • ✅ トリム状態の検証機能を実装

3. 機体XML生成ツールに警告を追加#

機体XML生成ツールでExternal Reactions使用時の警告を表示します。

警告例:

警告: External Reactionsを使用しています。
JSBSim組み込みのFGTrim機能は使用できません。
手動トリム探索を実装してください。
参考: docs/manual_trim_search.md

まとめ#

FGTrimがExternal Reactionsで動作しない問題は、JSBSim公式の既知の制限です。

原因:

  • FGTrimはエンジン/プロペラ推進系を前提
  • External Reactionsはスロットル制御に応答しない
  • JSBSim Issue #1010で記録済み

解決策:

  • scipy.optimizeを使用した手動トリム探索
  • 加速度・上昇率の二乗和を最小化
  • 重み付けを機体特性に応じて調整

予防策:

  • プロジェクト初期段階から手動トリム探索を計画
  • FGTrim依存の設計を避ける
  • XML生成ツールに警告を追加

External Reactionsの利点(簡易性、開発速度)を活かしつつ、手動トリム探索で正確なトリム解を得ることができます。


関連記事#

  • 【トラブル備忘】JSBSimトリム計算が収束しない - Cmalpha符号ミスの罠(記事E-2)
  • 【トラブル備忘】トリム計算失敗 - CD0過大による推力不足(記事E-6)

© 2025 Yaaasoh. All Rights Reserved.