def test_encode(self): # xxxxxxxxxx test the case with Ntx=2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxx Nt = 2 Nr = 2 data = np.r_[0:15*Nt] channel = randn_c(Nr, Nt) self.gmdmimo_object.set_channel_matrix(channel) encoded_data = self.gmdmimo_object.encode(data) # data_aux = data.reshape(Nt, -1) U, S, V_H = np.linalg.svd(channel) _, _, P = gmd(U, S, V_H) W = P / math.sqrt(Nt) expected_encoded_data = W.dot(data.reshape(Nr, -1)) np.testing.assert_array_almost_equal( expected_encoded_data, encoded_data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Test if an exception is raised for wrong size xxxxxxxxxxxxx # The exception is raised if the input array size is not a multiple # of the number of transmit antennas data2 = np.r_[0:15*Nt+1] with self.assertRaises(ValueError): self.gmdmimo_object.encode(data2)
def _calc_precoder(channel): """ Calculate the linear precoder for the MRT scheme. The MRT scheme corresponds to multiplying the symbol from each transmit antenna with a complex number corresponding to the inverse of the phase of the channel so as to ensure that the signals add constructively at the receiver. This also means that the MRT scheme only be applied to scenarios with a single receive antenna. Parameters ---------- channel : np.ndarray MIMO channel matrix with dimension (1, Nt). Returns ------- W : np.ndarray The precoder that can be applied to the input data. """ Nt = channel.shape[1] # The encode method will precode the transmit_data using the # matrix 'P' obtained from the gmd. U, S, V_H = np.linalg.svd(channel) _, _, P = gmd(U, S, V_H) W = P / math.sqrt(Nt) return W
def _calc_precoder(channel): """ Calculate the linear precoder for the MRT scheme. The MRT scheme corresponds to multiplying the symbol from each transmit antenna with a complex number corresponding to the inverse of the phase of the channel so as to ensure that the signals add constructively at the receiver. This also means that the MRT echeme only be applied to senarios with a single receive antenna. Parameters ---------- channel : 2D numpy array MIMO channel matrix with dimention (1, Nt). Returns ------- W : 2D numpy array The precoder that can be aplied to the input data. """ Nt = channel.shape[1] # The encode method will precode the transmit_data using the # matrix 'P' obtained from the gmd. U, S, V_H = np.linalg.svd(channel) _, _, P = gmd(U, S, V_H) W = P / math.sqrt(Nt) return W
def test_gmd(self): A = np.array([[6, 8, 0, 4], [8, 6, 7, 6], [10, 9, 7, 3], [6, 2, 9, 2]]) [U, S, V_H] = np.linalg.svd(A) # Store the SVD so that we can test later that gmd did not change # the input parameters U2 = U.copy() S2 = S.copy() V_H2 = V_H.copy() tol = 1e-6 Q, R, P = misc.gmd(U, S, V_H, tol) # xxxxxxxxxx Test if the input parameters were changed xxxxxxxxxxxx np.testing.assert_array_almost_equal(U, U2) np.testing.assert_array_almost_equal(S, S2) np.testing.assert_array_almost_equal(V_H, V_H2) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Test if Q and P are unitary xxxxxxxxxxxxxxxxxxxxxxxxxx np.testing.assert_almost_equal(np.eye(4), Q.dot(Q.conj().T)) np.testing.assert_almost_equal(np.eye(4), Q.conj().T.dot(Q)) np.testing.assert_almost_equal(np.eye(4), P.dot(P.conj().T)) np.testing.assert_almost_equal(np.eye(4), P.conj().T.dot(P)) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Test if R is an upper triangular matrix xxxxxxxxxxxxxx # Furthermore, all diagonal elements must be the geometric mean of # the singular values of 'A' lambda_bar = np.prod(S)**(1./4.) np.testing.assert_almost_equal(R.diagonal(), lambda_bar) for i in range(4): # Elements in the diagonal or above it are not equal to zero for j in range(i, 4): self.assertNotAlmostEqual(0.0, R[i, j]) # Elemetns below the diagonal are equal to zero for j in range(i): self.assertAlmostEqual(0.0, R[i, j]) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Test if the decomposition is right xxxxxxxxxxxxxxxxxxx np.testing.assert_almost_equal(A, Q.dot(R).dot(P.conj().T))
def test_gmd(self): A = np.array([[6, 8, 0, 4], [8, 6, 7, 6], [10, 9, 7, 3], [6, 2, 9, 2]]) [U, S, V_H] = np.linalg.svd(A) # Store the SVD so that we can test later that gmd did not change # the input parameters U2 = U.copy() S2 = S.copy() V_H2 = V_H.copy() tol = 1e-6 Q, R, P = misc.gmd(U, S, V_H, tol) # xxxxxxxxxx Test if the input parameters were changed xxxxxxxxxxxx np.testing.assert_array_almost_equal(U, U2) np.testing.assert_array_almost_equal(S, S2) np.testing.assert_array_almost_equal(V_H, V_H2) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Test if Q and P are unitary xxxxxxxxxxxxxxxxxxxxxxxxxx np.testing.assert_almost_equal(np.eye(4), Q.dot(Q.conj().T)) np.testing.assert_almost_equal(np.eye(4), Q.conj().T.dot(Q)) np.testing.assert_almost_equal(np.eye(4), P.dot(P.conj().T)) np.testing.assert_almost_equal(np.eye(4), P.conj().T.dot(P)) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Test if R is an upper triangular matrix xxxxxxxxxxxxxx # Furthermore, all diagonal elements must be the geometric mean of # the singular values of 'A' lambda_bar = np.prod(S)**(1. / 4.) np.testing.assert_almost_equal(R.diagonal(), lambda_bar) for i in range(4): # Elements in the diagonal or above it are not equal to zero for j in range(i, 4): self.assertNotAlmostEqual(0.0, R[i, j]) # Elements below the diagonal are equal to zero for j in range(i): self.assertAlmostEqual(0.0, R[i, j]) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Test if the decomposition is right xxxxxxxxxxxxxxxxxxx np.testing.assert_almost_equal(A, Q.dot(R).dot(P.conj().T))
def _calc_precoder(channel: np.ndarray) -> np.ndarray: """ Calculate the linear precoder for the GMD scheme. Parameters ---------- channel : np.ndarray MIMO channel matrix with dimension (1, Nt). Returns ------- W : np.ndarray The precoder that can be applied to the input data. """ Nt = channel.shape[1] # The encode method will precode the transmit_data using the # matrix 'P' obtained from the gmd. U, S, V_H = np.linalg.svd(channel) _, _, P = gmd(U, S, V_H) W = P / math.sqrt(Nt) return W
def _calc_receive_filter(channel, noise_var=None): """ Calculate the receive filter for the MRT scheme. Parameters ---------- channel : np.ndarray MIMO channel matrix. noise_var : float The noise variance. Returns ------- G_H : np.ndarray The receive_filter that can be applied to the input data. """ U, S, V_H = np.linalg.svd(channel) Q, R, _ = gmd(U, S, V_H) channel_eq = Q.dot(R) # Use the _calc_receive_filter method from the base class (Blast) G_H = Blast._calc_receive_filter(channel_eq, noise_var) return G_H
def _calc_receive_filter(channel, noise_var=None): """ Calculate the receive filter for the MRT scheme. Parameters ---------- channel : 2D numpy array MIMO channel matrix. noise_var : float The noise variance. Returns ------- G_H : 2D numpy array The receive_filter that can be aplied to the input data. """ U, S, V_H = np.linalg.svd(channel) Q, R, _ = gmd(U, S, V_H) channel_eq = Q.dot(R) # Use the _calc_receive_filter method from the base class (Blast) G_H = Blast._calc_receive_filter(channel_eq, noise_var) return G_H