瀏覽代碼

Alphabet mod/demod

Min 5 年之前
父節點
當前提交
ea0fb8a718
共有 7 個文件被更改,包括 247 次插入80 次删除
  1. 20 0
      alphabets/16qam.a
  2. 72 0
      alphabets/64qam.a
  3. 9 0
      alphabets/8psk.a
  4. 3 0
      alphabets/bpsk.a
  5. 5 0
      alphabets/qpsk.a
  6. 17 4
      main.py
  7. 121 76
      models/basic.py

+ 20 - 0
alphabets/16qam.a

@@ -0,0 +1,20 @@
+R
+1000,-1,1
+1001,-0.33333,1
+1011,0.33333,1
+1010,1,1
+
+1100,-1,0.33333
+1101,-0.33333,0.33333
+1111,0.33333,0.33333
+1110,1,0.33333
+
+0100,-1,-0.33333
+0101,-0.33333,-0.33333
+0111,0.33333,-0.33333
+0110,1,-0.33333
+
+0000,-1,-1
+0001,-0.33333,-1
+0011,0.33333,-1
+0010,1,-1

+ 72 - 0
alphabets/64qam.a

@@ -0,0 +1,72 @@
+R
+000000,-1,1
+000001,-0.7142857,1
+000011,-0.4285714,1
+000010,-0.1428571,1
+000110,0.1428571,1
+000111,0.4285714,1
+000101,0.7142857,1
+000100,1,1
+
+001000,-1,0.7142857
+001001,-0.7142857,0.7142857
+001011,-0.4285714,0.7142857
+001010,-0.1428571,0.7142857
+001110,0.1428571,0.7142857
+001111,0.4285714,0.7142857
+001101,0.7142857,0.7142857
+001100,1,0.7142857
+
+011000,-1,0.4285714
+011001,-0.7142857,0.4285714
+011011,-0.4285714,0.4285714
+011010,-0.1428571,0.4285714
+011110,0.1428571,0.4285714
+011111,0.4285714,0.4285714
+011101,0.7142857,0.4285714
+011100,1,0.4285714
+
+010000,-1,0.1428571
+010001,-0.7142857,0.1428571
+010011,-0.4285714,0.1428571
+010010,-0.1428571,0.1428571
+010110,0.1428571,0.1428571
+010111,0.4285714,0.1428571
+010101,0.7142857,0.1428571
+010100,1,0.1428571
+
+110000,-1,-0.1428571
+110001,-0.7142857,-0.1428571
+110011,-0.4285714,-0.1428571
+110010,-0.1428571,-0.1428571
+110110,0.1428571,-0.1428571
+110111,0.4285714,-0.1428571
+110101,0.7142857,-0.1428571
+110100,1,-0.1428571
+
+111000,-1,-0.4285714
+111001,-0.7142857,-0.4285714
+111011,-0.4285714,-0.4285714
+111010,-0.1428571,-0.4285714
+111110,0.1428571,-0.4285714
+111111,0.4285714,-0.4285714
+111101,0.7142857,-0.4285714
+111100,1,-0.4285714
+
+101000,-1,-0.7142857
+101001,-0.7142857,-0.7142857
+101011,-0.4285714,-0.7142857
+101010,-0.1428571,-0.7142857
+101110,0.1428571,-0.7142857
+101111,0.4285714,-0.7142857
+101101,0.7142857,-0.7142857
+101100,1,-0.7142857
+
+100000,-1,-1
+100001,-0.7142857,-1
+100011,-0.4285714,-1
+100010,-0.1428571,-1
+100110,0.1428571,-1
+100111,0.4285714,-1
+100101,0.7142857,-1
+100100,1,-1

+ 9 - 0
alphabets/8psk.a

@@ -0,0 +1,9 @@
+D8
+111,1,0
+110,1,45
+010,1,90
+011,1,135
+001,1,180
+000,1,225
+100,1,270
+101,1,315

+ 3 - 0
alphabets/bpsk.a

@@ -0,0 +1,3 @@
+R2
+1,0
+-1,0

+ 5 - 0
alphabets/qpsk.a

@@ -0,0 +1,5 @@
+R4
+1,1
+-1,1
+-1,-1
+1,-1

+ 17 - 4
main.py

@@ -3,9 +3,10 @@ import matplotlib.pyplot as plt
 import numpy as np
 from sklearn.metrics import accuracy_score
 from models import basic
-from models.basic import AWGNChannel, BPSKDemod, BPSKMod, BypassChannel, MaryMod, MaryDemod
+from models.basic import AWGNChannel, BPSKDemod, BPSKMod, BypassChannel, AlphabetMod, AlphabetDemod
 import misc
 
+
 def show_constellation(mod, chan, demod, samples=1000):
     x = misc.generate_random_bit_array(samples)
     x_mod = mod.forward(x)
@@ -42,10 +43,22 @@ def get_AWGN_ber(mod, demod, samples=1000, start=-8, stop=5, steps=30):
 
 
 if __name__ == '__main__':
+    # show_constellation(BPSKMod(10e6), AWGNChannel(-1), BPSKDemod(10e6, 10e3))
+
+    # get_ber(BPSKMod(10e6), AWGNChannel(-20), BPSKDemod(10e6, 10e3))
+    # mod = MaryMod('8psk', 10e6)
+    # misc.display_alphabet(mod.alphabet, a_vals=True)
+    # mod = MaryMod('qpsk', 10e6)
+    # misc.display_alphabet(mod.alphabet, a_vals=True)
+    # mod = MaryMod('16qam', 10e6)
+    # misc.display_alphabet(mod.alphabet, a_vals=True)
+    # mod = MaryMod('64qam', 10e6)
+    # misc.display_alphabet(mod.alphabet, a_vals=True)
 
-    plt.plot(*get_AWGN_ber(MaryMod(6, 10e6, gray=True), MaryDemod(6, 10e6), samples=12000, start=-15), '-', label='64-QAM')
-    plt.plot(*get_AWGN_ber(MaryMod(5, 10e6, gray=True), MaryDemod(5, 10e6), samples=12000, start=-15), '-', label='32-QAM')
-    plt.plot(*get_AWGN_ber(MaryMod(4, 10e6, gray=True), MaryDemod(4, 10e6), samples=12000, start=-15), '-', label='16-QAM')
+    plt.plot(*get_AWGN_ber(AlphabetMod('64qam', 10e6), AlphabetDemod('64qam', 10e6), samples=12000, start=-15), '-', label='64-QAM')
+    plt.plot(*get_AWGN_ber(AlphabetMod('16qam', 10e6), AlphabetDemod('16qam', 10e6), samples=12000, start=-15), '-', label='16-QAM')
+    plt.plot(*get_AWGN_ber(AlphabetMod('qpsk', 10e6), AlphabetDemod('qpsk', 10e6), samples=12000, start=-15), '-', label='QPSK')
+    plt.plot(*get_AWGN_ber(AlphabetMod('8psk', 10e6), AlphabetDemod('8psk', 10e6), samples=12000, start=-15), '-', label='8PSK')
     plt.plot(*get_AWGN_ber(BPSKMod(10e6), BPSKDemod(10e6, 10e3), samples=12000), '-', label='BPSK')
     plt.yscale('log')
     plt.gca().invert_xaxis()

+ 121 - 76
models/basic.py

@@ -3,71 +3,116 @@ import numpy as np
 import math
 import misc
 from scipy.spatial import cKDTree
-
-def _make_gray(n):
-    if n <= 0:
-        return []
-    arr = ['0', '1']
-    i = 2
-    while True:
-        if i >= 1 << n:
-            break
-        for j in range(i - 1, -1, -1):
-            arr.append(arr[j])
-        for j in range(i):
-            arr[j] = "0" + arr[j]
-        for j in range(i, 2 * i):
-            arr[j] = "1" + arr[j]
-        i = i << 1
-    return list(map(lambda x: int(x, 2), arr))
-
-
-def _gen_mary_alphabet(size, gray=True, polar=True):
-    alphabet = np.zeros((size, 2))
-    N = math.ceil(math.sqrt(size))
-
-    # if sqrt(size) != size^2 (not a perfect square),
-    # skip defines how many corners to cut off.
-    skip = 0
-    if N ** 2 > size:
-        skip = int(math.sqrt((N ** 2 - size) // 4))
-
-    step = 2 / (N - 1)
-    skipped = 0
-    for x in range(N):
-        for y in range(N):
-            i = x * N + y - skipped
-            if i >= size:
-                break
-            # Reverse y every odd column
-            if x % 2 == 0 and N < 4:
-                y = N - y - 1
-            if skip > 0:
-                if (x < skip or x + 1 > N - skip) and \
-                        (y < skip or y + 1 > N - skip):
-                    skipped += 1
-                    continue
-            # Exception for 3-ary alphabet, skip centre point
-            if size == 8 and x == 1 and y == 1:
-                skipped += 1
+from os import path
+
+ALPHABET_DIR = "./alphabets"
+# def _make_gray(n):
+#     if n <= 0:
+#         return []
+#     arr = ['0', '1']
+#     i = 2
+#     while True:
+#         if i >= 1 << n:
+#             break
+#         for j in range(i - 1, -1, -1):
+#             arr.append(arr[j])
+#         for j in range(i):
+#             arr[j] = "0" + arr[j]
+#         for j in range(i, 2 * i):
+#             arr[j] = "1" + arr[j]
+#         i = i << 1
+#     return list(map(lambda x: int(x, 2), arr))
+#
+#
+# def _gen_mary_alphabet(size, gray=True, polar=True):
+#     alphabet = np.zeros((size, 2))
+#     N = math.ceil(math.sqrt(size))
+#
+#     # if sqrt(size) != size^2 (not a perfect square),
+#     # skip defines how many corners to cut off.
+#     skip = 0
+#     if N ** 2 > size:
+#         skip = int(math.sqrt((N ** 2 - size) // 4))
+#
+#     step = 2 / (N - 1)
+#     skipped = 0
+#     for x in range(N):
+#         for y in range(N):
+#             i = x * N + y - skipped
+#             if i >= size:
+#                 break
+#             # Reverse y every odd column
+#             if x % 2 == 0 and N < 4:
+#                 y = N - y - 1
+#             if skip > 0:
+#                 if (x < skip or x + 1 > N - skip) and \
+#                         (y < skip or y + 1 > N - skip):
+#                     skipped += 1
+#                     continue
+#             # Exception for 3-ary alphabet, skip centre point
+#             if size == 8 and x == 1 and y == 1:
+#                 skipped += 1
+#                 continue
+#             alphabet[i, :] = [step * x - 1, step * y - 1]
+#     if gray:
+#         shape = alphabet.shape
+#         d1 = 4 if N > 4 else 2 ** N // 4
+#         g1 = np.array([0, 1, 3, 2])
+#         g2 = g1[:d1]
+#         hypershape = (d1, 4, 2)
+#         if N > 4:
+#             hypercube = alphabet.reshape(hypershape + (N-4, ))
+#             hypercube = hypercube[:, g1, :, :][g2, :, :, :]
+#         else:
+#             hypercube = alphabet.reshape(hypershape)
+#             hypercube = hypercube[:, g1, :][g2, :, :]
+#         alphabet = hypercube.reshape(shape)
+#     if polar:
+#         alphabet = misc.rect2polar(alphabet)
+#     return alphabet
+
+
+def load_alphabet(name, polar=True):
+    apath = path.join(ALPHABET_DIR, name + '.a')
+    if not path.exists(apath):
+        raise ValueError(f"Alphabet '{name}' does not exist")
+    data = []
+    indexes = []
+    with open(apath, 'r') as f:
+        header = f.readline().lower()
+        if 'd' not in header and 'r' not in header:
+            raise ValueError(f"Alphabet {name} header does not specify valid format")
+        for i, row in enumerate(f.readlines()):
+            row = row.strip()
+            if len(row) == 0:
                 continue
-            alphabet[i, :] = [step * x - 1, step * y - 1]
-    if gray:
-        shape = alphabet.shape
-        d1 = 4 if N > 4 else 2 ** N // 4
-        g1 = np.array([0, 1, 3, 2])
-        g2 = g1[:d1]
-        hypershape = (d1, 4, 2)
-        if N > 4:
-            hypercube = alphabet.reshape(hypershape + (N-4, ))
-            hypercube = hypercube[:, g1, :, :][g2, :, :, :]
-        else:
-            hypercube = alphabet.reshape(hypershape)
-            hypercube = hypercube[:, g1, :][g2, :, :]
-        alphabet = hypercube.reshape(shape)
+            cols = row.split(',')
+            try:
+                if len(cols) == 3:
+                    indexes.append(int(cols[0], 2))
+                    x = float(cols[1])
+                    y = float(cols[2])
+                elif len(cols) == 2:
+                    indexes.append(i)
+                    x = float(cols[0])
+                    y = float(cols[1])
+                else:
+                    raise ValueError()
+                if 'd' in header:
+                    p = y*math.pi/180
+                    y = math.sin(p) * x
+                    x = math.cos(p) * x
+                data.append((x, y))
+            except ValueError:
+                raise ValueError(f"Alphabet {name} line {i+1}: '{row}' has invalid values")
+
+    data2 = [None] * len(data)
+    for i, d in enumerate(data):
+        data2[indexes[i]] = d
+    arr = np.array(data2, dtype=float)
     if polar:
-        alphabet = misc.rect2polar(alphabet)
-    return alphabet
+        arr = misc.rect2polar(arr)
+    return arr
 
 
 class BypassChannel(defs.Channel):
@@ -127,14 +172,14 @@ class BPSKDemod(defs.Demodulator):
         return result
 
 
-class MaryMod(defs.Modulator):
+class AlphabetMod(defs.Modulator):
 
-    def __init__(self, N, carrier_f, gray=True):
-        if N < 2:
-            raise ValueError("M-ary modulator N value has to be larger than 1")
-        super().__init__(2 ** N)
+    def __init__(self, modulation, carrier_f):
+        # if N < 2:
+        #     raise ValueError("M-ary modulator N value has to be larger than 1")
+        self.alphabet = load_alphabet(modulation)
+        super().__init__(self.alphabet.shape[0])
         self.f = carrier_f
-        self.alphabet = _gen_mary_alphabet(self.alphabet_size, gray)
         self.mult_mat = np.array([2 ** i for i in range(self.N)])
 
     def forward(self, binary):
@@ -151,15 +196,15 @@ class MaryMod(defs.Modulator):
         return np.c_[a, p, f]  #, indices
 
 
-class MaryDemod(defs.Demodulator):
+class AlphabetDemod(defs.Demodulator):
 
-    def __init__(self, N, carrier_f, gray=True):
-        if N < 2:
-            raise ValueError("M-ary modulator N value has to be larger than 1")
-        super().__init__(2 ** N)
+    def __init__(self, modulation, carrier_f):
+        # if N < 2:
+        #     raise ValueError("M-ary modulator N value has to be larger than 1")
+        self.alphabet = load_alphabet(modulation, polar=False)
+        super().__init__(self.alphabet.shape[0])
         self.f = carrier_f
-        self.N = N
-        self.alphabet = _gen_mary_alphabet(self.alphabet_size, gray=gray, polar=False)
+        # self.alphabet = _gen_mary_alphabet(self.alphabet_size, gray=gray, polar=False)
         self.ktree = cKDTree(self.alphabet)
 
     def forward(self, binary):