diff --git a/ModeS.py b/ModeS.py index 21b612f..2589add 100644 --- a/ModeS.py +++ b/ModeS.py @@ -1,4 +1,5 @@ -from location import * +from ModeSLocation import ModeSLocation +import math class ModeS: """This class handles the ModeS ADSB manipulation @@ -11,12 +12,13 @@ class ModeS: format = 17 #The format type of an ADSB message - enc_alt = encode_alt_modes(alt, surface) + location = ModeSLocation() + enc_alt = location.encode_alt_modes(alt, surface) #print "Alt(%r): %X " % (surface, enc_alt) #encode that position - (evenenclat, evenenclon) = cpr_encode(lat, lon, False, surface) - (oddenclat, oddenclon) = cpr_encode(lat, lon, True, surface) + (evenenclat, evenenclon) = location.cpr_encode(lat, lon, False, surface) + (oddenclat, oddenclon) = location.cpr_encode(lat, lon, True, surface) #print "Even Lat/Lon: %X/%X " % (evenenclat, evenenclon) #print "Odd Lat/Lon: %X/%X " % (oddenclat, oddenclon) diff --git a/ModeSLocation.py b/ModeSLocation.py new file mode 100644 index 0000000..e87febe --- /dev/null +++ b/ModeSLocation.py @@ -0,0 +1,100 @@ +import math + +class ModeSLocation: + """This class does ModeS/ADSB Location calulations""" + + + +########################################################################## + +# Copyright 2010, 2012 Nick Foster +# +# This file is part of gr-air-modes +# +# gr-air-modes is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# gr-air-modes is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with gr-air-modes; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + + def encode_alt_modes(self, alt, bit13): + mbit = False + qbit = True + encalt = (int(alt) + 1000) / 25 + + if bit13 is True: + tmp1 = (encalt & 0xfe0) << 2 + tmp2 = (encalt & 0x010) << 1 + + else: + tmp1 = (encalt & 0xff8) << 1 + tmp2 = 0 + + return (encalt & 0x0F) | tmp1 | tmp2 | (mbit << 6) | (qbit << 4) + + latz = 15 + + def nz(self, ctype): + """ + Number of geographic latitude zones between equator and a pole. It is set to NZ = 15 for Mode-S CPR encoding + https://adsb-decode-guide.readthedocs.io/en/latest/content/cpr.html + """ + return 4 * self.latz - ctype + + def dlat(self, ctype, surface): + if surface == 1: + tmp = 90.0 + else: + tmp = 360.0 + + nzcalc = self.nz(ctype) + if nzcalc == 0: + return tmp + else: + return tmp / nzcalc + + def nl(self, declat_in): + if abs(declat_in) >= 87.0: + return 1.0 + return math.floor( (2.0*math.pi) * math.acos(1.0- (1.0-math.cos(math.pi/(2.0*self.latz))) / math.cos( (math.pi/180.0)*abs(declat_in) )**2 )**-1) + + def dlon(self, declat_in, ctype, surface): + if surface: + tmp = 90.0 + else: + tmp = 360.0 + nlcalc = max(self.nl(declat_in)-ctype, 1) + return tmp / nlcalc + + #encode CPR position + # https://adsb-decode-guide.readthedocs.io/en/latest/content/cpr.html + # compact position reporting + def cpr_encode(self, lat, lon, ctype, surface): + if surface is True: + scalar = 2.**19 + else: + scalar = 2.**17 + + #encode using 360 constant for segment size. + dlati = self.dlat(ctype, False) + yz = math.floor(scalar * ((lat % dlati)/dlati) + 0.5) + rlat = dlati * ((yz / scalar) + math.floor(lat / dlati)) + + #encode using 360 constant for segment size. + dloni = self.dlon(lat, ctype, False) + xz = math.floor(scalar * ((lon % dloni)/dloni) + 0.5) + + yz = int(yz) & (2**17-1) + xz = int(xz) & (2**17-1) + + return (yz, xz) #lat, lon diff --git a/README.md b/README.md index 76cb51a..a1e971a 100644 --- a/README.md +++ b/README.md @@ -16,15 +16,7 @@ $ ls Samples.iq8s Samples.iq8s $ ``` -2. Make the raw signal file aligned to 256K buffer size: -``` -$ dd if=Samples.iq8s of=Samples_256K.iq8s bs=4k seek=63 -1+0 records in -1+0 records out -4096 bytes (4.1 kB) copied, 0.00110421 s, 3.7 MB/s -$ -``` -3. Transmit the signal into air: +2. Transmit the signal into air: ``` $ hackrf_transfer -t Samples_256K.iq8s -f 868000000 -s 2000000 -x 10 call hackrf_sample_rate_set(2000000 Hz/2.000 MHz) diff --git a/conversions.py b/conversions.py deleted file mode 100644 index 547aef4..0000000 --- a/conversions.py +++ /dev/null @@ -1,6 +0,0 @@ - -import math - - - - diff --git a/location.py b/location.py deleted file mode 100644 index 71d7e83..0000000 --- a/location.py +++ /dev/null @@ -1,95 +0,0 @@ -########################################################################## - -# Copyright 2010, 2012 Nick Foster -# -# This file is part of gr-air-modes -# -# gr-air-modes is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# gr-air-modes is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with gr-air-modes; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -import math - -def encode_alt_modes(alt, bit13): - mbit = False - qbit = True - encalt = (int(alt) + 1000) / 25 - - if bit13 is True: - tmp1 = (encalt & 0xfe0) << 2 - tmp2 = (encalt & 0x010) << 1 - - else: - tmp1 = (encalt & 0xff8) << 1 - tmp2 = 0 - - return (encalt & 0x0F) | tmp1 | tmp2 | (mbit << 6) | (qbit << 4) - -latz = 15 - -def nz(ctype): - """ - Number of geographic latitude zones between equator and a pole. It is set to NZ = 15 for Mode-S CPR encoding - https://adsb-decode-guide.readthedocs.io/en/latest/content/cpr.html - """ - return 4 * latz - ctype - -def dlat(ctype, surface): - if surface == 1: - tmp = 90.0 - else: - tmp = 360.0 - - nzcalc = nz(ctype) - if nzcalc == 0: - return tmp - else: - return tmp / nzcalc - -def nl(declat_in): - if abs(declat_in) >= 87.0: - return 1.0 - return math.floor( (2.0*math.pi) * math.acos(1.0- (1.0-math.cos(math.pi/(2.0*latz))) / math.cos( (math.pi/180.0)*abs(declat_in) )**2 )**-1) - -def dlon(declat_in, ctype, surface): - if surface: - tmp = 90.0 - else: - tmp = 360.0 - nlcalc = max(nl(declat_in)-ctype, 1) - return tmp / nlcalc - -#encode CPR position -# https://adsb-decode-guide.readthedocs.io/en/latest/content/cpr.html -# compact position reporting -def cpr_encode(lat, lon, ctype, surface): - if surface is True: - scalar = 2.**19 - else: - scalar = 2.**17 - - #encode using 360 constant for segment size. - dlati = dlat(ctype, False) - yz = math.floor(scalar * ((lat % dlati)/dlati) + 0.5) - rlat = dlati * ((yz / scalar) + math.floor(lat / dlati)) - - #encode using 360 constant for segment size. - dloni = dlon(lat, ctype, False) - xz = math.floor(scalar * ((lon % dloni)/dloni) + 0.5) - - yz = int(yz) & (2**17-1) - xz = int(xz) & (2**17-1) - - return (yz, xz) #lat, lon diff --git a/parity.py b/parity.py deleted file mode 100644 index b7d1112..0000000 --- a/parity.py +++ /dev/null @@ -1,49 +0,0 @@ -''' - Copyright 2015 Wolfgang Nagele - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -''' -def bin2dec(buf): - if 0 == len(buf): # Crap input - return -1 - return int(buf, 2) - -# Ported from: http://www.radarspotters.eu/forum/index.php?topic=5617.msg41293#msg41293 -def get_parity(msg, extended): - msg_length = len(msg) - payload = msg[:msg_length - 24] - parity = msg[msg_length - 24:] - - data = bin2dec(payload[0:32]) - if extended: - data1 = bin2dec(payload[32:64]) - data2 = bin2dec(payload[64:]) << 8 - - hex_id = bin2dec(parity) << 8 - - for i in range(0, len(payload)): - if ((data & 0x80000000) != 0): - data ^= 0xFFFA0480 - data <<= 1 - - if extended: - if ((data1 & 0x80000000) != 0): - data |= 1 - data1 <<= 1 - - if ((data2 & 0x80000000) != 0): - data1 = data1 | 1 - data2 <<= 1 - - return data - #return (data ^ hex_id) >> 8