1090ES ADS-B送信機を作ってみた 〜李下に冠を正さず〜

2026/6/1 7M4MON

きっかけ

最近、ドローン向けADS-Bトランスポンダーの存在を知りました。例えば、uAvionixの ping1090i は、2,200 USD します。

「そんなにするのか……。これ、自分で作れないかな?」

そう思ったのが、今回の実験のきっかけでした。

最初に強調しておきますが、架空の航空機情報や、なりすまし(Spoofing)ADS-B信号を実際の電波として送信する行為は極めて危険です。

運航に支障を与えた場合、電波法や航空法などによる刑事罰だけでなく、民事上でも莫大な損害賠償責任を負う可能性があります。

本記事は、あくまで 「ADS-Bという仕組みが、技術的にどのように構成されているのか」 を学習・観察した記録です。

まず受信環境を作る

いきなり送信機を作る前に、まずは「本物のADS-B信号を正しく受信できること」を確認しました。

以下のものを使用しました。

  • RTL-SDR
  • dump1090
  • ADS-B受信ソフト Virtual Radar Server

参考ページを見ながら環境を構築しました。

正常に動作すれば、ADS-B信号を受信し、近くを飛んでいる航空機が地図上に表示されます。

ADS-Bの物理層とハードウェア

ADS-B、正確には 1090ES(1090 MHz Extended Squitter) の物理層は、比較的シンプルです。

項目 内容
周波数 1090 MHz
変調速度 1 Mbps
変調方式 PPM / Pulse Position Modulation

PPMでは、「0」と「1」をパルスの位置で表現します。

1 bit は 1 µs で、例えば以下のように表現されます。

  • 前半にパルス → 1
  • 後半にパルス → 0

つまり、0.5 µs単位でON/OFFを切り替えることで、ビット情報を表します。

この資料に詳細が記載されています。


ブロック図

今回の実験構成は以下のとおりです。



変調器の詳細については、安全上の理由から伏せます。

キャリア周波数を下げた状態でオシロスコープで波形を確認し、想定どおりに動作していそうなことを確認しました。



プリアンブル

ADS-Bフレームの先頭には、8 µs のプリアンブルがあります。

0.5 µs単位で並べると、以下のようになります。

1010000101000000

このプリアンブルを検出することで、受信機は 「ここからADS-Bフレームが始まる」 と認識します。

ADS-Bフレーム構造

例えば、有名な以下のADS-Bフレームがあります。

8D40621D58C382D690C8AC2863A7

これを分解すると、以下のようになります。

8D 40621D 58C382D690C8AC 2863A7
フィールド 内容
8D DF / CA
40621D ICAOアドレス
58C382D690C8AC MEフィールド
2863A7 CRC / パリティ

DFとCA

先頭の 8D には、以下の情報が含まれています。

  • DF / Downlink Format
  • CA / Capability

DF17は Extended Squitter、つまりADS-Bメッセージを表します。CAはトランスポンダー能力を示すフィールドです。

また、MEフィールドの先頭5 bitは Type Code です。このType Codeにより、そのADS-Bデータが何を表しているのかが決まります。

詳細については、以下の資料が参考になります。

ADS-B Decode Guide

地図アプリ上に機影を表示させるには、最低限、以下のメッセージが必要となります。

  • Aircraft Identification
  • Airborne Position Even
  • Airborne Position Odd
  • Airborne Velocity

ADS-Bでは、位置情報を Even / Odd の2種類に分けて送信します。これは CPR / Compact Position Reporting という仕組みです。

最後に24 bit CRCを付ければ、ADS-Bフレームとして成立します。

なお、安全上の理由から、ソースコードは公開しません。

実験用の独自フォーマット

以前、AISの学習のために、架空の船影を使った時計表示プログラムを作成したことがあります。

AISは、いわば船舶版ADS-Bのような仕組みで、船舶の位置や識別情報を周囲に知らせるためのものです。

このプログラムは、AISの電波を実際に送信するわけではありません。アナログ時計の針の位置に相当する場所へ架空の船のマーカーを配置し、そのAIS電文をシリアル経由でOpenCPNへ流し込んで表示させていました。

今回はその仕組みを改造し、1文でマーカー表示に必要な情報を送る独自フォーマットを定義して、PCからマイコンへ位置情報などを渡すことにしました。

NMEA0183風ですが、独自形式なので $P から始めています。

$PFAKE,ADSB,<ICAO_ID>,<AIRCRAFT_NAME>,<LAT>,<LON>,<TRACK_DEG>,<ALT_FT>,<GS_KT>*CS

これをRS422経由でマイコンへ送り、マイコン側でADS-Bフレームへ変換します。

AISの時計表示プログラムでは秒針も含めて毎秒更新していましたが、今回は処理や表示の都合上、分針と時針だけを動かす形にしました。

結果

結果として、Virtual Radar Server上に架空機体を表示することができました。

正直な感想としては、「1090ES ADS-B Out送信機は、RF送信機として見ればそれほど難しくない」というものでした。

1090 MHzの信号生成、PPM変調、ADS-Bフレーム生成などは、既存の無線技術や組み込み技術の延長線上にあります。実験レベルであれば、100ドル以下の部品代で構築できてしまいます。

これは大きな脅威でもあります。

もしこのような送信機が悪意ある形で使われ、GPS Spooferなどと組み合わされたらどうなるのか。存在しない航空機を地図上に表示させたり、実在する航空機に なりすます(※)ことは、技術的には十分に可能です。

そして、今回の実験を通して、改めて分かったことがあります。
それは、「技術的に作れること」と「製品として販売できること」はまったく別物だということです。

本当に難しいのは、その装置が送信するすべての情報が、航空安全上信頼できるものであることを証明することです。
ソフトウェア処理の妥当性、異常時の動作、環境耐性、製造品質、変更管理など、航空機器として求められる確認事項は多岐にわたり、非常に厳格な評価が必要になると思われます。
つまり、「技術的に作れる」ことと、「製品として販売できる」ことの間には、非常に大きな壁があります。
そして、その壁こそが航空機器における参入障壁の本質なのだと思いました。

※ なりすまし対策については、別途HMACを用いた認証タグ方式を考えてみました。

追記:HackRF Oneでも試してみた

Raspberry Pi Picoを使用してADS-B相当の信号を作れたので、次にHackRF OneとGNU Radio Companionでも同じような検証ができるか試してみました。

ただし、この部分についても、実際に送信可能なフローグラフや詳細な手順は公開しません。ADS-Bは航空安全に関わるシステムであり、公開の粒度を誤ると、そのまま危険な再現手順になってしまうためです。

方針としては、以前RFワールド No.50の特設記事「HackRF One+GRCでラジコン解析&エミュレート」で扱った、OOK信号の解析・エミュレーションの経験を応用しました。

そのときに作成したプログラムは、以下に置いてあります。

https://github.com/7m4mon/ook_enc_dec

また、AISの学習で使用した Mictronics/ais-simulator の構成も参考にしました。このAIS Simulatorは、WebSocket PDUで受け取ったデータをGNU Radio側で変調し、HackRFへ流し込む構成になっています。

この2つのフローグラフを組み合わせることで、ADS-B信号を生成することにしました。

構成としては、大きく2通り考えられます。

  • ADS-Bの生フレームをGRC側へ渡し、GRC側でプリアンブル付加やPPM変調を行う方法
  • PC側でプリアンブルやPPM相当の信号列まで生成し、GRC側には単純なビットストリームとして渡す方法

今回は後者を採用しました。GRC側をできるだけ軽くし、ADS-B固有の処理をPC側に寄せたほうが、実験の切り分けがしやすいためです。

PC側では、先ほどの時計表示プログラムを改造し、架空の機体情報からADS-B相当のフレームを生成し、それをプリアンブル付きの信号列に変換してGRCへ流し込むようにしました。

このとき、PC側ではADS-Bのビット列をPPM相当のON/OFFパターンへ分解るところまで担当します。その後、GRC側でHackRFへ渡すストリームのサンプルレートに合わせてオーバーサンプリングしています。GRC側でADS-B固有の処理を行うのではなく、GRCから見ると単なるON/OFFのサンプル列として扱えるようにした、というのが今回の構成のポイントです。

実際に試すと、GRC側はある程度のバッファが溜まらないと安定して送信を開始しないため、1つのメッセージの後ろに無信号区間を追加することで動作が安定しました。このあたりはGNU Radioのストリーム処理やバッファリングの都合によるものと思われます。

オシロスコープで確認した範囲では、自作のPPM変調器よりも、HackRFを使った場合のほうが波形としては整って見えました。

なお、ADS-B送信に関するGNU RadioやSDRの公開事例は、すでにGitHub上にいくつか存在します。たとえば、以下のようなリポジトリがあります。

  • krono-i2/gr-spoof1090
  • osmocom/osmo-adsb-gen
  • ktauchathuranga/adsb-tx

今さら私が追加で実装例を公開しても、社会的なインパクトがあるわけではなさそうですが、そのまま動作する手順を公開することにはリスクがあります。

今回の検証は、ソフトウェア無線を使うとデジタル信号処理とRFの境界をかなり身近に扱える、ということを再確認する実験でした。
広帯域信号のリプレイ、AISのGMSK信号、そして今回のようなPPM信号まで、同じSDR環境の上で発想を横展開できるのは面白いところです。HackRFは測定器でも完成品の無線機でもありませんが、信号処理を実際のRFに近い形で観察するための実験台としては、とてもよくできた道具だと思います。