realtime-adsb-out/ADSBLowLevelEncoder.py
Mathieu Peyréga bc9687feb9 Features:
- initial support for multiples tracks simulation

Enhancements:
- code profiling and optimization
 - faster lookup table based ppm + IQ generation
 - faster CRC24 computations
 - frame encoding

Bug fixes:
- callsign encoding
- typos
2022-03-15 20:23:40 +01:00

116 lines
4.0 KiB
Python

""" This class is responsible for low level encoding of IQ sample
This program 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 of the License, or (at your option) any later
version.
This program 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
this program. If not, see <http://www.gnu.org/licenses/>.
"""
from CustomDecorators import *
import numpy
@Singleton
class ADSBLowLevelEncoder:
def __init__(self):
self._adsb_frame_preamble = [0xA1,0x40]
self._adsb_frame_pause = [0]*4
# Build a manchester encoding lookup table
self._manchester_lookup = []
for i in range(256):
me = self.manchester_encode(i)
self._manchester_lookup.append([127*val for pair in zip(me, me) for val in pair])
# Build preamble and pause manchester encoded versions
me_bits = numpy.unpackbits(numpy.asarray(self._adsb_frame_preamble, dtype=numpy.uint8))
self._adsb_frame_preamble_IQ = [127*val for pair in zip(me_bits, me_bits) for val in pair]
self._adsb_frame_pause_IQ = self._adsb_frame_pause*16
self._len_pre_IQ = len(self._adsb_frame_preamble_IQ)
self._len_pause_IQ = len(self._adsb_frame_pause_IQ)
###############################################################
# Further work on fork
# Copyright (C) 2017 David Robinson
def extract_bit(self, byte, pos):
"""
Extract a bit from a given byte using MS ordering.
ie. B7 B6 B5 B4 B3 B2 B1 B0
"""
return (byte >> pos) & 0x01
def manchester_encode(self, byte):
"""
Encode a byte using Manchester encoding. Returns an array of bits.
Adds two start bits (1, 1) and one stop bit (0) to the array.
"""
manchester_encoded = []
# Encode byte
for i in range(7, -1, -1):
if self.extract_bit(byte, i):
manchester_encoded.extend([1,0])
else:
manchester_encoded.extend([0,1])
return manchester_encoded
def frame_1090es_ppm_modulate_IQ(self, even, odd = []):
"""
Args:
even and odd: The data frames that need to be converted to PPM
Returns:
The bytearray of the IQ samples for PPM modulated data
"""
length_even = len(even)
length_odd = len(odd)
if (length_even != 0 and length_odd == 0):
IQ = bytearray(32*length_even+2*self._len_pause_IQ+self._len_pre_IQ)
pos = self._len_pause_IQ
IQ[pos:pos+self._len_pre_IQ] = self._adsb_frame_preamble_IQ
pos += self._len_pre_IQ
tmp = []
for b in even:
tmp.extend(self._manchester_lookup[b])
IQ[pos:pos+32*length_even] = tmp
return IQ
elif (length_even != 0 and length_odd != 0):
IQ = bytearray(32*(length_even+length_odd)+2*self._len_pre_IQ+3*self._len_pause_IQ)
pos = self._len_pause_IQ
IQ[pos:pos+self._len_pre_IQ] = self._adsb_frame_preamble_IQ
pos += self._len_pre_IQ
tmp = []
for b in even:
tmp.extend(self._manchester_lookup[b])
length_even_IQ = 32*length_even
IQ[pos:pos+length_even_IQ] = tmp
pos += length_even_IQ
pos += self._len_pause_IQ
IQ[pos:pos+self._len_pre_IQ] = self._adsb_frame_preamble_IQ
pos += self._len_pre_IQ
tmp = []
for b in odd:
tmp.extend(self._manchester_lookup[b])
IQ[pos:pos+32*length_odd] = tmp
return IQ
else:
return None