سلام حبر. شاید هرڅوک چې کله هم په الوتکه کې خپلوانو یا ملګرو سره لیدلي یا لیدلي وي د Flightradar24 وړیا خدمت کارولی وي. دا په ریښتیني وخت کې د الوتکې موقعیت تعقیب کولو لپاره خورا اسانه لار ده.
В
История
په ښکاره ډول، د الوتکو ډاټا د کاروونکو لپاره د دوی په سمارټ فونونو کې د لیدلو لپاره نه لیږدول کیږي. سیسټم د ADS-B په نوم یادیږي (د اتوماتیک انحصاري څارنې - نشر)، او په اتوماتيک ډول د کنټرول مرکز ته د الوتکې په اړه معلومات لیږدولو لپاره کارول کیږي - د هغې پیژندونکی، همغږي، سمت، سرعت، لوړوالی او نور معلومات لیږدول کیږي. پخوا، د داسې سیسټمونو د راتګ دمخه، لیږونکي یوازې په رادار کې یو ټکی لیدلی شي. دا نور کافي نه و کله چې ډیری الوتکې وې.
په تخنیکي توګه، ADS-B په الوتکه کې یو ټرانسمیټر لري چې په وخت سره د 1090 MHz په کافي لوړ فریکونسۍ کې د معلوماتو کڅوړې لیږي (دلته نور حالتونه شتون لري، مګر موږ دوی ته دومره علاقه نه لرو، ځکه چې همغږي یوازې دلته لیږدول کیږي). البته ، د ټرانسمیټر سربیره ، په هوایی ډګر کې یو ځای ریسیور هم شتون لري ، مګر زموږ لپاره ، د کاروونکو په توګه ، زموږ خپل ریسیور په زړه پوری دی.
په هرصورت، د پرتله کولو لپاره، لومړی داسې سیسټم، ایرناو رادار باکس، چې د عادي کاروونکو لپاره ډیزاین شوی، په 2007 کې راڅرګند شو، او شاوخوا $ 900 لګښت لري؛ د شبکې خدماتو ګډون په کال کې 250 نور ډالر لګښت لري.
د دغو لومړنیو روسی مالکینو بیاکتنې په فورم کې لوستل کیدی شي
د سیګنالونو ترلاسه کول
لومړی، سیګنال باید ثبت شي. ټول سیګنال یوازې د 120 مایکرو ثانیو موده لري ، نو د دې اجزاو په آرامۍ سره جلا کولو لپاره ، لږترلږه د 5 MHz نمونې فریکونسۍ سره د SDR ریسیور مطلوب دی.
د ثبت کولو وروسته، موږ د 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()
پایله: موږ د شاليد شور په وړاندې څرګند "دالونه" ګورو.
هر "نبض" یو سیګنال دی، چې جوړښت یې په ښکاره ډول لیدل کیږي که تاسو په ګراف کې ریزولوشن زیات کړئ.
لکه څنګه چې تاسو لیدلی شئ، عکس د هغه څه سره سم دی چې پورته تشریح کې ورکړل شوی. تاسو کولی شئ د معلوماتو پروسس پیل کړئ.
کوډ کول
لومړی، تاسو اړتیا لرئ یو څه جریان ترلاسه کړئ. سیګنال پخپله د مانچسټر کوډ کولو په کارولو سره کوډ شوی دی:
په نبلونو کې د سطحې توپیر څخه د ریښتیني "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 بڼه، 5 bits) - د پیغام ډول ټاکي. څو ډولونه شتون لري:
موږ یوازې د DF17 ډول سره علاقه لرو ، ځکه چې ... دا هغه دی چې د الوتکې همغږي لري.
ICAO (24 بټونه) - د الوتکې نړیوال ځانګړی کوډ. تاسو کولی شئ الوتکه د دې کوډ له لارې چیک کړئ
تدوین: په
د معلوماتو (56 یا 112 بټونه) - ریښتینی معلومات چې موږ به یې کوډ کړو. د معلوماتو لومړی 5 بټونه ساحه ده د کوډ ډول، د ذخیره شوي معلوماتو فرعي ډول لري (د DF سره مغشوش نه وي). د دې ډولونو څخه ډیری شتون لري:
راځئ چې د کڅوړو یو څو مثالونه وګورو.
د الوتکې پیژندنه
په بائنري بڼه کې بېلګه:
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.
د مساوي او طاق کڅوړو بیلګه:
01011 000 000101110110 00 10111000111001000 10000110101111001
01011 000 000110010000 01 10010011110000110 10000011110001000
د همغږي محاسبه پخپله د یو خورا پیچلي فورمول سره سم ترسره کیږي:
(
زه د GIS متخصص نه یم، نو زه نه پوهیږم چې دا له کوم ځای څخه راځي. څوک پوهیږي، په نظرونو کې ولیکئ.
لوړوالی ساده ګڼل کیږي - د ځانګړي بټ پورې اړه لري، دا د 25 یا 100 فوټو ډیری په توګه ښودل کیدی شي.
د هوا سرعت
بسته د TC=19 سره. دلته په زړه پورې خبره دا ده چې سرعت کیدای شي دقیق وي، د ځمکې سره تړاو لري (د ځمکې سرعت)، یا د هوا له لارې، د الوتکې سینسر (Airspeed) لخوا اندازه کیږي. ډیری بیلابیل ساحې هم لیږدول کیږي:
(
پایلې
لکه څنګه چې تاسو لیدلی شئ، د ADS-B ټیکنالوژي په زړه پورې سمبیوسس بدل شوی، کله چې یو معیار نه یوازې د مسلکیانو لپاره، بلکې د عادي کاروونکو لپاره هم ګټور وي. مګر البته ، پدې کې کلیدي رول د ډیجیټل SDR ریسیور ارزانه ټیکنالوژۍ لخوا لوبول شوی و ، کوم چې وسیله ته اجازه ورکوي په لفظي ډول د ګیګاهرټز څخه پورته فریکونسۍ سره سیګنالونه ترلاسه کړي "د پیسو لپاره."
پخپله معیار کې، البته، ډیر څه شتون لري. علاقمندان کولی شي په پی ډی ایف پاڼه کې وګوري
دا امکان نلري چې پورته ټول به د ډیری لپاره ګټور وي، مګر لږترلږه عمومي نظر چې دا څنګه کار کوي، زه هیله لرم، پاتې شي.
په لاره کې، په پایتون کې یو چمتو شوی کوډونکی لا دمخه شتون لري، تاسو کولی شئ دا مطالعه کړئ
په مقاله کې تشریح شوي د پارسر سرچینې کوډ د کټ لاندې ورکړل شوی. دا د ازموینې بیلګه ده چې تولید نه کوي، مګر ځینې شیان پدې کې کار کوي، او دا پورته ثبت شوي فایل پارس کولو لپاره کارول کیدی شي.
د سرچینې کوډ (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