ΠΡΠΈΠ²Π΅Ρ Π₯Π°Π±Ρ. ΠΠ°Π²Π΅ΡΠ½ΠΎΠ΅ ΠΊΠ°ΠΆΠ΄ΡΠΉ, ΠΊΡΠΎ Ρ ΠΎΡΡ ΡΠ°Π· Π²ΡΡΡΠ΅ΡΠ°Π» ΠΈΠ»ΠΈ ΠΏΡΠΎΠ²ΠΎΠΆΠ°Π» ΡΠΎΠ΄ΡΡΠ²Π΅Π½Π½ΠΈΠΊΠΎΠ² ΠΈΠ»ΠΈ Π΄ΡΡΠ·Π΅ΠΉ Π½Π° ΡΠ°ΠΌΠΎΠ»Π΅Ρ, ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π»ΡΡ Π±Π΅ΡΠΏΠ»Π°ΡΠ½ΡΠΌ ΡΠ΅ΡΠ²ΠΈΡΠΎΠΌ Flightradar24. ΠΡΠΎ Π²Π΅ΡΡΠΌΠ° ΡΠ΄ΠΎΠ±Π½ΡΠΉ ΡΠΏΠΎΡΠΎΠ± ΠΎΡΡΠ»Π΅ΠΆΠΈΠ²Π°Π½ΠΈΡ ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΡ ΡΠ°ΠΌΠΎΠ»Π΅ΡΠ° Π² ΡΠ΅Π°Π»ΡΠ½ΠΎΠΌ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ.
Π
ΠΡΡΠΎΡΠΈΡ
ΠΡΠ΅Π²ΠΈΠ΄Π½ΠΎ, ΡΡΠΎ Π΄Π°Π½Π½ΡΠ΅ ΠΎ ΡΠ°ΠΌΠΎΠ»Π΅ΡΠ°Ρ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡΡΡ Π½Π΅ Π΄Π»Ρ ΡΠΎΠ³ΠΎ, ΡΡΠΎΠ±Ρ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΠΈ Π²ΠΈΠ΄Π΅Π»ΠΈ ΠΈΡ Π½Π° ΡΠ²ΠΎΠΈΡ ΡΠΌΠ°ΡΡΡΠΎΠ½Π°Ρ . Π‘ΠΈΡΡΠ΅ΠΌΠ° Π½Π°Π·ΡΠ²Π°Π΅ΡΡΡ ADSβB (Automatic dependent surveillanceβbroadcast), ΠΈ ΡΠ»ΡΠΆΠΈΡ Π΄Π»Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠΉ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠΈ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ ΠΎ Π²ΠΎΠ·Π΄ΡΡΠ½ΠΎΠΌ ΡΡΠ΄Π½Π΅ Π² Π΄ΠΈΡΠΏΠ΅ΡΡΠ΅ΡΡΠΊΠΈΠΉ ΡΠ΅Π½ΡΡ β ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡΡΡ Π΅Π³ΠΎ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡ, ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΡ, Π½Π°ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅, ΡΠΊΠΎΡΠΎΡΡΡ, Π²ΡΡΠΎΡΠ° ΠΈ ΠΏΡΠΎΡΠΈΠ΅ Π΄Π°Π½Π½ΡΠ΅. Π Π°Π½Π΅Π΅, Π΄ΠΎ ΠΏΠΎΡΠ²Π»Π΅Π½ΠΈΡ ΡΠ°ΠΊΠΈΡ ΡΠΈΡΡΠ΅ΠΌ, Π΄ΠΈΡΠΏΠ΅ΡΡΠ΅Ρ ΠΌΠΎΠ³ Π²ΠΈΠ΄Π΅ΡΡ Π»ΠΈΡΡ ΡΠΎΡΠΊΡ Π½Π° ΡΠ°Π΄Π°ΡΠ΅. ΠΡΠΎΠ³ΠΎ ΡΡΠ°Π»ΠΎ Π½Π΅Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ, ΠΊΠΎΠ³Π΄Π° ΡΠ°ΠΌΠΎΠ»Π΅ΡΠΎΠ² ΡΡΠ°Π»ΠΎ ΡΠ»ΠΈΡΠΊΠΎΠΌ ΠΌΠ½ΠΎΠ³ΠΎ.
Π’Π΅Ρ Π½ΠΈΡΠ΅ΡΠΊΠΈ, ADS-B ΡΠΎΡΡΠΎΠΈΡ ΠΈΠ· ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡΠΈΠΊΠ° Π½Π° Π²ΠΎΠ·Π΄ΡΡΠ½ΠΎΠΌ ΡΡΠ΄Π½Π΅, ΠΊΠΎΡΠΎΡΡΠΉ ΠΏΠ΅ΡΠΈΠΎΠ΄ΠΈΡΠ΅ΡΠΊΠΈ ΠΏΠΎΡΡΠ»Π°Π΅Ρ ΠΏΠ°ΠΊΠ΅ΡΡ Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠ΅ΠΉ Π½Π° Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ Π²ΡΡΠΎΠΊΠΎΠΉ ΡΠ°ΡΡΠΎΡΠ΅ 1090 ΠΠΡ (Π΅ΡΡΡ ΠΈ Π΄ΡΡΠ³ΠΈΠ΅ ΡΠ΅ΠΆΠΈΠΌΡ, Π½ΠΎ Π½Π°ΠΌ ΠΎΠ½ΠΈ Π½Π΅ ΡΠ°ΠΊ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ΅Π½Ρ, Ρ.ΠΊ. ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΡ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡΡΡ ΡΠΎΠ»ΡΠΊΠΎ Π·Π΄Π΅ΡΡ). Π Π°Π·ΡΠΌΠ΅Π΅ΡΡΡ, ΠΊΡΠΎΠΌΠ΅ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡΠΈΠΊΠ°, Π΅ΡΡΡ ΠΈ ΠΏΡΠΈΠ΅ΠΌΠ½ΠΈΠΊ Π³Π΄Π΅-ΡΠΎ Π² Π°ΡΡΠΎΠΏΠΎΡΡΡ, Π½ΠΎ Π΄Π»Ρ Π½Π°Ρ, ΠΊΠ°ΠΊ Π΄Π»Ρ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Π΅ΠΉ, ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ΅Π½ ΠΏΡΠΈΠ΅ΠΌΠ½ΠΈΠΊ Π½Π°Ρ ΡΠΎΠ±ΡΡΠ²Π΅Π½Π½ΡΠΉ.
ΠΡΡΠ°ΡΠΈ, Π΄Π»Ρ ΡΡΠ°Π²Π½Π΅Π½ΠΈΡ, ΠΏΠ΅ΡΠ²Π°Ρ ΡΠ°ΠΊΠ°Ρ ΡΠΈΡΡΠ΅ΠΌΠ°, Airnav Radarbox, ΡΠ°ΡΡΠΈΡΠ°Π½Π½Π°Ρ Π½Π° ΠΎΠ±ΡΡΠ½ΡΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Π΅ΠΉ, ΠΏΠΎΡΠ²ΠΈΠ»Π°ΡΡ Π² 2007 Π³ΠΎΠ΄Ρ, ΠΈ ΡΡΠΎΠΈΠ»Π° ΠΎΠΊΠΎΠ»ΠΎ 900$, Π΅ΡΠ΅ ΠΎΠΊΠΎΠ»ΠΎ 250$ Π² Π³ΠΎΠ΄ ΡΡΠΎΠΈΠ»Π° ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠ° Π½Π° ΡΠ΅ΡΠ΅Π²ΡΠ΅ ΡΠ΅ΡΠ²ΠΈΡΡ.
ΠΡΠ·ΡΠ²Ρ ΡΠ΅Ρ
ΠΏΠ΅ΡΠ²ΡΡ
ΡΠΎΡΡΠΈΠΉΡΠΊΠΈΡ
Π²Π»Π°Π΄Π΅Π»ΡΡΠ΅Π² ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΈΡΠ°ΡΡ Π½Π° ΡΠΎΡΡΠΌΠ΅
ΠΡΠΈΠ΅ΠΌ ΡΠΈΠ³Π½Π°Π»ΠΎΠ²
ΠΠ»Ρ Π½Π°ΡΠ°Π»Π°, ΡΠΈΠ³Π½Π°Π» Π½ΡΠΆΠ½ΠΎ Π·Π°ΠΏΠΈΡΠ°ΡΡ. ΠΠ΅ΡΡ ΡΠΈΠ³Π½Π°Π» ΠΈΠΌΠ΅Π΅Ρ Π΄Π»ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ Π²ΡΠ΅Π³ΠΎ Π»ΠΈΡΡ 120 ΠΌΠΈΠΊΡΠΎΡΠ΅ΠΊΡΠ½Π΄, ΠΏΠΎΡΡΠΎΠΌΡ ΡΡΠΎΠ±Ρ ΠΊΠΎΠΌΡΠΎΡΡΠ½ΠΎ ΡΠ°Π·ΠΎΠ±ΡΠ°ΡΡ Π΅Π³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ, ΠΆΠ΅Π»Π°ΡΠ΅Π»Π΅Π½ SDR-ΠΏΡΠΈΠ΅ΠΌΠ½ΠΈΠΊ Ρ ΡΠ°ΡΡΠΎΡΠΎΠΉ Π΄ΠΈΡΠΊΡΠ΅ΡΠΈΠ·Π°ΡΠΈΠΈ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅ 5ΠΠΡ.
ΠΠΎΡΠ»Π΅ Π·Π°ΠΏΠΈΡΠΈ ΠΌΡ ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌ WAV-ΡΠ°ΠΉΠ» Ρ ΡΠ°ΡΡΠΎΡΠΎΠΉ Π΄ΠΈΡΠΊΡΠ΅ΡΠΈΠ·Π°ΡΠΈΠΈ 5000000 ΡΠ΅ΠΌΠΏΠ»ΠΎΠ²/ΡΠ΅ΠΊ, 30 ΡΠ΅ΠΊΡΠ½Π΄ ΡΠ°ΠΊΠΎΠΉ Π·Π°ΠΏΠΈΡΠΈ Β«Π²Π΅ΡΡΡΒ» ΠΎΠΊΠΎΠ»ΠΎ 500ΠΠ±. Π‘Π»ΡΡΠ°ΡΡ Π΅Ρ ΠΌΠ΅Π΄ΠΈΠ°ΠΏΠ»Π΅Π΅ΡΠΎΠΌ ΡΠ°Π·ΡΠΌΠ΅Π΅ΡΡΡ, Π±Π΅ΡΠΏΠΎΠ»Π΅Π·Π½ΠΎ β ΡΠ°ΠΉΠ» ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ Π½Π΅ Π·Π²ΡΠΊ, Π° Π½Π΅ΠΏΠΎΡΡΠ΅Π΄ΡΡΠ²Π΅Π½Π½ΠΎ ΠΎΡΠΈΡΡΠΎΠ²Π°Π½Π½ΡΠΉ ΡΠ°Π΄ΠΈΠΎΡΠΈΠ³Π½Π°Π» β ΠΈΠΌΠ΅Π½Π½ΠΎ ΡΠ°ΠΊ ΡΠ°Π±ΠΎΡΠ°Π΅Ρ Software Defined Radio.
ΠΡΠΊΡΡΠ²Π°ΡΡ ΠΈ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡ ΡΠ°ΠΉΠ» ΠΌΡ Π±ΡΠ΄Π΅ΠΌ Ρ ΠΏΠΎΠΌΠΎΡΡΡ Python. ΠΠ΅Π»Π°ΡΡΠΈΠ΅ ΠΏΠΎΡΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈΡΠΎΠ²Π°ΡΡ ΡΠ°ΠΌΠΎΡΡΠΎΡΡΠ΅Π»ΡΠ½ΠΎ, ΠΌΠΎΠ³ΡΡ ΡΠΊΠ°ΡΠ°ΡΡ ΠΏΡΠΈΠΌΠ΅Ρ Π·Π°ΠΏΠΈΡΠΈ
ΠΠ°Π³ΡΡΠ·ΠΈΠΌ ΡΠ°ΠΉΠ», ΠΈ ΠΏΠΎΡΠΌΠΎΡΡΠΈΠΌ ΡΡΠΎ Π²Π½ΡΡΡΠΈ.
from scipy.io import wavfile
import matplotlib.pyplot as plt
import numpy as np
fs, data = wavfile.read("adsb_20190311_191728Z_1090000kHz_RF.wav")
data = data.astype(float)
I, Q = data[:, 0], data[:, 1]
A = np.sqrt(I*I + Q*Q)
plt.plot(A)
plt.show()
Π Π΅Π·ΡΠ»ΡΡΠ°Ρ: ΠΌΡ Π²ΠΈΠ΄ΠΈΠΌ ΡΠ²Π½ΡΠ΅ Β«ΠΈΠΌΠΏΡΠ»ΡΡΡΒ» Π½Π° ΡΠΎΠ½Π΅ ΡΡΠΌΠ°.
ΠΠ°ΠΆΠ΄ΡΠΉ Β«ΠΈΠΌΠΏΡΠ»ΡΡΒ» β ΡΡΠΎ ΠΈ Π΅ΡΡΡ ΡΠΈΠ³Π½Π°Π», ΡΡΡΡΠΊΡΡΡΡ ΠΊΠΎΡΠΎΡΠΎΠ³ΠΎ Ρ
ΠΎΡΠΎΡΠΎ Π²ΠΈΠ΄Π½ΠΎ, Π΅ΡΠ»ΠΈ ΡΠ²Π΅Π»ΠΈΡΠΈΡΡ ΡΠ°Π·ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ Π½Π° Π³ΡΠ°ΡΠΈΠΊΠ΅.
ΠΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ Π²ΠΈΠ΄Π΅ΡΡ, ΠΊΠ°ΡΡΠΈΠ½ΠΊΠ° Π²ΠΏΠΎΠ»Π½Π΅ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΠ΅Ρ ΡΠΎΠΌΡ, ΡΡΠΎ ΠΏΡΠΈΠ²Π΅Π΄Π΅Π½ΠΎ Π² ΠΎΠΏΠΈΡΠ°Π½ΠΈΠΈ Π²ΡΡΠ΅. ΠΠΎΠΆΠ½ΠΎ ΠΏΡΠΈΡΡΡΠΏΠ°ΡΡ ΠΊ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ΅ Π΄Π°Π½Π½ΡΡ
.
ΠΠ΅ΠΊΠΎΠ΄ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅
ΠΠ»Ρ Π½Π°ΡΠ°Π»Π°, Π½ΡΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡΡΠΈΡΡ Π±ΠΈΡΠΎΠ²ΡΠΉ ΠΏΠΎΡΠΎΠΊ. Π‘Π°ΠΌ ΡΠΈΠ³Π½Π°Π» Π·Π°ΠΊΠΎΠ΄ΠΈΡΠΎΠ²Π°Π½ Ρ ΠΏΠΎΠΌΠΎΡΡΡ manchester encoding:
ΠΠ· ΡΠ°Π·Π½ΠΈΡΡ ΡΡΠΎΠ²Π½Π΅ΠΉ Π² ΠΏΠΎΠ»ΡΠ±Π°ΠΉΡΠ°Ρ
Π»Π΅Π³ΠΊΠΎ ΠΏΠΎΠ»ΡΡΠΈΡΡ ΡΠ΅Π°Π»ΡΠ½ΡΠ΅ Β«0Β» ΠΈ Β«1Β».
bits_str = ""
for p in range(8):
pos = start_data + bit_len*p
p1, p2 = A[pos: pos + bit_len/2], A[pos + bit_len/2: pos + bit_len]
avg1, avg2 = np.average(p1), np.average(p2)
if avg1 < avg2:
bits_str += "0"
elif avg1 > avg2:
bits_str += "1"
Π‘ΡΡΡΠΊΡΡΡΠ° ΡΠ°ΠΌΠΎΠ³ΠΎ ΡΠΈΠ³Π½Π°Π»Π° ΠΈΠΌΠ΅Π΅Ρ ΡΠ»Π΅Π΄ΡΡΡΠΈΠΉ Π²ΠΈΠ΄:
Π Π°ΡΡΠΌΠΎΡΡΠΈΠΌ ΠΏΠΎΠ»Ρ Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎ.
DF (Downlink Format, 5 Π±ΠΈΡ) β ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ΅Ρ ΡΠΈΠΏ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ. ΠΡ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΡΠΈΠΏΠΎΠ²:
(
ΠΠ°Ρ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΡΠ΅Ρ ΡΠΎΠ»ΡΠΊΠΎ ΡΠΈΠΏ DF17, Ρ.ΠΊ. ΠΈΠΌΠ΅Π½Π½ΠΎ ΠΎΠ½ ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΡ Π²ΠΎΠ·Π΄ΡΡΠ½ΠΎΠ³ΠΎ ΡΡΠ΄Π½Π°.
ICAO (24 Π±ΠΈΡΠ°) β ΠΌΠ΅ΠΆΠ΄ΡΠ½Π°ΡΠΎΠ΄Π½ΡΠΉ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΡΠΉ ΠΊΠΎΠ΄ Π²ΠΎΠ·Π΄ΡΡΠ½ΠΎΠ³ΠΎ ΡΡΠ΄Π½Π°. ΠΡΠΎΠ²Π΅ΡΠΈΡΡ ΡΠ°ΠΌΠΎΠ»Π΅Ρ ΠΏΠΎ Π΅Π³ΠΎ ΠΊΠΎΠ΄Ρ ΠΌΠΎΠΆΠ½ΠΎ
ΠΡΠ°Π²ΠΊΠ°: Π²
DATA (56 ΠΈΠ»ΠΈ 112 Π±ΠΈΡ) β ΡΠΎΠ±ΡΡΠ²Π΅Π½Π½ΠΎ Π΄Π°Π½Π½ΡΠ΅, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΌΡ ΠΈ Π±ΡΠ΄Π΅ΠΌ Π΄Π΅ΠΊΠΎΠ΄ΠΈΡΠΎΠ²Π°ΡΡ. ΠΠ΅ΡΠ²ΡΠ΅ 5 Π±ΠΈΡ Π΄Π°Π½Π½ΡΡ β ΠΏΠΎΠ»Π΅ Type Code, ΡΠΎΠ΄Π΅ΡΠΆΠ°ΡΠ΅Π΅ ΠΏΠΎΠ΄ΡΠΈΠΏ Ρ ΡΠ°Π½ΡΡΠΈΡ ΡΡ Π΄Π°Π½Π½ΡΡ (Π½Π΅ ΠΏΡΡΠ°ΡΡ Ρ DF). Π’Π°ΠΊΠΈΡ ΡΠΈΠΏΠΎΠ² Π΄ΠΎΠ²ΠΎΠ»ΡΠ½ΠΎ ΠΌΠ½ΠΎΠ³ΠΎ:
(
Π Π°Π·Π±Π΅ΡΠ΅ΠΌ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΏΡΠΈΠΌΠ΅ΡΠΎΠ² ΠΏΠ°ΠΊΠ΅ΡΠΎΠ².
Aircraft identification
ΠΡΠΈΠΌΠ΅Ρ Π² Π±ΠΈΠ½Π°ΡΠ½ΠΎΠΌ Π²ΠΈΠ΄Π΅:
00100 011 000101 010111 000111 110111 110001 111000
ΠΠΎΠ»Ρ Π΄Π°Π½Π½ΡΡ :
+------+------+------+------+------+------+------+------+------+------+
| TC,5 | EC,3 | C1,6 | C2,6 | C3,6 | C4,6 | C5,6 | C6,6 | C7,6 | C8,6 |
+------+------+------+------+------+------+------+------+------+------+
TC = 00100b = 4, ΠΊΠ°ΠΆΠ΄ΡΠΉ ΡΠΈΠΌΠ²ΠΎΠ» C1-C8 ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ ΠΊΠΎΠ΄Ρ, ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠΈΠ΅ ΠΈΠ½Π΄Π΅ΠΊΡΠ°ΠΌ Π² ΡΡΡΠΎΠΊΠ΅:
#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######
Π Π°ΡΠΊΠΎΠ΄ΠΈΡΠΎΠ²Π°Π² ΡΡΡΠΎΠΊΡ, Π½Π΅ΡΠ»ΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡΡΠΈΡΡ ΠΊΠΎΠ΄ ΡΠ°ΠΌΠΎΠ»Π΅ΡΠ°: EWG7184
symbols = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######"
code_str = ""
for p in range(8):
c = int(bits_str[8 + 6*p:8 + 6*(p + 1)], 2)
code_str += symbols[c]
print("Aircraft Identification:", code_str.replace('#', ''))
Airborne position
ΠΡΠ»ΠΈ Ρ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ Π²ΡΠ΅ ΠΏΡΠΎΡΡΠΎ, ΡΠΎ Ρ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠ°ΠΌΠΈ ΠΏΠΎΡΠ»ΠΎΠΆΠ½Π΅Π΅. ΠΠ½ΠΈ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡΡΡ Π² Π²ΠΈΠ΄Π΅ 2Ρ , ΡΠ΅ΡΠ½ΡΡ ΠΈ Π½Π΅ΡΠ΅ΡΠ½ΡΡ ΡΡΠ΅ΠΉΠΌΠΎΠ². ΠΠΎΠ΄ ΠΏΠΎΠ»Ρ TC = 01011b = 11.
ΠΡΠΈΠΌΠ΅Ρ ΡΠ΅ΡΠ½ΠΎΠ³ΠΎ ΠΈ Π½Π΅ΡΠ΅ΡΠ½ΠΎΠ³ΠΎ ΠΏΠ°ΠΊΠ΅ΡΠΎΠ²:
01011 000 000101110110 00 10111000111001000 10000110101111001
01011 000 000110010000 01 10010011110000110 10000011110001000
Π‘Π°ΠΌΠΎ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΠ΅ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°Ρ ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΠΈΡ ΠΏΠΎ Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ Ρ ΠΈΡΡΠΎΠΉ ΡΠΎΡΠΌΡΠ»Π΅:
Π― Π½Π΅ ΡΠΏΠ΅ΡΠΈΠ°Π»ΠΈΡΡ ΠΏΠΎ ΠΠΠ‘, ΡΠ°ΠΊ ΡΡΠΎ ΠΎΡΠΊΡΠ΄Π° ΠΎΠ½ΠΎ Π²ΡΠ²ΠΎΠ΄ΠΈΡΡΡ, Π½Π΅ Π·Π½Π°Ρ. ΠΡΠΎ Π² ΠΊΡΡΡΠ΅, Π½Π°ΠΏΠΈΡΠΈΡΠ΅ Π² ΠΊΠΎΠΌΠΌΠ΅Π½ΡΠ°ΡΠΈΡΡ .
ΠΡΡΠΎΡΠ° ΡΡΠΈΡΠ°Π΅ΡΡΡ ΠΏΡΠΎΡΠ΅ β Π² Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΎΡ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ³ΠΎ Π±ΠΈΡΠ°, ΠΎΠ½Π° ΠΌΠΎΠΆΠ΅Ρ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΡΡΡΡ Π»ΠΈΠ±ΠΎ ΠΊΡΠ°ΡΠ½ΠΎΠΉ 25, Π»ΠΈΠ±ΠΎ 100 ΡΡΡΠ°ΠΌ.
Airborne Velocity
ΠΠ°ΠΊΠ΅Ρ Ρ TC=19. ΠΠ½ΡΠ΅ΡΠ΅ΡΠ½ΠΎ ΡΡΡ ΡΠΎ, ΡΡΠΎ ΡΠΊΠΎΡΠΎΡΡΡ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΠΊΠ°ΠΊ ΡΠΎΡΠ½Π°Ρ, ΠΎΡΠ½ΠΎΡΠΈΡΠ΅Π»ΡΠ½ΠΎ Π·Π΅ΠΌΠ»ΠΈ (Ground Speed), ΡΠ°ΠΊ ΠΈ Π²ΠΎΠ·Π΄ΡΡΠ½Π°Ρ, ΠΈΠ·ΠΌΠ΅ΡΡΠ΅ΠΌΠ°Ρ Π΄Π°ΡΡΠΈΠΊΠΎΠΌ ΡΠ°ΠΌΠΎΠ»Π΅ΡΠ° (Airspeed). ΠΡΠ΅ ΠΏΠ΅ΡΠ΅Π΄Π°Π΅ΡΡΡ ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²ΠΎ ΡΠ°Π·Π½ΡΡ ΠΏΠΎΠ»Π΅ΠΉ:
ΠΠ°ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅
ΠΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ Π²ΠΈΠ΄Π΅ΡΡ, ΡΠ΅Ρ Π½ΠΎΠ»ΠΎΠ³ΠΈΡ ADS-B ΡΡΠ°Π»Π° ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½ΡΠΌ ΡΠΈΠΌΠ±ΠΈΠΎΠ·ΠΎΠΌ, ΠΊΠΎΠ³Π΄Π° ΠΊΠ°ΠΊΠΎΠΉ-Π»ΠΈΠ±ΠΎ ΡΡΠ°Π½Π΄Π°ΡΡ ΠΏΡΠΈΠ³ΠΎΠΆΠ΄Π°Π΅ΡΡΡ Π½Π΅ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠΈΠΎΠ½Π°Π»Π°ΠΌ, Π½ΠΎ ΠΈ ΠΎΠ±ΡΡΠ½ΡΠΌ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΠΌ. ΠΠΎ ΡΠ°Π·ΡΠΌΠ΅Π΅ΡΡΡ, ΠΊΠ»ΡΡΠ΅Π²ΡΡ ΡΠΎΠ»Ρ Π² ΡΡΠΎΠΌ ΡΡΠ³ΡΠ°Π»ΠΎ ΡΠ΄Π΅ΡΠ΅Π²Π»Π΅Π½ΠΈΠ΅ ΡΠ΅Ρ Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ ΡΠΈΡΡΠΎΠ²ΡΡ SDR-ΠΏΡΠΈΠ΅ΠΌΠ½ΠΈΠΊΠΎΠ², ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡΡΠΈΠΌ Π½Π° Π΄Π΅Π²Π°ΠΉΡΠ΅ Π±ΡΠΊΠ²Π°Π»ΡΠ½ΠΎ Β«Π·Π° ΠΊΠΎΠΏΠ΅ΠΉΠΊΠΈΒ» ΠΏΡΠΈΠ½ΠΈΠΌΠ°ΡΡ ΡΠΈΠ³Π½Π°Π»Ρ Ρ ΡΠ°ΡΡΠΎΡΠΎΠΉ Π²ΡΡΠ΅ Π³ΠΈΠ³Π°Π³Π΅ΡΡΠ°.
Π ΡΠ°ΠΌΠΎΠΌ ΡΡΠ°Π½Π΄Π°ΡΡΠ΅ ΡΠ°Π·ΡΠΌΠ΅Π΅ΡΡΡ, Π³ΠΎΡΠ°Π·Π΄ΠΎ Π±ΠΎΠ»ΡΡΠ΅ Π²ΡΠ΅Π³ΠΎ. ΠΠ΅Π»Π°ΡΡΠΈΠ΅ ΠΌΠΎΠ³ΡΡ ΠΏΠΎΡΠΌΠΎΡΡΠ΅ΡΡ PDF Π½Π° ΡΡΡΠ°Π½ΠΈΡΠ΅
ΠΡΡΠ΄ Π»ΠΈ ΠΌΠ½ΠΎΠ³ΠΈΠΌ ΠΏΡΠΈΠ³ΠΎΠ΄ΠΈΡΡΡ Π²ΡΠ΅ Π²ΡΡΠ΅Π½Π°ΠΏΠΈΡΠ°Π½Π½ΠΎΠ΅, Π½ΠΎ ΠΏΠΎ ΠΊΡΠ°ΠΉΠ½Π΅ΠΉ ΠΌΠ΅ΡΠ΅ ΠΎΠ±ΡΠ°Ρ ΠΈΠ΄Π΅Ρ ΡΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΡΡΠΎ ΡΠ°Π±ΠΎΡΠ°Π΅Ρ, Π½Π°Π΄Π΅ΡΡΡ, ΠΎΡΡΠ°Π»Π°ΡΡ.
ΠΡΡΠ°ΡΠΈ, Π³ΠΎΡΠΎΠ²ΡΠΉ Π΄Π΅ΠΊΠΎΠ΄Π΅Ρ Π½Π° Python ΡΠΆΠ΅ ΡΡΡΠ΅ΡΡΠ²ΡΠ΅Ρ, Π΅Π³ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΠ·ΡΡΠΈΡΡ
ΠΡΡ
ΠΎΠ΄Π½ΡΠΉ ΠΊΠΎΠ΄ ΠΏΠ°ΡΡΠ΅ΡΠ°, ΠΎΠΏΠΈΡΠ°Π½Π½ΡΠΉ Π² ΡΡΠ°ΡΡΠ΅, ΠΏΡΠΈΠ²Π΅Π΄Π΅Π½ ΠΏΠΎΠ΄ ΠΊΠ°ΡΠΎΠΌ. ΠΡΠΎ ΡΠ΅ΡΡΠΎΠ²ΡΠΉ ΠΏΡΠΈΠΌΠ΅Ρ, Π½Π΅ ΠΏΡΠ΅ΡΠ΅Π½Π΄ΡΡΡΠΈΠΉ Π½Π° production, Π½ΠΎ ΠΊΠΎΠ΅-ΡΡΠΎ Π² Π½Π΅ΠΌ ΡΠ°Π±ΠΎΡΠ°Π΅Ρ, ΠΈ ΠΏΠ°ΡΡΠΈΡΡ Π·Π°ΠΏΠΈΡΠ°Π½Π½ΡΠΉ Π²ΡΡΠ΅ ΡΠ°ΠΉΠ», ΠΈΠΌ ΠΌΠΎΠΆΠ½ΠΎ.
ΠΡΡ
ΠΎΠ΄Π½ΡΠΉ ΠΊΠΎΠ΄ (Python)
from __future__ import print_function
from scipy.io import wavfile
from scipy import signal
import matplotlib.pyplot as plt
import numpy as np
import math
import sys
def parse_message(data, start, bit_len):
max_len = bit_len*128
A = data[start:start + max_len]
A = signal.resample(A, 10*max_len)
bits = np.zeros(10*max_len)
bit_len *= 10
start_data = bit_len*8
# Parse first 8 bits
bits_str = ""
for p in range(8):
pos = start_data + bit_len*p
p1, p2 = A[pos: pos + bit_len/2], A[pos + bit_len/2: pos + bit_len]
avg1, avg2 = np.average(p1), np.average(p2)
if avg1 < avg2:
bits_str += "0"
elif avg1 > avg2:
bits_str += "1"
df = int(bits_str[0:5], 2)
# Aircraft address (db - https://junzis.com/adb/?q=3b1c5c )
bits_str = ""
for p in range(8, 32):
pos = start_data + bit_len * p
p1, p2 = A[pos: pos + bit_len / 2], A[pos + bit_len / 2: pos + bit_len]
avg1, avg2 = np.average(p1), np.average(p2)
if avg1 < avg2:
bits_str += "0"
elif avg1 > avg2:
bits_str += "1"
# print "Aircraft address:", bits_str, hex(int(bits_str, 2))
address = hex(int(bits_str, 2))
# Filter specific aircraft (optional)
# if address != "0x3c5ee2":
# return
if df == 16 or df == 17 or df == 18 or df == 19 or df == 20 or df == 21:
# print "Pos:", start, "DF:", msg_type
# Data (56bit)
bits_str = ""
for p in range(32, 88):
pos = start_data + bit_len*p
p1, p2 = A[pos: pos + bit_len/2], A[pos + bit_len/2: pos + bit_len]
avg1, avg2 = np.average(p1), np.average(p2)
if avg1 < avg2:
bits_str += "0"
# bits[pos + bit_len / 2] = 50
elif avg1 > avg2:
bits_str += "1"
# http://www.lll.lu/~edward/edward/adsb/DecodingADSBposition.html
# print "Data:"
# print bits_str[:8], bits_str[8:20], bits_str[20:22], bits_str[22:22+17], bits_str[39:39+17]
# Type Code:
tc, ec = int(bits_str[:5], 2), int(bits_str[5:8], 2)
# print("DF:", df, "TC:", tc)
# 1 - 4 Aircraft identification
# 5 - 8 Surface position
# 9 - 18 Airborne position (w/ Baro Altitude)
# 19 Airborne velocities
if tc >= 1 and tc <= 4: # and (df == 17 or df == 18):
print("Aircraft address:", address)
print("Data:")
print(bits_str[:8], bits_str[8:14], bits_str[14:20], bits_str[20:26], bits_str[26:32], bits_str[32:38], bits_str[38:44])
symbols = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######"
code_str = ""
for p in range(8):
c = int(bits_str[8 + 6*p:8 + 6*(p + 1)], 2)
code_str += symbols[c]
print("Aircraft Identification:", code_str.replace('#', ''))
print()
if tc == 11:
print("Aircraft address:", address)
print("Data: (11)")
print(bits_str[:8], bits_str[8:20], bits_str[20:22], bits_str[22:22+17], bits_str[39:39+17])
# Bit 22 contains the F flag which indicates which CPR format is used (odd or even)
# First frame has F flag = 0 so is even and the second frame has F flag = 1 so odd
# f = bits_str[21:22]
# print("F:", int(f, 2))
# Altitude
alt1b = bits_str[8:20]
if alt1b[-5] == '1':
bits = alt1b[:-5] + alt1b[-4:]
n = int(bits, 2)
alt_ft = n*25 - 1000
print("Alt (ft)", alt_ft)
# lat_dec = int(bits_str[22:22+17], 2)
# lon_dec = int(bits_str[39:39+17], 2)
# print("Lat/Lon:", lat_dec, lon_dec)
# http://airmetar.main.jp/radio/ADS-B%20Decoding%20Guide.pdf
print()
if tc == 19:
print("Aircraft address:", address)
print("Data:")
# print(bits_str)
print(bits_str[:5], bits_str[5:8], bits_str[8:10], bits_str[10:13], bits_str[13] ,bits_str[14:24], bits_str[24], bits_str[25:35], bits_str[35:36], bits_str[36:65])
subtype = int(bits_str[5:8], 2)
# https://mode-s.org/decode/adsb/airborne-velocity.html
spd, hdg, rocd = -1, -1, -1
if subtype == 1 or subtype == 2:
print("Velocity Subtype 1: Ground speed")
v_ew_sign = int(bits_str[13], 2)
v_ew = int(bits_str[14:24], 2) - 1 # east-west velocity
v_ns_sign = int(bits_str[24], 2)
v_ns = int(bits_str[25:35], 2) - 1 # north-south velocity
v_we = -1*v_ew if v_ew_sign else v_ew
v_sn = -1*v_ns if v_ns_sign else v_ns
spd = math.sqrt(v_sn*v_sn + v_we*v_we) # unit in kts
hdg = math.atan2(v_we, v_sn)
hdg = math.degrees(hdg) # convert to degrees
hdg = hdg if hdg >= 0 else hdg + 360 # no negative val
if subtype == 3:
print("Subtype Subtype 3: Airspeed")
hdg = int(bits_str[14:24], 2)/1024.0*360.0
spd = int(bits_str[25:35], 2)
vr_sign = int(bits_str[36], 2)
vr = int(bits_str[36:45], 2)
rocd = -1*vr if vr_sign else vr # rate of climb/descend
print("Speed (kts):", spd, "Rate:", rocd, "Heading:", hdg)
print()
# print()
def calc_coordinates():
def _cprN(lat, is_odd):
nl = _cprNL(lat) - is_odd
return nl if nl > 1 else 1
def _cprNL(lat):
try:
nz = 15
a = 1 - math.cos(math.pi / (2 * nz))
b = math.cos(math.pi / 180.0 * abs(lat)) ** 2
nl = 2 * math.pi / (math.acos(1 - a/b))
return int(math.floor(nl))
except:
# happens when latitude is +/-90 degree
return 1
def floor_(x):
return int(math.floor(x))
lat1b, lon1b, alt1b = "10111000111010011", "10000110111111000", "000101111001"
lat2b, lon2b, alt2b = "10010011101011100", "10000011000011011", "000101110111"
lat1, lon1, alt1 = int(lat1b, 2), int(lon1b, 2), int(alt1b, 2)
lat2, lon2, alt2 = int(lat2b, 2), int(lon2b, 2), int(alt2b, 2)
# 131072 is 2^17, since CPR lat and lon are 17 bits each
cprlat_even, cprlon_even = lat1/131072.0, lon1/131072.0
cprlat_odd, cprlon_odd = lat2/131072.0, lon2/131072.0
print(cprlat_even, cprlon_even)
j = floor_(59*cprlat_even - 60*cprlat_odd)
print(j)
air_d_lat_even = 360.0 / 60
air_d_lat_odd = 360.0 / 59
# Lat
lat_even = float(air_d_lat_even * (j % 60 + cprlat_even))
lat_odd = float(air_d_lat_odd * (j % 59 + cprlat_odd))
if lat_even >= 270:
lat_even = lat_even - 360
if lat_odd >= 270:
lat_odd = lat_odd - 360
# Lon
ni = _cprN(lat_even, 0)
m = floor_(cprlon_even * (_cprNL(lat_even)-1) - cprlon_odd * _cprNL(lat_even) + 0.5)
lon = (360.0 / ni) * (m % ni + cprlon_even)
print("Lat", lat_even, "Lon", lon)
# Altitude
# Q-bit (bit 48) indicates whether the altitude is encoded in multiples of 25 or 100 ft (0: 100 ft, 1: 25 ft)
# The value can represent altitudes from -1000 to +50175 ft.
if alt1b[-5] == '1':
bits = alt1b[:-5] + alt1b[-4:]
n = int(bits, 2)
alt_ft = n*25 - 1000
print("Alt (ft)", alt_ft)
fs, data = wavfile.read("adsb_20190311_191728Z_1090000kHz_RF.wav")
T = 1/fs
print("Sample rate %f MS/s" % (fs / 1e6))
print("Cnt samples %d" % len(data))
print("Duration: %f s" % (T * len(data)))
data = data.astype(float)
cnt = data.shape[0]
# Processing only part on file (faster):
# cnt = 10000000
# data = data[:cnt]
print("Processing I/Q...")
I, Q = data[:, 0], data[:, 1]
A = np.sqrt(I*I + Q*Q)
bits = np.zeros(cnt)
# To see scope without any processing, uncomment
# plt.plot(A)
# plt.show()
# sys.exit(0)
print("Extracting signals...")
pos = 0
avg = 200
msg_start = 0
# Find beginning of each signal
while pos < cnt - 16*1024:
# P1 - message start
while pos < cnt - 16*1024:
if A[pos] < avg and A[pos+1] > avg and pos - msg_start > 1000:
msg_start = pos
bits[pos] = 100
pos += 4
break
pos += 1
start1, start2, start3, start4 = msg_start, 0, 0, 0
# P2
while pos < cnt - 16*1024:
if A[pos] < avg and A[pos+1] > avg:
start2 = pos
bits[pos] = 90
pos += 1
break
pos += 1
# P3
while pos < cnt - 16*1024:
if A[pos] < avg and A[pos+1] > avg:
start3 = pos
bits[pos] = 80
pos += 1
break
pos += 1
# P4
while pos < cnt - 16*1024:
if A[pos] < avg and A[pos+1] > avg:
start4 = pos
bits[pos] = 70
pos += 1
break
pos += 1
sig_diff = start4 - start1
if 20 < sig_diff < 25:
bits[msg_start] = 500
bit_len = int((start4 - start1) / 4.5)
# print(pos, start1, start4, ' - ', bit_len)
# start = start1 + 8*bit_len
parse_message(A, msg_start, bit_len)
pos += 450
# For debugging: check signal start
# plt.plot(A)
# plt.plot(bits)
# plt.show()
ΠΠ°Π΄Π΅ΡΡΡ, ΠΊΠΎΠΌΡ-ΡΠΎ Π±ΡΠ»ΠΎ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½ΠΎ, ΡΠΏΠ°ΡΠΈΠ±ΠΎ Π·Π° Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅.
ΠΡΡΠΎΡΠ½ΠΈΠΊ: habr.com