def test_calculating_the_chordal_distance(self): expected_chord_dist = np.array([0.473867859572]) # Test calcChordalDistance np.testing.assert_array_almost_equal(metrics.calc_chordal_distance(self.A, self.B), expected_chord_dist) # Test calcChordalDistance2 np.testing.assert_array_almost_equal(metrics.calc_chordal_distance_2(self.A, self.B), expected_chord_dist) # Test principal_angles = metrics.calc_principal_angles(self.A, self.B) np.testing.assert_array_almost_equal( metrics.calc_chordal_distance_from_principal_angles(principal_angles), expected_chord_dist ) # xxxxxxxxxx Now let's test with complex values xxxxxxxxxxxxxxxxxxx A = randn_c(3, 2) B = randn_c(3, 2) principal_angles2 = metrics.calc_principal_angles(A, B) dist1 = metrics.calc_chordal_distance(A, B) dist2 = metrics.calc_chordal_distance_2(A, B) dist3 = metrics.calc_chordal_distance_from_principal_angles(principal_angles2) self.assertAlmostEqual(dist1, dist2) self.assertAlmostEqual(dist3, dist2)
def test_decode(self): data = np.r_[0:15] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Test with an identity channel channel = np.eye(3) self.blast_object.set_channel_matrix(channel) encoded_data = self.blast_object.encode(data) decoded_data1 = self.blast_object.decode(encoded_data) np.testing.assert_array_almost_equal(decoded_data1, data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Test with a random channel and a zero-force filter self.blast_object.set_noise_var(None) # This should use the ZF filter channel = randn_c(4, 3) # 3 transmitt antennas and 4 receive antennas self.blast_object.set_channel_matrix(channel) received_data2 = np.dot(channel, encoded_data) decoded_data2 = self.blast_object.decode(received_data2) np.testing.assert_array_almost_equal(decoded_data2, data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Test with a random channel and a MMSE filter self.blast_object.set_noise_var(0.00000001) channel = randn_c(4, 3) # 3 transmitt antennas and 4 receive antennas self.blast_object.set_channel_matrix(channel) received_data3 = np.dot(channel, encoded_data) decoded_data3 = self.blast_object.decode(received_data3) np.testing.assert_array_almost_equal(decoded_data3.round(7), data)
def test_calculating_the_chordal_distance(self): expected_chord_dist = 0.473867859572 # Test calcChordalDistance self.assertAlmostEqual(metrics.calc_chordal_distance(self.A, self.B), expected_chord_dist) # Test calcChordalDistance2 self.assertAlmostEqual(metrics.calc_chordal_distance_2(self.A, self.B), expected_chord_dist) # Test principal_angles = metrics.calc_principal_angles(self.A, self.B) self.assertAlmostEqual( metrics.calc_chordal_distance_from_principal_angles( principal_angles), expected_chord_dist) # xxxxxxxxxx Now let's test with complex values xxxxxxxxxxxxxxxxxxx A = randn_c(3, 2) B = randn_c(3, 2) principal_angles2 = metrics.calc_principal_angles(A, B) dist1 = metrics.calc_chordal_distance(A, B) dist2 = metrics.calc_chordal_distance_2(A, B) dist3 = metrics.calc_chordal_distance_from_principal_angles( principal_angles2) self.assertAlmostEqual(dist1, dist2) self.assertAlmostEqual(dist3, dist2)
def test_encode(self): data = np.r_[0:15] # xxxxxxxxxx test the case with Ntx=2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxx Nt = 2 channel = randn_c(Nt) self.mrt_object.set_channel_matrix(channel) data_aux = data.reshape(1, data.size) # Useful for broadcasting ":type: np.ndarray" W = np.exp(-1j * np.angle(channel)).reshape(Nt, 1) / math.sqrt(Nt) ":type: np.ndarray" encoded_data = self.mrt_object.encode(data) expected_encoded_data = W * data_aux np.testing.assert_array_almost_equal(expected_encoded_data, encoded_data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx test the case with Ntx=4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxx Nt = 4 channel = randn_c(Nt) self.mrt_object.set_channel_matrix(channel) data_aux = data.reshape(1, data.size) # Useful for broadcasting ":type: np.ndarray" encoded_data = self.mrt_object.encode(data) W = np.exp(-1j * np.angle(channel)).reshape(Nt, 1) ":type: np.ndarray" expected_encoded_data = (1. / math.sqrt(Nt)) * W * data_aux np.testing.assert_array_almost_equal(expected_encoded_data, encoded_data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Test the case where the channel is 2D xxxxxxxxxxxxxxxx # Note tha in this case even though the channel is a 2D numpy array # the size of the first dimension (receive antennas) must be equal # to 1. Nt = 4 channel2 = randn_c(1, Nt) self.mrt_object.set_channel_matrix(channel2) data_aux = data.reshape(1, data.size) # Useful for broadcasting ":type: np.ndarray" encoded_data = self.mrt_object.encode(data) W = np.exp(-1j * np.angle(channel2)).reshape(Nt, 1) ":type: np.ndarray" expected_encoded_data = (1. / math.sqrt(Nt)) * W * data_aux np.testing.assert_array_almost_equal(expected_encoded_data, encoded_data)
def test_set_channel_matrix(self): self.alamouti_object.set_channel_matrix(randn_c(2)) self.assertEqual(self.alamouti_object.Nt, 2) self.assertEqual(self.alamouti_object.Nr, 1) self.alamouti_object.set_channel_matrix(randn_c(4, 2)) self.assertEqual(self.alamouti_object.Nt, 2) self.assertEqual(self.alamouti_object.Nr, 4) with self.assertRaises(ValueError): self.alamouti_object.set_channel_matrix(randn_c(4, 3))
def test_calc_receive_filter(self): Pu = self.Pu noise_var = self.noise_var num_users = self.num_users # num_antennas = self.num_antennas channel = randn_c(self.iNr, self.iNt) (newH, _) = blockdiagonalization.block_diagonalize(channel, num_users, Pu, noise_var) # W_bd is a block diagonal matrix, where each "small block" is the # receive filter of one user. W_bd = blockdiagonalization.calc_receive_filter(newH) np.testing.assert_array_almost_equal(np.dot(W_bd, newH), np.eye(self.iNt)) # Retest for each individual user W0 = W_bd[0:2, 0:2] newH0 = newH[0:2, 0:2] np.testing.assert_array_almost_equal(np.dot(W0, newH0), np.eye(self.iNt // 3)) W1 = W_bd[2:4, 2:4] newH1 = newH[2:4, 2:4] np.testing.assert_array_almost_equal(np.dot(W1, newH1), np.eye(self.iNt // 3)) W2 = W_bd[4:, 4:] newH2 = newH[4:, 4:] np.testing.assert_array_almost_equal(np.dot(W2, newH2), np.eye(self.iNt // 3))
def test_perform_normalized_waterfilling_power_scaling(self): channel = randn_c(self.iNr, self.iNt) (Ms_bad, Sigma) = self.BD._calc_BD_matrix_no_power_scaling(channel) Ms_good = self.BD._perform_normalized_waterfilling_power_scaling( Ms_bad, Sigma) # Ms_good = self.BD._perform_global_waterfilling_power_scaling( # Ms_bad, Sigma) # xxxxx Now lets test the power restriction xxxxxxxxxxxxxxxxxxxxxxx # Total power restriction total_power = self.Pu * self.num_users self.assertGreaterEqual(total_power, np.linalg.norm(Ms_good, 'fro') ** 2) # xxxxx Test the Individual power restriction of each user xxxxxxxx # Cummulated number of transmit antennas cum_Nt = np.cumsum( np.hstack([0, np.ones(self.num_users, dtype=int) * self.num_antenas])) individual_powers = [] for i in range(self.num_users): # Most likelly only one base station (the one with the worst # channel) will employ a precoder with total power of `Pu`, # while the other base stations will use less power. individual_powers.append( np.linalg.norm( Ms_good[:, cum_Nt[i]:cum_Nt[i] + self.num_antenas], 'fro' ) ** 2) # 1e-12 is included to avoid false test fails due to small # precision errors tol = 1e-12 self.assertGreaterEqual(self.Pu + tol, individual_powers[-1])
def test_perform_global_waterfilling_power_scaling(self): channel = randn_c(self.iNr, self.iNt) (Ms_bad, Sigma) = self.BD._calc_BD_matrix_no_power_scaling(channel) Ms_good = self.BD._perform_global_waterfilling_power_scaling( Ms_bad, Sigma) # Ms_good must have the same shape as Ms_bad np.testing.assert_array_equal(Ms_bad.shape, Ms_good.shape) # The total available power is equal to the power per user times # the number of users total_power = self.Pu * self.num_users # The square of the Frobenius norm of Ms_good must be equal to the # total available power self.assertAlmostEqual(np.linalg.norm(Ms_good, 'fro') ** 2, total_power) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Ms_good must still be able to block diagonalize the channel A = np.ones([self.iNrk, self.iNtk]) mask = block_diag(A, A, A) newH = np.dot(channel, Ms_good) # With the mask we can create a masked array of the block # diagonalized channel masked_newH = np.ma.masked_array(newH, mask) # Now we can sum all elements of this masked array (which # effectively means all elements outside the block diagonal) and # see if it is close to zero. self.assertAlmostEqual(0., np.abs(masked_newH).sum())
def test_calc_BD_matrix_no_power_scaling(self): channel = randn_c(self.iNr, self.iNt) (Ms_bad, _) = self.BD._calc_BD_matrix_no_power_scaling(channel) newH = np.dot(channel, Ms_bad) # Because Ms_bad does not have any power scaling and each column of # it comes is a singular vector calculated with the SVD, then the # square of its Frobenius norm is equal to its dimension. self.assertAlmostEqual(np.linalg.norm(Ms_bad, 'fro') ** 2, Ms_bad.shape[0]) # Now let's test if newH is really a block diagonal matrix. # First we create a 'mask' A = np.ones([self.iNrk, self.iNtk]) mask = block_diag(A, A, A) # With the mask we can create a masked array of the block # diagonalized channel which effectively removes the elements in # the block diagonal masked_newH = np.ma.masked_array(newH, mask) # If we sum all the elements in the masked channel (the mask # removes the elements in the block diagonal) it should be equal to # zero self.assertAlmostEqual(0., np.abs(masked_newH).sum())
def test_calc_receive_filter(self): Pu = self.Pu noise_var = self.noise_var num_users = self.num_users # num_antenas = self.num_antenas channel = randn_c(self.iNr, self.iNt) (newH, _) = blockdiagonalization.block_diagonalize( channel, num_users, Pu, noise_var) # W_bd is a block diagonal matrix, where each "small block" is the # receive filter of one user. W_bd = blockdiagonalization.calc_receive_filter(newH) np.testing.assert_array_almost_equal(np.dot(W_bd, newH), np.eye(np.sum(self.iNt))) # Retest for each individual user W0 = W_bd[0:2, 0:2] newH0 = newH[0:2, 0:2] np.testing.assert_array_almost_equal(np.dot(W0, newH0), np.eye(self.iNt/3)) W1 = W_bd[2:4, 2:4] newH1 = newH[2:4, 2:4] np.testing.assert_array_almost_equal(np.dot(W1, newH1), np.eye(self.iNt/3)) W2 = W_bd[4:, 4:] newH2 = newH[4:, 4:] np.testing.assert_array_almost_equal(np.dot(W2, newH2), np.eye(self.iNt/3))
def test_init(self): channel1 = randn_c(3) mrt_object1 = MRT(channel1) self.assertEqual(3, mrt_object1.Nt) self.assertEqual(1, mrt_object1.Nr) channel2 = randn_c(1, 3) mrt_object2 = MRT(channel2) self.assertEqual(3, mrt_object2.Nt) self.assertEqual(1, mrt_object2.Nr) channel3 = randn_c(2, 3) # Number of receive antennas must be exact 1. Since channel3 has 2 # receive antennas, an exception should be raised with self.assertRaises(ValueError): MRT(channel3)
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 test_modulate_and_demodulate(self): awgn_noise = randn_c(20,) * 1e-2 # xxxxxxxxxx Test for 4-QAM xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx input_data = np.random.random_integers(0, 4 - 1, 20) modulated_data = self.qam_obj.modulate(input_data) demodulated_data = self.qam_obj.demodulate(modulated_data + awgn_noise) np.testing.assert_array_equal(input_data, demodulated_data) # xxxxxxxxxx Test for 16-QAM xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx input_data2 = np.random.random_integers(0, 16 - 1, 20) modulated_data2 = self.qam_obj2.modulate(input_data2) demodulated_data2 = self.qam_obj2.demodulate(modulated_data2 + awgn_noise) np.testing.assert_array_equal(input_data2, demodulated_data2) # xxxxxxxxxx Test for 64-QAM xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx input_data3 = np.random.random_integers(0, 64 - 1, 20) modulated_data3 = self.qam_obj3.modulate(input_data3) demodulated_data3 = self.qam_obj3.demodulate(modulated_data3 + awgn_noise) np.testing.assert_array_equal(input_data3, demodulated_data3) # Test if an exception is raised for invalid arguments with self.assertRaises(ValueError): self.qam_obj.modulate(4) with self.assertRaises(ValueError): self.qam_obj2.modulate(16) with self.assertRaises(ValueError): self.qam_obj3.modulate(65)
def test_decode(self): Nt = 4 # xxxxxxxxxx test the case with a single receive antenna xxxxxxxxxx channel = randn_c(Nt) self.mrt_object.set_channel_matrix(channel) data = np.r_[0:15] encoded_data = self.mrt_object.encode(data) # Add '0.1' as a noise term received_data = channel.dot(encoded_data) + 0.0001 decoded_data = self.mrt_object.decode(received_data) self.assertEqual(len(decoded_data.shape), 1) np.testing.assert_array_almost_equal(decoded_data, data, decimal=4) # Now we are explicitting changing the shape of the channel # variable to include the first dimension corresponding to a single # receive antenna channel.shape = (1, Nt) self.mrt_object.set_channel_matrix(channel) # The encoded data should be the same encoded_data = self.mrt_object.encode(data) # Add '0.1' as a noise term received_data = channel.dot(encoded_data) + 0.0001 decoded_data = self.mrt_object.decode(received_data) self.assertEqual(len(decoded_data.shape), 1) np.testing.assert_array_almost_equal(decoded_data, data, decimal=4)
def test_modulate_and_demodulate(self): awgn_noise = randn_c(20, ) * 1e-2 # xxxxxxxxxx Test for 4-QAM xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx input_data = np.random.randint(0, 4, 20) modulated_data = self.qam_obj.modulate(input_data) demodulated_data = self.qam_obj.demodulate(modulated_data + awgn_noise) np.testing.assert_array_equal(input_data, demodulated_data) # xxxxxxxxxx Test for 16-QAM xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx input_data2 = np.random.randint(0, 16, 20) modulated_data2 = self.qam_obj2.modulate(input_data2) demodulated_data2 = self.qam_obj2.demodulate(modulated_data2 + awgn_noise) np.testing.assert_array_equal(input_data2, demodulated_data2) # xxxxxxxxxx Test for 64-QAM xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx input_data3 = np.random.randint(0, 64, 20) modulated_data3 = self.qam_obj3.modulate(input_data3) demodulated_data3 = self.qam_obj3.demodulate(modulated_data3 + awgn_noise) np.testing.assert_array_equal(input_data3, demodulated_data3) # Test if an exception is raised for invalid arguments with self.assertRaises(ValueError): self.qam_obj.modulate(4) with self.assertRaises(ValueError): self.qam_obj2.modulate(16) with self.assertRaises(ValueError): self.qam_obj3.modulate(65)
def simulate_and_compute_Rxx_U0(M, N, SNR, beam_sep): """ Simulate and generate Rxx and U0 considering that three wavefronts were sent. M : int N : int SNR : float beam_sep : float Normalized beamwidth separation between the wavefronts. This separation is normalized by the beamwidth. """ qpsk = modulators.QPSK() d = 3 # Number of inpinging waves mu_b = 2 * np.pi / M mu = np.array([-beam_sep * mu_b, 0, beam_sep * mu_b]) # Standard beamwidth data = np.random.randint(4, size=(d, N)) modulated_data = qpsk.modulate(data) / sqrt(d) noise_power = 1. / dB2Linear(SNR) noise = sqrt(noise_power) * randn_c(M, N) steering_vec = calc_a_phi_vect(M, mu) received_data = steering_vec @ modulated_data + noise # Covariance matrix of the received Data Rxx = received_data @ received_data.T.conj() U, S, V_H = np.linalg.svd(Rxx) U0 = U[:, d:] return Rxx, U0
def test_calc_BD_matrix_no_power_scaling(self): channel = randn_c(self.iNr, self.iNt) (Ms_bad, _) = self.BD._calc_BD_matrix_no_power_scaling(channel) newH = np.dot(channel, Ms_bad) # Because Ms_bad does not have any power scaling and each column of # it comes is a singular vector calculated with the SVD, then the # square of its Frobenius norm is equal to its dimension. self.assertAlmostEqual( np.linalg.norm(Ms_bad, 'fro')**2, Ms_bad.shape[0]) # Now let's test if newH is really a block diagonal matrix. # First we create a 'mask' A = np.ones([self.iNrk, self.iNtk]) mask = block_diag(A, A, A) # With the mask we can create a masked array of the block # diagonalized channel which effectively removes the elements in # the block diagonal masked_newH = np.ma.masked_array(newH, mask) # If we sum all the elements in the masked channel (the mask # removes the elements in the block diagonal) it should be equal to # zero self.assertAlmostEqual(0., np.abs(masked_newH).sum())
def test_perform_global_waterfilling_power_scaling(self): channel = randn_c(self.iNr, self.iNt) (Ms_bad, Sigma) = self.BD._calc_BD_matrix_no_power_scaling(channel) Ms_good = self.BD._perform_global_waterfilling_power_scaling( Ms_bad, Sigma) # Ms_good must have the same shape as Ms_bad np.testing.assert_array_equal(Ms_bad.shape, Ms_good.shape) # The total available power is equal to the power per user times # the number of users total_power = self.Pu * self.num_users # The square of the Frobenius norm of Ms_good must be equal to the # total available power self.assertAlmostEqual(np.linalg.norm(Ms_good, 'fro')**2, total_power) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Ms_good must still be able to block diagonalize the channel A = np.ones([self.iNrk, self.iNtk]) mask = block_diag(A, A, A) newH = np.dot(channel, Ms_good) # With the mask we can create a masked array of the block # diagonalized channel masked_newH = np.ma.masked_array(newH, mask) # Now we can sum all elements of this masked array (which # effectively means all elements outside the block diagonal) and # see if it is close to zero. self.assertAlmostEqual(0., np.abs(masked_newH).sum())
def test_perform_normalized_waterfilling_power_scaling(self): channel = randn_c(self.iNr, self.iNt) (Ms_bad, Sigma) = self.BD._calc_BD_matrix_no_power_scaling(channel) Ms_good = self.BD._perform_normalized_waterfilling_power_scaling( Ms_bad, Sigma) # Ms_good = self.BD._perform_global_waterfilling_power_scaling( # Ms_bad, Sigma) # xxxxx Now lets test the power restriction xxxxxxxxxxxxxxxxxxxxxxx # Total power restriction total_power = self.Pu * self.num_users self.assertGreaterEqual(total_power, np.linalg.norm(Ms_good, 'fro')**2) # xxxxx Test the Individual power restriction of each user xxxxxxxx # accumulated number of transmit antennas cum_Nt = np.cumsum( np.hstack( [0, np.ones(self.num_users, dtype=int) * self.num_antennas])) individual_powers = [] for i in range(self.num_users): # Most likely only one base station (the one with the worst # channel) will employ a precoder with total power of `Pu`, # while the other base stations will use less power. individual_powers.append( np.linalg.norm( Ms_good[:, cum_Nt[i]:cum_Nt[i] + self.num_antennas], 'fro')**2) # 1e-12 is included to avoid false test fails due to small # precision errors tol = 1e-12 self.assertGreaterEqual(self.Pu + tol, individual_powers[-1])
def test_encode(self): data = np.r_[0:15] # xxxxxxxxxx test the case with Ntx=2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxx Nt = 2 channel = randn_c(Nt) self.mrt_object.set_channel_matrix(channel) data_aux = data.reshape(1, data.size) # Useful for broadcasting W = np.exp(-1j * np.angle(channel)).reshape(Nt, 1) / math.sqrt(Nt) encoded_data = self.mrt_object.encode(data) expected_encoded_data = W * data_aux np.testing.assert_array_almost_equal(expected_encoded_data, encoded_data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx test the case with Ntx=4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxx Nt = 4 channel = randn_c(Nt) self.mrt_object.set_channel_matrix(channel) data_aux = data.reshape(1, data.size) # Useful for broadcasting encoded_data = self.mrt_object.encode(data) W = np.exp(-1j * np.angle(channel)).reshape(Nt, 1) expected_encoded_data = (1. / math.sqrt(Nt)) * W * data_aux np.testing.assert_array_almost_equal(expected_encoded_data, encoded_data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Test the case where the channel is 2D xxxxxxxxxxxxxxxx # Note tha in this case even though the channel is a 2D numpy array # the size of the first dimension (receive antennas) must be equal # to 1. Nt = 4 channel2 = randn_c(1, Nt) self.mrt_object.set_channel_matrix(channel2) data_aux = data.reshape(1, data.size) # Useful for broadcasting encoded_data = self.mrt_object.encode(data) W = np.exp(-1j * np.angle(channel2)).reshape(Nt, 1) expected_encoded_data = (1. / math.sqrt(Nt)) * W * data_aux np.testing.assert_array_almost_equal(expected_encoded_data, encoded_data)
def test_calc_receive_filter(self): # Equivalent channel without including stream reduction Heq_k = randn_c(3, 3) Re_k = randn_c(3, 2) Re_k = np.dot(Re_k, Re_k.transpose().conjugate()) P1 = blockdiagonalization._calc_stream_reduction_matrix(Re_k, 1) P2 = blockdiagonalization._calc_stream_reduction_matrix(Re_k, 2) P3 = blockdiagonalization._calc_stream_reduction_matrix(Re_k, 3) # Equivalent channels with the stream reduction Heq_k_P1 = np.dot(Heq_k, P1) Heq_k_P2 = np.dot(Heq_k, P2) Heq_k_P3 = np.dot(Heq_k, P3) W1 = blockdiagonalization.EnhancedBD.calc_receive_filter_user_k( Heq_k_P1, P1) W2 = blockdiagonalization.EnhancedBD.calc_receive_filter_user_k( Heq_k_P2, P2) W3 = blockdiagonalization.EnhancedBD.calc_receive_filter_user_k( Heq_k_P3, P3) # Note that since P3 is actually including all streams, then the # performance is the same as if we don't reduce streams. However W3 # and W_full are different matrices, since W3 has to compensate the # right multiplication of the equivalent channel by P3 and W_full # does not. The performance is the same because no energy is lost # due to stream reduction and the Frobenius norms of W3 and W_full # are equal. W_full = blockdiagonalization.EnhancedBD.calc_receive_filter_user_k( Heq_k) np.testing.assert_array_almost_equal(np.dot(W1, np.dot(Heq_k, P1)), np.eye(1)) np.testing.assert_array_almost_equal(np.dot(W2, np.dot(Heq_k, P2)), np.eye(2)) np.testing.assert_array_almost_equal(np.dot(W3, np.dot(Heq_k, P3)), np.eye(3)) np.testing.assert_array_almost_equal(np.dot(W_full, Heq_k), np.eye(3)) overbar_P2 = calcProjectionMatrix(P2) expected_W2 = np.dot( np.linalg.pinv(np.dot(overbar_P2, np.dot(Heq_k, P2))), overbar_P2) np.testing.assert_array_almost_equal(expected_W2, W2)
def test_decode(self): data = np.r_[0:16] + np.r_[0:16] * 1j encoded_data = self.alamouti_object.encode(data) # We will test the deconding with a random channel channel = randn_c(3, 2) self.alamouti_object.set_channel_matrix(channel) received_data = np.dot(channel, encoded_data) decoded_data = self.alamouti_object.decode(received_data) np.testing.assert_array_almost_equal(decoded_data, data)
def test_calc_decorrelation_matrix(self): A = misc.randn_c(3, 3) # B is symmetric and positive semi-definite B = np.dot(A, A.conjugate().T) Wd = misc.calc_decorrelation_matrix(B) D = np.dot(np.dot(Wd.conjugate().T, B), Wd) # D must be a diagonal matrix np.testing.assert_array_almost_equal(D, np.diag(D.diagonal()))
def test_calc_whitening_matrix(self): A = misc.randn_c(3, 3) # B is symmetric and positive semi-definite B = np.dot(A, A.conjugate().T) Wd = misc.calc_whitening_matrix(B) D = np.dot(np.dot(Wd.conjugate().T, B), Wd) # D must be an identity matrix np.testing.assert_array_almost_equal(D, np.eye(3))
def test_decode(self): # xxxxxxxxxx test the case with Ntx=2, NRx=2 xxxxxxxxxxxxxxxxxxxxxx Nt = 2 Nr = 2 data = np.r_[0:15*Nt] channel = randn_c(Nr, Nt) self.svdmimo_object.set_channel_matrix(channel) encoded_data = self.svdmimo_object.encode(data) received_data = channel.dot(encoded_data) decoded_data = self.svdmimo_object.decode(received_data) np.testing.assert_array_almost_equal(data, decoded_data)
def test_modulate_and_demodulate(self): input_data = np.random.random_integers(0, 1, 20) modulated_data = self.bpsk_obj.modulate(input_data) awgn_noise = randn_c(20,) * 1e-2 demodulated_data = self.bpsk_obj.demodulate(modulated_data + awgn_noise) np.testing.assert_array_equal(input_data, demodulated_data) # Test if an exception is raised for invalid arguments with self.assertRaises(ValueError): self.bpsk_obj.modulate(2)
def test_modulate_and_demodulate(self): input_data = np.random.random_integers(0, 1, 20) modulated_data = self.bpsk_obj.modulate(input_data) awgn_noise = randn_c(20, ) * 1e-2 demodulated_data = self.bpsk_obj.demodulate(modulated_data + awgn_noise) np.testing.assert_array_equal(input_data, demodulated_data) # Test if an exception is raised for invalid arguments with self.assertRaises(ValueError): self.bpsk_obj.modulate(2)
def test_decode(self): data = np.r_[0:15] num_streams = 3 # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Test with an identity channel channel = np.eye(num_streams) self.mrc_object.set_channel_matrix(channel) encoded_data = self.mrc_object.encode(data) decoded_data1 = self.mrc_object.decode(encoded_data) np.testing.assert_array_almost_equal(decoded_data1, data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Test with a random channel and a zero-force filter self.mrc_object.set_noise_var(None) # This should use the ZF filter channel = randn_c(4, num_streams) # 4 receive antennas self.mrc_object.set_channel_matrix(channel) received_data2 = np.dot(channel, encoded_data) decoded_data2 = self.mrc_object.decode(received_data2) np.testing.assert_array_almost_equal(decoded_data2, data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Test with a random channel and a MMSE filter self.mrc_object.set_noise_var(0.00000001) channel = randn_c(4, num_streams) # 4 receive antennas self.mrc_object.set_channel_matrix(channel) received_data3 = np.dot(channel, encoded_data) decoded_data3 = self.mrc_object.decode(received_data3) np.testing.assert_array_almost_equal(decoded_data3.round(7), data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # test with a single stream self.mrc_object.set_noise_var(None) # This should use the ZF filter channel = randn_c(4) # 4 receive antennas self.mrc_object.set_channel_matrix(channel) encoded_data2 = self.mrc_object.encode(data) received_data4 = np.dot(channel[:,np.newaxis], encoded_data2) decoded_data4 = self.mrc_object.decode(received_data4) np.testing.assert_array_almost_equal(decoded_data4, data)
def test_modulate_and_demodulate(self) -> None: input_data = np.random.randint(0, 2, 20) modulated_data = self.bpsk_obj.modulate(input_data) awgn_noise = randn_c(20, ) * 1e-2 demodulated_data = self.bpsk_obj.demodulate(modulated_data + awgn_noise) np.testing.assert_array_equal(input_data, demodulated_data) # Test if an exception is raised for invalid arguments with self.assertRaises(ValueError): # noinspection PyTypeChecker self.bpsk_obj.modulate(2)
def test_block_diagonalize(self): Pu = self.Pu noise_var = self.noise_var num_users = self.num_users num_antenas = self.num_antenas channel = randn_c(self.iNr, self.iNt) (newH, Ms) = blockdiagonalization.block_diagonalize( channel, num_users, Pu, noise_var) # xxxxx Test if the channel is really block diagonal xxxxxxxxxxxxxx # First we build a 'mask' to filter out the elements in the block # diagonal. A = np.ones([self.iNrk, self.iNtk]) mask = block_diag(A, A, A) # With the mask we can create a masked array of the block # diagonalized channel masked_newH = np.ma.masked_array(newH, mask) # Now we can sum all elements of this masked array (which # effectively means all elements outside the block diagonal) and # see if it is close to zero. self.assertAlmostEqual(0., np.abs(masked_newH).sum()) # xxxxx Now lets test the power restriction xxxxxxxxxxxxxxxxxxxxxxx # Total power restriction total_power = num_users * Pu self.assertGreaterEqual(total_power, np.linalg.norm(Ms, 'fro') ** 2) # Cummulated number of receive antennas cum_Nt = np.cumsum( np.hstack([0, np.ones(num_users, dtype=int) * num_antenas])) # Individual power restriction of each class individual_powers = [] tol = 1e-12 # Tolerance for the GreaterEqual test for i in range(num_users): # Most likelly only one base station (the one with the worst # channel) will employ a precoder a precoder with total power # of `Pu`, while the other base stations will use less power. individual_powers.append( np.linalg.norm( Ms[:, cum_Nt[i]:cum_Nt[i] + num_antenas], 'fro') ** 2) self.assertGreaterEqual(Pu + tol, individual_powers[-1])
def test_block_diagonalize(self): Pu = self.Pu noise_var = self.noise_var num_users = self.num_users num_antennas = self.num_antennas channel = randn_c(self.iNr, self.iNt) (newH, Ms) = blockdiagonalization.block_diagonalize(channel, num_users, Pu, noise_var) # xxxxx Test if the channel is really block diagonal xxxxxxxxxxxxxx # First we build a 'mask' to filter out the elements in the block # diagonal. A = np.ones([self.iNrk, self.iNtk]) mask = block_diag(A, A, A) # With the mask we can create a masked array of the block # diagonalized channel masked_newH = np.ma.masked_array(newH, mask) # Now we can sum all elements of this masked array (which # effectively means all elements outside the block diagonal) and # see if it is close to zero. self.assertAlmostEqual(0., np.abs(masked_newH).sum()) # xxxxx Now lets test the power restriction xxxxxxxxxxxxxxxxxxxxxxx # Total power restriction total_power = num_users * Pu self.assertGreaterEqual(total_power, np.linalg.norm(Ms, 'fro')**2) # accumulated number of receive antennas cum_Nt = np.cumsum( np.hstack([0, np.ones(num_users, dtype=int) * num_antennas])) # Individual power restriction of each class individual_powers = [] tol = 1e-12 # Tolerance for the GreaterEqual test for i in range(num_users): # Most likely only one base station (the one with the worst # channel) will employ a precoder a precoder with total power # of `Pu`, while the other base stations will use less power. individual_powers.append( np.linalg.norm(Ms[:, cum_Nt[i]:cum_Nt[i] + num_antennas], 'fro')**2) self.assertGreaterEqual(Pu + tol, individual_powers[-1])
def test_calc_post_processing_SINRs(self): Nr = 1 Nt = 2 noise_var = 0.01 channel = randn_c(Nr, Nt) self.alamouti_object.set_channel_matrix(channel) # W = self.alamouti_object._calc_precoder(channel) # G_H = self.alamouti_object._calc_receive_filter(channel, noise_var) expected_sinrs = linear2dB( (np.linalg.norm(channel, 'fro')**2)/noise_var) # Calculate the SINR using method in the Alamouti class. Note that # we only need to pass the noise variance, since the mimo object # knows the channel. sinrs = self.alamouti_object.calc_SINRs(noise_var) np.testing.assert_array_almost_equal(sinrs, expected_sinrs, 2)
def test_modulate_and_demodulate(self): awgn_noise = randn_c(20, ) * 1e-2 input_data = np.random.randint(0, 4, 20) modulated_data = self.psk_obj.modulate(input_data) demodulated_data = self.psk_obj.demodulate(modulated_data + awgn_noise) np.testing.assert_array_equal(input_data, demodulated_data) input_data2 = np.random.randint(0, 8, 20) modulated_data2 = self.psk_obj2.modulate(input_data2) demodulated_data2 = self.psk_obj2.demodulate(modulated_data2 + awgn_noise) np.testing.assert_array_equal(input_data2, demodulated_data2) # Test if an exception is raised for invalid arguments with self.assertRaises(ValueError): # noinspection PyTypeChecker self.psk_obj.modulate(4) with self.assertRaises(ValueError): self.psk_obj2.modulate(10)
def test_calc_post_processing_SINRs(self): Nr = 3 Nt = 3 noise_var = 0.01 channel = randn_c(Nr, Nt) self.svdmimo_object.set_channel_matrix(channel) W = self.svdmimo_object._calc_precoder(channel) G_H = self.svdmimo_object._calc_receive_filter(channel, noise_var) expected_sinrs = linear2dB(calc_SINRs(channel, W, G_H, noise_var)) # Calculate the SINR using the function in the mimo module. Note # that we need to pass the channel, the precoder, the receive # filter and the noise variance. sinrs = calc_post_processing_SINRs(channel, W, G_H, noise_var) np.testing.assert_array_almost_equal(sinrs, expected_sinrs, 2) # Calculate the SINR using method in the MIMO class. Note that we # only need to pass the noise variance, since the mimo object knows # the channel and it can calculate the precoder and receive filter. sinrs_other = self.svdmimo_object.calc_linear_SINRs(noise_var) np.testing.assert_array_almost_equal(sinrs_other, expected_sinrs, 2)
def gen_codebook(codebook_size, dimension): """ Generate a new codebook. Parameters ---------- codebook_size : int The number of code words in the codebook. dimension : int The dimension of each precoder. Returns ------- codebook : 2D numpy array The generated codebook. """ codebook = np.empty([codebook_size, dimension], dtype=complex) for i in range(codebook_size): H = misc.randn_c(dimension, 1) [U, _, _] = np.linalg.svd(H) codebook[i] = U[:, 0] return codebook
# Perform the Block Diagonalization of the channel (newH, Ms) = blockdiagonalization.block_diagonalize( # We only add the first np.sum(Nt) columns of big_H # because the remaining columns come from the external # interference sources, which don't participate in the Block # Diagonalization Process. multiuser_channel.big_H[:, 0:np.sum(Nt)], num_cells, transmit_power, # noise_var 1e-50) # Prepare the transmit data. precoded_data = np.dot(Ms, symbols) external_int_data = np.sqrt(pe) * misc.randn_c(ext_int_rank, NSymbs) all_data = np.vstack([precoded_data, external_int_data]) # Pass the precoded data through the channel received_signal = multiuser_channel.corrupt_concatenated_data(all_data) # Filter the received data receive_filter = np.linalg.pinv(newH) received_symbols = np.dot(receive_filter, received_signal) # Demodulate the filtered symbols decoded_symbols = modulator.demodulate(received_symbols) # Calculates the number of symbol errors num_symbol_errors += np.sum(decoded_symbols != input_data) num_symbols += input_data.size
= quant_small_matrix( true_matrix[rx_start:rx_end, tx_start:tx_end], codebook) return quantize_channel if __name__ == '__main__1': codebook_size = 5 dimension = 4 C = gen_codebook(codebook_size, dimension) Nt = 2 Nr = 2 K = 3 H = misc.randn_c(Nr * K, Nt * K) Hquant = my_quant_func(H, Nr, Nt, K, C) if __name__ == '__main__': SNR = 15.0 noise_var = 1 / dB2Linear(SNR) M = 2 NSymbs = 50 rep_max = 300 modulator = fundamental.BPSK() K = 3 Nr = np.ones(K, dtype=int) * 2 Nt = np.ones(K, dtype=int) * 2 Ns = np.ones(K, dtype=int) * 1 multi_user_channel = pyphysim.channels.multiuser.MultiUserChannelMatrix()
# Perform the Block Diagonalization of the channel (newH, Ms) = blockdiagonalization.block_diagonalize( # We only add the first np.sum(Nt) columns of big_H # because the remaining columns come from the external # interference sources, which don't participate in the Block # Diagonalization Process. multiuser_channel.big_H[:, 0 : np.sum(Nt)], num_cells, transmit_power, # noise_var 1e-50, ) # Prepare the transmit data. precoded_data = np.dot(Ms, symbols) external_int_data = np.sqrt(pe) * misc.randn_c(ext_int_rank, NSymbs) all_data = np.vstack([precoded_data, external_int_data]) # Pass the precoded data through the channel received_signal = multiuser_channel.corrupt_concatenated_data(all_data) # Filter the received data receive_filter = np.linalg.pinv(newH) received_symbols = np.dot(receive_filter, received_signal) # Demodulate the filtered symbols decoded_symbols = modulator.demodulate(received_symbols) # Calculates the number of symbol errors num_symbol_errors += np.sum(decoded_symbols != input_data) num_symbols += input_data.size
def _run_simulation(self, current_parameters): """The _run_simulation method is where the actual code to simulate the system is. The implementation of this method is required by every subclass of SimulationRunner. """ # xxxxx Input parameters (set in the constructor) xxxxxxxxxxxxxxxxx NSymbs = current_parameters['NSymbs'] modulator = current_parameters['modulator'] M = modulator.M SNR = current_parameters["SNR"] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Input Data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx inputData = np.random.randint(0, M, NSymbs) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Modulate input data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx modulatedData = modulator.modulate(inputData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Pass through the channel xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx noiseVar = 1. / dB2Linear(SNR) noise = misc.randn_c(NSymbs) * np.sqrt(noiseVar) receivedData = modulatedData + noise # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Demodulate received data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx demodulatedData = modulator.demodulate(receivedData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Calculates the symbol and bit error rates xxxxxxxxxxxxxxxxx symbolErrors = sum(inputData != demodulatedData) bitErrors = misc.count_bit_errors(inputData, demodulatedData) numSymbols = inputData.size numBits = inputData.size * fundamental.level2bits(M) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Return the simulation results xxxxxxxxxxxxxxxxxxxxxxxxxxxxx symbolErrorsResult = Result.create( "symbol_errors", Result.SUMTYPE, symbolErrors) numSymbolsResult = Result.create( "num_symbols", Result.SUMTYPE, numSymbols) bitErrorsResult = Result.create( "bit_errors", Result.SUMTYPE, bitErrors) numBitsResult = Result.create("num_bits", Result.SUMTYPE, numBits) berResult = Result.create("ber", Result.RATIOTYPE, bitErrors, numBits) serResult = Result.create( "ser", Result.RATIOTYPE, symbolErrors, numSymbols) simResults = SimulationResults() simResults.add_result(symbolErrorsResult) simResults.add_result(numSymbolsResult) simResults.add_result(bitErrorsResult) simResults.add_result(numBitsResult) simResults.add_result(berResult) simResults.add_result(serResult) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx return simResults
def _run_simulation(self, current_parameters): # xxxxx Input parameters (set in the constructor) xxxxxxxxxxxxxxxxx NSymbs = current_parameters["NSymbs"] M = self.modulator.M Nr = current_parameters["Nr"] Nt = current_parameters["Nt"] SNR = current_parameters["SNR"] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Create the channel xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx channel = misc.randn_c(Nr, Nt) self.mimo_object.set_channel_matrix(channel) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Input Data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx num_layers = self.mimo_object.getNumberOfLayers() inputData = np.random.randint(0, M, NSymbs * num_layers) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Modulate input data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx modulatedData = self.modulator.modulate(inputData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Encode with the MIMO scheme xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx transmit_signal = self.mimo_object.encode(modulatedData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Pass through the channel xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx noiseVar = 1 / dB2Linear(SNR) awgn_noise = (misc.randn_c(Nr, NSymbs) * np.sqrt(noiseVar)) received_signal = np.dot(channel, transmit_signal) + awgn_noise # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Decode with the MIMO Scheme xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx mimo_decoded_data = self.mimo_object.decode(received_signal) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Demodulate received data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx demodulatedData = self.modulator.demodulate(mimo_decoded_data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Calculates the symbol and bit error rates xxxxxxxxxxxxxxxxx symbolErrors = sum(inputData != demodulatedData) bitErrors = misc.count_bit_errors(inputData, demodulatedData) numSymbols = inputData.size numBits = inputData.size * fundamental.level2bits(M) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Return the simulation results xxxxxxxxxxxxxxxxxxxxxxxxxxxxx symbolErrorsResult = Result.create( "symbol_errors", Result.SUMTYPE, symbolErrors) numSymbolsResult = Result.create( "num_symbols", Result.SUMTYPE, numSymbols) bitErrorsResult = Result.create("bit_errors", Result.SUMTYPE, bitErrors) numBitsResult = Result.create("num_bits", Result.SUMTYPE, numBits) berResult = Result.create("ber", Result.RATIOTYPE, bitErrors, numBits) serResult = Result.create( "ser", Result.RATIOTYPE, symbolErrors, numSymbols) simResults = SimulationResults() simResults.add_result(symbolErrorsResult) simResults.add_result(numSymbolsResult) simResults.add_result(bitErrorsResult) simResults.add_result(numBitsResult) simResults.add_result(berResult) simResults.add_result(serResult) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx return simResults
def _run_simulation(self, current_parameters): """The _run_simulation method is where the actual code to simulate the system is. The implementation of this method is required by every subclass of SimulationRunner. """ # xxxxx Input parameters (set in the constructor) xxxxxxxxxxxxxxxxx NSymbs = current_parameters['NSymbs'] modulator = current_parameters['modulator'] M = modulator.M SNR = current_parameters["SNR"] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Input Data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx inputData = np.random.randint(0, M, NSymbs) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Modulate input data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx modulatedData = modulator.modulate(inputData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Pass through the channel xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx noiseVar = 1. / dB2Linear(SNR) noise = misc.randn_c(NSymbs) * np.sqrt(noiseVar) receivedData = modulatedData + noise # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Demodulate received data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx demodulatedData = modulator.demodulate(receivedData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Calculates the symbol and bit error rates xxxxxxxxxxxxxxxxx symbolErrors = sum(inputData != demodulatedData) bitErrors = misc.count_bit_errors(inputData, demodulatedData) numSymbols = inputData.size numBits = inputData.size * fundamental.level2bits(M) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Return the simulation results xxxxxxxxxxxxxxxxxxxxxxxxxxxxx symbolErrorsResult = Result.create("symbol_errors", Result.SUMTYPE, symbolErrors) numSymbolsResult = Result.create("num_symbols", Result.SUMTYPE, numSymbols) bitErrorsResult = Result.create("bit_errors", Result.SUMTYPE, bitErrors) numBitsResult = Result.create("num_bits", Result.SUMTYPE, numBits) berResult = Result.create("ber", Result.RATIOTYPE, bitErrors, numBits) serResult = Result.create("ser", Result.RATIOTYPE, symbolErrors, numSymbols) simResults = SimulationResults() simResults.add_result(symbolErrorsResult) simResults.add_result(numSymbolsResult) simResults.add_result(bitErrorsResult) simResults.add_result(numBitsResult) simResults.add_result(berResult) simResults.add_result(serResult) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx return simResults
= quant_small_matrix( true_matrix[rx_start:rx_end, tx_start:tx_end], codebook) return quantize_channel if __name__ == '__main__1': codebook_size = 5 dimension = 4 C = gen_codebook(codebook_size, dimension) Nt = 2 Nr = 2 K = 3 H = misc.randn_c(Nr * K, Nt * K) Hquant = my_quant_func(H, Nr, Nt, K, C) if __name__ == '__main__': SNR = 15.0 noise_var = 1 / dB2Linear(SNR) M = 2 NSymbs = 50 rep_max = 300 modulator = fundamental.BPSK() K = 3 Nr = np.ones(K, dtype=int) * 2 Nt = np.ones(K, dtype=int) * 2 Ns = np.ones(K, dtype=int) * 1