1
0
Fork 0
mirror of https://github.com/hb9fxq/gr-digitalhf synced 2024-12-22 07:09:59 +00:00

prel. support for 12800 baud 110C bursts added

This commit is contained in:
cmayer 2019-05-23 20:34:41 +02:00
parent 7f706f6134
commit 91a06406fe

View file

@ -45,16 +45,27 @@ QAM64=np.array(
range(64)), common.CONST_DTYPE) range(64)), common.CONST_DTYPE)
## for test ## for test
#QAM64 = QAM64[(7,3,24,56,35,39,60,28),] QAM64p = QAM64[(3,24,56,35,39,60,28,7),]
#QAM64['symbols'] = [1, 0, 2, 6, 4, 5, 7, 3] QAM64p['symbols'] = range(8) ## not used
## ---- Walsh-4 codes ----------------------------------------------------------
WALSH4 = np.array([[0,0,0,0], # 0 - 00
[0,1,0,1], # 1 - 01
[0,0,1,1], # 2 - 10
[0,1,1,0]], # 3 - 11
dtype=np.uint8)
FROM_WALSH4 = -np.ones(256, dtype=np.int8)
for i in range(4):
FROM_WALSH4[np.packbits(WALSH4[i][:])[0]] = i
## ---- constellation indices --------------------------------------------------- ## ---- constellation indices ---------------------------------------------------
MODE_BPSK = 0 MODE_BPSK = 0
MODE_QPSK = 1 MODE_QPSK = 1
MODE_8PSK = 2 MODE_8PSK = 2
MODE_16QAM = 3 MODE_16QAM = 3
MODE_32QAM = 4 MODE_32QAM = 4
MODE_64QAM = 5 MODE_64QAM = 5
MODE_64QAMp = 6
## ---- data scrambler ----------------------------------------------------------- ## ---- data scrambler -----------------------------------------------------------
class ScrambleData(object): class ScrambleData(object):
@ -76,6 +87,35 @@ class ScrambleData(object):
self._state = np.concatenate(([self._state.dot(self._taps)&1], self._state = np.concatenate(([self._state.dot(self._taps)&1],
self._state[0:-1])) self._state[0:-1]))
class ScrambleDataP(object):
"""data scrambling sequence generator"""
def __init__(self):
self._i = 0
state = np.array([0,0,0,0,0,0,0,0,0,0,0,1], dtype=np.uint8)
taps = np.array([1,1,0,0,1,0,1,0,0,0,0,0], dtype=np.uint8)
n = 10000
m = len(state)
sequence = np.zeros(n, dtype=np.uint8)
sequence[0:m] = state
for i in range(m,n):
sequence[i] = sequence[i-m:i].dot(taps)&1
idx = np.arange(160, dtype=np.uint32)
self._seq = 4*sequence[3530+idx] + 2*sequence[4042+idx] + sequence[4796+idx]
def reset(self):
self._i = 0
def get_seq(self):
return self._seq
def next(self):
if self._i == 160:
self._i = 0
s = self._seq[self._i]
self._i += 1
return s
## ---- preamble definitions --------------------------------------------------- ## ---- preamble definitions ---------------------------------------------------
## 184 = 8*23 ## 184 = 8*23
PREAMBLE=common.n_psk(8, np.array( PREAMBLE=common.n_psk(8, np.array(
@ -203,7 +243,7 @@ class PhysicalLayer(object):
"""intialization""" """intialization"""
self._sps = sps self._sps = sps
self._frame_counter = -2 self._frame_counter = -2
self._constellations = [BPSK, QPSK, PSK8, QAM16, QAM32, QAM64] self._constellations = [BPSK, QPSK, PSK8, QAM16, QAM32, QAM64, QAM64p]
self._preamble = self.get_preamble() self._preamble = self.get_preamble()
self._scramble = ScrambleData() self._scramble = ScrambleData()
self._viterbi_decoder = viterbi27(0x6d, 0x4f) self._viterbi_decoder = viterbi27(0x6d, 0x4f)
@ -307,28 +347,36 @@ class PhysicalLayer(object):
self._rate_info = rate_info = TO_RATE[self._mode['rate']] self._rate_info = rate_info = TO_RATE[self._mode['rate']]
self._intl_info = intl_info = TO_INTERLEAVER[self._mode['interleaver']] self._intl_info = intl_info = TO_INTERLEAVER[self._mode['interleaver']]
print('======== rate,interleaver:', rate_info, intl_info) self._12800burst_mode = mode['rate']==(1,1,0) and mode['interleaver']==(0,0,1)
self._interleaver_frames = intl_info['frames'] print('======== rate,interleaver:', rate_info, intl_info, self._12800burst_mode)
baud = rate_info['baud'] if self._12800burst_mode:
intl_id = intl_info['id'] self._scrp = ScrambleDataP()
intl_size = INTL_SIZE[baud][intl_id] self._constellation_index = MODE_BPSK# 64QAMp
intl_incr = INTL_INCR[baud][intl_id] self._data_scramble = np.ones (256, dtype=np.complex64)
if self._deintl_depunct == None: self._data_scramble_xor = np.zeros(256, dtype=np.uint8)
self._deintl_depunct = DeIntl_DePunct(size=intl_size, ##self._data_scramble = QAM64p['points'][self._scrp.next() for _ in range(256)]
incr=intl_incr)
self._constellation_index = rate_info['ci']
print('constellation index', self._constellation_index)
self._scramble.reset()
num_bits = max(3, rate_info['bits_per_symbol'])
iscr = np.array([self._scramble.next(num_bits) for _ in range(256)],
dtype=np.uint8)
print('iscr=', iscr)
self._data_scramble = np.ones (256, dtype=np.complex64)
self._data_scramble_xor = np.zeros(256, dtype=np.uint8)
if rate_info['ci'] > MODE_8PSK:
self._data_scramble_xor = iscr
else: else:
self._data_scramble = common.n_psk(8, iscr) self._interleaver_frames = intl_info['frames']
baud = rate_info['baud']
intl_id = intl_info['id']
intl_size = INTL_SIZE[baud][intl_id]
intl_incr = INTL_INCR[baud][intl_id]
if self._deintl_depunct == None:
self._deintl_depunct = DeIntl_DePunct(size=intl_size,
incr=intl_incr)
self._constellation_index = rate_info['ci']
print('constellation index', self._constellation_index)
self._scramble.reset()
num_bits = max(3, rate_info['bits_per_symbol'])
iscr = np.array([self._scramble.next(num_bits) for _ in range(256)],
dtype=np.uint8)
print('iscr=', iscr)
self._data_scramble = np.ones (256, dtype=np.complex64)
self._data_scramble_xor = np.zeros(256, dtype=np.uint8)
if rate_info['ci'] > MODE_8PSK:
self._data_scramble_xor = iscr
else:
self._data_scramble = common.n_psk(8, iscr)
return success return success
def make_reinserted_preamble(self, offset, success): def make_reinserted_preamble(self, offset, success):
@ -344,7 +392,10 @@ class PhysicalLayer(object):
def make_data_frame(self, success): def make_data_frame(self, success):
self._preamble_offset = -72 ## all following reinserted preambles start at index -72 self._preamble_offset = -72 ## all following reinserted preambles start at index -72
a = np.zeros(256+31, common.SYMB_SCRAMBLE_DTYPE) a = np.zeros(256+31, common.SYMB_SCRAMBLE_DTYPE)
a['scramble'][:256] = self._data_scramble if self._12800burst_mode:
a['scramble'][:256] = QAM64p['points'][[self._scrp.next() for _ in range(256)]]
else:
a['scramble'][:256] = self._data_scramble
a['scramble_xor'][:256] = self._data_scramble_xor a['scramble_xor'][:256] = self._data_scramble_xor
n = (self._frame_counter-1)%72 n = (self._frame_counter-1)%72
if self._frame_counter == 72: if self._frame_counter == 72:
@ -362,16 +413,30 @@ class PhysicalLayer(object):
return a return a
def decode_soft_dec(self, soft_dec): def decode_soft_dec(self, soft_dec):
r = self._deintl_depunct.load(soft_dec) if self._12800burst_mode:
if r.shape[0] == 0: print('decode_soft_dec', len(soft_dec))
return [] n = len(soft_dec) // 32
self._viterbi_decoder.reset() soft_bits = np.zeros(2*n, dtype=np.float32)
decoded_bits = np.roll(self._viterbi_decoder.udpate(r), 7) for i in range(n):
print('bits=', decoded_bits[:100]) w = np.sum(soft_dec[32*i:32*(i+1)].reshape(8,4),0)
print('quality={}% ({},{})'.format(120.0*self._viterbi_decoder.quality()/(2*len(decoded_bits)), b = FROM_WALSH4[np.packbits(w>0)[0]] ## TODO use 2nd half of WALSH bits
self._viterbi_decoder.quality(), abs_soft_dec = np.mean(np.abs(w))
len(decoded_bits))) print('WALSH', i, w, b, abs_soft_dec)
return decoded_bits soft_bits[2*i] = abs_soft_dec*(2*(b>>1)-1)
soft_bits[2*i+1] = abs_soft_dec*(2*(b &1)-1)
return soft_bits>0
else:
r = self._deintl_depunct.load(soft_dec)
if r.shape[0] == 0:
return []
self._viterbi_decoder.reset()
decoded_bits = np.roll(self._viterbi_decoder.udpate(r), 7)
print('bits=', decoded_bits[:100])
print('quality={}% ({},{})'.format(120.0*self._viterbi_decoder.quality()/(2*len(decoded_bits)),
self._viterbi_decoder.quality(),
len(decoded_bits)))
return decoded_bits
@staticmethod @staticmethod
def get_preamble(): def get_preamble():
@ -407,3 +472,6 @@ if __name__ == '__main__':
# print(QAM64['points'][i]) # print(QAM64['points'][i])
print([s.next(6) for _ in range(256)]) print([s.next(6) for _ in range(256)])
s = ScrambleDataP()
assert(np.all(s.get_seq()[0:20]==np.array([0,2,4,3,3,6,4,5,7,6,7,0,5,5,4,3,5,4,3,7], dtype=np.uint8)))