|
1 | | - |
2 | | - |
3 | | -# Authors: Veeresh Taranalli <veeresht@gmail.com> |
| 1 | +# Authors: CommPy contributors |
4 | 2 | # License: BSD 3-Clause |
5 | 3 |
|
6 | | -from numpy import array |
7 | | -from numpy.random import randint |
8 | | -from numpy.testing import assert_array_equal |
| 4 | +from numpy import array, inf |
| 5 | +from numpy.random import randint, randn, seed |
| 6 | +from numpy.testing import assert_array_equal, dec, run_module_suite |
| 7 | + |
9 | 8 | from commpy.channelcoding.convcode import Trellis, conv_encode, viterbi_decode |
10 | 9 |
|
| 10 | + |
11 | 11 | class TestConvCode(object): |
12 | 12 |
|
13 | 13 | @classmethod |
14 | 14 | def setup_class(cls): |
| 15 | + cls.trellis = [] |
| 16 | + cls.desired_next_state_table = [] |
| 17 | + cls.desired_output_table = [] |
| 18 | + cls.desired_encode_msg = [] |
| 19 | + cls.mes = array((0, 0, 1, 0)) |
| 20 | + |
| 21 | + ### 1/2 - rate codes ### |
| 22 | + |
15 | 23 | # Convolutional Code 1: G(D) = [1+D^2, 1+D+D^2] |
16 | 24 | memory = array([2]) |
17 | | - g_matrix = array([[0o5, 0o7]]) |
18 | | - cls.code_type_1 = 'default' |
19 | | - cls.trellis_1 = Trellis(memory, g_matrix, 0, cls.code_type_1) |
20 | | - cls.desired_next_state_table_1 = array([[0, 2], |
21 | | - [0, 2], |
22 | | - [1, 3], |
23 | | - [1, 3]]) |
24 | | - cls.desired_output_table_1 = array([[0, 3], |
25 | | - [3, 0], |
26 | | - [1, 2], |
27 | | - [2, 1]]) |
28 | | - |
| 25 | + g_matrix = array([[5, 7]]) |
| 26 | + cls.trellis.append(Trellis(memory, g_matrix, code_type='default')) |
| 27 | + cls.desired_next_state_table.append(array([[0, 2], |
| 28 | + [0, 2], |
| 29 | + [1, 3], |
| 30 | + [1, 3]])) |
| 31 | + cls.desired_output_table.append(array([[0, 3], |
| 32 | + [3, 0], |
| 33 | + [1, 2], |
| 34 | + [2, 1]])) |
| 35 | + cls.desired_encode_msg.append(array([0., 0., 0., 0., 1., 1., 0., 1.])) |
29 | 36 |
|
30 | 37 | # Convolutional Code 2: G(D) = [1 1+D+D^2/1+D] |
31 | 38 | memory = array([2]) |
32 | | - g_matrix = array([[0o1, 0o7]]) |
33 | | - feedback = 0o5 |
34 | | - cls.code_type_2 = 'rsc' |
35 | | - cls.trellis_2 = Trellis(memory, g_matrix, feedback, cls.code_type_2) |
36 | | - cls.desired_next_state_table_2 = array([[0, 2], |
37 | | - [2, 0], |
38 | | - [1, 3], |
39 | | - [3, 1]]) |
40 | | - cls.desired_output_table_2 = array([[0, 3], |
41 | | - [0, 3], |
42 | | - [1, 2], |
43 | | - [1, 2]]) |
44 | | - |
| 39 | + g_matrix = array([[1, 7]]) |
| 40 | + feedback = 5 |
| 41 | + cls.trellis.append(Trellis(memory, g_matrix, feedback, 'rsc')) |
| 42 | + cls.desired_next_state_table.append(array([[0, 2], |
| 43 | + [2, 0], |
| 44 | + [1, 3], |
| 45 | + [3, 1]])) |
| 46 | + cls.desired_output_table.append(array([[0, 3], |
| 47 | + [0, 3], |
| 48 | + [1, 2], |
| 49 | + [1, 2]])) |
| 50 | + cls.desired_encode_msg.append(array([0., 0., 0., 0., 1., 1., 0., 1.])) |
| 51 | + |
| 52 | + ### 2/3 - rate codes ### |
| 53 | + |
| 54 | + # Convolutional Code 1: G(D) = [[1+D^2, 1+D+D^2 0], [0, D, 1+D]] |
| 55 | + memory = array([2, 1]) |
| 56 | + g_matrix = array([[5, 7, 0], [0, 2, 3]]) |
| 57 | + cls.trellis.append(Trellis(memory, g_matrix, code_type='default')) |
| 58 | + cls.desired_next_state_table.append(array([[0, 1, 4, 5], |
| 59 | + [0, 1, 4, 5], |
| 60 | + [0, 1, 4, 5], |
| 61 | + [0, 1, 4, 5], |
| 62 | + [2, 3, 6, 7], |
| 63 | + [2, 3, 6, 7], |
| 64 | + [2, 3, 6, 7], |
| 65 | + [2, 3, 6, 7]])) |
| 66 | + cls.desired_output_table.append(array([[0, 1, 6, 7], |
| 67 | + [3, 2, 5, 4], |
| 68 | + [6, 7, 0, 1], |
| 69 | + [5, 4, 3, 2], |
| 70 | + [2, 3, 4, 5], |
| 71 | + [1, 0, 7, 6], |
| 72 | + [4, 5, 2, 3], |
| 73 | + [7, 6, 1, 0]])) |
| 74 | + cls.desired_encode_msg.append(array([0., 0., 0., 1., 1., 0.])) |
| 75 | + |
| 76 | + # Convolutional Code 2: G(D) = [[1, 0, 0], [0, 1, 1+D]]; F(D) = [[D, D], [1+D, 1]] |
| 77 | + memory = array([1, 1]) |
| 78 | + g_matrix = array([[1, 0, 0], [0, 1, 3]]) |
| 79 | + feedback = array([[2, 2], [3, 1]]) |
| 80 | + cls.trellis.append(Trellis(memory, g_matrix, feedback, 'rsc')) |
| 81 | + cls.desired_next_state_table.append(array([[0, 1, 1, 0], |
| 82 | + [2, 3, 3, 2], |
| 83 | + [3, 2, 2, 3], |
| 84 | + [1, 0, 0, 1]])) |
| 85 | + cls.desired_output_table.append(array([[0, 3, 4, 7], |
| 86 | + [1, 2, 5, 6], |
| 87 | + [0, 3, 4, 7], |
| 88 | + [1, 2, 5, 6]])) |
| 89 | + cls.desired_encode_msg.append(array([0., 0., 0., 1., 0., 0.])) |
45 | 90 |
|
46 | 91 | @classmethod |
47 | 92 | def teardown_class(cls): |
48 | 93 | pass |
49 | 94 |
|
50 | 95 | def test_next_state_table(self): |
51 | | - assert_array_equal(self.trellis_1.next_state_table, self.desired_next_state_table_1) |
52 | | - assert_array_equal(self.trellis_2.next_state_table, self.desired_next_state_table_2) |
| 96 | + for i in range(len(self.trellis)): |
| 97 | + assert_array_equal(self.trellis[i].next_state_table, self.desired_next_state_table[i]) |
53 | 98 |
|
54 | 99 | def test_output_table(self): |
55 | | - assert_array_equal(self.trellis_1.output_table, self.desired_output_table_1) |
56 | | - assert_array_equal(self.trellis_2.output_table, self.desired_output_table_2) |
| 100 | + for i in range(len(self.trellis)): |
| 101 | + assert_array_equal(self.trellis[i].output_table, self.desired_output_table[i]) |
57 | 102 |
|
58 | 103 | def test_conv_encode(self): |
59 | | - pass |
| 104 | + for i in range(len(self.trellis)): |
| 105 | + assert_array_equal(conv_encode(self.mes, self.trellis[i],'cont'), self.desired_encode_msg[i]) |
60 | 106 |
|
61 | 107 | def test_viterbi_decode(self): |
62 | | - pass |
| 108 | + pass # Tested below |
63 | 109 |
|
| 110 | + @dec.slow |
64 | 111 | def test_conv_encode_viterbi_decode(self): |
65 | 112 | niters = 10 |
66 | 113 | blocklength = 1000 |
67 | 114 |
|
68 | | - for i in range(niters): |
| 115 | + for n in range(niters): |
69 | 116 | msg = randint(0, 2, blocklength) |
70 | 117 |
|
71 | | - coded_bits = conv_encode(msg, self.trellis_1) |
72 | | - decoded_bits = viterbi_decode(coded_bits.astype(float), self.trellis_1, 15) |
73 | | - assert_array_equal(decoded_bits[:-2], msg) |
74 | | - |
75 | | - coded_bits = conv_encode(msg, self.trellis_1, termination = 'cont') |
76 | | - decoded_bits = viterbi_decode(coded_bits.astype(float), self.trellis_1, 15) |
77 | | - assert_array_equal(decoded_bits, msg) |
78 | | - |
79 | | - coded_bits = conv_encode(msg, self.trellis_1) |
80 | | - coded_syms = 2.0*coded_bits - 1 |
81 | | - decoded_bits = viterbi_decode(coded_syms, self.trellis_1, 15, 'unquantized') |
82 | | - assert_array_equal(decoded_bits[:-2], msg) |
83 | | - |
84 | | - coded_bits = conv_encode(msg, self.trellis_2) |
85 | | - decoded_bits = viterbi_decode(coded_bits.astype(float), self.trellis_2, 15) |
86 | | - assert_array_equal(decoded_bits[:-2], msg) |
87 | | - |
88 | | - coded_bits = conv_encode(msg, self.trellis_2) |
89 | | - coded_syms = 2.0*coded_bits - 1 |
90 | | - decoded_bits = viterbi_decode(coded_syms, self.trellis_2, 15, 'unquantized') |
91 | | - assert_array_equal(decoded_bits[:-2], msg) |
| 118 | + # Previous tests |
| 119 | + for i in range(len(self.trellis)): |
| 120 | + coded_bits = conv_encode(msg, self.trellis[i]) |
| 121 | + decoded_bits = viterbi_decode(coded_bits.astype(float), self.trellis[i], 15) |
| 122 | + assert_array_equal(decoded_bits[:len(msg)], msg) |
| 123 | + |
| 124 | + coded_bits = conv_encode(msg, self.trellis[i], termination='cont') |
| 125 | + decoded_bits = viterbi_decode(coded_bits.astype(float), self.trellis[i], 15) |
| 126 | + assert_array_equal(decoded_bits, msg) |
| 127 | + |
| 128 | + coded_bits = conv_encode(msg, self.trellis[i]) |
| 129 | + coded_syms = 2.0 * coded_bits - 1 |
| 130 | + decoded_bits = viterbi_decode(coded_syms, self.trellis[i], 15, 'unquantized') |
| 131 | + assert_array_equal(decoded_bits[:len(msg)], msg) |
| 132 | + |
| 133 | + coded_bits = conv_encode(msg, self.trellis[i]) |
| 134 | + coded_syms = 10.0 * coded_bits - 5 + randn(len(coded_bits)) * 2 |
| 135 | + decoded_bits = viterbi_decode(coded_syms, self.trellis[i], 15, 'soft') |
| 136 | + assert_array_equal(decoded_bits[:len(msg)], msg) |
| 137 | + |
| 138 | + coded_bits = conv_encode(msg, self.trellis[i], termination='cont') |
| 139 | + coded_syms = 10.0 * coded_bits - 5 + randn(len(coded_bits)) * 2 |
| 140 | + decoded_bits = viterbi_decode(coded_syms, self.trellis[i], 15, 'soft') |
| 141 | + assert_array_equal(decoded_bits, msg) |
| 142 | + |
| 143 | + coded_bits = conv_encode(msg, self.trellis[i]) |
| 144 | + coded_syms = (2.0 * coded_bits - 1) * inf |
| 145 | + decoded_bits = viterbi_decode(coded_syms, self.trellis[i], 15, 'soft') |
| 146 | + assert_array_equal(decoded_bits[:len(msg)], msg) |
| 147 | + |
| 148 | + coded = conv_encode(msg, self.trellis[i], termination='cont') |
| 149 | + coded_bits = coded.astype(float) |
| 150 | + coded_bits[coded_bits == 1.0] = inf |
| 151 | + coded_bits[coded_bits == 0.0] = -inf |
| 152 | + decoded_bits = viterbi_decode(coded_bits, self.trellis[i], 15, 'soft') |
| 153 | + assert_array_equal(decoded_bits, msg) |
| 154 | + |
| 155 | + |
| 156 | +if __name__ == "__main__": |
| 157 | + seed(17121996) |
| 158 | + run_module_suite() |
| 159 | + |
0 commit comments