gr-digitalhf/python/physical_layer/MIL_STD_188_110D.py

1030 lines
68 KiB
Python

## -*- python -*-
from __future__ import print_function
import numpy as np
from . import common
from digitalhf.digitalhf_swig import viterbi27, viterbi29
## ---- constellations ---------------------------------------------------------
BPSK=np.array(list(zip(np.exp(2j*np.pi*np.arange(2)/2), [0,1])), common.CONST_DTYPE)
QPSK=np.array(list(zip(np.exp(2j*np.pi*np.arange(4)/4), [0,1,3,2])), common.CONST_DTYPE)
PSK8=np.array(list(zip(np.exp(2j*np.pi*np.arange(8)/8), [1,0,2,3,7,6,4,5])), common.CONST_DTYPE)
QAM16=np.array(
list(zip([+0.866025+0.500000j, +0.500000+0.866025j, +1.000000+0.000000j, +0.258819+0.258819j,
-0.500000+0.866025j, +0.000000+1.000000j, -0.866025+0.500000j, -0.258819+0.258819j,
+0.500000-0.866025j, +0.000000-1.000000j, +0.866025-0.500000j, +0.258819-0.258819j,
-0.866025-0.500000j, -0.500000-0.866025j, -1.000000+0.000000j, -0.258819-0.258819j],
range(16))), common.CONST_DTYPE)
QAM32=np.array(
list(zip([+0.866380+0.499386j, +0.984849+0.173415j, +0.499386+0.866380j, +0.173415+0.984849j,
+0.520246+0.520246j, +0.520246+0.173415j, +0.173415+0.520246j, +0.173415+0.173415j,
-0.866380+0.499386j, -0.984849+0.173415j, -0.499386+0.866380j, -0.173415+0.984849j,
-0.520246+0.520246j, -0.520246+0.173415j, -0.173415+0.520246j, -0.173415+0.173415j,
+0.866380-0.499386j, +0.984849-0.173415j, +0.499386-0.866380j, +0.173415-0.984849j,
+0.520246-0.520246j, +0.520246-0.173415j, +0.173415-0.520246j, +0.173415-0.173415j,
-0.866380-0.499386j, -0.984849-0.173415j, -0.499386-0.866380j, -0.173415-0.984849j,
-0.520246-0.520246j, -0.520246-0.173415j, -0.173415-0.520246j, -0.173415-0.173415j],
range(32))), common.CONST_DTYPE)
QAM64=np.array(
list(zip([+1.000000+0.000000j, 0.822878+0.568218j, 0.821137+0.152996j, 0.932897+0.360142j,
+0.000000-1.000000j, 0.822878-0.568218j, 0.821137-0.152996j, 0.932897-0.360142j,
+0.568218+0.822878j, 0.588429+0.588429j, 0.588429+0.117686j, 0.588429+0.353057j,
+0.568218-0.822878j, 0.588429-0.588429j, 0.588429-0.117686j, 0.588429-0.353057j,
+0.152996+0.821137j, 0.117686+0.588429j, 0.117686+0.117686j, 0.117686+0.353057j,
+0.152996-0.821137j, 0.117686-0.588429j, 0.117686-0.117686j, 0.117686-0.353057j,
+0.360142+0.932897j, 0.353057+0.588429j, 0.353057+0.117686j, 0.353057+0.353057j,
+0.360142-0.932897j, 0.353057-0.588429j, 0.353057-0.117686j, 0.353057-0.353057j,
+0.000000+1.000000j, -0.822878+0.568218j, -0.821137+0.152996j, -0.932897+0.360142j,
-1.000000+0.000000j, -0.822878-0.568218j, -0.821137-0.152996j, -0.932897-0.360142j,
-0.568218+0.822878j, -0.588429+0.588429j, -0.588429+0.117686j, -0.588429+0.353057j,
-0.568218-0.822878j, -0.588429-0.588429j, -0.588429-0.117686j, -0.588429-0.353057j,
-0.152996+0.821137j, -0.117686+0.588429j, -0.117686+0.117686j, -0.117686+0.353057j,
-0.152996-0.821137j, -0.117686-0.588429j, -0.117686-0.117686j, -0.117686-0.353057j,
-0.360142+0.932897j, -0.353057+0.588429j, -0.353057+0.117686j, -0.353057+0.353057j,
-0.360142-0.932897j, -0.353057-0.588429j, -0.353057-0.117686j, -0.353057-0.353057j],
range(64))), common.CONST_DTYPE)
QAM256=np.array(
list(zip([+0.959366+0.056433j, +0.959366+0.169300j, +0.846499+0.507899j, +0.959366+0.282166j,
+0.846499+0.056433j, +0.846499+0.169300j, +0.846499+0.395033j, +0.846499+0.282166j,
+0.959366-0.056433j, +0.959366-0.169300j, +0.846499-0.507899j, +0.959366-0.282166j,
+0.846499-0.056433j, +0.846499-0.169300j, +0.846499-0.395033j, +0.846499-0.282166j,
+0.169300+0.959366j, +0.056433+0.998304j, +0.733632+0.507899j, +0.733632+0.620766j,
+0.733632+0.056433j, +0.733632+0.169300j, +0.733632+0.395033j, +0.733632+0.282166j,
+0.169300-0.959366j, +0.056433-0.998304j, +0.733632-0.507899j, +0.733632-0.620766j,
+0.733632-0.056433j, +0.733632-0.169300j, +0.733632-0.395033j, +0.733632-0.282166j,
+0.507899+0.846499j, +0.507899+0.733632j, +0.507899+0.507899j, +0.507899+0.620766j,
+0.507899+0.056433j, +0.507899+0.169300j, +0.507899+0.395033j, +0.507899+0.282166j,
+0.507899-0.846499j, +0.507899-0.733632j, +0.507899-0.507899j, +0.507899-0.620766j,
+0.507899-0.056433j, +0.507899-0.169300j, +0.507899-0.395033j, +0.507899-0.282166j,
+0.282166+0.959366j, +0.620766+0.733632j, +0.620766+0.507899j, +0.620766+0.620766j,
+0.620766+0.056433j, +0.620766+0.169300j, +0.620766+0.395033j, +0.620766+0.282166j,
+0.282166-0.959366j, +0.620766-0.733632j, +0.620766-0.507899j, +0.620766-0.620766j,
+0.620766-0.056433j, +0.620766-0.169300j, +0.620766-0.395033j, +0.620766-0.282166j,
##
+0.056433+0.846499j, +0.056433+0.733632j, +0.056433+0.507899j, +0.056433+0.620766j,
+0.056433+0.056433j, +0.056433+0.169300j, +0.056433+0.395033j, +0.056433+0.282166j,
+0.056433-0.846499j, +0.056433-0.733632j, +0.056433-0.507899j, +0.056433-0.620766j,
+0.056433-0.056433j, +0.056433-0.169300j, +0.056433-0.395033j, +0.056433-0.282166j,
+0.169300+0.846499j, +0.169300+0.733632j, +0.169300+0.507899j, +0.169300+0.620766j,
+0.169300+0.056433j, +0.169300+0.169300j, +0.169300+0.395033j, +0.169300+0.282166j,
+0.169300-0.846499j, +0.169300-0.733632j, +0.169300-0.507899j, +0.169300-0.620766j,
+0.169300-0.056433j, +0.169300-0.169300j, +0.169300-0.395033j, +0.169300-0.282166j,
+0.395033+0.846499j, +0.395033+0.733632j, +0.395033+0.507899j, +0.395033+0.620766j,
+0.395033+0.056433j, +0.395033+0.169300j, +0.395033+0.395033j, +0.395033+0.282166j,
+0.395033-0.846499j, +0.395033-0.733632j, +0.395033-0.507899j, +0.395033-0.620766j,
+0.395033-0.056433j, +0.395033-0.169300j, +0.395033-0.395033j, +0.395033-0.282166j,
+0.282166+0.846499j, +0.282166+0.733632j, +0.282166+0.507899j, +0.282166+0.620766j,
+0.282166+0.056433j, +0.282166+0.169300j, +0.282166+0.395033j, +0.282166+0.282166j,
+0.282166-0.846499j, +0.282166-0.733632j, +0.282166-0.507899j, +0.282166-0.620766j,
+0.282166-0.056433j, +0.282166-0.169300j, +0.282166-0.395033j, +0.282166-0.282166j,
##
-0.959366+0.056433j, -0.959366+0.169300j, -0.846499+0.507899j, -0.959366+0.282166j,
-0.846499+0.056433j, -0.846499+0.169300j, -0.846499+0.395033j, -0.846499+0.282166j,
-0.959366-0.056433j, -0.959366-0.169300j, -0.846499-0.507899j, -0.959366-0.282166j,
-0.846499-0.056433j, -0.846499-0.169300j, -0.846499-0.395033j, -0.846499-0.282166j,
-0.169300+0.959366j, -0.056433+0.998304j, -0.733632+0.507899j, -0.733632+0.620766j,
-0.733632+0.056433j, -0.733632+0.169300j, -0.733632+0.395033j, -0.733632+0.282166j,
-0.169300-0.959366j, -0.056433-0.998304j, -0.733632-0.507899j, -0.733632-0.620766j,
-0.733632-0.056433j, -0.733632-0.169300j, -0.733632-0.395033j, -0.733632-0.282166j,
-0.507899+0.846499j, -0.507899+0.733632j, -0.507899+0.507899j, -0.507899+0.620766j,
-0.507899+0.056433j, -0.507899+0.169300j, -0.507899+0.395033j, -0.507899+0.282166j,
-0.507899-0.846499j, -0.507899-0.733632j, -0.507899-0.507899j, -0.507899-0.620766j,
-0.507899-0.056433j, -0.507899-0.169300j, -0.507899-0.395033j, -0.507899-0.282166j,
-0.282166+0.959366j, -0.620766+0.733632j, -0.620766+0.507899j, -0.620766+0.620766j,
-0.620766+0.056433j, -0.620766+0.169300j, -0.620766+0.395033j, -0.620766+0.282166j,
-0.282166-0.959366j, -0.620766-0.733632j, -0.620766-0.507899j, -0.620766-0.620766j,
-0.620766-0.056433j, -0.620766-0.169300j, -0.620766-0.395033j, -0.620766-0.282166j,
##
-0.056433+0.846499j, -0.056433+0.733632j, -0.056433+0.507899j, -0.056433+0.620766j,
-0.056433+0.056433j, -0.056433+0.169300j, -0.056433+0.395033j, -0.056433+0.282166j,
-0.056433-0.846499j, -0.056433-0.733632j, -0.056433-0.507899j, -0.056433-0.620766j,
-0.056433-0.056433j, -0.056433-0.169300j, -0.056433-0.395033j, -0.056433-0.282166j,
-0.169300+0.846499j, -0.169300+0.733632j, -0.169300+0.507899j, -0.169300+0.620766j,
-0.169300+0.056433j, -0.169300+0.169300j, -0.169300+0.395033j, -0.169300+0.282166j,
-0.169300-0.846499j, -0.169300-0.733632j, -0.169300-0.507899j, -0.169300-0.620766j,
-0.169300-0.056433j, -0.169300-0.169300j, -0.169300-0.395033j, -0.169300-0.282166j,
-0.395033+0.846499j, -0.395033+0.733632j, -0.395033+0.507899j, -0.395033+0.620766j,
-0.395033+0.056433j, -0.395033+0.169300j, -0.395033+0.395033j, -0.395033+0.282166j,
-0.395033-0.846499j, -0.395033-0.733632j, -0.395033-0.507899j, -0.395033-0.620766j,
-0.395033-0.056433j, -0.395033-0.169300j, -0.395033-0.395033j, -0.395033-0.282166j,
-0.282166+0.846499j, -0.282166+0.733632j, -0.282166+0.507899j, -0.282166+0.620766j,
-0.282166+0.056433j, -0.282166+0.169300j, -0.282166+0.395033j, -0.282166+0.282166j,
-0.282166-0.846499j, -0.282166-0.733632j, -0.282166-0.507899j, -0.282166-0.620766j,
-0.282166-0.056433j, -0.282166-0.169300j, -0.282166-0.395033j, -0.282166-0.282166j],
range(256))), common.CONST_DTYPE)
## ---- constellation indices ---------------------------------------------------
MODE_WALSH = 0
MODE_BPSK = 0
MODE_QPSK = 1
MODE_8PSK = 2
MODE_16QAM = 3
MODE_32QAM = 4
MODE_64QAM = 5
MODE_256QAM = 6
WID_MODE = [MODE_WALSH, # 0
MODE_BPSK, # 1
MODE_BPSK, # 2
MODE_BPSK, # 3
MODE_BPSK, # 4
MODE_BPSK, # 5
MODE_QPSK, # 6
MODE_8PSK, # 7
MODE_16QAM, # 8
MODE_32QAM, # 9
MODE_64QAM, # 10
MODE_64QAM, # 11
MODE_256QAM, # 12
MODE_QPSK] # 13
BW_UNKNOWN = { ## BW -> unknown[WID]
'3 kHz': ['N/A', 48, 48, 96, 96, 256, 256, 256, 256, 256, 256, 360, 360, 256],
'6 kHz': ['N/A', 96, 96, 204, 204, 544, 544, 544, 544, 544, 544, 540, 540 ],
'9 kHz': ['N/A', 288, 288, 288, '-', 768, 768, 768, 768, 768, 768, 1080, 1080 ],
'12 kHz': ['N/A', 192, 192, 384, 384, 1024, 1024, 1024, 1024, 1024, 1024, 1080, 1080 ],
'15 kHz': ['N/A', 288, 288, 288, 288, 1280, 1280, 1280, 1280, 1280, 1280, 1152, 1152 ],
'18 kHz': ['N/A', 448, 448, 448, '-', 1536, 1536, 1536, 1536, 1536, 1536, 1920, 1920 ],
'21 kHz': ['N/A', 320, 320, 320, 320, 1344, 1344, 1344, 1344, 1344, 1344, 2560, 2560 ],
'24 kHz': ['N/A', 272, 272, 816, 816, 2176, 2176, 2176, 2176, 2176, 2176, 1920, 1920 ],
'30 kHz': ['N/A', 576, 576, 576, 576, 2560, 2560, 2560, 2560, 2560, 2560, 2700, 2700 ],
'36 kHz': ['N/A', 1152, 1152, 1152, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3240, 3240 ],
'42 kHz': ['N/A', 768, 768, 768, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3840, 3840 ],
'48 kHz': ['N/A', 512, 512, 512, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2880, 2880 ]
}
BW_KNOWN = { ## BW -> known[WID]
'3 kHz': ['N/A', 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 24, 24, 32],
'6 kHz': ['N/A', 96, 96, 68, 68, 68, 68, 68, 68, 68, 68, 36, 36 ],
'9 kHz': ['N/A', 144, 144, 144, '-', 96, 96, 96, 96, 96, 96, 72, 72 ],
'12 kHz': ['N/A', 192, 192, 128, 128, 128, 128, 128, 128, 128, 128, 72, 72 ],
'15 kHz': ['N/A', 192, 192, 192, 192, 160, 160, 160, 160, 160, 160, 128, 128 ],
'18 kHz': ['N/A', 224, 224, 224, '-', 192, 192, 192, 192, 192, 192, 128, 128 ],
'21 kHz': ['N/A', 240, 240, 240, 240, 224, 224, 224, 224, 224, 224, 128, 128 ],
'24 kHz': ['N/A', 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 128, 128 ],
'30 kHz': ['N/A', 384, 384, 384, 384, 320, 320, 320, 320, 320, 320, 180, 180 ],
'36 kHz': ['N/A', 576, 576, 576, 384, 384, 384, 384, 384, 384, 384, 216, 216 ],
'42 kHz': ['N/A', 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 192, 192 ],
'48 kHz': ['N/A', 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 192, 192 ]
}
MP_LEN_BASE_SHIFT = {
24: {'base_len': 13, 'base_shift': 6},
32: {'base_len': 16, 'base_shift': 8},
36: {'base_len': 19, 'base_shift': 9},
48: {'base_len': 25, 'base_shift': 12},
64: {'base_len': 36, 'base_shift': 18},
68: {'base_len': 36, 'base_shift': 18},
72: {'base_len': 36, 'base_shift': 18},
96: {'base_len': 49, 'base_shift': 24},
128: {'base_len': 64, 'base_shift': 32},
144: {'base_len': 81, 'base_shift': 40},
160: {'base_len': 81, 'base_shift': 40},
180: {'base_len': 100, 'base_shift': 50},
192: {'base_len': 100, 'base_shift': 50},
216: {'base_len': 121, 'base_shift': 60},
224: {'base_len': 121, 'base_shift': 60},
240: {'base_len': 121, 'base_shift': 60},
272: {'base_len': 144, 'base_shift': 72},
320: {'base_len': 169, 'base_shift': 85},
384: {'base_len': 196, 'base_shift': 98},
512: {'base_len': 256, 'base_shift': 128},
576: {'base_len': 289, 'base_shift': 145}
}
def mp_base(n):
#mp=@(n,q) exp(1i*pi*(2*sqrt(n)*floor([0:n-1]/sqrt(n)) .* [0:n-1]*q/n))
if n == 13: ## Barker-13 sequence
return np.array([1,1,1,1,1,-1,-1,1,1,-1,1,-1,1],
dtype=np.complex64)
if n == 19: ## [1 -Legendre(k/19)]
return np.array([1,-1,1,1,-1,-1,-1,-1,1,-1,1,-1,1,1,1,1,-1,-1,1],
dtype=np.complex64)
w = np.arange(n)
m = np.sqrt(n)
return np.exp(-2j*np.pi * m*np.floor(w/m) * w / n,
dtype=np.complex64)
def make_mp(length, base_len, shift):
z = np.roll(mp_base(base_len), -shift)
while len(z) < length:
n = len(z)
z = np.append(z, z[0:min(n, length-n)])
return z
##------------------------------------------------------------------------------
INTERLEAVERS = ['US', 'S', 'M', 'L']
BW_INTL = { ## [BW][WID][INTL] -> [Number of Frames, Number of bits, Number of Input Bits]
'3 kHz': [
{'US': ['-', '-', '-'], 'S': [40, 80, 40], 'M': [144, 288, 144], 'L': [576, 1152, 576]}, ## WID 0
{'US': [ 4, 192, 24], 'S': [16, 768, 96], 'M': [ 64, 3072, 384], 'L': [256, 12288, 1536]}, ## WID 1
{'US': [ 4, 192, 48], 'S': [16, 768, 192], 'M': [ 64, 3072, 768], 'L': [256, 12288, 3072]}, ## WID 2
{'US': [ 2, 192, 64], 'S': [ 8, 768, 256], 'M': [ 32, 3072, 1024], 'L': [128, 12288, 4096]}, ## WID 3
{'US': [ 2, 192, 128], 'S': [ 8, 768, 512], 'M': [ 32, 3072, 2048], 'L': [128, 12288, 8192]}, ## WID 4
{'US': [ 1, 256, 192], 'S': [ 4, 1024, 768], 'M': [ 16, 4096, 3072], 'L': [ 64, 16384, 12288]}, ## WID 5
{'US': [ 1, 512, 384], 'S': [ 4, 2048, 1536], 'M': [ 16, 8192, 6144], 'L': [ 64, 32768, 24576]}, ## WID 6
{'US': [ 1, 768, 576], 'S': [ 4, 3072, 2304], 'M': [ 16, 12288, 9216], 'L': [ 64, 49152, 36864]}, ## WID 7
{'US': [ 1, 1024, 768], 'S': [ 4, 4096, 3072], 'M': [ 16, 16384, 12288], 'L': [ 64, 65536, 49152]}, ## WID 8
{'US': [ 1, 1280, 960], 'S': [ 4, 5120, 3840], 'M': [ 16, 20480, 15360], 'L': [ 64, 81920, 61440]}, ## WID 9
{'US': [ 1, 1536, 1152], 'S': [ 4, 6144, 4608], 'M': [ 16, 24576, 18432], 'L': [ 64, 98304, 73728]}, ## WID 10
{'US': [ 1, 2160, 1920], 'S': [ 4, 8640, 7680], 'M': [ 16, 34560, 30720], 'L': [ 64, 138240, 122880]}, ## WID 11
{'US': [ 1, 2880, 2560], 'S': [ 4, 11520, 10240], 'M': [ 16, 46080, 40960], 'L': [ 64, 184320, 163840]}, ## WID 12
{'US': [ 1, 512, 288], 'S': [ 4, 2048, 1152], 'M': [ 16, 8192, 4608], 'L': [ 64, 32768, 18432]}], ## WID 13
'6 kHz': [
{'US': ['-', '-', '-'], 'S': [80, 160, 80], 'M': [288, 576, 288], 'L': [1152, 2304, 1152]}, ## WID 0
{'US': [ 4, 384, 48], 'S': [16, 1536, 192], 'M': [ 64, 6144, 768], 'L': [ 256, 24576, 3072]}, ## WID 1
{'US': [ 4, 384, 96], 'S': [16, 1536, 384], 'M': [ 64, 6144, 1536], 'L': [ 256, 24576, 6144]}, ## WID 2
{'US': [ 2, 408, 136], 'S': [ 8, 1632, 544], 'M': [ 32, 6528, 2176], 'L': [ 128, 26112, 8704]}, ## WID 3
{'US': [ 2, 408, 272], 'S': [ 8, 1632, 1088], 'M': [ 32, 6528, 4352], 'L': [ 128, 26112, 17408]}, ## WID 4
{'US': [ 1, 544, 408], 'S': [ 4, 2176, 1632], 'M': [ 16, 8704, 6528], 'L': [ 64, 34816, 26112]}, ## WID 5
{'US': [ 1, 1088, 816], 'S': [ 4, 4352, 3264], 'M': [ 16, 17408, 13056], 'L': [ 64, 69632, 52224]}, ## WID 6
{'US': [ 1, 1632, 1224], 'S': [ 4, 6528, 4896], 'M': [ 16, 26112, 19584], 'L': [ 64, 104448, 78336]}, ## WID 7
{'US': [ 1, 2176, 1632], 'S': [ 4, 8704, 6528], 'M': [ 16, 34816, 26112], 'L': [ 64, 139264, 104448]}, ## WID 8
{'US': [ 1, 2720, 2040], 'S': [ 4, 10880, 8160], 'M': [ 16, 43520, 32640], 'L': [ 64, 174080, 130560]}, ## WID 9
{'US': [ 1, 3264, 2448], 'S': [ 4, 13056, 9792], 'M': [ 16, 52224, 39168], 'L': [ 64, 208896, 156672]}, ## WID 10
{'US': [ 1, 3240, 2880], 'S': [ 4, 12960, 11520], 'M': [ 16, 51840, 46080], 'L': [ 64, 207360, 184320]}, ## WID 11
{'US': [ 1, 4320, 3840], 'S': [ 4, 17280, 15360], 'M': [ 16, 69120, 61440], 'L': [ 64, 276480, 245760]}], ## WID 12
'9 kHz': [
{'US': ['-', '-', '-'], 'S': [120, 240, 160], 'M': [432, 864, 576], 'L': [1728, 3456, 2304]}, ## WID 0
{'US': [ 2, 576, 72], 'S': [ 8, 2304, 288], 'M': [ 32, 9216, 1152], 'L': [ 128, 36864, 4608]}, ## WID 1
{'US': [ 2, 576, 144], 'S': [ 8, 2304, 576], 'M': [ 32, 9216, 2304], 'L': [ 128, 36864, 9216]}, ## WID 2
{'US': [ 2, 576, 288], 'S': [ 8, 2304, 1152], 'M': [ 32, 9216, 4608], 'L': [ 128, 36864, 18432]}, ## WID 3
{'US': ['-', '-', '-'], 'S': ['-', '-', '-'], 'M': ['-', '-', '-'], 'L': [ '-', '-', '-']}, ## WID 4
{'US': [ 1, 768, 576], 'S': [ 4, 3072, 2304], 'M': [ 16, 12288, 9216], 'L': [ 64, 49152, 36864]}, ## WID 5
{'US': [ 1, 1536, 1152], 'S': [ 4, 6144, 4608], 'M': [ 16, 24576, 18432], 'L': [ 64, 98304, 73728]}, ## WID 6
{'US': [ 1, 2304, 1728], 'S': [ 4, 9216, 6912], 'M': [ 16, 36864, 27648], 'L': [ 64, 147456, 110592]}, ## WID 7
{'US': [ 1, 3072, 2304], 'S': [ 4, 12288, 9216], 'M': [ 16, 49152, 36864], 'L': [ 64, 196608, 147456]}, ## WID 8
{'US': [ 1, 3840, 2880], 'S': [ 4, 15360, 11520], 'M': [ 16, 61440, 46080], 'L': [ 64, 245760, 184320]}, ## WID 9
{'US': [ 1, 4608, 3456], 'S': [ 4, 18432, 13824], 'M': [ 16, 73728, 55296], 'L': [ 64, 294912, 221184]}, ## WID 10
{'US': [ 1, 6480, 5760], 'S': [ 4, 25920, 23040], 'M': [ 16, 103680, 92160], 'L': [ 64, 414720, 368640]}, ## WID 11
{'US': [ 1, 8640, 7680], 'S': [ 4, 34560, 30720], 'M': [ 16, 138240, 122880], 'L': [ 64, 552960, 491520]}], ## WID 12
'12 kHz': [
{'US': ['-', '-', '-'], 'S': [160, 320, 160], 'M': [576, 1152, 576], 'L': [2304, 4608, 2304]}, ## WID 0
{'US': [ 3, 576, 72], 'S': [ 12, 2304, 288], 'M': [ 48, 9216, 1152], 'L': [ 192, 36864, 4608]}, ## WID 1
{'US': [ 3, 576, 144], 'S': [ 12, 2304, 576], 'M': [ 48, 9216, 2304], 'L': [ 192, 36864, 9216]}, ## WID 2
{'US': [ 2, 768, 256], 'S': [ 8, 3072, 1024], 'M': [ 32, 12288, 4096], 'L': [ 128, 49152, 16384]}, ## WID 3
{'US': [ 2, 768, 512], 'S': [ 8, 3072, 2048], 'M': [ 32, 12288, 8192], 'L': [ 128, 49152, 32768]}, ## WID 4
{'US': [ 1, 1024, 768], 'S': [ 4, 4096, 3072], 'M': [ 16, 16384, 12288], 'L': [ 64, 65536, 49152]}, ## WID 5
{'US': [ 1, 2048, 1536], 'S': [ 4, 8192, 6144], 'M': [ 16, 32768, 24576], 'L': [ 64, 131072, 98304]}, ## WID 6
{'US': [ 1, 3072, 2304], 'S': [ 4, 12288, 9216], 'M': [ 16, 49152, 36864], 'L': [ 64, 196608, 147456]}, ## WID 7
{'US': [ 1, 4096, 3072], 'S': [ 4, 16384, 12288], 'M': [ 16, 65536, 49152], 'L': [ 64, 262144, 196608]}, ## WID 8
{'US': [ 1, 5120, 3840], 'S': [ 4, 20480, 15360], 'M': [ 16, 81920, 61440], 'L': [ 64, 327680, 245760]}, ## WID 9
{'US': [ 1, 6144, 4608], 'S': [ 4, 24576, 18432], 'M': [ 16, 98304, 73728], 'L': [ 64, 393216, 294912]}, ## WID 10
{'US': [ 1, 6480, 5760], 'S': [ 4, 25920, 23040], 'M': [ 16, 103680, 92160], 'L': [ 64, 414720, 368640]}, ## WID 11
{'US': [ 1, 8640, 7680], 'S': [ 4, 34560, 30720], 'M': [ 16, 138240, 122880], 'L': [ 64, 552960, 491520]}], ## WID 12
'15 kHz': [
{'US': ['-', '-', '-'], 'S': [200, 400, 160], 'M': [720, 1440, 576], 'L': [2880, 5760, 2304]}, ## WID 0
{'US': [ 3, 864, 72], 'S': [ 12, 3456, 288], 'M': [ 48, 13824, 1152], 'L': [ 192, 55296, 4608]}, ## WID 1
{'US': [ 3, 864, 144], 'S': [ 12, 3456, 576], 'M': [ 48, 13824, 2304], 'L': [ 192, 55296, 9216]}, ## WID 2
{'US': [ 3, 864, 288], 'S': [ 12, 3456, 1152], 'M': [ 48, 13824, 4608], 'L': [ 192, 55296, 18432]}, ## WID 3
{'US': [ 3, 864, 576], 'S': [ 12, 3456, 2304], 'M': [ 48, 13824, 9216], 'L': [ 192, 55296, 36864]}, ## WID 4
{'US': [ 1, 1280, 960], 'S': [ 4, 5120, 3840], 'M': [ 16, 20480, 15360], 'L': [ 64, 81920, 61440]}, ## WID 5
{'US': [ 1, 2560, 1920], 'S': [ 4, 10240, 7680], 'M': [ 16, 40960, 30720], 'L': [ 64, 163840, 122880]}, ## WID 6
{'US': [ 1, 3840, 2880], 'S': [ 4, 15360, 11520], 'M': [ 16, 61440, 46080], 'L': [ 64, 245760, 184320]}, ## WID 7
{'US': [ 1, 5120, 3840], 'S': [ 4, 20480, 15360], 'M': [ 16, 81920, 61440], 'L': [ 64, 327680, 245760]}, ## WID 8
{'US': [ 1, 6400, 4800], 'S': [ 4, 25600, 19200], 'M': [ 16, 102400, 76800], 'L': [ 64, 409600, 307200]}, ## WID 9
{'US': [ 1, 7680, 5760], 'S': [ 4, 30720, 23040], 'M': [ 16, 122880, 92160], 'L': [ 64, 491520, 368640]}, ## WID 10
{'US': [ 1, 6912, 6144], 'S': [ 4, 27648, 24576], 'M': [ 16, 110592, 98304], 'L': [ 64, 442368, 393216]}, ## WID 11
{'US': [ 1, 9216, 8192], 'S': [ 4, 36864, 32768], 'M': [ 16, 147456, 131072], 'L': [ 64, 589824, 524288]}], ## WID 12
'18 kHz': [
{'US': ['-', '-', '-'], 'S': [240, 480, 320], 'M': [864, 1728, 1152], 'L': [3456, 6912, 4608]}, ## WID 0
{'US': [ 3, 1344, 168], 'S': [ 12, 5376, 672], 'M': [ 48, 21504, 2688], 'L': [ 192, 86016, 10752]}, ## WID 1
{'US': [ 3, 1344, 336], 'S': [ 12, 5376, 1344], 'M': [ 48, 21504, 5376], 'L': [ 192, 86016, 21504]}, ## WID 2
{'US': [ 3, 1344, 672], 'S': [ 12, 5376, 2688], 'M': [ 48, 21504, 10752], 'L': [ 192, 86016, 43008]}, ## WID 3
{'US': ['-', '-', '-'], 'S': ['-', '-', '-'], 'M': ['-', '-', '-'], 'L': [ '-', '-', '-']}, ## WID 4
{'US': [ 1, 1536, 1152], 'S': [ 4, 6144, 4608], 'M': [ 16, 24576, 18432], 'L': [ 64, 98304, 73728]}, ## WID 5
{'US': [ 1, 3072, 2304], 'S': [ 4, 12288, 9216], 'M': [ 16, 49152, 36864], 'L': [ 64, 196608, 147456]}, ## WID 6
{'US': [ 1, 4608, 3456], 'S': [ 4, 18432, 13824], 'M': [ 16, 73728, 55296], 'L': [ 64, 294912, 221184]}, ## WID 7
{'US': [ 1, 6144, 4608], 'S': [ 4, 24576, 18432], 'M': [ 16, 98304, 73728], 'L': [ 64, 393216, 294912]}, ## WID 8
{'US': [ 1, 7680, 5760], 'S': [ 4, 30720, 23040], 'M': [ 16, 122880, 92160], 'L': [ 64, 491520, 368640]}, ## WID 9
{'US': [ 1, 9216, 6912], 'S': [ 4, 36864, 27648], 'M': [ 16, 147456, 110592], 'L': [ 64, 589824, 442368]}, ## WID 10
{'US': [ 1, 11520, 10240], 'S': [ 4, 46080, 40960], 'M': [ 16, 184320, 163840], 'L': [ 64, 737280, 655360]}, ## WID 11
{'US': [ 1, 15360, 12800], 'S': [ 4, 61440, 51200], 'M': [ 16, 245760, 204800], 'L': [ 64, 983040, 819200]}], ## WID 12
'21 kHz': [
{'US': ['-', '-', '-'], 'S': [280, 560, 160], 'M': [1008, 2016, 576], 'L': [4032, 8064, 2304]}, ## WID 0
{'US': [ 4, 1280, 80], 'S': [ 16, 5120, 320], 'M': [ 64, 20480, 1280], 'L': [ 256, 81920, 5120]}, ## WID 1
{'US': [ 4, 1280, 160], 'S': [ 16, 5120, 640], 'M': [ 64, 20480, 2560], 'L': [ 256, 81920, 10240]}, ## WID 2
{'US': [ 4, 1280, 320], 'S': [ 16, 5120, 1280], 'M': [ 64, 20480, 5120], 'L': [ 256, 81920, 20480]}, ## WID 3
{'US': [ 4, 1280, 640], 'S': [ 16, 5120, 2560], 'M': [ 64, 20480, 10240], 'L': [ 256, 81920, 40960]}, ## WID 4
{'US': [ 1, 1344, 896], 'S': [ 4, 5376, 3584], 'M': [ 16, 21504, 14336], 'L': [ 64, 86016, 57344]}, ## WID 5
{'US': [ 1, 2688, 1792], 'S': [ 4, 10752, 7168], 'M': [ 16, 43008, 28672], 'L': [ 64, 172032, 114688]}, ## WID 6
{'US': [ 1, 4032, 2688], 'S': [ 4, 16128, 10752], 'M': [ 16, 64512, 43008], 'L': [ 64, 258048, 172032]}, ## WID 7
{'US': [ 1, 5376, 3584], 'S': [ 4, 21504, 14336], 'M': [ 16, 86016, 57344], 'L': [ 64, 344064, 229376]}, ## WID 8
{'US': [ 1, 6720, 4480], 'S': [ 4, 26880, 17920], 'M': [ 16, 107520, 71680], 'L': [ 64, 430080, 286720]}, ## WID 9
{'US': [ 1, 8064, 5376], 'S': [ 4, 32256, 21504], 'M': [ 16, 129024, 86016], 'L': [ 64, 516096, 344064]}, ## WID 10
{'US': [ 1, 15360, 12288], 'S': [ 4, 61440, 49152], 'M': [ 16, 245760, 196608], 'L': [ 64, 983040, 786432]}, ## WID 11
{'US': [ 1, 20480, 18432], 'S': [ 4, 81920, 73728], 'M': [ 16, 327680, 294912], 'L': [ 64, 1310720, 1179648]}], ## WID 12
'24 kHz': [
{'US': ['-', '-', '-'], 'S': [320, 640, 320], 'M': [1152, 2304, 1152], 'L': [4608, 9216, 4608]}, ## WID 0
{'US': [ 4, 1088, 136], 'S': [ 16, 4352, 544], 'M': [ 64, 17408, 2176], 'L': [ 256, 69632, 8704]}, ## WID 1
{'US': [ 4, 1088, 272], 'S': [ 16, 4352, 1088], 'M': [ 64, 17408, 4352], 'L': [ 256, 69632, 17408]}, ## WID 2
{'US': [ 2, 1632, 544], 'S': [ 8, 6528, 2176], 'M': [ 32, 26112, 8704], 'L': [ 128, 104448, 34816]}, ## WID 3
{'US': [ 2, 1632, 1088], 'S': [ 8, 6528, 4352], 'M': [ 32, 26112, 17408], 'L': [ 128, 104448, 69632]}, ## WID 4
{'US': [ 1, 2176, 1632], 'S': [ 4, 8704, 6528], 'M': [ 16, 34816, 26112], 'L': [ 64, 139264, 104448]}, ## WID 5
{'US': [ 1, 4352, 3264], 'S': [ 4, 17408, 13056], 'M': [ 16, 69632, 52224], 'L': [ 64, 278528, 208896]}, ## WID 6
{'US': [ 1, 6528, 4896], 'S': [ 4, 26112, 19584], 'M': [ 16, 104448, 78336], 'L': [ 64, 417792, 313344]}, ## WID 7
{'US': [ 1, 8704, 6528], 'S': [ 4, 34816, 26112], 'M': [ 16, 139264, 104448], 'L': [ 64, 557056, 417792]}, ## WID 8
{'US': [ 1, 10880, 8160], 'S': [ 4, 43520, 32640], 'M': [ 16, 174080, 130560], 'L': [ 64, 696320, 522240]}, ## WID 9
{'US': [ 1, 13056, 9792], 'S': [ 4, 52224, 39168], 'M': [ 16, 208896, 156672], 'L': [ 64, 835584, 626688]}, ## WID 10
{'US': [ 1, 11520, 10240], 'S': [ 4, 46080, 40960], 'M': [ 16, 184320, 163840], 'L': [ 64, 737280, 655360]}, ## WID 11
{'US': [ 1, 15360, 12800], 'S': [ 4, 61440, 51200], 'M': [ 16, 245760, 204800], 'L': [ 64, 983040, 819200]}], ## WID 12
'30 kHz': [
{'US': ['-', '-', '-'], 'S': [400, 800, 320], 'M': [1440, 2880, 1152], 'L': [5760, 11520, 4608]}, ## WID 0
{'US': [ 3, 1728, 144], 'S': [ 12, 6912, 576], 'M': [ 48, 27648, 2304], 'L': [ 192, 110592, 9216]}, ## WID 1
{'US': [ 3, 1728, 288], 'S': [ 12, 6912, 1152], 'M': [ 48, 27648, 4608], 'L': [ 192, 110592, 18432]}, ## WID 2
{'US': [ 3, 1728, 576], 'S': [ 12, 6912, 2304], 'M': [ 48, 27648, 9216], 'L': [ 192, 110592, 36864]}, ## WID 3
{'US': [ 3, 1728, 1152], 'S': [ 12, 6912, 4608], 'M': [ 48, 27648, 18432], 'L': [ 192, 110592, 73728]}, ## WID 4
{'US': [ 1, 2560, 1920], 'S': [ 4, 10240, 7680], 'M': [ 16, 40960, 30720], 'L': [ 64, 163840, 122880]}, ## WID 5
{'US': [ 1, 5120, 3840], 'S': [ 4, 20480, 15360], 'M': [ 16, 81920, 61440], 'L': [ 64, 327680, 245760]}, ## WID 6
{'US': [ 1, 7680, 5760], 'S': [ 4, 30720, 23040], 'M': [ 16, 122880, 92160], 'L': [ 64, 491520, 368640]}, ## WID 7
{'US': [ 1, 10240, 7680], 'S': [ 4, 40960, 30720], 'M': [ 16, 163840, 122880], 'L': [ 64, 655360, 491520]}, ## WID 8
{'US': [ 1, 12800, 9600], 'S': [ 4, 51200, 38400], 'M': [ 16, 204800, 153600], 'L': [ 64, 819200, 614400]}, ## WID 9
{'US': [ 1, 15360, 11520], 'S': [ 4, 61440, 46080], 'M': [ 16, 245760, 184320], 'L': [ 64, 983040, 737280]}, ## WID 10
{'US': [ 1, 16200, 14400], 'S': [ 4, 64800, 57600], 'M': [ 16, 259200, 230400], 'L': [ 64, 1036800, 921600]}, ## WID 11
{'US': [ 1, 21600, 19200], 'S': [ 4, 86400, 76800], 'M': [ 16, 345600, 307200], 'L': [ 64, 1382400, 1228800]}], ## WID 12
'36 kHz': [
{'US': ['-', '-', '-'], 'S': [480, 960, 640], 'M': [1728, 3456, 2304], 'L': [6912, 13824, 9216]}, ## WID 0
{'US': [ 2, 2304, 288], 'S': [ 8, 9216, 1152], 'M': [ 32, 36864, 4608], 'L': [ 128, 147456, 18432]}, ## WID 1
{'US': [ 2, 2304, 576], 'S': [ 8, 9216, 2304], 'M': [ 32, 36864, 9216], 'L': [ 128, 147456, 36864]}, ## WID 2
{'US': [ 2, 2304, 1152], 'S': [ 8, 9216, 4608], 'M': [ 32, 36864, 18432], 'L': [ 128, 147456, 73728]}, ## WID 3
{'US': [ 1, 3072, 1536], 'S': [ 4, 12288, 6144], 'M': [ 16, 49152, 24576], 'L': [ 64, 196608, 98304]}, ## WID 4
{'US': [ 1, 3072, 2304], 'S': [ 4, 12288, 9216], 'M': [ 16, 49152, 36864], 'L': [ 64, 196608, 147456]}, ## WID 5
{'US': [ 1, 6144, 4608], 'S': [ 4, 24576, 18432], 'M': [ 16, 98304, 73728], 'L': [ 64, 393216, 294912]}, ## WID 6
{'US': [ 1, 9216, 6912], 'S': [ 4, 36864, 27648], 'M': [ 16, 147456, 110592], 'L': [ 64, 589824, 442368]}, ## WID 7
{'US': [ 1, 12288, 9216], 'S': [ 4, 49152, 36864], 'M': [ 16, 196608, 147456], 'L': [ 64, 786432, 589824]}, ## WID 8
{'US': [ 1, 15360, 11520], 'S': [ 4, 61440, 46080], 'M': [ 16, 245760, 184320], 'L': [ 64, 983040, 737280]}, ## WID 9
{'US': [ 1, 18432, 13824], 'S': [ 4, 73728, 55296], 'M': [ 16, 294912, 221184], 'L': [ 64, 1179648, 884736]}, ## WID 10
{'US': [ 1, 19440, 17280], 'S': [ 4, 77760, 69120], 'M': [ 16, 311040, 276480], 'L': [ 64, 1244160, 1105920]}, ## WID 11
{'US': [ 1, 25920, 23040], 'S': [ 4, 103680, 92160], 'M': [ 16, 414720, 368640], 'L': [ 64, 1658880, 1474560]}], ## WID 12
'42 kHz': [
{'US': ['-', '-', '-'], 'S': [560, 1120, 640], 'M': [2016, 4032, 2304], 'L': [8064, 16128, 9216]}, ## WID 0
{'US': [ 3, 2304, 288], 'S': [ 12, 9216, 1152], 'M': [ 48, 36864, 4608], 'L': [ 192, 147456, 18432]}, ## WID 1
{'US': [ 3, 2304, 576], 'S': [ 12, 9216, 2304], 'M': [ 48, 36864, 9216], 'L': [ 192, 147456, 36864]}, ## WID 2
{'US': [ 3, 2304, 1152], 'S': [ 12, 9216, 4608], 'M': [ 48, 36864, 18432], 'L': [ 192, 147456, 73728]}, ## WID 3
{'US': [ 1, 3456, 1728], 'S': [ 4, 13824, 6912], 'M': [ 16, 55296, 27648], 'L': [ 64, 221184, 110592]}, ## WID 4
{'US': [ 1, 3456, 2304], 'S': [ 4, 13824, 9216], 'M': [ 16, 55296, 36864], 'L': [ 64, 221184, 147456]}, ## WID 5
{'US': [ 1, 6912, 4608], 'S': [ 4, 27648, 18432], 'M': [ 16, 110592, 73728], 'L': [ 64, 442368, 294912]}, ## WID 6
{'US': [ 1, 10368, 6912], 'S': [ 4, 41472, 27648], 'M': [ 16, 165888, 110592], 'L': [ 64, 663552, 442368]}, ## WID 7
{'US': [ 1, 13824, 9216], 'S': [ 4, 55296, 36864], 'M': [ 16, 221184, 147456], 'L': [ 64, 884736, 589824]}, ## WID 8
{'US': [ 1, 17280, 11520], 'S': [ 4, 69120, 46080], 'M': [ 16, 276480, 184320], 'L': [ 64, 1105920, 737280]}, ## WID 9
{'US': [ 1, 20736, 13824], 'S': [ 4, 82944, 55296], 'M': [ 16, 331776, 221184], 'L': [ 64, 1327104, 884736]}, ## WID 10
{'US': [ 1, 23040, 19200], 'S': [ 4, 92160, 76800], 'M': [ 16, 368640, 307200], 'L': [ 64, 1474560, 1228800]}, ## WID 11
{'US': [ 1, 30720, 23040], 'S': [ 4, 122880, 92160], 'M': [ 16, 491520, 368640], 'L': [ 64, 1966080, 1474560]}], ## WID 12
'48 kHz': [
{'US': ['-', '-', '-'], 'S': [640, 1280, 640], 'M': [2304, 4608, 2304], 'L': [9216, 18432, 9216]}, ## WID 0
{'US': [ 3, 1536, 192], 'S': [ 18, 9216, 1152], 'M': [ 72, 36864, 4608], 'L': [ 288, 147456, 18432]}, ## WID 1
{'US': [ 3, 1536, 384], 'S': [ 18, 9216, 2304], 'M': [ 72, 36864, 9216], 'L': [ 288, 147456, 36864]}, ## WID 2
{'US': [ 3, 1536, 768], 'S': [ 18, 9216, 4608], 'M': [ 72, 36864, 18432], 'L': [ 288, 147456, 73728]}, ## WID 3
{'US': [ 1, 2560, 1280], 'S': [ 6, 15360, 7680], 'M': [ 24, 61440, 30720], 'L': [ 96, 245760, 122880]}, ## WID 4
{'US': [ 1, 2560, 1920], 'S': [ 6, 15360, 11520], 'M': [ 24, 61440, 46080], 'L': [ 96, 245760, 184320]}, ## WID 5
{'US': [ 1, 5120, 3840], 'S': [ 6, 30720, 23040], 'M': [ 24, 122880, 92160], 'L': [ 96, 491520, 368640]}, ## WID 6
{'US': [ 1, 7680, 5760], 'S': [ 6, 46080, 34560], 'M': [ 24, 184320, 138240], 'L': [ 96, 737280, 552960]}, ## WID 7
{'US': [ 1, 10240, 7680], 'S': [ 6, 61440, 46080], 'M': [ 24, 245760, 184320], 'L': [ 96, 983040, 737280]}, ## WID 8
{'US': [ 1, 12800, 9600], 'S': [ 6, 76800, 57600], 'M': [ 24, 307200, 230400], 'L': [ 96, 1228800, 921600]}, ## WID 9
{'US': [ 1, 15360, 11520], 'S': [ 6, 92160, 69120], 'M': [ 24, 368640, 276480], 'L': [ 96, 1474560, 1105920]}, ## WID 10
{'US': [ 1, 17280, 15360], 'S': [ 6, 103680, 92160], 'M': [ 24, 414720, 368640], 'L': [ 96, 1658880, 1474560]}, ## WID 11
{'US': [ 1, 23040, 19200], 'S': [ 6, 138240, 115200], 'M': [ 24, 552960, 460800], 'L': [ 96, 2211840, 1843200]}] ## WID 12
}
BW_INTL_INCR = { ## [BW][WID][INTL] -> interleaver increment
'3 kHz': [
{'US': '-', 'S': 11, 'M': 37, 'L': 145}, ## WID 0
{'US': 25, 'S': 97, 'M': 385, 'L': 1543}, ## WID 1
{'US': 25, 'S': 97, 'M': 385, 'L': 1543}, ## WID 2
{'US': 25, 'S': 97, 'M': 385, 'L': 1549}, ## WID 3
{'US': 25, 'S': 97, 'M': 385, 'L': 1549}, ## WID 4
{'US': 33, 'S': 129, 'M': 513, 'L': 2081}, ## WID 5
{'US': 65, 'S': 257, 'M': 1025, 'L': 4161}, ## WID 6
{'US': 97, 'S': 385, 'M': 1537, 'L': 6241}, ## WID 7
{'US': 129, 'S': 513, 'M': 2049, 'L': 8321}, ## WID 8
{'US': 161, 'S': 641, 'M': 2561, 'L': 10403}, ## WID 9
{'US': 193, 'S': 769, 'M': 3073, 'L': 12481}, ## WID 10
{'US': 271, 'S': 1081, 'M': 4321, 'L': 17551}, ## WID 11
{'US': 361, 'S': 1441, 'M': 5761, 'L': 23401}, ## WID 12
{'US': 65, 'S': 257, 'M': 1025, 'L': 4161}], ## WID 13
'6 kHz': [
{'US': '-', 'S': 21, 'M': 73, 'L': 289}, ## WID 0
{'US': 49, 'S': 193, 'M': 769, 'L': 3085}, ## WID 1
{'US': 49, 'S': 193, 'M': 769, 'L': 3085}, ## WID 2
{'US': 53, 'S': 205, 'M': 817, 'L': 3293}, ## WID 3
{'US': 53, 'S': 205, 'M': 817, 'L': 3293}, ## WID 4
{'US': 69, 'S': 273, 'M': 1089, 'L': 4421}, ## WID 5
{'US': 137, 'S': 545, 'M': 2177, 'L': 8841}, ## WID 6
{'US': 205, 'S': 817, 'M': 3265, 'L': 13261}, ## WID 7
{'US': 273, 'S': 1089, 'M': 4353, 'L': 17681}, ## WID 8
{'US': 341, 'S': 1361, 'M': 5441, 'L': 22103}, ## WID 9
{'US': 409, 'S': 1633, 'M': 6529, 'L': 26521}, ## WID 10
{'US': 409, 'S': 1621, 'M': 6481, 'L': 26329}, ## WID 11
{'US': 553, 'S': 2161, 'M': 8641, 'L': 35113}], ## WID 12
'9 kHz': [
{'US': '-', 'S': 31, 'M': 109, 'L': 433}, ## WID 0
{'US': 73, 'S': 289, 'M': 1153, 'L': 4645}, ## WID 1
{'US': 73, 'S': 289, 'M': 1153, 'L': 4645}, ## WID 2
{'US': 73, 'S': 289, 'M': 1153, 'L': 4645}, ## WID 3
{'US': '-', 'S': '-', 'M': '-', 'L': '-'}, ## WID 4
{'US': 97, 'S': 385, 'M': 1537, 'L': 6241}, ## WID 5
{'US': 193, 'S': 769, 'M': 3073, 'L': 12481}, ## WID 6
{'US': 289, 'S': 1153, 'M': 4609, 'L': 18721}, ## WID 7
{'US': 385, 'S': 1537, 'M': 6145, 'L': 24961}, ## WID 8
{'US': 481, 'S': 1921, 'M': 7681, 'L': 31207}, ## WID 9
{'US': 577, 'S': 2305, 'M': 9217, 'L': 37441}, ## WID 10
{'US': 811, 'S': 3241, 'M': 13771, 'L': 52651}, ## WID 11
{'US': 1081, 'S': 4321, 'M': 18361, 'L': 70201}], ## WID 12
'12 kHz': [
{'US': '-', 'S': 41, 'M': 145, 'L': 577}, ## WID 0
{'US': 73, 'S': 289, 'M': 1153, 'L': 4633}, ## WID 1
{'US': 73, 'S': 289, 'M': 1153, 'L': 4633}, ## WID 2
{'US': 97, 'S': 385, 'M': 1537, 'L': 6193}, ## WID 3
{'US': 97, 'S': 385, 'M': 1537, 'L': 6193}, ## WID 4
{'US': 129, 'S': 513, 'M': 2049, 'L': 8321}, ## WID 5
{'US': 257, 'S': 1025, 'M': 4097, 'L': 16641}, ## WID 6
{'US': 385, 'S': 1537, 'M': 6145, 'L': 24961}, ## WID 7
{'US': 513, 'S': 2049, 'M': 8193, 'L': 33281}, ## WID 8
{'US': 641, 'S': 2561, 'M': 10241, 'L': 41603}, ## WID 9
{'US': 769, 'S': 3073, 'M': 13057, 'L': 49921}, ## WID 10
{'US': 811, 'S': 3241, 'M': 13771, 'L': 52651}, ## WID 11
{'US': 1081, 'S': 4321, 'M': 18361, 'L': 70201}], ## WID 12
'15 kHz': [
{'US': '-', 'S': 51, 'M': 181, 'L': 721}, ## WID 0
{'US': 109, 'S': 433, 'M': 1729, 'L': 6949}, ## WID 1
{'US': 109, 'S': 433, 'M': 1729, 'L': 6949}, ## WID 2
{'US': 109, 'S': 433, 'M': 1729, 'L': 6949}, ## WID 3
{'US': 109, 'S': 433, 'M': 1729, 'L': 6949}, ## WID 4
{'US': 161, 'S': 641, 'M': 2561, 'L': 10401}, ## WID 5
{'US': 321, 'S': 1281, 'M': 5121, 'L': 20801}, ## WID 6
{'US': 481, 'S': 1921, 'M': 7681, 'L': 31201}, ## WID 7
{'US': 641, 'S': 2561, 'M': 10241, 'L': 41601}, ## WID 8
{'US': 801, 'S': 3201, 'M': 13603, 'L': 52003}, ## WID 9
{'US': 961, 'S': 3841, 'M': 16321, 'L': 62401}, ## WID 10
{'US': 865, 'S': 3457, 'M': 14689, 'L': 56161}, ## WID 11
{'US': 1153, 'S': 4609, 'M': 19585, 'L': 74881}], ## WID 12
'18 kHz': [
{'US': '-', 'S': 61, 'M': 217, 'L': 865}, ## WID 0
{'US': 169, 'S': 673, 'M': 2689, 'L': 10811}, ## WID 1
{'US': 169, 'S': 673, 'M': 2689, 'L': 10811}, ## WID 2
{'US': 169, 'S': 673, 'M': 2689, 'L': 10811}, ## WID 3
{'US': '-', 'S': '-', 'M': '-', 'L': '-'}, ## WID 4
{'US': 193, 'S': 769, 'M': 3073, 'L': 12481}, ## WID 5
{'US': 385, 'S': 1537, 'M': 6145, 'L': 24961}, ## WID 6
{'US': 577, 'S': 2305, 'M': 9217, 'L': 37441}, ## WID 7
{'US': 769, 'S': 3073, 'M': 13057, 'L': 49921}, ## WID 8
{'US': 961, 'S': 3841, 'M': 16327, 'L': 62407}, ## WID 9
{'US': 1153, 'S': 4609, 'M': 19585, 'L': 74881}, ## WID 10
{'US': 1441, 'S': 5761, 'M': 24481, 'L': 93601}, ## WID 11
{'US': 1921, 'S': 7681, 'M': 32641, 'L': 124801}], ## WID 12
'21 kHz': [
{'US': '-', 'S': 71, 'M': 253, 'L': 1009}, ## WID 0
{'US': 161, 'S': 641, 'M': 2561, 'L': 10281}, ## WID 1
{'US': 161, 'S': 641, 'M': 2561, 'L': 10281}, ## WID 2
{'US': 161, 'S': 641, 'M': 2561, 'L': 10281}, ## WID 3
{'US': 161, 'S': 641, 'M': 2561, 'L': 10281}, ## WID 4
{'US': 169, 'S': 673, 'M': 2689, 'L': 10921}, ## WID 5
{'US': 337, 'S': 1345, 'M': 5377, 'L': 21841}, ## WID 6
{'US': 505, 'S': 2017, 'M': 8065, 'L': 32761}, ## WID 7
{'US': 673, 'S': 2689, 'M': 11425, 'L': 43681}, ## WID 8
{'US': 841, 'S': 3361, 'M': 14293, 'L': 54613}, ## WID 9
{'US': 1009, 'S': 4033, 'M': 17137, 'L': 65521}, ## WID 10
{'US': 1921, 'S': 7681, 'M': 32641, 'L': 124801}, ## WID 11
{'US': 2561, 'S': 10241, 'M': 43521, 'L': 166401}], ## WID 12
'24 kHz': [
{'US': '-', 'S': 81, 'M': 289, 'L': 1153}, ## WID 0
{'US': 137, 'S': 545, 'M': 2177, 'L': 8739}, ## WID 1
{'US': 137, 'S': 545, 'M': 2177, 'L': 8739}, ## WID 2
{'US': 205, 'S': 817, 'M': 3265, 'L': 13159}, ## WID 3
{'US': 205, 'S': 817, 'M': 3265, 'L': 13159}, ## WID 4
{'US': 273, 'S': 1089, 'M': 4353, 'L': 17681}, ## WID 5
{'US': 545, 'S': 2177, 'M': 8705, 'L': 35361}, ## WID 6
{'US': 817, 'S': 3265, 'M': 13873, 'L': 53041}, ## WID 7
{'US': 1089, 'S': 4353, 'M': 18497, 'L': 70721}, ## WID 8
{'US': 1361, 'S': 5441, 'M': 23123, 'L': 88403}, ## WID 9
{'US': 1633, 'S': 6529, 'M': 27745, 'L': 106081}, ## WID 10
{'US': 1441, 'S': 5761, 'M': 24481, 'L': 93601}, ## WID 11
{'US': 1921, 'S': 7681, 'M': 32641, 'L': 124801}], ## WID 12
'30 kHz': [
{'US': '-', 'S': 119, 'M': 431, 'L': 1673}, ## WID 0
{'US': 275, 'S': 1259, 'M': 4207, 'L': 15445}, ## WID 1
{'US': 275, 'S': 1259, 'M': 4207, 'L': 15445}, ## WID 2
{'US': 275, 'S': 1259, 'M': 4207, 'L': 15445}, ## WID 3
{'US': 275, 'S': 1259, 'M': 4207, 'L': 15445}, ## WID 4
{'US': 381, 'S': 2951, 'M': 8729, 'L': 24989}, ## WID 5
{'US': 781, 'S': 5893, 'M': 29161, 'L': 49991}, ## WID 6
{'US': 1207, 'S': 8821, 'M': 26221, 'L': 71341}, ## WID 7
{'US': 1529, 'S': 11837, 'M': 43733, 'L': 142017}, ## WID 8
{'US': 1941, 'S': 14711, 'M': 54541, 'L': 221051}, ## WID 9
{'US': 2257, 'S': 17623, 'M': 65557, 'L': 288127}, ## WID 10
{'US': 2473, 'S': 18643, 'M': 55669, 'L': 281233}, ## WID 11
{'US': 3281, 'S': 25097, 'M': 74329, 'L': 374993}], ## WID 12
'36 kHz': [
{'US': '-', 'S': 143, 'M': 511, 'L': 2011}, ## WID 0
{'US': 901, 'S': 1577, 'M': 11843, 'L': 22595}, ## WID 1
{'US': 901, 'S': 1577, 'M': 11843, 'L': 22595}, ## WID 2
{'US': 901, 'S': 1577, 'M': 11843, 'L': 22595}, ## WID 3
{'US': 455, 'S': 3557, 'M': 17575, 'L': 26663}, ## WID 4
{'US': 455, 'S': 3557, 'M': 17575, 'L': 26663}, ## WID 5
{'US': 911, 'S': 7027, 'M': 35179, 'L': 69763}, ## WID 6
{'US': 1633, 'S': 10867, 'M': 52741, 'L': 90013}, ## WID 7
{'US': 1913, 'S': 14245, 'M': 70337, 'L': 119977}, ## WID 8
{'US': 2411, 'S': 17831, 'M': 87931, 'L': 133351}, ## WID 9
{'US': 2719, 'S': 22267, 'M': 105163, 'L': 174025}, ## WID 10
{'US': 2851, 'S': 22381, 'M': 110509, 'L': 197491}, ## WID 11
{'US': 4049, 'S': 29977, 'M': 148361, 'L': 281057}], ## WID 12
'40 kHz': [
{'US': '-', 'S': 167, 'M': 601, 'L': 2371}, ## WID 0
{'US': 1001, 'S': 1687, 'M': 5867, 'L': 30619}, ## WID 1
{'US': 1001, 'S': 1687, 'M': 5867, 'L': 30619}, ## WID 2
{'US': 1001, 'S': 1687, 'M': 5867, 'L': 30619}, ## WID 3
{'US': 593, 'S': 4007, 'M': 11789, 'L': 33757}, ## WID 4
{'US': 593, 'S': 4007, 'M': 11789, 'L': 33757}, ## WID 5
{'US': 1019, 'S': 7993, 'M': 23641, 'L': 67505}, ## WID 6
{'US': 1531, 'S': 11995, 'M': 35335, 'L': 101203}, ## WID 7
{'US': 2029, 'S': 15965, 'M': 47137, 'L': 134965}, ## WID 8
{'US': 2581, 'S': 19901, 'M': 58871, 'L': 168701}, ## WID 9
{'US': 3079, 'S': 23995, 'M': 70669, 'L': 202411}, ## WID 10
{'US': 3499, 'S': 26539, 'M': 78571, 'L': 249943}, ## WID 11
{'US': 4673, 'S': 35281, 'M': 104857, 'L': 333113}], ## WID 12
'48 kHz': [
{'US': '-', 'S': 191, 'M': 697, 'L': 2693}, ## WID 0
{'US': 943, 'S': 1735, 'M': 6805, 'L': 14425}, ## WID 1
{'US': 943, 'S': 1735, 'M': 6805, 'L': 14425}, ## WID 2
{'US': 943, 'S': 1735, 'M': 6805, 'L': 14425}, ## WID 3
{'US': 397, 'S': 2941, 'M': 8393, 'L': 39551}, ## WID 4
{'US': 397, 'S': 2941, 'M': 8393, 'L': 39551}, ## WID 5
{'US': 797, 'S': 5881, 'M': 16739, 'L': 72607}, ## WID 6
{'US': 1231, 'S': 8827, 'M': 25099, 'L': 104197}, ## WID 7
{'US': 1509, 'S': 11729, 'M': 46729, 'L': 137413}, ## WID 8
{'US': 1911, 'S': 14701, 'M': 41981, 'L': 181541}, ## WID 9
{'US': 2281, 'S': 17623, 'M': 70183, 'L': 217873}, ## WID 10
{'US': 2569, 'S': 19831, 'M': 56599, 'L': 247963}, ## WID 11
{'US': 3401, 'S': 26449, 'M': 105209, 'L': 326729}] ## WID 12
}
BW_CODE_RATE = { # [BW][WID] -> code rate
'3 kHz': [ '1/2', '1/8' , '1/4', '1/3', '2/3', '3/4', '3/4', '3/4', '3/4', '3/4', '3/4', '8/9', '8/9', '9/16'],
'6 kHz': [ '1/2', '1/8' , '1/4', '1/3', '2/3', '3/4', '3/4', '3/4', '3/4', '3/4', '3/4', '8/9', '8/9' ],
'9 kHz': [ '2/3', '1/8' , '1/4', '1/2', '-', '3/4', '3/4', '3/4', '3/4', '3/4', '3/4', '8/9', '8/9' ],
'12 kHz': [ '1/2', '1/8' , '1/4', '1/3', '2/3', '3/4', '3/4', '3/4', '3/4', '3/4', '3/4', '8/9', '8/9' ],
'15 kHz': [ '2/5', '1/12', '1/6', '1/3', '2/3', '3/4', '3/4', '3/4', '3/4', '3/4', '3/4', '8/9', '8/9' ],
'18 kHz': [ '2/3', '1/8' , '1/4', '1/2', '-', '3/4', '3/4', '3/4', '3/4', '3/4', '3/4', '8/9', '5/6' ],
'21 kHz': [ '2/7', '1/16', '1/8', '1/4', '1/2', '2/3', '2/3', '2/3', '2/3', '2/3', '2/3', '4/5', '9/10'],
'24 kHz': [ '1/2', '1/8' , '1/4', '1/3', '2/3', '3/4', '3/4', '3/4', '3/4', '3/4', '3/4', '8/9', '5/6' ],
'30 kHz': [ '2/5', '1/12', '1/6', '1/3', '2/3', '3/4', '3/4', '3/4', '3/4', '3/4', '3/4', '8/9', '8/9' ],
'36 kHz': [ '2/3', '1/8' , '1/4', '1/2', '1/2', '3/4', '3/4', '3/4', '3/4', '3/4', '3/4', '8/9', '8/9' ],
'42 kHz': [ '4/7', '1/8' , '1/4', '1/2', '1/2', '2/3', '2/3', '2/3', '2/3', '2/3', '2/3', '5/6', '3/4' ],
'48 kHz': [ '1/2', '1/8' , '1/4', '1/2', '1/2', '3/4', '3/4', '3/4', '3/4', '3/4', '3/4', '8/9', '5/6' ]
}
## Code Rate K=7 Puncture Pattern K=9 Puncture Pattern Number of Repeats
CODE_RATE_PUNCT = { # [code rate][K] -> punct pattern, [code rate]['Rep'] -> # repetitions
'9/10': { 'K=7': ['111101110','100010001'], 'K=9': ['111000101','100111010'], 'Rep': 1 },
'8/9' : { 'K=7': [ '11110100', '10001011'], 'K=9': [ '11100000', '10011111'], 'Rep': 1 },
'5/6' : { 'K=7': [ '11010', '10101'], 'K=9': [ '10110', '11001'], 'Rep': 1 },
'4/5' : { 'K=7': [ '1111', '1000'], 'K=9': [ '1101', '1010'], 'Rep': 1 },
'3/4' : { 'K=7': [ '110', '101'], 'K=9': [ '111', '100'], 'Rep': 1 },
'2/3' : { 'K=7': [ '11', '10'], 'K=9': [ '11', '10'], 'Rep': 1 },
'4/7' : { 'K=7': [ '1111', '0111'], 'K=9': [ '1111', '0111'], 'Rep': 1 },
'9/16': { 'K=7': ['111101111','111111011'], 'K=9': ['111101111','111111011'], 'Rep': 1 },
'1/2' : { 'K=7': [ '1', '1'], 'K=9': [ '1', '1'], 'Rep': 1 },
'2/5' : { 'K=7': [ '1110', '1010'], 'K=9': [ '1110', '1010'], 'Rep': 2 },
'1/3' : { 'K=7': [ '11', '10'], 'K=9': [ '11', '10'], 'Rep': 2 },
'2/7' : { 'K=7': [ '1111', '0111'], 'K=9': [ '1111', '0111'], 'Rep': 2 },
'1/4' : { 'K=7': [ '1', '1'], 'K=9': [ '1', '1'], 'Rep': 2 },
'1/6' : { 'K=7': [ '1', '1'], 'K=9': [ '1', '1'], 'Rep': 3 },
'1/8' : { 'K=7': [ '1', '1'], 'K=9': [ '1', '1'], 'Rep': 4 },
'1/12': { 'K=7': [ '1', '1'], 'K=9': [ '1', '1'], 'Rep': 6 },
'1/16': { 'K=7': [ '1', '1'], 'K=9': [ '1', '1'], 'Rep': 8 }
}
## ---- deinterleaver -----------------------------------------------------------
class Deinterleaver(object):
"""deinterleave"""
def __init__(self, length, incr):
self._length = length
self._array = np.zeros(length, dtype=np.float32)
self._incr = incr
self._idx = np.mod(incr*np.arange(length), length)
self._i = 0
def fetch(self):
self._i = 0
return self._array[self._idx]
def load(self, a):
print('deinterleaver load', len(a), self._i, self._incr, self._length)
input_len = len(a)
assert(self._i+input_len <= self._length)
self._array[self._i:self._i+input_len] = a
self._i += input_len
return (self._i == self._length)
## ---- 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
WALSH16 = np.array([[0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0], # 0 - 0000
[0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1], # 1 - 0001
[0,0,1,1, 0,0,1,1, 0,0,1,1, 0,0,1,1], # 2 - 0010
[0,1,1,0, 0,1,1,0, 0,1,1,0, 0,1,1,0], # 3 - 0011
[0,0,0,0, 1,1,1,1, 0,0,0,0, 1,1,1,1], # 4 - 0100
[0,1,0,1, 1,0,1,0, 0,1,0,1, 1,0,1,0], # 5 - 0101
[0,0,1,1, 1,1,0,0, 0,0,1,1, 1,1,0,0], # 6 - 0110
[0,1,1,0, 1,0,0,1, 0,1,1,0, 1,0,0,1], # 7 - 0111
[0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1], # 8 - 1000
[0,1,0,1, 0,1,0,1, 1,0,1,0, 1,0,1,0], # 9 - 1001
[0,0,1,1, 0,0,1,1, 1,1,0,0, 1,1,0,0], # 10 - 1010
[0,1,1,0, 0,1,1,0, 1,0,0,1, 1,0,0,1], # 11 - 1011
[0,0,0,0, 1,1,1,1, 1,1,1,1, 0,0,0,0], # 12 - 1100
[0,1,0,1, 1,0,1,0, 1,0,1,0, 0,1,0,1], # 13 - 1101
[0,0,1,1, 1,1,0,0, 1,1,0,0, 0,0,1,1], # 14 - 1110
[0,1,1,0, 1,0,0,1, 1,0,0,1, 0,1,1,0]], # 15 - 1111
dtype=np.uint8)
FROM_WALSH16 = -np.ones(256, dtype=np.int8)
for i in range(16):
FROM_WALSH16[np.packbits(WALSH16[i][:])[0]] = i
## ---- band width - Walsh lengths table ---------------------------------------
WALSH_BW_LENGTHS = {
'3 kHz': 32,
'6 kHz': 64,
'9 kHz': 96,
'12 kHz': 128,
'15 kHz': 160,
'18 kHz': 192,
'21 kHz': 224,
'24 kHz': 256,
'30 kHz': 320, ## by extrapolation using 32 * BW / 3kHz
'36 kHz': 384,
'42 kHz': 448,
'48 kHz': 512
}
## ---- di-bit scramble sequences for preamble ---------------------------------
FIXED_PN = np.array(
[2,4,0,0,6,2,1,4,6,1,0,5,7,3,4,1,2,6,1,7,0,7,3,2,2,2,3,2,4,6,3,6,
6,3,7,5,4,7,5,6,7,4,0,2,6,1,5,3,0,4,2,4,6,4,5,2,5,4,5,3,1,5,4,5,
6,5,1,0,7,1,0,1,0,5,3,5,2,2,4,5,4,0,6,4,1,4,0,3,3,0,0,3,3,7,3,4,
2,7,4,4,4,0,3,4,7,6,4,2,6,2,0,3,5,3,2,2,4,5,2,0,0,3,5,0,3,2,6,6,
1,4,2,3,6,1,3,0,3,3,2,4,2,2,6,5,5,3,6,7,6,5,6,6,5,2,5,4,2,3,3,3,
5,7,5,5,3,7,0,4,7,0,4,1,6,2,3,5,5,6,2,6,4,6,3,4,0,7,0,0,5,2,1,5,
4,3,4,5,7,0,5,3,7,6,6,6,4,5,6,0,2,0,4,2,3,4,4,0,7,6,6,2,0,0,3,3,
0,5,2,4,2,2,4,5,4,6,6,6,3,2,1,0,3,2,6,0,6,2,4,0,6,4,1,3,3,5,3,6],
dtype=np.uint8)
CNT_PN = np.array(
[5,5,2,2,0,2,5,6,7,1,3,5,1,5,6,5,3,7,0,4,0,3,3,2,1,3,0,3,1,6,2,6,
0,6,4,1,2,5,6,3,5,3,7,4,2,6,7,3,0,2,0,1,7,5,0,6,1,5,0,3,2,2,5,2,
5,2,3,4,2,7,6,1,1,5,2,1,5,4,0,3,5,5,0,3,1,4,0,5,0,3,0,6,0,0,3,1,
6,1,4,4,7,7,0,5,7,0,1,5,1,0,1,3,1,5,0,7,1,2,2,2,7,1,2,5,0,3,3,2,
2,0,4,5,1,3,1,3,5,3,1,7,5,2,7,1,3,1,5,6,2,4,6,0,6,1,0,0,3,6,2,7,
3,2,4,7,6,4,1,3,6,6,0,3,0,0,7,5,4,5,1,2,1,5,0,3,1,0,4,6,6,1,0,5,
2,6,3,2,7,4,2,4,0,1,7,0,7,0,5,1,4,5,7,2,0,4,4,3,5,2,7,7,4,5,1,4,
4,6,3,3,0,5,1,5,5,4,3,2,0,3,0,4,7,4,5,1,5,5,7,7,6,2,4,3,5,2,2,4],
dtype=np.uint8)
WID_PN = np.array(
[2,3,0,3,7,3,3,0,1,4,4,6,5,5,4,5,6,2,0,5,6,6,5,3,5,5,2,2,1,2,3,6,
1,1,4,3,1,0,5,1,0,3,3,0,3,0,4,4,6,2,5,6,1,7,2,6,2,0,0,4,7,2,3,5,
2,7,1,6,5,0,4,1,6,2,1,5,4,3,5,0,3,4,1,3,2,1,6,1,5,7,0,4,7,6,6,0,
4,7,6,6,6,6,2,3,5,0,7,0,3,1,5,1,2,0,5,3,2,4,5,6,6,7,7,3,5,1,6,0,
1,4,4,5,6,0,6,7,2,4,4,0,3,7,2,0,0,1,4,0,7,1,7,4,5,4,5,5,5,3,3,2,
0,5,1,3,1,5,3,4,1,5,4,1,4,4,2,2,4,3,0,7,4,1,5,7,1,4,7,2,5,5,6,6,
1,6,5,6,3,0,2,5,7,7,4,4,3,4,4,6,0,7,2,2,0,0,2,1,0,0,3,6,6,4,0,2,
4,3,4,5,2,6,3,7,7,5,7,3,0,7,0,0,7,2,6,2,2,6,1,4,3,7,6,5,0,6,5,4],
dtype=np.uint8);
FIXED_WALSH_SYMBOLS = [0,0,2, 1,2,1, 0,2,3]
## ---- data scrambler -----------------------------------------------------------
class ScrambleData(object):
"""data scrambling sequence generator"""
def __init__(self, nbits):
self._nbits = nbits
self.reset()
def reset(self):
self._state = [0,0,0,0,0,0,0,0,1]
def next(self):
val = 0
for i in range(self._nbits):
val += (1<<i) * self._state[-(1+i)]
for i in range(self._nbits):
self._advance()
return val
def _advance(self):
new_state = [ self._state[4] ^ self._state[8] ]
new_state.extend(self._state[:-1])
self._state = new_state
class ScrambleWalsh(object):
## Trinomial(159,31)
def __init__(self):
self.reset()
def reset(self):
self._counter = 0
self._state = np.array([0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1,
1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0,
1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1,
0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1,
1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0,
1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,
1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1], dtype=np.bool)
def next(self):
if self._counter == 2048:
self._reset()
self._advance()
self._counter += 1
return 4*self._state[2] + 2*self._state[1] + self._state[0]
def _advance(self):
for i in range(16):
new_bit = self._state[31] ^ self._state[158]
self._state = np.roll(self._state,1)
self._state[0] = new_bit
## ---- physcal layer class -----------------------------------------------------
class PhysicalLayer(object):
"""Physical layer description for MIL-STD-188-110 Appendix D"""
def __init__(self, sps):
"""intialization"""
self._sps = sps
self._bw = 3
self._frame_counter = -1
self._constellations = [BPSK, QPSK, PSK8, QAM16, QAM32, QAM64, QAM256]
self._scr_data = ScrambleData(3) ## TODO
def get_constellations(self):
return self._constellations
def get_next_frame(self, symbols):
"""returns a tuple describing the frame:
[0] ... known+unknown symbols and scrambling
[1] ... modulation type after descrambling
[2] ... a boolean indicating if the processing should continue
[3] ... a boolean indicating if the soft decision for the unknown
symbols are saved"""
print('-------------------- get_frame --------------------',
self._frame_counter)
success = True
if self._frame_counter == -1: ## preamble mode
if len(symbols) == 0:
self._state = 'FIXED'
return [self._fixed_s,MODE_BPSK,success,False]
else:
if self._state == 'FIXED':
success = self.decode_fixed(symbols)
self._state = 'CNT'
return [self._cnt_s,MODE_BPSK,success,False]
if self._state == 'CNT':
success = self.decode_cnt(symbols)
self._state = 'WID'
return [self._wid_s,MODE_BPSK,success,False]
if self._state == 'WID':
success = self.decode_wid(symbols)
if self._superframe_counter != 0:
self._state = 'FIXED'
return [self._fixed_s,MODE_BPSK,success,False]
else:
self._frame_counter = 0
if self._wid != MODE_WALSH:
self._scr_data.reset()
self._state = 'MP'
[mode,a] = self.get_next_data_frame(success)
return [a,mode,success,True]
else: ## WID0
self._frame_counter += 1
return [self._walsh_s,MODE_BPSK,success,True]
else: ## data mode
print('XXXXX {} frame_counter={}'.format(self._state, self._frame_counter))
if self._wid != MODE_WALSH:
[mode,a] = self.get_next_data_frame(success)
self._frame_counter += (self._state == 'MP')
success = np.abs(np.real(np.mean(symbols[::2]))) > 0.5 if self._state == 'MP' else True
if success == False:
print('TEST: {} success={} {} {}'.format(self._state, success, symbols[::2], np.mean(symbols[::2])))
return [a,mode,success,True]
else: ## WID0
self._frame_counter += 1
## TODO: WALSH16 check for BW > 30kHz
m = len(symbols)//32
z = np.zeros(8*m, dtype=np.complex64)
for i,s in enumerate(symbols.reshape(m, 32)):
# print('WALSH test:', i,
# np.mean(s.reshape(8,4)[0::2], 0)<0,
# np.mean(s.reshape(8,4)[1::2], 0)<0)
z[8*i :8*i+4] = np.mean(s.reshape(8,4)[0::2], 0)
z[8*i+4:8*i+8] = np.mean(s.reshape(8,4)[1::2], 0)
success = [np.mean(np.abs(np.real(z))) > 0.5, np.mean(np.abs(np.imag(z))) < 0.5]
print('WALSH test:',z[-8:], success)
return [self._walsh_s,MODE_BPSK,all(success),True]
def get_next_data_frame(self, success):
## TODO
if self._state == 'MP':
self._state = 'DATA'
a = np.zeros(self._known, common.SYMB_SCRAMBLE_DTYPE)
if (self._frame_counter % self._intl_frames) == self._intl_frames-1:
print('next_data_fram MP_shifted ', self._frame_counter, self._intl_frames)
a['symb'][:] = self._mp_shifted
a['scramble'][:] = self._mp_shifted
else:
print('next_data_frame MP_regular', self._frame_counter, self._intl_frames)
a['symb'][:] = self._mp
a['scramble'][:] = self._mp
return MODE_BPSK,a
else:
self._state = 'MP'
a = np.zeros(self._unknown, common.SYMB_SCRAMBLE_DTYPE)
a['scramble'][:] = 1
self._scr_data.reset()
if self._data_mode <= MODE_8PSK: ## not QAM
for i in range(self._unknown):
a['scramble'][i] = np.exp(2j*np.pi*self._scr_data.next()/8)
else: ## QAM modes
for i in range(self._unknown):
a['scramble_xor'][i] = self._scr_data.next()
return self._data_mode,a
def get_doppler(self, iq_samples):
"""quality check and doppler estimation for preamble"""
print('get_doppler', len(iq_samples))
success,doppler = True,0
sps = self._sps
wlen = self._wlen
_,zp = self.get_preamble_z()
cc = np.correlate(iq_samples, zp)
imax = np.argmax(np.abs(cc[0:wlen*sps]))
idx = np.arange(wlen*sps)
print('get_doppler ccmax: ', imax, np.abs(cc[imax]))
pks = [np.correlate(iq_samples[imax+i*wlen*sps+idx],
zp[i*wlen*sps+idx])[0]
for i in range((len(iq_samples)-imax) // (wlen*sps))]
print('get_doppler pks: ', pks, np.angle(pks))
doppler = common.freq_est(pks)/(wlen*sps)
print('get_doppler doppler: ', doppler)
## TODO
return success,doppler
def decode_walsh(self, symbols):
wlen = self._wlen
return np.array([FROM_WALSH4[np.packbits
(np.real
(np.sum
(symbols[wlen*i:wlen*(i+1)].reshape((wlen//4,4)),0))<0)[0]]
for i in range(len(symbols)//wlen)],
dtype=np.uint8)
def decode_fixed(self, symbols):
print('decode_fixed: ', len(symbols))
data = self.decode_walsh(symbols)
success = np.all(data[2:] == FIXED_WALSH_SYMBOLS[2:])
print('data=', data, success)
return success
def decode_cnt(self, symbols):
print('decode_cnt: ', len(symbols))
data = self.decode_walsh(symbols)
print('data=', data)
b = np.unpackbits(data.reshape(4,1), axis=1)
b = np.concatenate([b[i][6:8] for i in range(4)])
b = np.flip(b)
b[7] ^= b[1] ^ b[2] ^ b[3]
b[6] ^= b[2] ^ b[3] ^ b[4]
b[5] ^= b[0] ^ b[1] ^ b[2]
success = np.all(b[5:8] == 0)
b = np.flip(b)
self._superframe_counter = np.packbits(b)[0]
print('b=', b, success, self._superframe_counter)
return success
def decode_wid(self, symbols):
print('decode_wid: ', len(symbols))
data = self.decode_walsh(symbols)
print('data=', data)
b = np.unpackbits(data.reshape(5,1), axis=1)
b = np.concatenate([b[i][6:8] for i in range(5)])
b = np.flip(b)
b[2] ^= b[9] ^ b[8] ^ b[7]
b[1] ^= b[7] ^ b[6] ^ b[5]
b[0] ^= b[5] ^ b[4] ^ b[3]
success = np.all(b[0:3] == 0)
b = np.flip(b)
self._wid = wid = np.packbits(b[0:4])[0]>>4
self._intl_type = INTERLEAVERS[np.packbits(b[4:6])[0]>>6]
self._constraint_length = 'K=7' if b[6] == 0 else 'K=9'
self._data_mode = WID_MODE[self._wid]
print('WID:', self._wid, self._intl_type, self._constraint_length,self._data_mode)
self._unknown = -1
self._known = 0
if wid != MODE_WALSH:
self._unknown = BW_UNKNOWN[self._bw][self._wid]
self._known = BW_KNOWN[self._bw][self._wid]
mp_info = MP_LEN_BASE_SHIFT[self._known]
self._mp = make_mp(self._known, mp_info['base_len'], 0)
self._mp_shifted = make_mp(self._known, mp_info['base_len'], mp_info['base_shift'])
intl_info = BW_INTL[self._bw][self._wid][self._intl_type]
self._intl_frames = intl_info[0]
code_rate = BW_CODE_RATE[self._bw][self._wid]
punct = CODE_RATE_PUNCT[code_rate]
self._deinterleaver = Deinterleaver(length = intl_info[1],
incr = BW_INTL_INCR[self._bw][self._wid][self._intl_type])
self._depuncturer = common.Depuncturer(repeat = punct['Rep'],
puncture_pattern = punct[self._constraint_length])
self._viterbi_decoder = viterbi27(0x6d, 0x4f) if self._constraint_length == 'K=7' else viterbi29()
print('b=', b, success, self._wid, self._intl_type, self._intl_frames, self._constraint_length,
self._known, self._unknown)
return success
def set_mode(self, bw):
self._bw = bw
## ---- di-bit codes -----------------------------------------------------------
self._wlen = wlen = WALSH_BW_LENGTHS[bw]
DIBIT = np.zeros((4,wlen), dtype=np.uint8)
for i in range(4):
DIBIT[i][:] = np.concatenate([WALSH4[i][:] for _ in range(wlen//4)])
## ---- preamble symbols ---------------------------------------------------------
SYNC_SYMB = common.n_psk(2, np.concatenate([DIBIT[i][:]
for i in FIXED_WALSH_SYMBOLS]))
CNT_SYMB = np.zeros(4*wlen, dtype=np.complex64)
WID_SYMB = np.zeros(5*wlen, dtype=np.complex64)
## ---- preamble scramble symbols ------------------------------------------------
SYNC_SCR = common.n_psk(8, np.concatenate([FIXED_PN[:wlen] for _ in range(9)]))
CNT_SCR = common.n_psk(8, np.concatenate([CNT_PN[:wlen] for _ in range(4)]))
WID_SCR = common.n_psk(8, np.concatenate([WID_PN[:wlen] for _ in range(5)]))
self._fixed_s = common.make_scr(SYNC_SCR*SYNC_SYMB,
SYNC_SCR)
print('FIXED: ', np.round(np.mod(np.angle(self._fixed_s['symb'])/np.pi*4, 8)))
self._cnt_s = common.make_scr(CNT_SCR*CNT_SYMB,
CNT_SCR)
self._wid_s = common.make_scr(WID_SCR*WID_SYMB,
WID_SCR)
self._walsh_s = np.zeros(2048, dtype=common.SYMB_SCRAMBLE_DTYPE)
scr_walsh = ScrambleWalsh()
self._walsh_s['scramble'] = common.n_psk(8, np.array([scr_walsh.next() for _ in range(2048)], dtype=np.uint8))
def decode_soft_dec(self, soft_dec):
print('decode_soft_dec', len(soft_dec), soft_dec.dtype)
interleaver_is_full = False
if self._wid == MODE_WALSH: ## TODO: WALSH16 decoding for BW > 30kHz
n = len(soft_dec) // 32
soft_bits = np.zeros(2*n, dtype=np.float32)
for i in range(n):
w = np.sum(soft_dec[32*i:32*(i+1)].reshape(4,8),0)
b = FROM_WALSH4[np.packbits(w[0:4]>0)[0]] ## TODO use 2nd half of WALSH bits
print('WALSH', i, w, b)
abs_soft_dec = np.mean(np.abs(w))
soft_bits[2*i] = abs_soft_dec*(2*(b>>1)-1)
soft_bits[2*i+1] = abs_soft_dec*(2*(b &1)-1)
#print('WALSH soft_bits=', soft_bits)
interleaver_is_full = self._deinterleaver.load(soft_bits)
else:
interleaver_is_full = self._deinterleaver.load(soft_dec)
if not interleaver_is_full:
return []
r = self._deinterleaver.fetch()
rd = self._depuncturer.process(r)
self._viterbi_decoder.reset()
decoded_bits = np.roll(self._viterbi_decoder.udpate(rd), 7)
print('quality={}% num_bits={}'.format(100.0*self._viterbi_decoder.quality()/(2*len(decoded_bits)),
len(decoded_bits)))
return decoded_bits
def get_preamble(self):
"""fixed symbols + scrambler"""
return self._fixed_s
def get_preamble_z(self):
"""preamble symbols for preamble correlation"""
return 2,np.array([z for z in self._fixed_s['symb']
for _ in range(self._sps)])
if __name__ == '__main__':
p = PhysicalLayer(5)
p.set_mode('24 kHz')
#s = ScrambleData(3)
#for i in range(10):
# print(i, s.next())
# print(np.real(make_mp(24,13,0)))
# print(np.real(make_mp(24,13,6)))
print(mp_base(196))
s = ScrambleWalsh()
x = [s.next() for _ in range(32)]
print(x)
print(x == [5, 6, 2, 1, 7, 3, 1, 1, 6, 0, 5, 4, 0, 7, 7, 0, 5, 3, 1, 3, 3, 2, 2, 5, 5, 4, 7, 3, 5, 4, 3, 0])