def test_block_diagonalize_no_waterfilling(self): Nr = np.array([2, 2]) Nt = np.array([2, 2]) K = Nt.size Nti = 1 iPu = 1e-1 # Power for each user (linear scale) pe = 1e-3 # External interference power (in linear scale) noise_var = 1e-4 # # The modulator and packet_length are required in the # # effective_throughput metric case # psk_obj = modulators.PSK(4) # packet_length = 120 multiUserChannel = multiuser.MultiUserChannelMatrixExtInt() multiUserChannel.randomize(Nr, Nt, K, Nti) # Channel from all transmitters to the first receiver H1 = multiUserChannel.get_Hk_without_ext_int(0) # Channel from all transmitters to the second receiver H2 = multiUserChannel.get_Hk_without_ext_int(1) # Create the whiteningBD object and the regular BD object whiteningBD_obj = blockdiagonalization.WhiteningBD( K, iPu, noise_var, pe) # noise_plus_int_cov_matrix \ # = multiUserChannel.calc_cov_matrix_extint_plus_noise( # noise_var, pe) # xxxxx First we test without ext. int. handling xxxxxxxxxxxxxxxxxx (Ms_all, Wk_all, Ns_all) \ = whiteningBD_obj.block_diagonalize_no_waterfilling( multiUserChannel) Ms1 = Ms_all[0] Ms2 = Ms_all[1] self.assertEqual(Ms1.shape[1], Ns_all[0]) self.assertEqual(Ms2.shape[1], Ns_all[1]) # 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. tol = 1e-10 self.assertGreaterEqual(iPu + tol, np.linalg.norm(Ms1, 'fro')**2) # 1e-12 is included to avoid false test fails due to small # precision errors self.assertGreaterEqual(iPu + tol, np.linalg.norm(Ms2, 'fro')**2) # Test if the precoder block diagonalizes the channel self.assertNotAlmostEqual(np.linalg.norm(np.dot(H1, Ms1), 'fro'), 0) self.assertAlmostEqual(np.linalg.norm(np.dot(H1, Ms2), 'fro'), 0) self.assertNotAlmostEqual(np.linalg.norm(np.dot(H2, Ms2), 'fro'), 0) self.assertAlmostEqual(np.linalg.norm(np.dot(H2, Ms1), 'fro'), 0)
def test_calc_whitening_matrices(self): Nr = np.array([2, 2]) Nt = np.array([2, 2]) K = Nt.size Nti = 1 iPu = 1e-1 # Power for each user (linear scale) pe = 1e-3 # External interference power (in linear scale) noise_var = 1e-4 # Generate the multi-user channel mu_channel = multiuser.MultiUserChannelMatrixExtInt() mu_channel.randomize(Nr, Nt, K, Nti) mu_channel.noise_var = noise_var bd_obj = blockdiagonalization.BDWithExtIntBase(K, iPu, noise_var, pe) W_all_k = bd_obj.calc_whitening_matrices(mu_channel) R_all_k = mu_channel.calc_cov_matrix_extint_plus_noise(pe) for W, R in zip(W_all_k, R_all_k): np.testing.assert_array_almost_equal( W, calc_whitening_matrix(R).conjugate().T)
def __init__(self, read_command_line_args=True, save_parsed_file=False): default_config_file = 'bd_config_file.txt' # xxxxxxxxxx Simulation Parameters Specification xxxxxxxxxxxxxxxxxx spec = """[Grid] cell_radius=float(min=0.01, default=1.0) num_cells=integer(min=3,default=3) num_clusters=integer(min=1,default=1) [Scenario] NSymbs=integer(min=10, max=1000000, default=500) SNR=real_numpy_array(min=-50, max=100, default=0:3:31) Pe_dBm=real_numpy_array(min=-50, max=100, default=[-10. 0. 10.]) Nr=integer(default=2) Nt=integer(default=2) N0=float(default=-116.4) ext_int_rank=integer(min=1,default=1) user_positioning_method=option("Random", 'Symmetric Far Away', default="Symmetric Far Away") [Modulation] M=integer(min=4, max=512, default=4) modulator=option('QPSK', 'PSK', 'QAM', 'BPSK', default="PSK") packet_length=integer(min=1,default=60) [General] rep_max=integer(min=1, default=5000) unpacked_parameters=string_list(default=list('SNR','Pe_dBm')) """.split("\n") # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Initialize parameters configuration xxxxxxxxxxxxxxxxxx # Among other things, this will create the self.params object with # the simulation parameters read from the config file. SimulationRunner.__init__( self, default_config_file=default_config_file, config_spec=spec, read_command_line_args=read_command_line_args, save_parsed_file=save_parsed_file) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Channel Parameters xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx self.path_loss_obj = pathloss.PathLoss3GPP1() self.multiuser_channel = multiuser.MultiUserChannelMatrixExtInt() # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx RandomState objects seeds xxxxxxxxxxxxxxxxxxxxxxxxxxxx # This is only useful to reproduce a simulation for debugging # purposed channel_seed = None # 22522 self.noise_seed = None # 4445 self.data_gen_seed = np.random.randint(10000) # 2105 ext_data_gen_seed = None # 6114 # self.multiuser_channel.set_channel_seed(channel_seed) self.multiuser_channel.set_noise_seed(self.noise_seed) self.data_RS = np.random.RandomState(self.data_gen_seed) self.ext_data_RS = np.random.RandomState(ext_data_gen_seed) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Creates the modulator object xxxxxxxxxxxxxxxxxxxxxxxxx M = self.params['M'] modulator_options = { 'PSK': fundamental.PSK, 'QPSK': fundamental.QPSK, 'QAM': fundamental.QAM, 'BPSK': fundamental.BPSK } self.modulator = modulator_options[self.params['modulator']](M) ":type: fundamental.PSK | fundamental.QPSK | fundamental.QAM | fundamental.BPSK" # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx General Parameters xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Maximum number of repetitions for each unpacked parameters set # self.params self.results self.rep_max = self.params['rep_max'] # # max_bit_errors is used in the _keep_going method to stop the # # simulation earlier if possible. We stop the simulation if the # # accumulated number of bit errors becomes greater then 5% of the # # total number of simulated bits # self.max_bit_errors = self.rep_max * NSymbs * 5. / 100. self.progressbar_message = "SNR: {SNR}, Pe_dBm: {Pe_dBm}" # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Dependent parameters (don't change these) xxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # These two will be set in the _on_simulate_current_params_start # method self.pe = 0 # Path loss (in linear scale) from the cell center to # self.path_loss_border = self.path_loss_obj.calc_path_loss( # self.cell_radius) # Cell Grid self.cell_grid = cell.Grid() self.cell_grid.create_clusters(self.params['num_clusters'], self.params['num_cells'], self.params['cell_radius']) self.noise_var = dBm2Linear(self.params['N0']) self.multiuser_channel.noise_var = self.noise_var # This can be either 'screen' or 'file'. If it is 'file' then the # progressbar will write the progress to a file with appropriated # filename self.progress_output_type = 'screen'
def test_block_diagonalize_no_waterfilling(self): Nr = np.array([2, 2]) Nt = np.array([2, 2]) K = Nt.size Nti = 1 iPu = 1e-1 # Power for each user (linear scale) pe = 1e-3 # External interference power (in linear scale) noise_var = 1e-1 # The modulator and packet_length are required in the # effective_throughput metric case psk_obj = fundamental.PSK(4) packet_length = 120 multiUserChannel = multiuser.MultiUserChannelMatrixExtInt() multiUserChannel.randomize(Nr, Nt, K, Nti) multiUserChannel.noise_var = noise_var # Channel from all transmitters to the first receiver H1 = multiUserChannel.get_Hk_without_ext_int(0) # Channel from all transmitters to the second receiver H2 = multiUserChannel.get_Hk_without_ext_int(1) # Create the enhancedBD object enhancedBD_obj = blockdiagonalization.EnhancedBD(K, iPu, noise_var, pe) noise_plus_int_cov_matrix \ = multiUserChannel.calc_cov_matrix_extint_plus_noise(pe) # xxxxx First we test without ext. int. handling xxxxxxxxxxxxxxxxxx enhancedBD_obj.set_ext_int_handling_metric(None) (Ms_all, Wk_all, Ns_all) \ = enhancedBD_obj.block_diagonalize_no_waterfilling( multiUserChannel) Ms1 = Ms_all[0] Ms2 = Ms_all[1] self.assertEqual(Ms1.shape[1], Ns_all[0]) self.assertEqual(Ms2.shape[1], Ns_all[1]) # 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. tol = 1e-10 self.assertGreaterEqual(iPu + tol, np.linalg.norm(Ms1, 'fro')**2) # 1e-12 is included to avoid false test fails due to small # precision errors self.assertGreaterEqual(iPu + tol, np.linalg.norm(Ms2, 'fro')**2) # Test if the precoder block diagonalizes the channel self.assertNotAlmostEqual(np.linalg.norm(np.dot(H1, Ms1), 'fro'), 0) self.assertAlmostEqual(np.linalg.norm(np.dot(H1, Ms2), 'fro'), 0) self.assertNotAlmostEqual(np.linalg.norm(np.dot(H2, Ms2), 'fro'), 0) self.assertAlmostEqual(np.linalg.norm(np.dot(H2, Ms1), 'fro'), 0) # Equivalent sinrs (in linear scale) sinrs = np.empty(K, dtype=np.ndarray) sinrs[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs( np.dot(H1, Ms1), Wk_all[0], noise_plus_int_cov_matrix[0]) sinrs[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs( np.dot(H2, Ms2), Wk_all[1], noise_plus_int_cov_matrix[1]) # Spectral efficiency # noinspection PyPep8 se = (np.sum( psk_obj.calcTheoreticalSpectralEfficiency(linear2dB( sinrs[0]), packet_length)) + np.sum( psk_obj.calcTheoreticalSpectralEfficiency( linear2dB(sinrs[1]), packet_length))) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Now with the Naive Stream Reduction xxxxxxxxxxxxxxxxxxxxxxx num_streams = 1 enhancedBD_obj.set_ext_int_handling_metric( 'naive', {'num_streams': num_streams}) (MsPk_naive_all, Wk_naive_all, Ns_naive_all) \ = enhancedBD_obj.block_diagonalize_no_waterfilling( multiUserChannel) MsPk_naive_1 = MsPk_naive_all[0] MsPk_naive_2 = MsPk_naive_all[1] self.assertEqual(MsPk_naive_1.shape[1], Ns_naive_all[0]) self.assertEqual(MsPk_naive_2.shape[1], Ns_naive_all[1]) self.assertEqual(Ns_naive_all[0], num_streams) self.assertEqual(Ns_naive_all[1], num_streams) # Test if the square of the Frobenius norm of the precoder of each # user is equal to the power available to that user. self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_naive_1, 'fro')**2) self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_naive_2, 'fro')**2) # Test if MsPk really block diagonalizes the channel self.assertNotAlmostEqual( np.linalg.norm(np.dot(H1, MsPk_naive_1), 'fro'), 0) self.assertAlmostEqual(np.linalg.norm(np.dot(H1, MsPk_naive_2), 'fro'), 0) self.assertNotAlmostEqual( np.linalg.norm(np.dot(H2, MsPk_naive_2), 'fro'), 0) self.assertAlmostEqual(np.linalg.norm(np.dot(H2, MsPk_naive_1), 'fro'), 0) sinrs4 = np.empty(K, dtype=np.ndarray) sinrs4[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs( np.dot(H1, MsPk_naive_1), Wk_naive_all[0], noise_plus_int_cov_matrix[0]) sinrs4[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs( np.dot(H2, MsPk_naive_2), Wk_naive_all[1], noise_plus_int_cov_matrix[1]) # Spectral efficiency # se4 = ( # np.sum(psk_obj.calcTheoreticalSpectralEfficiency( # linear2dB(sinrs4[0]), # packet_length)) # + # np.sum(psk_obj.calcTheoreticalSpectralEfficiency( # linear2dB(sinrs4[1]), # packet_length))) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Now with the Fixed Stream Reduction xxxxxxxxxxxxxxxxxxxxxxx # The 'fixed' metric requires that metric_func_extra_args_dict is # provided and has the 'num_streams' key. If this is not the case # an exception is raised with self.assertRaises(AttributeError): enhancedBD_obj.set_ext_int_handling_metric('fixed') # Now let's test the fixed metric num_streams = 1 enhancedBD_obj.set_ext_int_handling_metric( 'fixed', {'num_streams': num_streams}) (MsPk_fixed_all, Wk_fixed_all, Ns_fixed_all) \ = enhancedBD_obj.block_diagonalize_no_waterfilling( multiUserChannel) MsPk_fixed_1 = MsPk_fixed_all[0] MsPk_fixed_2 = MsPk_fixed_all[1] self.assertEqual(MsPk_fixed_1.shape[1], Ns_fixed_all[0]) self.assertEqual(MsPk_fixed_2.shape[1], Ns_fixed_all[1]) self.assertEqual(Ns_fixed_all[0], num_streams) self.assertEqual(Ns_fixed_all[1], num_streams) # Test if the square of the Frobenius norm of the precoder of each # user is equal to the power available to that user. self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_fixed_1, 'fro')**2) self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_fixed_2, 'fro')**2) # Test if MsPk really block diagonalizes the channel self.assertNotAlmostEqual( np.linalg.norm(np.dot(H1, MsPk_fixed_1), 'fro'), 0) self.assertAlmostEqual(np.linalg.norm(np.dot(H1, MsPk_fixed_2), 'fro'), 0) self.assertNotAlmostEqual( np.linalg.norm(np.dot(H2, MsPk_fixed_2), 'fro'), 0) self.assertAlmostEqual(np.linalg.norm(np.dot(H2, MsPk_fixed_1), 'fro'), 0) sinrs5 = np.empty(K, dtype=np.ndarray) sinrs5[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs( np.dot(H1, MsPk_fixed_1), Wk_fixed_all[0], noise_plus_int_cov_matrix[0]) sinrs5[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs( np.dot(H2, MsPk_fixed_2), Wk_fixed_all[1], noise_plus_int_cov_matrix[1]) # Spectral efficiency # se5 = ( # np.sum(psk_obj.calcTheoreticalSpectralEfficiency( # linear2dB(sinrs5[0]), # packet_length)) # + # np.sum(psk_obj.calcTheoreticalSpectralEfficiency( # linear2dB(sinrs5[1]), # packet_length))) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Handling external interference xxxxxxxxxxxxxxxxxxxxxxxxxxxx # Handling external interference using the capacity metric enhancedBD_obj.set_ext_int_handling_metric('capacity') (MsPk_all, Wk_cap_all, Ns_cap_all) \ = enhancedBD_obj.block_diagonalize_no_waterfilling( multiUserChannel) MsPk_cap_1 = MsPk_all[0] MsPk_cap_2 = MsPk_all[1] self.assertEqual(MsPk_cap_1.shape[1], Ns_cap_all[0]) self.assertEqual(MsPk_cap_2.shape[1], Ns_cap_all[1]) # Test if the square of the Frobenius norm of the precoder of each # user is equal to the power available to that user. self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_cap_1, 'fro')**2) self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_cap_2, 'fro')**2) # Test if MsPk really block diagonalizes the channel self.assertNotAlmostEqual( np.linalg.norm(np.dot(H1, MsPk_cap_1), 'fro'), 0) self.assertAlmostEqual(np.linalg.norm(np.dot(H1, MsPk_cap_2), 'fro'), 0) self.assertNotAlmostEqual( np.linalg.norm(np.dot(H2, MsPk_cap_2), 'fro'), 0) self.assertAlmostEqual(np.linalg.norm(np.dot(H2, MsPk_cap_1), 'fro'), 0) sinrs2 = np.empty(K, dtype=np.ndarray) sinrs2[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs( np.dot(H1, MsPk_cap_1), Wk_cap_all[0], noise_plus_int_cov_matrix[0]) sinrs2[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs( np.dot(H2, MsPk_cap_2), Wk_cap_all[1], noise_plus_int_cov_matrix[1]) # Spectral efficiency # noinspection PyPep8 se2 = (np.sum( psk_obj.calcTheoreticalSpectralEfficiency(linear2dB( sinrs2[0]), packet_length)) + np.sum( psk_obj.calcTheoreticalSpectralEfficiency( linear2dB(sinrs2[1]), packet_length))) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Handling external interference xxxxxxxxxxxxxxxxxxxxxxxxxxxx # Handling external interference using the effective_throughput metric enhancedBD_obj.set_ext_int_handling_metric( 'effective_throughput', { 'modulator': psk_obj, 'packet_length': packet_length }) (MsPk_effec_all, Wk_effec_all, Ns_effec_all) \ = enhancedBD_obj.block_diagonalize_no_waterfilling( multiUserChannel) MsPk_effec_1 = MsPk_effec_all[0] MsPk_effec_2 = MsPk_effec_all[1] self.assertEqual(MsPk_effec_1.shape[1], Ns_effec_all[0]) self.assertEqual(MsPk_effec_2.shape[1], Ns_effec_all[1]) # Test if the square of the Frobenius norm of the precoder of each # user is equal to the power available to that user. self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_effec_1, 'fro')**2) self.assertAlmostEqual(iPu, np.linalg.norm(MsPk_effec_2, 'fro')**2) # Test if MsPk really block diagonalizes the channel self.assertNotAlmostEqual( np.linalg.norm(np.dot(H1, MsPk_effec_1), 'fro'), 0) self.assertAlmostEqual(np.linalg.norm(np.dot(H1, MsPk_effec_2), 'fro'), 0) self.assertNotAlmostEqual( np.linalg.norm(np.dot(H2, MsPk_effec_2), 'fro'), 0) self.assertAlmostEqual(np.linalg.norm(np.dot(H2, MsPk_effec_1), 'fro'), 0) sinrs3 = np.empty(K, dtype=np.ndarray) sinrs3[0] = blockdiagonalization.EnhancedBD._calc_linear_SINRs( np.dot(H1, MsPk_effec_1), Wk_effec_all[0], noise_plus_int_cov_matrix[0]) sinrs3[1] = blockdiagonalization.EnhancedBD._calc_linear_SINRs( np.dot(H2, MsPk_effec_2), Wk_effec_all[1], noise_plus_int_cov_matrix[1]) # Spectral efficiency # noinspection PyPep8 se3 = (np.sum( psk_obj.calcTheoreticalSpectralEfficiency(linear2dB( sinrs3[0]), packet_length)) + np.sum( psk_obj.calcTheoreticalSpectralEfficiency( linear2dB(sinrs3[1]), packet_length))) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Test if the effective_throughput obtains a better spectral # efficiency then the capacity and not handling interference. self.assertGreater(se3 + tol, se2) self.assertGreater(se3 + tol, se)