áááºá¹ááá¬áá« Habrá áá±áá¬ááºáá±á«áºááœáẠááœá±áá»áá¯ážáá»á¬áž ááá¯á·ááá¯áẠáá°áááºáá»ááºážáá»á¬ážááŸáá·áº ááœá±á·áá¯á¶áá°ážáá° ááá¯á·ááá¯áẠááŒááºáá°ážáá°ááá¯ááºážááẠá¡ááá²á· Flightradar24 áááºáá±á¬ááºááŸá¯ááᯠá¡áá¯á¶ážááŒá¯áá°ážááŒáá±áááºá á€áááºááŸá¬ áá±áá¬ááºá áááºáá±áá¬ááᯠá¡áá»áááºááŸáá·áºáááŒá±ážáá® ááŒá±áá¬áá¶ááẠá¡ááœááºá¡áááºááŒá±áá±á¬ áááºážáááºážááŒá áºáááºá
Ð
áá¯á¶ááŒááº
áááºááŸá¬ážáááºááŸá¬á á¡áá¯á¶ážááŒá¯áá°áá»á¬ážááẠáááºážááá¯á·á á áááºáá¯ááºážáá»á¬ážáá±á«áºááœáẠááŒááºááœá±á·ááá¯ááºááẠáá±áá¬ááºáá±áá¬ááᯠááá¯á·ááœáŸááºááŒááºážááá¯ááºáá«á á¡ááá¯áá«á áá áºááᯠADS-B (á¡ááá¯á¡áá»á±á¬ááºááŸá®ááá¯á á±á¬áá·áºááŒáá·áºááŒááºážâá¡áá¶ááœáŸáá·áºááŒááºáž) áá¯áá±á«áºááŒá®áž áá±áá¬ááºááŸáá·áºáááºáááºáá±á¬ á¡áá»ááºá¡áááºáá»á¬ážááᯠááááºážáá»á¯ááºáá±ážá ááºáá¬ááá¯á· á¡ááá¯á¡áá»á±á¬áẠááá¯á·ááœáŸááºáááºá¡ááœáẠá¡áá¯á¶ážááŒá¯ááẠ- áááºážá identifierá ááŒáá®ááááºáá»á¬ážá áŠážáááºáá»ááºá á¡ááŒááºááŸá¯ááºážá á¡ááŒáá·áºááŸáá·áº á¡ááŒá¬ážáá±áá¬áá»á¬ážááᯠáá±ážááá¯á·áá«áááºá ááááºá ááá¯ááá¯á·áá±á¬á áá áºáá»á¬ážáááœááºážáá¬ážáá®ááœáẠáá±áá«áá±á«áºá០á¡ááŸááºáá áºáá¯ááá¯áᬠááœáŸááºáááºáá°á ááŒááºááá¯ááºáá²á·áááºá áá±áá¬ááºááœá± á¡áááºážáá»á¬ážáá¬áá²á·á¡áá« áá«á ááá¯á¶áá±á¬ááºáá±á¬á·áá°ážá
áááºážááá¬ááá¯ááºážá¡áá ADS-B ááœáẠ1090 MHz á¡ááœááºááŒáá·áºáá¬ážáá±á¬ ááŒáááºááŸá¯ááºážááŒáá·áº á¡áá»ááºá¡áááºáá¯ááºááá¯ážááŸá¯áá»á¬ážááᯠá¡áá«á¡á¬ážáá»á±á¬áºá áœá¬ áá±ážááá¯á·ááá·áº áá±áá¬ááºáá±á«áºááœáẠáá¯ááºááœáŸáá·áºááŸá¯áá áºáá¯áá«ááŸáááẠ(á¡ááŒá¬ážáá¯ááºáá»á¬ážááŸááá±á¬áºáááºážá ááŒáá®ááááºáá»á¬ážááᯠá€áá±áá¬ááœááºáᬠáá±ážááá¯á·áá±á¬ááŒá±á¬áá·áº áááºážááá¯á·ááᯠáá»áœááºá¯ááºááá¯á· ááááºá áááºááááºá á¬ážáá«)á áá¯ááºáá«áááºá á¡áá¶ááœáŸáá·áºá ááºá¡ááŒááºá áá±ááááºáá áºáá±áá¬áá¬ááŸá¬ áááºáá¶áá°áááºáž ááŸááá«áááºá áá«áá±ááá·áº áá¯á¶ážá áœá²áá°ááœá±á¡ááœááºáá±á¬á· áá»áœááºáá±á¬áºááá¯á·áá²á· ááá¯ááºááá¯áẠreceiver á á áááºáááºá á¬ážá áá¬áá«áá²á
á áá¬ážáá ááºá ááŸáá¯ááºážááŸááºáááºá¡ááœááºá áá¬áááºá¡áá¯á¶ážááŒá¯áá°áá»á¬ážá¡ááœáẠáá®ááá¯ááºážáá¯ááºáá¬ážááá·áº Airnav Radarbox ááẠáááá áá¯ááŸá áºááœáẠáá±á«áºáá¬áá²á·ááŒá®áž áá±á«áºáᬠááá ááá·áº áá¯ááºáá»áᬠááœááºáááºáááºáá±á¬ááºááŸá¯áá»á¬ážá¡ááœáẠá á¬áááºážááœááºážááŸá¯áá áºáá¯ááẠáá áºááŸá áºáá»áŸáẠáá±á«áºáᬠáá á áá¯ááºáá»áááºá
ááááá¯á¶áž áá¯ááŸá¬ážááá¯ááºááŸááºááœá±áá²á· áá¯á¶ážáááºáá»ááºááœá±ááᯠááá¯áááºááŸá¬ áááºááŸá¯ááá¯ááºáá«áááºá
á¡áá»ááºááŒááŸá¯áá»á¬ážááᯠáááºáá¶ááŒááºážá
ááááŠážá áœá¬ signal ááá¯ááŸááºáááºážáááºáááºááá¯á¡ááºáááºá á¡áá»ááºááŒááŸá¯áá áºáá¯áá¯á¶ážááẠ120 microseconds áá¬ááŒá¬áá»áááºááŒá áºáá±á¬ááŒá±á¬áá·áº áááºážáá¡á áááºá¡ááá¯ááºážáá»á¬ážááᯠá¡áááºááŒá±ááŒá±ááŒá¯ááºááá¯ááºá á±ááẠá¡áááºážáá¯á¶áž 5 MHz ááá°áá¬ááŒáááºááŸá¯ááºážááŸááá±á¬ SDR áááºáá¶áá°ááẠááŸá áºááá¯ááœááºáá±á¬ááºážáááºá
ááŸááºáááºážáááºááŒá®ážáá±á¬ááºá áá»áœááºá¯ááºááá¯á·ááẠááá°áá¬ááŸá¯ááºáž 5000000 ááá°áá¬/sec ááŒáá·áº WAV ááá¯ááºááᯠáááºáá¶áááŸááááºá ááá¯áá²á·ááá¯á·áá±á¬ á¡áá¶ááœááºážááŸá¯á á
áá¹ááá·áº 30 ááŒá¬ "á¡áá±ážáá»áááº" 500MB ááá·áºááŸááááºá áá®áá®áá¬ááá±áá¬ááŒáá·áº áá¬ážáá±á¬ááºááŒááºážááẠá¡áá¯á¶ážááááºáá« - ááá¯ááºááœáẠá¡áá¶ááá«áááºáá±á¬áºáááºáž ááá¯ááºááá¯ááºáá
áºáá»á
áºáááºá¡áá¶ááœáŸáá·áºá¡áá»ááºááŒááŒááºáž - á€áááºááŸá¬ 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()
ááááº- áá±á¬ááºáá¶áá°áá¶áá¶ááŸáá·áº ááá·áºáá»ááºáááºááœáẠáááºááŸá¬ážáá±á¬ "pulses" ááᯠáá»áœááºá¯ááºááá¯á· ááŒááºáá±ááá«áááºá
"ááœá±ážáá¯ááºááŸá¯ááºáž" áá
áºáá¯á
á®ááẠááááºáá
áºáá±á«áºááŸá ááŒááºáááºááŒááºáá¬ážááŸá¯ááᯠááá¯ážááŒáŸáá·áºáá«á áááºážááœá²á·á
ááºážáá¯á¶ááẠááŸááºážáááºážá
áœá¬ááŒááºááá¯ááºáááºá
áááºááœá±á·ááŒááºáááá·áºá¡ááá¯ááºážá áá¯á¶ááẠá¡áááºáá±á¬áºááŒáá»ááºááœááºáá±á¬áºááŒáá¬ážááá·áºá¡áá¬áá»á¬ážááŸáá·áº á¡áá±á¬áºáá±ážááá¯ááºáá®áá«áááºá áá±áá¬ááᯠá
áááºáá¯ááºáá±á¬ááºááá¯ááºáá«áááºá
áá¯ááºááœá²ááŒááºážá
ááááŠážá áœá¬á áááºááẠbit stream ááá¯ááááºááá¯á¡ááºáááºá á¡áá»ááºááŒááᯠáááºáá»ááºá áᬠáá¯ááºááŒáá·áº áá¯ááºáá¯ááºáá¬ážáááº-
nibbles áá¡ááá·áºááœá¬ááŒá¬ážáá»ááºááŸááŸááºáááºáá±á¬ "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"
signal ááá¯ááºááá¯ááºááœá²á·á ááºážáá¯á¶ááŸá¬ á¡á±á¬ááºáá«á¡ááá¯ááºážááŒá áºáááºá
á¡ááœááºááœá±ááᯠá¡áá±ážá
áááºááŒáá·áºáá¡á±á¬ááºá
DF (Downlink Formatá 5 bits) - áááºáá±á·ááºá»á¡áá»áá¯ážá¡á á¬ážááᯠáá¯á¶ážááŒááºáááºá á¡áá»áá¯ážá¡á á¬ážáá»á¬ážá áœá¬ááŸááááº-
(
áá»áœááºá¯ááºááá¯á·ááẠDF17 á¡áá»áá¯ážá¡á á¬ážááá¯áᬠá áááºáááºá á¬ážáá±á¬ááŒá±á¬áá·áº... áááºážááẠáá±áá¬ááºá ááŒááááááºáá»á¬ážáá«áááºáááºá
ICAO (24 bits) - áá±áá¬ááºáááá¯ááºáá¶ááá¬áá°ážááŒá¬ážáá±á¬áá¯ááºá áá±áá¬ááºááᯠáááºážááá¯ááºááŒáá·áº á
á
áºáá±ážááá¯ááºáááºá
áááºážááŒááºáááº
á¡áá»ááºá¡ááẠ(56 ááá¯á·ááá¯áẠ112 bits) - áá»áœááºá¯ááºááá¯á· áá¯ááºáá¯ááºááá·áº áááá·áºáá±áá¬á ááááá¯á¶ážáá±áᬠ5 bits ááẠá¡ááœááºááŒá áºáááºá Code ááá¯ááá¯ááºáá«ááááºážáááºážáá¬ážááá·áº áá±áá¬á¡áá»áá¯ážá¡á á¬ážááœá² áá«áááºááẠ(DF ááŸáá·áº ááá±á¬ááœá±ážá)á á€á¡áá»áá¯ážá¡á á¬ážáá»á¬ážáá²á០á¡áááºážááẠááŸááá«áááºá
(
áááºáá±á·áá»áºáá»á¬ážá ááá°áá¬á¡áááºážáááºááᯠááŒáá·áºááŒáá«á áá¯á·á
áá±áá¬ááºááŸááºáá¯á¶áááºááŒááºážá
á¥ááᬠbinary áá¯á¶á á¶-
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('#', ''))
áá±áááºá¡áá±á¡áá¬áž
áá¬áááºá ááá¯ážááá¯ážááá¯ááẠááŒááááááºááœá±á ááá¯ááŸá¯ááºááœá±ážáááºá áááºážááá¯á·ááᯠá¡áá±á¬ááºááŸáá·áº áá°ážáááºážáá±á¬áá±á¬ááºáá»á¬áž 2 áá¯á¶á á¶ááŒáá·áº áá°ážá ááºáááºá á¡ááœááºáá¯áẠTC = 01011b = 11á
á¡áá®ááŸáá·áº odd packets áá»á¬ážá á¥ááá¬-
01011 000 000101110110 00 10111000111001000 10000110101111001
01011 000 000110010000 01 10010011110000110 10000011110001000
ááŒáá®ááááºáá»á¬áž ááœááºáá»ááºááŒááºážááẠá¡áá±á¬áºáá±áž áááºážáá»ááºáá±á¬ áá±á¬áºááŒá°áá¬á¡á ááŒá áºáá±á«áºááẠá
(
áá»áœááºá¯ááºááẠGIS áá»áœááºážáá»ááºáá°ááá¯ááºáá«á ááá¯á·ááŒá±á¬áá·áºáááºážáááºáááºááá¬áááºááááá«á áááá²á·áá°áá»á¬áž comment ááŸá¬áá±ážáá±ážáá²á·áá«áŠážá
á¡ááŒáá·áºááᯠááá¯ááá¯ážááŸááºážáááºáᯠááŸááºáá°ááẠ- áááá»áá±á¬ bit áá±á«áºáá°áááºá áááºážááᯠ25 áá± ááá¯á·ááá¯áẠ100 áá±á á¡ááá áºáá¯á¡ááŒá Ạááá¯ááºá á¬ážááŒá¯ááá¯ááºáááºá
áá±áááºá¡áá»ááº
TC=19 áá«áá±á¬ áááºáá±á·áá»áºá áá®áá±áá¬ááŸá¬ á áááºáááºá á¬ážá áá¬áá±á¬ááºážáá¬á á¡ááŒááºááŸá¯ááºážáᬠááŒá±ááŒáẠ(Ground Speed) áá«ááŸááá¯áẠáá±áá¬ááºá¡á¬áá¯á¶áá¶áááááᬠ(Airspeed) áá²á· ááá¯ááºážáá¬áá²á· áááá»áá²á· á¡ááŒááºááŸá¯ááºáž ááŒá áºááá¯ááºáááºá ááá°áá®áá±á¬áááºáááºáá»á¬ážá áœá¬ááá¯áááºáž ááá¯á·ááœáŸááºáááº-
(
áá±á¬ááºáá»ááº
áááºááœá±á·ááŒááºáááá·áºá¡ááá¯ááºáž ADS-B áááºážááá¬ááẠá á¶ááŸá¯ááºážáá áºáá¯ááẠááá±á¬áºáááºááŸááºáááºáá»á¬ážá¡ááœááºáá¬áá áá¬áááºá¡áá¯á¶ážááŒá¯áá°áá»á¬ážá¡ááœááºáá« á¡áá¯á¶ážáááºáá¬áá±á¬á¡áá«ááœáẠADS-B áááºážááá¬ááẠá áááºáááºá á¬ážá áá¬áá±á¬ááºážáá±á¬ áá±á«ááºážá ááºááŸá¯áá áºáᯠááŒá áºáá¬áá²á·áááºá ááá¯á·áá±á¬áºá á€á¡áá¬ááœáẠá¡ááááá»áá±á¬ á¡áááºážááá¹áááᯠá ááºáá á¹á ááºážááẠgigahertz âfor penniesâ á¡áááºááœááºááŸááá±á¬ ááŒáááºááŸá¯ááºážáá»á¬ážááŒáá·áº á á¬áá¬ážáááºáá¶ááá¯ááºá á±ááá·áº á á»á±ážáááºáá¬áá±á¬ áá áºáá»á áºááẠSDR áááºáá¶áááááá¬áá»á¬ážá á á»á±ážáááºáá¬áá±á¬áááºážááá¬ááŒáá·áº áá á¬ážáá²á·áááºá
á
á¶ááŸáá¯ááºáá²ááŸá¬á áá¯ááºáá«áááºá áá®áááºá¡áá»á¬ážááŒá®ážááŸááá«áááºá á
áááºáá«áááºá
á¬ážáá°áá»á¬áž Page ááœáẠPDF ááᯠááŒáá·áºááŸá¯ááá¯ááºáá«áááºá
á¡áááºáá±á¬áºááŒáá«á¡á¬ážáá¯á¶ážááẠáá°á¡áá»á¬ážá¡ááœáẠá¡áá¯á¶ážáááºáááá·áºáááºááá¯ááºáá±á ááá¯á·áá±á¬áº á¡áááºážáá¯á¶áž áááºážáááºááá¯á·á¡áá¯ááºáá¯ááºáá¯á¶á áá±áá°áá»á¡áá°á¡áááŸá¬ áá»ááºááŸááá±áááºáᯠáá»áŸá±á¬áºááá·áºáá«áááºá
á
áá¬ážáá
ááºá Python ááœáẠá¡áááºááá·áºáá¯ááºáá¬ážáá±á¬ áá®áá¯ááºáá«áá
áºáᯠááŸáááŸáá·áºááŒá®ážááŒá
áºá áááºážááᯠáááºáá±á·áá¬ááá¯ááºáááºá
áá±á¬ááºážáá«ážááœááºáá±á¬áºááŒáá¬ážáá±á¬ parser áá¡áááºážá¡ááŒá
áºáá¯ááºááá¯ááŒááºáá±á¬ááºááŸá¯á¡á±á¬ááºááœááºáá±á¬áºááŒáá¬ážáááºá áááºážááẠáá¯ááºáá¯ááºááŸá¯áá²á·ááá¯á· áááºáá±á¬ááºááŒááºážáááŸááá±á¬ á
ááºážáááºááá°áá¬áá
áºáá¯ááŒá
áºááŒá®áž á¡áá»áá¯á·á¡áá¬áá»á¬ážááẠáááºážááœááºá¡áá¯ááºáá¯ááºááŒá®áž á¡áááºááœááºááŸááºáááºážáááºáá¬ážááá·áºááá¯ááºááá¯ááœá²ááŒááºážá
áááºááŒá¬ááẠáááºážááá¯á¡áá¯á¶ážááŒá¯ááá¯ááºáá«áááºá
á¡áááºážá¡ááŒá
áºáá¯áẠ(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()
áá áºáá±á¬ááºáá±á¬ááºá á áááºáááºá á¬ážáááºááá¯á· áá»áŸá±á¬áºááá·áºáá«áááºá áááºážáá²á·á¡á¬áá¯á¶á áá¯ááºááŸá¯á¡ááœáẠáá»á±ážáá°ážáááºáá«áááºá
source: www.habr.com