Source code for imtoolkit.OSTBCode

# Copyright (c) IMToolkit Development Team
# This toolkit is released under the MIT License, see LICENSE.txt

import itertools
import numpy as np
from .Modulator import Modulator


[docs]class OSTBCode(object): """Orthogonal space-time block code (OSTBC). A seminal research can be found in [1]. - [1] S. Alamouti, ``A simple transmit diversity technique for wireless communications,'' IEEE J. Sel. Areas Commun., vol. 16, no. 8, pp. 1451--1458, 1998. """ def __init__(self, M, modtype, L, nsymbols=1): """ Args: M (int): the number of transmit antennas. modtype (string): the constellation type. L (int): the constellation size. nsymbols (int): the number of embedded symbols. """ self.M = M mod = Modulator(modtype, L) if M == 2: nsymbols = M elif M == 4: if modtype == "PSK" or modtype == "SQAM": if nsymbols != 2 and nsymbols != 3: print("Please specify nsymbols = 2 or 3. I use nsymbols = 2.") nsymbols = 2 elif modtype == "PAM": nsymbols = M elif M == 8: if modtype == "PSK" or modtype == "SQAM": print("OSTBC with M=8 and PSK is not supported") elif modtype == "PAM": nsymbols = M elif M == 16: nsymbols = M self.B = nsymbols * np.log2(L) self.Nc = int(2 ** self.B) # initialize codes kfoldsymbols = np.array(list(itertools.product(mod.symbols, repeat=nsymbols))) # L^nsymbols \times nsymbols self.codes = np.zeros((self.Nc, M, M), dtype=complex) for i in range(kfoldsymbols.shape[0]): s = kfoldsymbols[i, :] if M == 2: self.codes[i] = [[s[0], s[1]], [-np.conj(s[1]), np.conj(s[0])]] self.codes[i] /= np.sqrt(nsymbols) if M == 4: if modtype == "PSK" or modtype == "SQAM": if nsymbols == 2: self.codes[i, 0, 0] = s[0] self.codes[i, 0, 1] = s[1] self.codes[i, 1, 0] = -np.conj(s[1]) self.codes[i, 1, 1] = np.conj(s[0]) self.codes[i, 2, 2] = s[0] self.codes[i, 2, 3] = s[1] self.codes[i, 3, 2] = -np.conj(s[1]) self.codes[i, 3, 3] = np.conj(s[0]) self.codes[i] /= np.sqrt(nsymbols) elif nsymbols == 3: self.codes[i, 0, 0] = s[0] self.codes[i, 0, 1] = s[1] self.codes[i, 0, 2] = s[2] self.codes[i, 1, 0] = -np.conj(s[1]) self.codes[i, 1, 1] = np.conj(s[0]) self.codes[i, 1, 3] = s[2] self.codes[i, 2, 0] = np.conj(s[2]) self.codes[i, 2, 2] = -np.conj(s[0]) self.codes[i, 2, 3] = s[1] self.codes[i, 3, 1] = np.conj(s[2]) self.codes[i, 3, 2] = -np.conj(s[1]) self.codes[i, 3, 3] = -s[0] self.codes[i] /= np.sqrt(nsymbols) elif modtype == "PAM": self.codes[i, 0, 0] = s[0] self.codes[i, 0, 1] = s[1] self.codes[i, 0, 2] = s[2] self.codes[i, 0, 3] = s[3] self.codes[i, 1, 0] = -s[1] self.codes[i, 1, 1] = s[0] self.codes[i, 1, 2] = -s[3] self.codes[i, 1, 3] = s[2] self.codes[i, 2, 0] = -s[2] self.codes[i, 2, 1] = s[3] self.codes[i, 2, 2] = s[0] self.codes[i, 2, 3] = -s[1] self.codes[i, 3, 0] = -s[3] self.codes[i, 3, 1] = -s[2] self.codes[i, 3, 2] = s[1] self.codes[i, 3, 3] = s[0] self.codes[i] /= np.sqrt(nsymbols) elif M == 8: if modtype == "PAM": self.codes[i, 0] = [+s[0], +s[1], +s[2], +s[3], +s[4], +s[5], +s[6], +s[7]] self.codes[i, 1] = [-s[1], +s[0], +s[3], -s[2], +s[5], -s[4], -s[7], +s[6]] self.codes[i, 2] = [-s[2], -s[3], +s[0], +s[1], +s[6], +s[7], -s[4], -s[5]] self.codes[i, 3] = [-s[3], +s[2], -s[1], +s[0], +s[7], -s[6], +s[5], -s[4]] self.codes[i, 4] = [-s[4], -s[5], -s[6], -s[7], +s[0], +s[1], +s[2], +s[3]] self.codes[i, 5] = [-s[5], +s[4], -s[7], +s[6], -s[1], +s[0], -s[3], +s[2]] self.codes[i, 6] = [-s[6], +s[7], +s[4], -s[5], -s[2], +s[3], +s[0], -s[1]] self.codes[i, 7] = [-s[7], -s[6], +s[5], +s[4], -s[3], -s[2], +s[1], +s[0]] self.codes[i] /= np.sqrt(nsymbols) elif M == 16: for k in range(8): self.codes[i, 0 + k * 2, 0 + k * 2] = s[0 + k * 2] self.codes[i, 0 + k * 2, 1 + k * 2] = s[1 + k * 2] self.codes[i, 1 + k * 2, 0 + k * 2] = -np.conj(s[1 + k * 2]) self.codes[i, 1 + k * 2, 1 + k * 2] = np.conj(s[0 + k * 2]) self.codes[i] /= np.sqrt(2)
[docs] def putRate(self): print("B / M = %d / %d = %d [bit/symbol]" % (self.B, self.M, self.B / self.M))