Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول

سلام حبر. شاید هرڅوک چې کله هم په الوتکه کې خپلوانو یا ملګرو سره لیدلي یا لیدلي وي د Flightradar24 وړیا خدمت کارولی وي. دا په ریښتیني وخت کې د الوتکې موقعیت تعقیب کولو لپاره خورا اسانه لار ده.

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول

В لومړی برخه د دې ډول آنلاین خدمت عملیاتي اصول تشریح شوي. موږ به اوس مخ په وړاندې لاړ شو او معلومه کړو چې کوم معلومات د الوتکې څخه ترلاسه کونکي سټیشن ته لیږل کیږي او ترلاسه کیږي او د Python په کارولو سره یې پخپله کوډ کوي.

История

په ښکاره ډول، د الوتکو ډاټا د کاروونکو لپاره د دوی په سمارټ فونونو کې د لیدلو لپاره نه لیږدول کیږي. سیسټم د ADS-B په نوم یادیږي (د اتوماتیک انحصاري څارنې - نشر)، او په اتوماتيک ډول د کنټرول مرکز ته د الوتکې په اړه معلومات لیږدولو لپاره کارول کیږي - د هغې پیژندونکی، همغږي، سمت، سرعت، لوړوالی او نور معلومات لیږدول کیږي. پخوا، د داسې سیسټمونو د راتګ دمخه، لیږونکي یوازې په رادار کې یو ټکی لیدلی شي. دا نور کافي نه و کله چې ډیری الوتکې وې.

په تخنیکي توګه، ADS-B په الوتکه کې یو ټرانسمیټر لري چې په وخت سره د 1090 MHz په کافي لوړ فریکونسۍ کې د معلوماتو کڅوړې لیږي (دلته نور حالتونه شتون لري، مګر موږ دوی ته دومره علاقه نه لرو، ځکه چې همغږي یوازې دلته لیږدول کیږي). البته ، د ټرانسمیټر سربیره ، په هوایی ډګر کې یو ځای ریسیور هم شتون لري ، مګر زموږ لپاره ، د کاروونکو په توګه ، زموږ خپل ریسیور په زړه پوری دی.

په هرصورت، د پرتله کولو لپاره، لومړی داسې سیسټم، ایرناو رادار باکس، چې د عادي کاروونکو لپاره ډیزاین شوی، په 2007 کې راڅرګند شو، او شاوخوا $ 900 لګښت لري؛ د شبکې خدماتو ګډون په کال کې 250 نور ډالر لګښت لري.

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول

د دغو لومړنیو روسی مالکینو بیاکتنې په فورم کې لوستل کیدی شي راډیو سکینر. اوس چې د RTL-SDR رسیدونکي په پراخه کچه شتون لري، ورته وسیله د $ 30 لپاره راټول کیدی شي؛ په دې اړه نور معلومات لومړی برخه. راځئ چې پخپله پروتوکول ته لاړ شو - راځئ وګورو چې دا څنګه کار کوي.

د سیګنالونو ترلاسه کول

لومړی، سیګنال باید ثبت شي. ټول سیګنال یوازې د 120 مایکرو ثانیو موده لري ، نو د دې اجزاو په آرامۍ سره جلا کولو لپاره ، لږترلږه د 5 MHz نمونې فریکونسۍ سره د SDR ریسیور مطلوب دی.

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول

د ثبت کولو وروسته، موږ د 5000000 نمونو / ثانیو د نمونې اندازې سره د WAV فایل ترلاسه کوو؛ د 30 ثانیو دا ډول ریکارډ "وزن" شاوخوا 500MB دی. د میډیا پلیر سره یې اوریدل ، البته ، بې ګټې دي - فایل غږ نلري ، مګر مستقیم ډیجیټل شوی راډیو سیګنال - دا په حقیقت کې د سافټویر تعریف شوي راډیو کار کوي.

موږ به د 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()

پایله: موږ د شاليد شور په وړاندې څرګند "دالونه" ګورو.

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول

هر "نبض" یو سیګنال دی، چې جوړښت یې په ښکاره ډول لیدل کیږي که تاسو په ګراف کې ریزولوشن زیات کړئ.

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول

لکه څنګه چې تاسو لیدلی شئ، عکس د هغه څه سره سم دی چې پورته تشریح کې ورکړل شوی. تاسو کولی شئ د معلوماتو پروسس پیل کړئ.

کوډ کول

لومړی، تاسو اړتیا لرئ یو څه جریان ترلاسه کړئ. سیګنال پخپله د مانچسټر کوډ کولو په کارولو سره کوډ شوی دی:

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول

په نبلونو کې د سطحې توپیر څخه د ریښتیني "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"

پخپله د سیګنال جوړښت په لاندې ډول دی:

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول

راځئ چې ساحې په ډیر تفصیل سره وګورو.

DF (Downlink بڼه، 5 bits) - د پیغام ډول ټاکي. څو ډولونه شتون لري:

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول
(د میز سرچینه)

موږ یوازې د DF17 ډول سره علاقه لرو ، ځکه چې ... دا هغه دی چې د الوتکې همغږي لري.

ICAO (24 بټونه) - د الوتکې نړیوال ځانګړی کوډ. تاسو کولی شئ الوتکه د دې کوډ له لارې چیک کړئ په آنلاین توګه (له بده مرغه، لیکوال د ډیټابیس تازه کول بند کړي، مګر دا لاهم اړونده ده). د مثال په توګه، د کوډ 3c5ee2 لپاره موږ لاندې معلومات لرو:

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول

تدوین: په مقالې ته تبصرې د ICAO کوډ توضیحات په ډیر تفصیل سره ورکړل شوي؛ زه وړاندیز کوم چې علاقه لرونکي یې ولولي.

د معلوماتو (56 یا 112 بټونه) - ریښتینی معلومات چې موږ به یې کوډ کړو. د معلوماتو لومړی 5 بټونه ساحه ده د کوډ ډول، د ذخیره شوي معلوماتو فرعي ډول لري (د DF سره مغشوش نه وي). د دې ډولونو څخه ډیری شتون لري:

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول
(د میز سرچینه)

راځئ چې د کڅوړو یو څو مثالونه وګورو.

د الوتکې پیژندنه

په بائنري بڼه کې بېلګه:

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####_#################################################

د تار په کوډ کولو سره، د الوتکې کوډ ترلاسه کول اسانه دي: 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('#', ''))

هوایی موقعیت

که نوم ساده وي، نو همغږي ډیر پیچلي دي. دوی د 2، حتی او عجیب چوکاټونو په بڼه لیږدول کیږي. د ساحې کوډ TC = 01011b = 11.

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول

د مساوي او طاق کڅوړو بیلګه:

01011 000 000101110110 00 10111000111001000 10000110101111001
01011 000 000110010000 01 10010011110000110 10000011110001000

د همغږي محاسبه پخپله د یو خورا پیچلي فورمول سره سم ترسره کیږي:

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول
(سرچینه)

زه د GIS متخصص نه یم، نو زه نه پوهیږم چې دا له کوم ځای څخه راځي. څوک پوهیږي، په نظرونو کې ولیکئ.

لوړوالی ساده ګڼل کیږي - د ځانګړي بټ پورې اړه لري، دا د 25 یا 100 فوټو ډیری په توګه ښودل کیدی شي.

د هوا سرعت

بسته د TC=19 سره. دلته په زړه پورې خبره دا ده چې سرعت کیدای شي دقیق وي، د ځمکې سره تړاو لري (د ځمکې سرعت)، یا د هوا له لارې، د الوتکې سینسر (Airspeed) لخوا اندازه کیږي. ډیری بیلابیل ساحې هم لیږدول کیږي:

Flightradar24 - دا څنګه کار کوي؟ برخه 2، ADS-B پروتوکول
(سرچینه)

پایلې

لکه څنګه چې تاسو لیدلی شئ، د ADS-B ټیکنالوژي په زړه پورې سمبیوسس بدل شوی، کله چې یو معیار نه یوازې د مسلکیانو لپاره، بلکې د عادي کاروونکو لپاره هم ګټور وي. مګر البته ، پدې کې کلیدي رول د ډیجیټل SDR ریسیور ارزانه ټیکنالوژۍ لخوا لوبول شوی و ، کوم چې وسیله ته اجازه ورکوي په لفظي ډول د ګیګاهرټز څخه پورته فریکونسۍ سره سیګنالونه ترلاسه کړي "د پیسو لپاره."

پخپله معیار کې، البته، ډیر څه شتون لري. علاقمندان کولی شي په پی ډی ایف پاڼه کې وګوري ICAO یا پورته ذکر شوي څخه لیدنه وکړئ ویب پاڼه.

دا امکان نلري چې پورته ټول به د ډیری لپاره ګټور وي، مګر لږترلږه عمومي نظر چې دا څنګه کار کوي، زه هیله لرم، پاتې شي.

په لاره کې، په پایتون کې یو چمتو شوی کوډونکی لا دمخه شتون لري، تاسو کولی شئ دا مطالعه کړئ دلته. او د SDR ریسیورونو مالکین کولی شي د چمتو شوي ADS-B ډیکوډر راټول او پیل کړي له پاڼې څخهپه دې اړه په ډیر تفصیل سره بحث وشو لومړی برخه.

په مقاله کې تشریح شوي د پارسر سرچینې کوډ د کټ لاندې ورکړل شوی. دا د ازموینې بیلګه ده چې تولید نه کوي، مګر ځینې شیان پدې کې کار کوي، او دا پورته ثبت شوي فایل پارس کولو لپاره کارول کیدی شي.
د سرچینې کوډ (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()

زه امید لرم چې یو څوک علاقه لري ، ستاسو د پاملرنې څخه مننه.

سرچینه: www.habr.com

Add a comment