|
21 | 21 |
|
22 | 22 | """ |
23 | 23 | from bisect import insort |
24 | | -from itertools import product |
25 | 24 |
|
26 | 25 | import matplotlib.pyplot as plt |
27 | | -from numpy import arange, array, zeros, pi, cos, sin, sqrt, log2, argmin, \ |
| 26 | +from numpy import arange, array, zeros, pi, sqrt, log2, argmin, \ |
28 | 27 | hstack, repeat, tile, dot, shape, concatenate, exp, \ |
29 | | - log, vectorize, empty, eye, kron, inf, full, abs, newaxis, minimum, clip |
| 28 | + log, vectorize, empty, eye, kron, inf, full, abs, newaxis, minimum, clip, fromiter |
30 | 29 | from numpy.fft import fft, ifft |
31 | 30 | from numpy.linalg import qr, norm |
| 31 | +from sympy.combinatorics.graycode import GrayCode |
32 | 32 |
|
33 | 33 | from commpy.utilities import bitarray2dec, dec2bitarray, signal_power |
34 | 34 |
|
@@ -65,10 +65,16 @@ class Modem: |
65 | 65 | If the constellation is changed to an array-like with length that is not a power of 2. |
66 | 66 | """ |
67 | 67 |
|
68 | | - def __init__(self, constellation): |
| 68 | + def __init__(self, constellation, reorder_as_gray=True): |
69 | 69 | """ Creates a custom Modem object. """ |
70 | 70 |
|
71 | | - self.constellation = constellation |
| 71 | + if reorder_as_gray: |
| 72 | + m = log2(len(constellation)) |
| 73 | + gray_code_sequence = GrayCode(m).generate_gray() |
| 74 | + gray_code_sequence_array = fromiter((int(g, 2) for g in gray_code_sequence), int, len(constellation)) |
| 75 | + self.constellation = constellation[gray_code_sequence_array.argsort()] |
| 76 | + else: |
| 77 | + self.constellation = constellation |
72 | 78 |
|
73 | 79 | def modulate(self, input_bits): |
74 | 80 | """ Modulate (map) an array of bits to constellation symbols. |
@@ -197,10 +203,7 @@ class PSKModem(Modem): |
197 | 203 | def __init__(self, m): |
198 | 204 | """ Creates a Phase Shift Keying (PSK) Modem object. """ |
199 | 205 |
|
200 | | - def _constellation_symbol(i): |
201 | | - return cos(2 * pi * (i - 1) / m) + sin(2 * pi * (i - 1) / m) * (0 + 1j) |
202 | | - |
203 | | - self.constellation = list(map(_constellation_symbol, arange(m))) |
| 206 | + super().__init__(exp(1j * arange(0, 2 * pi, 2 * pi / m))) |
204 | 207 |
|
205 | 208 |
|
206 | 209 | class QAMModem(Modem): |
@@ -241,12 +244,10 @@ def __init__(self, m): |
241 | 244 |
|
242 | 245 | """ |
243 | 246 |
|
244 | | - def _constellation_symbol(i): |
245 | | - return (2 * i[0] - 1) + (2 * i[1] - 1) * (1j) |
246 | | - |
247 | | - mapping_array = arange(1, sqrt(m) + 1) - (sqrt(m) / 2) |
248 | | - self.constellation = list(map(_constellation_symbol, |
249 | | - list(product(mapping_array, repeat=2)))) |
| 247 | + num_symb_pam = int(sqrt(m)) |
| 248 | + pam = arange(-num_symb_pam + 1, num_symb_pam, 2) |
| 249 | + constellation = tile(hstack((pam, pam[::-1])), num_symb_pam // 2) * 1j + pam.repeat(num_symb_pam) |
| 250 | + super().__init__(constellation) |
250 | 251 |
|
251 | 252 |
|
252 | 253 | def ofdm_tx(x, nfft, nsc, cp_length): |
|
0 commit comments