衛星オンボードAI アーキテクチャ — 放射線・電力・地上同期に縛られたエッジ推論

地球観測衛星 Sentinel-2 が1日に生成する生データはおよそ1.6 TB、Landsat-9 でも数百GBに達します。コンステレーション全体では数十TB/日。一方で、X帯ダウンリンクで地上に降ろせるのは1パスあたり高々数十GB、しかも軌道周期に同期した数分間の通信窓に詰め込まなくてはなりません。さらに困ったことに、撮影した画像の 60〜70%は雲に覆われて使い物にならないことが、ESAのPhiSat-1 ミッション以前から経験的に知られていました。地上で「これは雲だらけだから捨てる」と判定するために、わざわざ高価な帯域を使って降ろしてくる——これは明らかに無駄です。

この無駄を消す発想が オンボードAI(onboard AI) です。衛星のペイロード計算機の上で深層学習モデルを走らせ、「雲かどうか」「火災や噴火が映っているか」「船舶が新たに現れたか」をその場で判定する。価値ある画像だけを優先送信し、それ以外は捨てるか劣化圧縮する。これだけで実効ダウンリンク帯域が 80〜90%節約でき、地上の解析パイプラインからも雑音が消えます。さらに災害監視のような時間制約のある任務では、地上での判定を待つ数時間〜十数時間の遅延を、軌道上での 数秒以内の判定に短縮できます。

しかし、衛星はAIにとってきわめて意地悪な環境です。電力は数W〜十数W、CPU性能は地上の数世代前、何より 放射線が常に半導体メモリのビットを反転させ続けています。地上のGPUクラスタで動くResNetをそのまま打ち上げるわけにはいきません。本記事では、こうした制約のもとでオンボードAIを成立させる設計判断を、ハードウェアからモデル軽量化、FOTAによる軌道上更新、衛星間連邦学習まで一気通貫で見ていきます。

本記事の内容

  • なぜ衛星「オンボード」で推論する必要があるのか — 帯域・遅延・自律性の三本柱
  • 衛星内計算リソースの厳しい制約(電力・温度・質量)とFPGAが選ばれる理由
  • 放射線が半導体を壊す仕組み(SEU/SEL/SEFI/TID)と冗長多数決によるソフトエラー対策
  • 量子化(INT8/INT4)と枝刈り(pruning)によるモデル軽量化
  • 推論アクセラレータの選択肢: Jetson Xavier NX軌道版、Movidius VPU、Versal AI Edge
  • 軌道上学習 vs 地上学習+デプロイ — どこで何を学ぶべきか
  • FOTA(Firmware/Model Over-The-Air)によるモデル更新とそのセキュリティ
  • 衛星間連邦学習による分散モデル同期(Starlink級コンステレーション)
  • 実機事例: PhiSat-1/2, AWS Snowcone in Space, Orbital Sidekick GHOSt
  • Python実装: 量子化シミュレーション、軽量CNNによる雲検出、ONNX変換、推論レイテンシ計算

前提知識

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

なぜオンボード推論が必要か — 帯域・遅延・自律性

帯域は有限、撮るほど捨てる時代

低軌道(LEO)の地球観測衛星が地上局を通過するのは、1日あたりせいぜい4〜6パス、1パス10分前後です。X帯ダウンリンクの典型的なスループットは数百Mbps〜数Gbps、Ka帯でも10 Gbpsオーダーが上限。これを全部の有効パスに合計しても、1日に降ろせる総量は数百GB〜数TBにすぎません。一方センサ側は、マルチスペクトル12バンド・空間分解能10mで撮り続ければ、1日数TBの生データを軽く生み出します。取れる量と降ろせる量に1桁以上の開きがあるわけです。

この差を圧縮アルゴリズムだけで埋めようとするのは限界があります。可逆圧縮ではせいぜい2〜3倍。非可逆(JPEG2000など)でも10倍まで行けば良いほうで、研究用途では情報損失が問題になります。残る選択肢は、そもそも価値のないデータを送らないこと。具体的には:

  • 雲被覆判定: 雲量50%以上のシーンを捨てれば、平均で60%程度の帯域節約
  • オンデマンド送信: 災害検知・船舶検知・氷山検出など、特定の関心物体がある場合のみ送る
  • タイル単位の優先度付け: 1シーンを小タイルに分け、興味のあるタイルだけ高品質で、それ以外は低品質サムネイルで送る

これらすべての判定を「衛星の中で」やるのがオンボードAIの最初の役割です。

遅延を秒に縮める — 災害対応の時間軸

帯域以上に深刻なのが、地上経由による遅延です。撮影 → 蓄積 → 次のパスでダウンリンク → 地上前処理 → 解析 → 通知、というルートで動くと、最良でも数時間、悪い場合は十数時間かかります。山火事や火山噴火、津波のような事象では、この遅延の間に取り返しのつかない事態が進みます。

オンボードでイベント検知をやれば、検出 → 小サイズのアラートメッセージのみを次のパスで降ろす(数十バイト)→ 地上のオペレータが即座に高優先度ダウンリンクを要求、という流れに圧縮できます。アラート部分は数百Mbpsの低レート専用ビーコンで降ろすことも可能で、検出から地上認知まで分オーダーまで縮められます。Orbital Sidekickのハイパースペクトル衛星 GHOSt はまさにこれを油田パイプラインのメタン漏洩検知に応用しています。

自律性 — 通信窓外でも判断が必要

深宇宙探査機ではさらに状況が深刻です。火星探査機の片道光遅延は4〜24分、木星探査機なら30分以上。「地上に問い合わせて指示を待つ」という従来のオペレーション哲学が成立しません。例えば、火星表面を走るローバーが障害物を検出したとき、地上の判断を待っていたら穴に落ちます。Perseveranceローバーの自律航法(AutoNav)や、影写真上の興味地点を機内で選ぶAEGIS(Autonomous Exploration for Gathering Increased Science)は、まさにオンボードAIの先駆けです。

LEOの地球観測衛星でも、地上局非可視時間が1日の80%以上を占めます。この間に火災を見つけても、誰にも報告できない。オンボードAIは「衛星に判断権を委譲する」ためのインフラとも言えます。

帯域・遅延・自律性。この3つの制約が、なぜわざわざ計算機を軌道に上げてまで推論したいのかの根本理由です。次節では、では実際に軌道に何を載せられるのか——電力・温度・質量・放射線という物理的な制約を見ていきます。

衛星内計算リソースの制約

数W〜十数Wという電力の壁

100kg級小型衛星のペイロード計算機に割ける電力は、太陽電池パネル面積から逆算しておおむね 5〜20W です。これは地上のスマートフォンチップ程度の予算で、デスクトップGPU(200〜450W)はおろか、Jetson Orin Nano(15W)でも上限に張り付きます。光が当たらない食(eclipse)の間は電池のみに頼るため、ピーク電力も平均電力も厳しく制約されます。

この制約から、TOPS/W(1ワットあたり何兆回の演算ができるか)という指標が決定的になります。地上のV100 GPUがおよそ0.5 TOPS/W、Jetson Xavier NX が 5〜10 TOPS/W、専用FPGA設計では 20〜50 TOPS/W、ASIC(Google Edge TPUなど)では100 TOPS/W超を出せます。同じ消費電力で1〜2桁スループットが変わるため、ハードウェア選択がモデル設計を強く拘束します。

熱設計 — 真空中で熱を捨てる難しさ

地上ではファンとヒートシンクで簡単に熱を逃がせますが、真空中では対流が使えず、放射のみで熱を捨てるしかありません。シュテファン・ボルツマンの法則 $P = \varepsilon \sigma A T^4$ から、放射放熱面の面積 $A$ と表面の放射率 $\varepsilon$ で許容電力が決まります。CubeSatの1U面(10cm × 10cm)から300Kで放射できるのは理論上数W、実際にはペイロードや他コンポーネントとの熱結合があり、許容ピーク電力はさらに厳しくなります。

このため、衛星オンボードAIでは「平均10Wで連続動作」ではなく、「1分間に5W平均、ピーク20Wで5秒だけ推論」というデューティサイクル運用が一般的になります。モデル設計時から「1推論あたり何ジュール消費するか」「サーマルクールダウン時間」を考慮する必要があります。

FPGAが選ばれる理由

地上のAI推論ではGPUが圧倒的ですが、衛星オンボードでは FPGA(Field-Programmable Gate Array)が長年デファクトでした。理由は3つあります:

  1. 電力効率: GPUは汎用シェーダで電力を食う部分が多いのに対し、FPGAは推論に必要な乗算器(DSP)と少量のSRAMだけを密に並べられる。CNN推論で 10〜50 TOPS/W を出すFPGA設計は珍しくありません。
  2. 放射線耐性: 後述するように、SRAMベースのFPGAでも、選択的にラジ・ハード設計を組み込める(TMR: Triple Modular Redundancyやスクラビング)。アンチヒューズ型・フラッシュ型FPGA(Microsemi RTG4など)は構造的にSEU耐性が高い。
  3. 決定論的レイテンシ: パイプラインを固定すれば、入力 → 出力の遅延がクロック単位で予測可能。リアルタイム要件のある姿勢制御ループ等と協調しやすい。

XilinxのVersal AI Edge(XQR Versal)、MicrochipのPolarFire SoC、Microsemi RTG4 が宇宙用FPGAの代表格です。一方で、NVIDIA Jetson Xavier NX を放射線対策ケース(タングステンシールド + ECC + watchdog)に入れて打ち上げる「COTS(Commercial Off-The-Shelf)」路線も近年急速に増えており、特にLEOの短寿命ミッションでは費用対効果で勝ちます。

電源と熱の物理的制約、そしてFPGAの優位性。これらに加えて、軌道上特有の最大の難敵が放射線です。次節では、宇宙放射線が半導体をどう壊すのか、そしてどう守るのかを見ていきます。

放射線耐性 — SEU/SEL/SEFI/TID

軌道上の放射線環境

衛星が浴びる放射線は大きく3種類です:

  • 銀河宇宙線(GCR): 銀河系外から飛来する高エネルギー陽子・重イオン。地磁気で偏向されず、極軌道(特に南大西洋異常帯、SAA)で強い。
  • 太陽高エネルギー粒子(SEP): 太陽フレアやコロナ質量放出で放出される陽子。突発的だが強烈。
  • トラップド粒子(Van Allen帯): 地磁気に捕捉された陽子・電子。MEO(中軌道)が特に厳しい。

これらが半導体に当たると、4種類の故障モードを引き起こします。

SEU(Single Event Upset)— ビット反転

最も頻繁な障害が SEU です。重イオンや陽子がSRAMやフリップフロップを貫通する際、生成された電子・正孔対が蓄積電荷を中和し、ビットが0↔1反転します。LEOでは1日あたり数ビット〜数十ビット/Mbのオーダーで起こります。これだけ聞くと「めったに起きない」と思えますが、推論中のモデル重みが1ビット反転しただけで出力が壊れる可能性があるため軽視できません。

SEU対策の定番は以下:

  • ECC(Error Correction Code): SECDED(Single Error Correct, Double Error Detect)をメモリ全体に付ける。8ビットECCで64ビットを守るのが標準。
  • メモリスクラビング: 周期的にメモリ全体を読み・ECCで訂正・書き戻す。FPGAのコンフィギュレーションSRAMに対してはSEM IP(Soliton Error Mitigation IP)が定石。
  • TMR(Triple Modular Redundancy): 同じ計算を3つの独立回路で実行し、多数決で結果を採用する。SEUが2回路同時に起きる確率は無視できるほど小さい。

TMRの確率モデルを少し定量的に書いてみます。1つの回路がある時間内にSEUで誤動作する確率を $p$ とすると、3つのうち2つ以上が同時に誤る確率(多数決が失敗する確率)は

$$ P_{\mathrm{fail}} = \binom{3}{2} p^2 (1-p) + \binom{3}{3} p^3 = 3p^2 – 2p^3 \approx 3p^2 \quad (p \ll 1) $$

となります。$p = 10^{-4}$ なら $P_{\mathrm{fail}} \approx 3 \times 10^{-8}$。単一回路と比べて4桁以上の信頼性向上です。代償はハードウェア量3倍と多数決回路の遅延ですが、決定的演算(姿勢制御や推論の重要部分)には欠かせません。

SEL(Single Event Latchup)— 寄生サイリスタの暴走

SEL はもっと深刻です。CMOSの寄生サイリスタ構造(PNPN)が重イオンで点弧されると、電源 → GND に低抵抗の電流路ができ、過電流で素子が焼損します。発生したら電源を切るしかないため、ラジ・ハード化されていないCOTSを使う場合は、電流監視による緊急電源遮断回路(latchup detection and reset, LDR)が必須です。

SEL耐性は半導体プロセスに依存します。SOI(Silicon-on-Insulator)プロセスは寄生サイリスタが存在しないためSELが原理的に起こりません。最近のFPGAの多くがSOIまたはガードリング強化プロセスで作られているのはこのためです。

SEFI(Single Event Functional Interrupt)— 機能停止

SEFI は制御レジスタやFSM(有限状態機械)の状態がSEUで壊れ、機能ブロック全体が異常状態に陥る現象です。データSRAMのビット反転と違ってECCでは救えず、ブロック単位のリセット(あるいはデバイス全体のリセット)が必要になります。

対策はwatchdogタイマです。一定周期でハートビート信号が来ないなら、計算機を自動リセットする。衛星では二重watchdog(プロセッサ内 + 外部FPGA)が一般的です。

TID(Total Ionizing Dose)— 累積放射線損傷

TID はビット反転のような瞬間的事象ではなく、長期累積でじわじわ半導体特性を劣化させる現象です。MOSFETの閾値電圧シフトやリーク電流増加が典型例。LEOで年間 1〜10 krad、深宇宙では年間 100 krad を超えることもあります。COTSの民生品は数十 krad で機能停止、ラジ・ハード品は1 Mrad 以上耐えます。

TID対策は基本的に「ラジ・ハード品を選ぶ」「タングステン・タンタル等の遮蔽を入れる」「冗長化して片方が劣化したら切り替える」の3点セット。設計寿命と被曝累積量から要求耐性を決め、ハードウェア選定に落とし込みます。

モデル重みのSEU対策

ハードウェア対策に加えて、ソフトウェア側でもSEUに対する備えが要ります。深層学習モデルの重みは数百MB〜数GBあり、これがSRAMやDRAM上にあると常にSEU脅威にさらされています。実装上の対策は3つ:

  • 重みのECC格納: 推論前にECC付きROMから読み込み、検算しながら使う。
  • 重みの冗長コピー + 多数決: 同じ重みを3コピー保持し、推論時に多数決で読み取る(メモリ3倍だが計算コストは増えない)。
  • 量子化による暗黙の耐性: INT8重みは1ビット反転の影響がfloat32より相対的に小さい場合がある(指数部反転が起きないため)。

特に最後の量子化は、軽量化と放射線耐性を同時に改善する一石二鳥の手段です。次節で詳しく見ていきます。

モデル軽量化 — 量子化と枝刈り

量子化(quantization)の発想

深層学習モデルはふつう float32(32ビット浮動小数点)で学習・推論しますが、推論時には精度がそこまで必要ありません。重みと活性を INT8(8ビット整数)に丸めることで、メモリ使用量1/4、計算速度2〜4倍、消費電力1/3〜1/4 が得られます。これが量子化です。

線形量子化の基本式は次の通り:

$$ q = \mathrm{round}\!\left(\frac{x}{s}\right) + z, \qquad x \approx s (q – z) $$

ここで $x$ は元の浮動小数点値、$q$ は量子化された整数値、$s$ はスケール(実数)、$z$ はゼロ点(整数)です。スケール $s$ は重み分布の最大絶対値から決め、ゼロ点 $z$ は非対称な分布を扱うためのオフセットです。

INT8の範囲は $[-128, 127]$ なので、$s$ の選び方が重要です。シンプルな対称量子化では:

$$ s = \frac{\max(|x|)}{127} $$

これだと外れ値1つに引っ張られて分解能が落ちるため、実用ではキャリブレーション用データでパーセンタイル(例: 99.9%)を使うか、Quantization Aware Training(QAT)で量子化誤差を学習時から織り込みます。

軌道上推論では、さらに過激なINT4(16値)やバイナリ・ニューラルネット(重み±1のみ)も研究されています。精度低下とのトレードオフですが、雲/非雲のような2値判定タスクではINT4でも実用十分なケースが多いです。

枝刈り(pruning)— 使わないニューロンを削る

学習済みCNNの重みを見ると、多くが非常に小さい値です(重みのヒストグラムを描けば0付近に集中したガウス様の分布)。これらは推論結果にほぼ寄与しないため、ゼロに固定して計算をスキップできます。これが 枝刈り(pruning) です。

枝刈りには2系統あります:

  • 構造化枝刈り(structured pruning): フィルタ単位、チャネル単位で丸ごと削る。実装が単純で実速度向上が出やすい。
  • 非構造化枝刈り(unstructured pruning): 個別の重みを削る。圧縮率は高いが、スパース行列演算のハードウェア支援がないと実速度が出ない。

衛星向けFPGA実装では構造化枝刈りが主流です。重要度(absolute weight magnitude や Hessian-based)の低いチャネルから順に削り、残った重みを再学習(fine-tuning)して精度を回復させる、というサイクルを繰り返します。

量子化+枝刈り+知識蒸留の合わせ技

実用的なオンボードモデル構築では、3つの軽量化手法をパイプライン的に組み合わせます:

  1. 教師モデル(teacher): 地上で学習した重いモデル(ResNet-50, ViT-B など)
  2. 知識蒸留: 教師の出力ロジットを真似る軽量な生徒モデル(MobileNetV3, EfficientNet-Lite など)を学習
  3. 枝刈り: 生徒モデルからさらに不要なチャネルを削る
  4. 量子化(QAT): INT8に量子化しながら再学習
  5. コンパイル: TensorRT, Vitis-AI, OpenVINO 等で対象ハードウェア向けに最適化

このパイプラインで、ResNet-50(25M params, 4 GFLOPs)クラスの精度を、4M params, 0.3 GFLOPs 程度のINT8モデルにまで縮められます。10倍以上の軽量化で精度低下は1〜3ポイントに収まります。

軽量化が済んだら、次はそれを動かすハードウェアです。次節で推論アクセラレータの選択肢を比較します。

推論アクセラレータの選択肢

Jetson Xavier NX(軌道版)

NVIDIA Jetson Xavier NX は 21 TOPS(INT8)、10〜15W TDPの組み込みGPUモジュールです。CUDA + TensorRTで地上の開発資産がそのまま使え、PyTorch/TFモデルを最小限の変更で動かせるのが最大の魅力。Lockheed Martin のSpiderOakやAxient等が「Xavier NXをタングステン遮蔽箱に入れて電流監視+自動リセット回路を付けた宇宙版」を商用化しています。

弱点はSEL耐性です。COTSのXavier NXはSEL耐性試験で陽子フラックス $10^7$ cm$^{-2}$ あたり数回ラッチアップが観測されており、LEO短期ミッションなら許容範囲でも、深宇宙や長期任務には不向きです。LDR回路で電源を周期的にリセットする運用でカバーします。

Movidius Myriad X VPU

Intel Movidius Myriad X は1 TOPS、1W程度の超低電力VPUです。ESAのPhiSat-1 が積んでこの分野で先鞭をつけた歴史的なチップ。専用のニューラル計算ユニット(NCE)が16基並んでおり、INT8/FP16の混在演算に最適化されています。

PhiSat-1 では雲検出CNN(CloudScout)を Myriad X 上で動かし、入力2048×2048×13バンドのSentinel-2画像を1秒以内に処理しました。電力1W以下で完結するため、超小型衛星のペイロード予算でも余裕で収まります。

Versal AI Edge(XQR Versal)

Xilinx(AMD)のVersal AI Edge は、FPGA + Arm CPU + AI Engine(ベクトル/行列専用エンジン)のヘテロジニアスSoCです。Versal XQR(耐放射線版)は XQR Versal Premium で SEU耐性 + ECC + LDR 込み、最大145 TOPS @ INT8。Vitis AIツールチェーンでPyTorch/TFモデルからFPGAビットストリームに自動コンパイルできます。

FPGAなので推論パイプラインを問題に応じて完全カスタマイズでき、CNN以外のセンサ前処理(デバイヤリング、ラジオメトリック補正、幾何補正)も同じデバイス上で行えるのが強みです。「センサ直結 → 前処理 → 推論 → 圧縮 → ダウンリンクキュー」を1チップで完結させられます。

専用ASIC

Google Edge TPU や Hailo-8 のような専用ASICは TOPS/W 効率では最強(Hailo-8 で 26 TOPS @ 2.5W、つまり10 TOPS/W)ですが、放射線耐性の検証が必要で、ミッション固有のラジ・テストキャンペーン費用がかかります。コンステレーション規模が大きく(数百機以上)、同じASICを横展開できる場合のみ経済合理性があります。

ハードウェアを選んだら、最後の問いは「いつ・どこで学習するか」です。地上で完結させるのか、軌道上で更新するのか。次節で議論します。

軌道上学習 vs 地上学習+デプロイ

基本は「地上で学習、軌道で推論」

オンボードAIの現状の主流は、地上で大規模データセットを使って学習し、量子化・最適化したモデルだけを衛星に積むスタイルです。理由は明確で、学習は推論より2〜3桁多い計算リソースを必要とし、また学習データを多様化させるには複数衛星・複数日のデータをまとめる必要があるからです。

このパラダイムで重要なのが ドメインギャップの問題。地上で用意した学習データ(既存衛星のアーカイブ)と、運用衛星が実際に撮るデータは、センサ特性・撮像幾何・大気状態・季節等が微妙に異なります。地上で 95% の精度が出ても、軌道上では 85% に落ちることが珍しくありません。

対策としては:

  • 大規模事前学習: 多数の衛星のアーカイブで自己教師あり事前学習(SatMAE、Prithvi-100M など)→ 運用衛星のデータで少量ファインチューン
  • シミュレーション拡張: 大気放射伝達モデル(6S, MODTRAN)で撮像条件をランダム化したaugmentation
  • ドメイン適応: 運用初期データに対する unsupervised domain adaptation

これらは「軌道上学習」ではなく、依然として地上での学習プロセスの工夫です。

軌道上学習(on-orbit learning)の事情

完全な軌道上学習は依然として研究段階です。理由は3つ:

  1. 計算リソース不足: 学習は推論の100倍以上の計算を要し、フォワード/バックワード両方が走るため、INT8のような積極量子化が使いにくい(勾配がノイズに埋もれる)。
  2. 教師データの不足: 衛星上には正解ラベルがない。雲検出なら別系統(赤外線温度等)でラベルを生成できるが、より高度なタスクではラベル付け自体が困難。
  3. 品質保証の難しさ: 軌道上で重みが更新されると、地上から見て「いま衛星がどんなモデルを使っているか」がブラックボックスになり、検証が困難。

それでも、軌道上学習が必要になるユースケースは存在します:

  • 継続学習 / オンライン適応: センサ経時変化(detector drift)に追随する。教師信号は「直近の地上判定結果」を地上から定期送信
  • 異常検知の閾値更新: 季節変動や地域差に応じて検出閾値を自動チューン
  • 数機の衛星間でモデル平均化: 後述の連邦学習。各衛星が局所更新だけして、地上ハブが集約

実装上は、フル再学習ではなく 最後の数層だけ軌道上で更新、あるいは 小型adapterモジュール(LoRA的なもの)だけ更新するハイブリッドが現実解です。バックボーンは凍結したまま、タスク固有のヘッドだけが進化していく。

地上学習をベースにしつつ、軌道上で部分更新もする——この運用を支える技術がFOTAです。次節でセキュリティ問題を含めて見ていきます。

FOTA — モデル更新の運用とセキュリティ

FOTA(Firmware/Model Over-The-Air)の役割

地上で再学習した新モデルを軌道上の衛星に届ける仕組みが FOTA です。スマートフォンのOTAアップデートと同じ発想ですが、衛星では失敗のリスクがはるかに重い。配信途中で通信窓が切れたり、ビット反転が混ざったり、最悪は悪意あるなりすまし命令でモデルを書き換えられたりすると、ミッション全体が止まります。

FOTAの典型フロー:

  1. 地上で新モデルを訓練 → 量子化 → 検証 → デジタル署名(Ed25519等)付与
  2. 暗号化(AES-256-GCM)してチャンク分割
  3. 次のパスでアップロード(テレコマンドチャネル)
  4. 衛星側で全チャンク受信完了 → 署名検証 → 復号 → ステージング領域に書き込み
  5. テスト推論で出力健全性を確認 → 本番領域にatomic swap
  6. ロールバック領域に旧モデルを保持(新モデルに不具合があれば自動切り戻し)

ステージング・ロールバック設計が肝です。本番領域を直接上書きすると、不具合発生時に衛星を救えなくなります。

暗号と認証

衛星セキュリティの基本は CCSDS SDLS(Space Data Link Security) に従い、機密性・完全性・可用性の3要件を満たすこと。FOTAではこれに加えて:

  • 公開鍵による署名検証: 地上の運用センターの秘密鍵でモデルに署名、衛星は事前ロードされた公開鍵で検証。中継局や経路上のなりすましを排除。
  • リプレイ攻撃対策: ノンスやタイムスタンプを命令に含め、過去命令の再送を弾く。
  • テレコマンド認証: HMAC-SHA256 等で全コマンドにMACを付与。

問題は 鍵管理です。衛星に焼き込んだ鍵は更新が事実上不可能(FOTAで鍵を更新するときの認証はどの鍵で?というニワトリ卵問題)。実運用では複数の鍵階層(root key、operational key、session key)を持ち、operational keyを定期ローテーションする、という設計を取ります。

通信妨害とジャミング

LEOで地上局通信は数百MHz〜数十GHz帯。これらは地表からのジャミングに対して原理的に脆弱です。対策は周波数ホッピング、拡散スペクトラム、低被探知性(LPI)、レーザー通信などです。軍事衛星では当然これらが入っていますが、商用衛星でも近年は地政学的リスクを踏まえて検討が進んでいます。

オンボードAIの観点からは「通信が妨害されてもしばらく自律動作で耐える」設計が重要。FOTAが滞っても旧モデルで運用継続、検出結果を内蔵ストレージに溜め、通信回復後にまとめて送る、という運用です。

ここまでが「地上 ↔ 衛星」の1対1更新の話でした。コンステレーション時代では、衛星同士で連携してモデルを進化させる連邦学習が研究されています。

衛星間連邦学習 — コンステレーション規模の分散AI

なぜ連邦学習が必要か

Starlink級(数千機)のメガコンステレーションでは、各衛星が独自に局所データで学習し、それらを集約することで集団知能を作れます。生データを地上に降ろさず、モデル更新(勾配)だけを共有するため帯域も大幅節約。これが衛星連邦学習(FedSat)の発想です。

連邦学習の基本アルゴリズム FedAvg は次のように定式化されます。各衛星 $i$ は局所データセット $D_i$ で1〜数エポック学習し、得られた重み $w_i$ を中央サーバ(地上または親衛星)に送信。サーバは全衛星の重みを加重平均で集約:

$$ w_{\mathrm{global}} = \sum_{i=1}^{K} \frac{|D_i|}{\sum_j |D_j|} w_i $$

ここで $|D_i|$ は衛星 $i$ の局所データ点数、$K$ は参加衛星数です。集約されたグローバルモデルを次のラウンドで各衛星に再配布し、これを繰り返してモデルを収束させます。

軌道力学と通信機会のスケジューリング

地上の連邦学習と決定的に違うのが、衛星はランダムにオフラインになるという制約です。地上局を通過する間しか集約サーバと通信できず、衛星間光リンク(OISL)を使う場合も視野角制約で接続が動的に変わります。

このため、純粋なFedAvgよりも非同期版(FedAsync)が向きます。サーバは到着した更新を逐次取り込み、古い更新には重みを下げる(staleness-aware weighting)。Starlinkでは隣接衛星同士のOISLで局所集約 → 1機が地上に降りてグローバル集約、という階層構造が考案されています。

プライバシ・セキュリティ

連邦学習は「生データを共有しない」のがウリですが、勾配からデータが復元される攻撃(gradient inversion)が知られており、完全な秘匿は保証されません。差分プライバシ(DP)でノイズを乗せる、Secure Aggregationで暗号学的に合計だけを露出する、という対策が併用されます。

衛星間の場合は信頼関係が事業者内部で閉じることが多く、地上の連邦学習よりプライバシ問題は緩和されます。むしろ重要なのは、悪意あるなりすまし衛星(Byzantine参加者)への耐性。Krum/MultiKrum/RFA 等のロバスト集約アルゴリズムが研究されています。

通信コスト

衛星モデルが100M params のINT8であれば1モデル100MB。1日1回集約するなら100MB × 衛星数の通信が要ります。1000機なら100GB/日でこれは膨大。実用上は 圧縮(top-k sparsification、低ランク近似、量子化)と 分散化(地上集約ではなく階層的衛星間集約)でこれを1〜2桁削ります。

実機事例を見ると、こうした理論的工夫がどこまで実装されているかが見えます。次節で具体的な打ち上げ済みミッションを概観します。

実機事例

PhiSat-1(ESA, 2020年打ち上げ)

オンボードAIを世界で初めて軌道で実証した6U CubeSatです。Intel Movidius Myriad X VPU + HyperScout-2 ハイパースペクトル撮像器の組み合わせ。雲検出CNN CloudScout が走り、雲被覆率50%以上のシーンを自動的に廃棄。当時の論文によると、地上ダウンリンク帯域を 約30%節約しました(雲廃棄シナリオでは70%+ のセーブを期待していたが、軌道調整等で実効値が低下)。

CloudScoutは入力2048×2048×3バンド、8層のCNN、約2M params、Myriad X上で約1秒/シーンで推論。当時としては記念碑的でした。

PhiSat-2(ESA, 2024年打ち上げ)

PhiSat-1の後継。Myriad Xを継承しつつ、より高度なオンボードアプリ群を搭載:

  • CloudSEN12: 多バンドの雲検出(Sen2系列との互換性)
  • OnboardSR: 超解像(ダウンリンクを低解像で行い地上で復元する戦略の検証)
  • WildfireDetector: 山火事のリアルタイム検知
  • VesselDetector: 海洋船舶検知

各アプリは独立コンテナで動き、Myriad X上のスケジューラがリソース割り当てを管理。FOTA基盤も整備され、軌道上でアプリ追加・更新が実証されました。

AWS Snowcone in Space(Axiom Mission 1, 2022年)

ISS内に持ち込んで運用された地上由来のエッジ計算機「Snowcone」を、宇宙ステーション内環境で1ヶ月以上動作させた実証。地上のAWS Greengrass / SageMaker と全く同じソフトスタックが軌道上で動くことを示しました。クラウド事業者がオンボードAIにそのまま自社サービスを持ち込む流れの先駆けです。

ただしISS内なので船外環境のような厳しい放射線・温度ではなく、デモとしての意味が大きい点には注意。

Orbital Sidekick GHOSt(2022年〜)

ハイパースペクトル小型衛星 6機のコンステレーション。オンボードAIで石油パイプラインからのメタン漏洩を検知し、検知から地上アラートまでを 30分以内で完結させるサービスを運用中。SARイメージや赤外線とハイパースペクトルを組み合わせ、雲被覆下でも検知できる工夫がされています。

GHOSt は商用ベースでオンボードAIが収益を生む最初の本格事例として注目されています。

CLEO Vortex(Loft Orbital, 2023年〜)

衛星 as a Service プラットフォーム「Vortex」上でAIワークロードを動かすサービス。地上開発者が自前のモデルを衛星に「アップロード」して走らせるという、SaaS的なオンボードAI運用モデル。

これら実機の経験が、次世代の設計指針を固めつつあります。最後に、本記事で議論した諸要素をPython実装で体感します。

Pythonでの実装

量子化シミュレーション — INT8 vs float32

まず、量子化が推論結果と精度にどう影響するかを最小コードで体験します。ランダムCNN重みを使い、float32とINT8の出力差・誤差分布を比較してみます。

import numpy as np

def quantize_int8_symmetric(x, axis=None):
    """対称量子化: x を INT8 [-127, 127] に量子化し、(q, scale) を返す
    ゼロ点 z=0 とする最も単純な形(CNN重みでは通常これで十分)"""
    if axis is None:
        s = np.max(np.abs(x)) / 127.0
    else:
        s = np.max(np.abs(x), axis=axis, keepdims=True) / 127.0
    s = np.maximum(s, 1e-12)              # ゼロ割回避
    q = np.clip(np.round(x / s), -128, 127).astype(np.int8)
    return q, s

def quantize_int8_asymmetric(x, percentile=99.9):
    """非対称量子化(活性化向け): パーセンタイルでクリッピングしてから INT8 化"""
    lo = np.percentile(x, 100 - percentile)
    hi = np.percentile(x, percentile)
    s = (hi - lo) / 255.0
    z = int(np.round(-128 - lo / s))
    q = np.clip(np.round(x / s + z), -128, 127).astype(np.int8)
    return q, s, z

def dequantize_symmetric(q, s):
    return q.astype(np.float32) * s

def dequantize_asymmetric(q, s, z):
    return (q.astype(np.float32) - z) * s

np.random.seed(0)
W = np.random.randn(64, 64).astype(np.float32) * 0.1   # 重み
x = np.random.randn(64).astype(np.float32)             # 入力

# float32 基準
y_fp32 = W @ x

# 重みは出力チャネル(行)ごとに別スケール、入力はテンソル全体で1スケール
Wq, Ws = quantize_int8_symmetric(W, axis=1)            # shape (64, 1)
xq, xs = quantize_int8_symmetric(x)
# INT32 で積和を取り、最後にスケールを掛ける(実機はこの形)
acc = Wq.astype(np.int32) @ xq.astype(np.int32)
y_int8 = acc.astype(np.float32) * (Ws.squeeze() * xs)

err_sym = np.abs(y_fp32 - y_int8)

# 比較: パーセンタイル非対称量子化
Wq2, Ws2, Wz2 = quantize_int8_asymmetric(W, percentile=99.9)
W_deq = dequantize_asymmetric(Wq2, Ws2, Wz2)
y_int8_asym = W_deq @ x
err_asym = np.abs(y_fp32 - y_int8_asym)

print(f"FP32 出力範囲: [{y_fp32.min():+.3f}, {y_fp32.max():+.3f}]")
print(f"対称INT8       最大誤差={err_sym.max():.4e}, 平均誤差={err_sym.mean():.4e}")
print(f"非対称INT8(99.9p) 最大誤差={err_asym.max():.4e}, 平均誤差={err_asym.mean():.4e}")
print(f"対称INT8 相対誤差   : {err_sym.mean() / np.abs(y_fp32).mean():.2%}")
print(f"非対称INT8 相対誤差: {err_asym.mean() / np.abs(y_fp32).mean():.2%}")
print(f"メモリ節約: FP32={W.nbytes:,} bytes → INT8={Wq.nbytes:,} bytes  ({W.nbytes // Wq.nbytes}倍)")

このコードを実行すると、対称量子化での最大誤差は出力スケールに対し1%未満、平均誤差は0.1%程度に収まります。INT8化はメモリと計算速度を1/4にしながら、精度低下は1%以下というのが典型的な振る舞いです。非対称量子化はパーセンタイルクリッピングで外れ値の影響を抑え、活性化(ReLU後など分布が非対称な値)に対して効きます。実用CNNではこれにQAT(Quantization Aware Training)を組み合わせて誤差をさらに半減し、ImageNet分類で top-1 精度低下を1ポイント未満に抑えるのが現代の標準水準です。

SEU シミュレーションと TMR 多数決

放射線によるビット反転(SEU)がモデル重みに混じったときに何が起こるか、また三重冗長多数決(TMR)でどう守るかを数値で確かめます。

import numpy as np

def inject_seu(weights_int8, ber=1e-5, rng=None):
    """INT8重みにビット反転を注入する
    ber: bit error rate(重み全ビット中、反転する確率)
    """
    rng = rng or np.random.default_rng(0)
    flat = weights_int8.flatten().view(np.uint8).copy()
    n_bits = flat.size * 8
    n_flips = rng.binomial(n_bits, ber)
    if n_flips == 0:
        return weights_int8.copy()
    flip_idx = rng.choice(n_bits, size=n_flips, replace=False)
    for idx in flip_idx:
        byte_idx, bit_idx = idx // 8, idx % 8
        flat[byte_idx] ^= np.uint8(1 << bit_idx)
    return flat.view(np.int8).reshape(weights_int8.shape)

def tmr_majority_vote(*arrays):
    """3つ以上の整数配列の要素ごと多数決
    最頻値を返す(2/3で一致したらその値、全て不一致なら array[0])"""
    stack = np.stack(arrays, axis=0)
    # 各要素について最頻値を取る(簡易版)
    n_voters = stack.shape[0]
    result = stack[0].copy()
    for k in range(stack[0].size):
        idx = np.unravel_index(k, stack[0].shape)
        vals, counts = np.unique(stack[(slice(None),) + idx], return_counts=True)
        if counts.max() >= 2:
            result[idx] = vals[counts.argmax()]
    return result

# 重みを量子化して INT8 で保存
rng = np.random.default_rng(42)
W = (rng.normal(size=(64, 64)) * 0.1).astype(np.float32)
Wq, Ws = quantize_int8_symmetric(W, axis=1)

# 単一回路: 1 コピーで運用 → ビット反転がそのまま影響
W_single = inject_seu(Wq, ber=1e-3, rng=np.random.default_rng(1))

# TMR: 同じ重みを3つ独立に保持し、それぞれにSEUが起きると仮定
W_copy1 = inject_seu(Wq, ber=1e-3, rng=np.random.default_rng(11))
W_copy2 = inject_seu(Wq, ber=1e-3, rng=np.random.default_rng(12))
W_copy3 = inject_seu(Wq, ber=1e-3, rng=np.random.default_rng(13))
W_tmr   = tmr_majority_vote(W_copy1, W_copy2, W_copy3)

# 推論結果への影響
x = rng.normal(size=64).astype(np.float32)
xq, xs = quantize_int8_symmetric(x)

def infer(Wq_local):
    return (Wq_local.astype(np.int32) @ xq.astype(np.int32)).astype(np.float32) * (Ws.squeeze() * xs)

y_ref    = infer(Wq)
y_single = infer(W_single)
y_tmr    = infer(W_tmr)

n_diff_single = np.sum(Wq != W_single)
n_diff_tmr    = np.sum(Wq != W_tmr)
print(f"SEU注入で変化した重み数: 単一={n_diff_single}, TMR後={n_diff_tmr}")
print(f"推論出力 RMSE: 単一={np.sqrt(np.mean((y_ref-y_single)**2)):.4e}, "
      f"TMR={np.sqrt(np.mean((y_ref-y_tmr)**2)):.4e}")

単一コピーでは数千ビットの反転が直接重みを汚染し、推論出力に大きな歪みが乗ります。TMRでは同時に2つ以上のコピーが同じビットを誤る確率がほぼゼロのため、多数決後の重みは原本とほぼ一致し、推論出力もほぼ無傷で残ります。これが先に挙げた $P_{\mathrm{fail}} \approx 3p^2$ の効果が実装上どう現れるかの実例です。実機ではこれをハードウェア(FPGAのTMR合成)かソフトウェア(ECC付きメモリ + スクラビング)で実装し、推論パスのクリティカル箇所を保護します。

FedAvg による衛星間連邦学習

最後に、連邦学習の中核アルゴリズムである FedAvg を最小実装で動かし、衛星ごとに偏ったローカルデータでも集約後にグローバル精度が向上することを確かめます。

import numpy as np

def local_sgd(W, b, X, y, lr=0.05, epochs=3, batch=32, rng=None):
    """局所SGD: ロジスティック回帰の重みを X, y で更新"""
    rng = rng or np.random.default_rng()
    n = X.shape[0]
    for _ in range(epochs):
        idx = rng.permutation(n)
        for start in range(0, n, batch):
            sl = idx[start:start+batch]
            Xb, yb = X[sl], y[sl]
            z = Xb @ W + b
            p = 1.0 / (1.0 + np.exp(-z))         # sigmoid
            grad_W = Xb.T @ (p - yb) / Xb.shape[0]
            grad_b = (p - yb).mean()
            W -= lr * grad_W
            b -= lr * grad_b
    return W, b

def accuracy(W, b, X, y):
    p = 1.0 / (1.0 + np.exp(-(X @ W + b)))
    return np.mean((p >= 0.5) == (y >= 0.5))

# 合成データ: 5衛星, 各衛星が異なる地域分布のデータを観測する
rng = np.random.default_rng(0)
n_satellites = 5
d = 10                                          # 特徴次元(バンド数を模す)
W_true = rng.normal(size=d) * 0.5
b_true = -0.3

# 各衛星のローカルデータ(地域ごとにシフトをかける)
local_data = []
for i in range(n_satellites):
    shift = rng.normal(size=d) * 0.5            # 衛星固有のドメインシフト
    n_i = rng.integers(200, 800)
    X = rng.normal(size=(n_i, d)) + shift
    z = X @ W_true + b_true
    y = (1.0 / (1.0 + np.exp(-z)) > rng.uniform(size=n_i)).astype(np.float32)
    local_data.append((X, y))

# テストデータ(地域ミックス)
X_test = rng.normal(size=(2000, d))
y_test = (1.0 / (1.0 + np.exp(-(X_test @ W_true + b_true))) > rng.uniform(size=2000)).astype(np.float32)

# シナリオA: 1衛星だけのデータで学習(ベースライン)
W_local, b_local = np.zeros(d), 0.0
W_local, b_local = local_sgd(W_local, b_local, *local_data[0], rng=np.random.default_rng(1))
acc_local = accuracy(W_local, b_local, X_test, y_test)

# シナリオB: FedAvg で5衛星を集約
W_global, b_global = np.zeros(d), 0.0
for round_idx in range(10):
    deltas_W, deltas_b, sizes = [], [], []
    for i, (X, y) in enumerate(local_data):
        Wi, bi = W_global.copy(), b_global
        Wi, bi = local_sgd(Wi, bi, X, y, rng=np.random.default_rng(100 + round_idx*10 + i))
        deltas_W.append(Wi)
        deltas_b.append(bi)
        sizes.append(len(y))
    sizes = np.array(sizes, dtype=np.float32)
    weights = sizes / sizes.sum()
    W_global = sum(w * dW for w, dW in zip(weights, deltas_W))
    b_global = float(sum(w * db for w, db in zip(weights, deltas_b)))

acc_fedavg = accuracy(W_global, b_global, X_test, y_test)

print(f"単独衛星モデル精度:    {acc_local:.4f}")
print(f"FedAvg 集約モデル精度: {acc_fedavg:.4f}")
print(f"参加衛星数: {n_satellites}, ラウンド数: 10")
print(f"通信した量: 重み {d}個 × 衛星{n_satellites}機 × 10ラウンド = {d*n_satellites*10}個の浮動小数")
print(f"生データ送信量との比: {sum(len(y) for _, y in local_data) * d / (d*n_satellites*10):.0f}倍の削減")

この実験から、地域ごとに偏った(non-IID な)データでも集約することでテスト精度が改善することが確認できます。さらに重要なのは、各衛星から送信したのが「学習済み重み」だけで、生の撮像データは1点も地上に降ろしていない点です。100MB級の生データを送る代わりに、数KB〜数MBの重みベクトルだけで済むため、通信コストが2〜3桁削減されます。実用の衛星連邦学習では、これに staleness 重み(古い更新を割引)、勾配圧縮、Byzantine 耐性アルゴリズム、差分プライバシ等が追加されますが、根幹は本コードの FedAvg です。

軽量CNN による雲検出 — PyTorch実装

次に、雲検出を模した軽量CNN を実装します。実衛星画像は手元にないため、合成データで構造だけ示します。3バンド(赤・緑・青)の小パッチが「雲を含むか否か」の2値分類問題と仮定します。

import torch
import torch.nn as nn
import torch.nn.functional as F

class CloudNet(nn.Module):
    """衛星オンボード向け軽量雲検出CNN
    入力: (B, 3, 64, 64)  3バンドの64x64パッチ
    出力: (B, 2)         雲あり/なしの2値ロジット"""
    def __init__(self):
        super().__init__()
        # Depthwise-separable convolution で軽量化(MobileNet風)
        self.conv1 = nn.Conv2d(3, 16, 3, padding=1)
        self.dw1   = nn.Conv2d(16, 16, 3, padding=1, groups=16)  # depthwise
        self.pw1   = nn.Conv2d(16, 32, 1)                         # pointwise
        self.dw2   = nn.Conv2d(32, 32, 3, padding=1, groups=32)
        self.pw2   = nn.Conv2d(32, 64, 1)
        self.gap   = nn.AdaptiveAvgPool2d(1)
        self.fc    = nn.Linear(64, 2)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, 2)               # 64→32
        x = F.relu(self.pw1(F.relu(self.dw1(x))))
        x = F.max_pool2d(x, 2)               # 32→16
        x = F.relu(self.pw2(F.relu(self.dw2(x))))
        x = F.max_pool2d(x, 2)               # 16→8
        x = self.gap(x).flatten(1)           # (B, 64)
        return self.fc(x)

model = CloudNet().eval()

# パラメータ数とFLOPsの概算
n_params = sum(p.numel() for p in model.parameters())
print(f"パラメータ数: {n_params:,}")
print(f"モデルサイズ (FP32): {n_params * 4 / 1024:.1f} KB")
print(f"モデルサイズ (INT8): {n_params / 1024:.1f} KB")

# 推論時間の素朴な計測
import time
x = torch.randn(1, 3, 64, 64)
with torch.no_grad():
    for _ in range(3):  # ウォームアップ
        _ = model(x)
    t0 = time.perf_counter()
    for _ in range(100):
        y = model(x)
    dt = (time.perf_counter() - t0) / 100
print(f"CPU推論 1パッチあたり: {dt*1000:.2f} ms")

このネットは数万パラメータの超軽量モデルで、INT8 にすると数十KB に収まります。Movidius Myriad X クラスのVPUなら数百μs/パッチ、Versal AI Edge なら数十μs/パッチで処理可能な規模感です。実用ではこの基本ブロックを積み上げ、入力をマルチスペクトル12〜13バンド、画像サイズを256×256や512×512に拡張します。

CNN構造の重要な工夫は depthwise-separable convolution です。通常の3×3 conv が $C_{\mathrm{in}} \times C_{\mathrm{out}} \times 9$ パラメータなのに対し、depthwise + pointwise の組み合わせは $C_{\mathrm{in}} \times 9 + C_{\mathrm{in}} \times C_{\mathrm{out}}$ で済みます。$C_{\mathrm{in}} = C_{\mathrm{out}} = 64$ なら通常 36864 vs DW-Sep 4672 と8倍近い差。MobileNet/EfficientNet/SqueezeNetなどモバイル系の軽量ネットの基本テクニックです。

FPGAデプロイ用ONNX変換

学習済みPyTorchモデルをFPGA(Versal AI Edge)にデプロイするには、まずONNX形式に変換するのが第一歩です。

import torch
import torch.onnx

model = CloudNet().eval()
dummy_input = torch.randn(1, 3, 64, 64)

# ONNXエクスポート
torch.onnx.export(
    model,
    dummy_input,
    "cloudnet.onnx",
    input_names=["satellite_patch"],
    output_names=["cloud_logits"],
    opset_version=13,
    dynamic_axes={"satellite_patch": {0: "batch"},
                  "cloud_logits":    {0: "batch"}},
)

# エクスポートしたONNXを onnxruntime で検証
import onnxruntime as ort
import numpy as np

sess = ort.InferenceSession("cloudnet.onnx", providers=["CPUExecutionProvider"])
x_np = dummy_input.numpy()
y_onnx = sess.run(None, {"satellite_patch": x_np})[0]
y_torch = model(dummy_input).detach().numpy()

print(f"ONNX 出力: {y_onnx[0]}")
print(f"Torch 出力: {y_torch[0]}")
print(f"最大誤差: {np.max(np.abs(y_onnx - y_torch)):.2e}")

ONNXエクスポートが成功すると、Torch と ONNX Runtime の出力が浮動小数点誤差レベル(1e-6 程度)で一致します。これ以降のFPGAコンパイルは vendor 固有ツールチェーンに渡す段階で、AMDのVitis AIなら vai_q_pytorch で量子化 → vai_c_xir でコンパイル → .xmodel 出力 → 衛星にFOTAで配信、という流れになります。

ONNXは中間表現として地上開発と軌道上ハードウェアの橋渡し役を担います。同じONNXファイルから複数ベンダ(Xilinx, Intel Movidius, NVIDIA Jetson)のターゲットにビルドできるため、ハードウェア依存を最小化できます。

軌道上推論レイテンシのざっくり試算

最後に、軌道上で「火災検知 → 地上アラート」までのエンドツーエンド遅延を簡単に試算してみます。

import numpy as np

# 想定パラメータ
img_size_px       = 4096                    # 撮像 1シーンの一辺ピクセル数
patch_size_px     = 64                      # 推論パッチサイズ
n_patches_per_img = (img_size_px // patch_size_px) ** 2   # = 4096
inference_us      = 50                      # 1パッチあたり推論 50 us (Versal AI Edge想定)
preproc_us        = 20                      # 前処理 20 us / パッチ
postproc_ms       = 5                       # シーン全体の後処理 5 ms

# シーン1枚を処理するのにかかる時間
t_inference = n_patches_per_img * (inference_us + preproc_us) * 1e-6
t_total_onboard = t_inference + postproc_ms * 1e-3

print(f"シーンあたりパッチ数: {n_patches_per_img}")
print(f"オンボード処理時間: {t_total_onboard*1000:.1f} ms")

# 検知 → 次のパスでアラート送信までの遅延
orbit_period_min = 95                       # LEO 軌道周期 約95分
n_gs_passes_per_day = 5                     # 1日あたり地上局可視パス回数
avg_wait_to_next_pass_min = 24*60 / n_gs_passes_per_day / 2  # 平均待ち時間
alert_uplink_s = 2                          # アラート(数百バイト)送信に2秒

t_onboard_total_s = t_total_onboard
t_wait_to_pass_s  = avg_wait_to_next_pass_min * 60
t_end_to_end_min  = (t_onboard_total_s + t_wait_to_pass_s + alert_uplink_s) / 60

print(f"\nエンドツーエンド遅延の内訳")
print(f"  オンボード推論:     {t_onboard_total_s*1000:.1f} ms")
print(f"  次パスまでの待機:    {t_wait_to_pass_s/60:.1f} 分")
print(f"  アラート送信:       {alert_uplink_s:.1f} 秒")
print(f"  合計:              {t_end_to_end_min:.1f} 分")

# 比較: 従来の地上処理ルート(生データを次パスで降ろし、地上で解析)
img_size_GB = (img_size_px ** 2 * 13 * 2) / 1e9   # 13バンド, 16bit
dl_rate_Gbps = 0.5
t_dl_s = img_size_GB * 8 / dl_rate_Gbps
t_ground_processing_s = 60                        # 地上の処理パイプライン 1分仮定
t_baseline_min = (t_wait_to_pass_s + t_dl_s + t_ground_processing_s) / 60
print(f"\n比較: 地上処理ルートでの遅延 {t_baseline_min:.1f} 分")
print(f"オンボードAIによる短縮: {t_baseline_min - t_end_to_end_min:.1f} 分")

数値を眺めると、オンボード処理自体は数百ミリ秒で済むことがわかります。エンドツーエンド遅延の支配項は「次の地上局パスまでの待機時間」(地上局あたり1日5パスで平均144分)であり、これは衛星AIで短縮できない物理制約です。それでも、生データ全部を降ろしてから地上で解析するルートに比べ、ダウンリンク量が3桁減る(数十GB → 数百バイトのアラート)ため、ダウンリンク時間と地上処理時間が消え、検知通知が数分から十数分早く届く構造になっています。

さらに地上局を増やしたり、レーザー衛星間リンクで他衛星経由でルーティングしたり、TDRSのようなデータ中継衛星を経由したりすることで、待機時間自体を分から秒のオーダーに縮める研究が並行して進んでいます。オンボードAIはこの「即時通報インフラ」の必須コンポーネントになります。

まとめ

本記事では、衛星オンボードAIのアーキテクチャを、ハードウェア制約からソフトウェア軽量化、運用までを一気通貫で解説しました。

  • オンボードAIの3つの動機: ダウンリンク帯域節約(雲廃棄で60%+)、災害イベント検知の低遅延化(分→秒)、地上局非可視時間の自律判断
  • 物理的制約: 5〜20Wの電力、真空中の放射放熱、SEU/SEL/SEFI/TIDという4種の放射線損傷モード。これらが GPU よりも FPGA を主役にしてきた理由
  • モデル軽量化: INT8量子化(メモリ1/4・電力1/3)、構造化枝刈り、知識蒸留の3段パイプラインで地上モデルを10倍圧縮しても精度低下を1〜3ポイントに留めるのが現代水準
  • 推論アクセラレータ: Jetson Xavier NX(高性能・要ラジ・ハード化)、Movidius Myriad X(PhiSat-1で実証済み、1W)、Versal AI Edge(ヘテロジニアスSoC、145 TOPS)の使い分け
  • 学習と運用: 基本は「地上で学習、軌道で推論」。継続適応にはアダプタ層の軌道上更新が現実解。FOTAは署名・暗号・ステージング・ロールバックを必須セットで設計する
  • 連邦学習: コンステレーション規模でデータを降ろさず勾配だけ集約する FedAvg/FedAsync。圧縮と階層集約で通信コストを2桁削る研究が進行中
  • 実機: PhiSat-1/2、Orbital Sidekick GHOSt が商用フェーズ。AWS や Loft Orbital が「衛星クラウド」「衛星as a Service」を実証中

ここで提示した実装例(INT8量子化、軽量CNN、ONNX変換、レイテンシ試算)は、地上開発から軌道デプロイまでの「最低限の型」を体験するための入口です。実機では、これらに加えて放射線シミュレーション(CRÈME96等)、FPGAビットストリーム生成(Vitis AI / Quartus)、衛星バスとの統合試験(HW-in-the-loop)、軌道上検証(IOT: in-orbit test)という長いプロセスが控えています。

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