class BDSimulationRunner(SimulationRunner): # pylint: disable=R0902 """ Simulation runner for a Block Diagonalization transmission. """ 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 _create_users_according_to_scenario(self, current_params): """ Create the users according to the current_params['user_positioning_method'] parameter. This method will call one of the "_create*_scenario" methods. """ scenario = current_params['user_positioning_method'] if scenario == 'Symmetric Far Away': self._create_symmetric_far_away_users_scenario(current_params) elif scenario == 'Random': self._create_random_users_scenario(current_params) else: raise RuntimeError("Invalid scenario: {0}".format(scenario)) def _create_random_users_scenario(self, current_params): """Run this method to set variables specific to the 'RandomUsers' scenario. The 'RandomUsers' scenario places a user at a random location in each cell. """ cluster0 = self.cell_grid.get_cluster_from_index(0) cell_ids = np.arange(1, current_params['num_cells'] + 1) cluster0.delete_all_users() cluster0.add_random_users(cell_ids) def _create_symmetric_far_away_users_scenario(self, current_params): """Run this method to set variables specific to the 'FarAwayUsers' scenario. The 'FarAwayUsers70%' scenario place a user in each cell at a the angle further away from the cell center in a distance from the cell center to the cell border equivalent to 70% of the cell radius. """ cluster0 = self.cell_grid.get_cluster_from_index(0) cell_ids = np.arange(1, current_params['num_cells'] + 1) angles = np.array([210, -30, 90]) cluster0.delete_all_users() cluster0.add_border_users(cell_ids, angles, 0.7) def _create_users_channels(self, current_params): """Create the channels of all the users. The users must have already been created. """ cluster0 = self.cell_grid.get_cluster_from_index(0) # xxxxx Distances between each transmitter and each receiver xxxxxx # This `dists` matrix may be indexed as dists[user, cell]. dists = cluster0.calc_dist_all_users_to_each_cell() # Path loss from each base station to each user pathloss = self.path_loss_obj.calc_path_loss(dists) # xxx Distances between each receiver and the ext. int. source xxxx # Calculates the distance of each user to the cluster center # # Note: Because we are using the cluster0.get_all_users() method # THIS CODE ONLY WORKS when there is a single user at each cell. distance_users_to_cluster_center = np.array( [cluster0.calc_dist(i) for i in cluster0.get_all_users()]) pathlossInt = self.path_loss_obj.calc_path_loss( cluster0.external_radius - distance_users_to_cluster_center) # The number of rows is equal to the number of receivers, while the # cumber of columns is equal to the number of external interference # sources. pathlossInt.shape = (current_params['num_cells'], 1) # Generate a random channel and set the path loss self.multiuser_channel.randomize(current_params['Nr'], current_params['Nt'], current_params['num_cells'], current_params['ext_int_rank']) self.multiuser_channel.set_pathloss(pathloss, pathlossInt) def _on_simulate_current_params_start(self, current_params): """This method is called once for each combination of transmit parameters. """ # pylint: disable=W0201 # IMPORTANT: Re-seed the channel and the noise RandomState # objects. Without this, when you perform the simulation in # parallel (call the simulate_in_parallel method(from the # SimulationRunner class) you will get the same channel samples and # noise for all parallel process. self.multiuser_channel.re_seed() # xxxxx Calculates the transmit power at each base station. xxxxxxx # Because this value does not change in the different iterations of # _run_simulation, but only when the parameters change the # calculation is performed here in the # _on_simulate_current_params_start. transmit_power = BDSimulationRunner._calc_transmit_power( current_params['SNR'], current_params['N0'], current_params['cell_radius'], self.path_loss_obj) # External interference power self.pe = dBm2Linear(current_params['Pe_dBm']) # xxxxx Create the BD object with the None metric xxxxxxxxxxxxxxxxx self.bd_obj_None = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_None.set_ext_int_handling_metric( "None", { 'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1 }) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with the Naive metric xxxxxxxxxxxxxxxx self.bd_obj_naive = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_naive.set_ext_int_handling_metric( "naive", { 'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1 }) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with the fixed metric xxxxxxxxxxxxxxxx self.bd_obj_fixed = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_fixed.set_ext_int_handling_metric( "fixed", { 'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1 }) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with the capacity metric xxxxxxxxxxxxx self.bd_obj_capacity = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_capacity.set_ext_int_handling_metric( "capacity", { 'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1 }) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xx Create the BD object with the effective_throughput metric xxxx self.bd_obj_effec_throughput = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_effec_throughput.set_ext_int_handling_metric( "effective_throughput", { 'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1 }) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with whitening xxxxxxxxxxxxxxxxxxxxxxx self.bd_obj_whitening = WhiteningBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx def _run_simulation(self, current_parameters): # pylint: disable=R0914 """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. Parameters ---------- current_parameters : SimulationParameters object SimulationParameters object with the parameters for the simulation. The self.params variable is not used directly. It is first unpacked (in the SimulationRunner.simulate method which then calls _run_simulation) for each combination. """ # xxxxxxxxxx Prepare the scenario for this iteration. xxxxxxxxxxxxx # This will place the users at the locations specified by the # scenario (random locations or not), calculate the path loss and # generate a new random channel (in the self.multiuser_channel # variable). self._create_users_according_to_scenario(current_parameters) # This will calculate pathloss and generate random channels from # all transmitters to all receivers as well as from the external # interference sources to all receivers. This method must be called # after the _create_users_according_to_scenario method so that the # users are already created (we need their positions for the # pathloss) self._create_users_channels(current_parameters) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Perform the block diagonalization for each metric xxxxxxxxx # None Metric (MsPk_all_users_None, Wk_all_users_None, Ns_all_users_None) \ = self.bd_obj_None.block_diagonalize_no_waterfilling( self.multiuser_channel) # Naive Metric (MsPk_all_users_naive, Wk_all_users_naive, Ns_all_users_naive) \ = self.bd_obj_naive.block_diagonalize_no_waterfilling( self.multiuser_channel) # Fixed Metric (MsPk_all_users_fixed, Wk_all_users_fixed, Ns_all_users_fixed) \ = self.bd_obj_fixed.block_diagonalize_no_waterfilling( self.multiuser_channel) # Capacity Metric (MsPk_all_users_capacity, Wk_all_users_capacity, Ns_all_users_capacity) \ = self.bd_obj_capacity.block_diagonalize_no_waterfilling( self.multiuser_channel) # effective_throughput Metric (MsPk_all_users_effec_throughput, Wk_all_users_effec_throughput, Ns_all_users_effec_throughput) \ = self.bd_obj_effec_throughput.block_diagonalize_no_waterfilling( self.multiuser_channel) (Ms_all_users_Whitening, Wk_all_users_Whitening, Ns_all_users_Whitening) \ = self.bd_obj_whitening.block_diagonalize_no_waterfilling( self.multiuser_channel) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Since we will use the same data for the external interference no # matter which metric is used, lets create that data here. external_int_data_all_metrics = (np.sqrt(self.pe) * misc.randn_c_RS( self.ext_data_RS, current_parameters['ext_int_rank'], current_parameters['NSymbs'])) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxx Run the Simulation and get the results for each metric xxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # None metric (ber_result_None, ser_result_None, per_result_None, spec_effic_result_None, sinr_result_None) = self.__simulate_for_one_metric( Ns_all_users_None, external_int_data_all_metrics, MsPk_all_users_None, Wk_all_users_None, 'None', current_parameters) # naive metric (ber_result_naive, ser_result_naive, per_result_naive, spec_effic_result_naive, sinr_result_naive) = self.__simulate_for_one_metric( Ns_all_users_naive, external_int_data_all_metrics, MsPk_all_users_naive, Wk_all_users_naive, 'naive', current_parameters) # fixed metric (ber_result_fixed, ser_result_fixed, per_result_fixed, spec_effic_result_fixed, sinr_result_fixed) = self.__simulate_for_one_metric( Ns_all_users_fixed, external_int_data_all_metrics, MsPk_all_users_fixed, Wk_all_users_fixed, 'fixed', current_parameters) # capacity metric (ber_result_capacity, ser_result_capacity, per_result_capacity, spec_effic_result_capacity, sinr_result_capacity) = self.__simulate_for_one_metric( Ns_all_users_capacity, external_int_data_all_metrics, MsPk_all_users_capacity, Wk_all_users_capacity, 'capacity', current_parameters) # effective throughput metric (ber_result_effec_throughput, ser_result_effec_throughput, per_result_effec_throughput, spec_effic_result_effec_throughput, sinr_result_effec_throughput) = self.__simulate_for_one_metric( Ns_all_users_effec_throughput, external_int_data_all_metrics, MsPk_all_users_effec_throughput, Wk_all_users_effec_throughput, 'effec_throughput', current_parameters) # Whitening BD (ber_result_Whitening, ser_result_Whitening, per_result_Whitening, spec_effic_result_Whitening, sinr_result_Whitening) = self.__simulate_for_one_metric( Ns_all_users_Whitening, external_int_data_all_metrics, Ms_all_users_Whitening, Wk_all_users_Whitening, 'Whitening', current_parameters) simResults = SimulationResults() # Add the 'None' results simResults.add_result(ber_result_None) simResults.add_result(ser_result_None) simResults.add_result(per_result_None) simResults.add_result(spec_effic_result_None) simResults.add_result(sinr_result_None) # Add the naive results simResults.add_result(ber_result_naive) simResults.add_result(ser_result_naive) simResults.add_result(per_result_naive) simResults.add_result(spec_effic_result_naive) simResults.add_result(sinr_result_naive) # Add the fixed results simResults.add_result(ber_result_fixed) simResults.add_result(ser_result_fixed) simResults.add_result(per_result_fixed) simResults.add_result(spec_effic_result_fixed) simResults.add_result(sinr_result_fixed) # Add the capacity results simResults.add_result(ber_result_capacity) simResults.add_result(ser_result_capacity) simResults.add_result(per_result_capacity) simResults.add_result(spec_effic_result_capacity) simResults.add_result(sinr_result_capacity) # Add the effective throughput results simResults.add_result(ber_result_effec_throughput) simResults.add_result(ser_result_effec_throughput) simResults.add_result(per_result_effec_throughput) simResults.add_result(spec_effic_result_effec_throughput) simResults.add_result(sinr_result_effec_throughput) # Add the 'Whitening' results simResults.add_result(ber_result_Whitening) simResults.add_result(ser_result_Whitening) simResults.add_result(per_result_Whitening) simResults.add_result(spec_effic_result_Whitening) simResults.add_result(sinr_result_Whitening) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx return simResults def __simulate_for_one_metric(self, Ns_all_users, external_int_data_all_metrics, MsPk_all_users, Wk_all_users, metric_name, current_parameters): """ This method is only called inside the _run_simulation method. This method has the common code that is execute for each metric inside the _run_simulation method. Parameters ---------- Ns_all_users : np.ndarray Number of streams for each user. This variable controls how many data streams will be generated for each user of the K users. This is a 1D numpy array of size K. external_int_data_all_metrics : np.ndarray The data of the external interference sources (2D numpy array). MsPk_all_users : np.ndarray The precoders of all users returned by the block diagonalize method for the given metric. This is a 1D numpy array of 2D numpy arrays. Wk_all_users : np.ndarray The receive filter for all users (1D numpy array of 2D numpy arrays). metric_name : string Metric name. This string will be appended to each result name. Returns ------- TODO: Write the rest of the docstring """ # pylint: disable=R0914 Ns_total = np.sum(Ns_all_users) self.data_RS = np.random.RandomState(self.data_gen_seed) input_data = self.data_RS.randint( 0, current_parameters['M'], [Ns_total, current_parameters['NSymbs']]) symbols = self.modulator.modulate(input_data) # Prepare the transmit data. That is, the precoded_data as well as # the external interference sources' data. precoded_data = np.dot(np.hstack(MsPk_all_users), symbols) # external_int_data_all_metrics = ( # np.sqrt(self.pe) # * misc.randn_c_RS( # self.ext_data_RS, self.ext_int_rank, self.NSymbs)) all_data = np.vstack([precoded_data, external_int_data_all_metrics]) # xxxxxxxxxx Pass the precoded data through the channel xxxxxxxxxxx self.multiuser_channel.set_noise_seed(self.noise_seed) received_signal = self.multiuser_channel.corrupt_concatenated_data( all_data) # xxxxxxxxxx Filter the received data xxxxxxxxxxxxxxxxxxxxxxxxxxxxx # noinspection PyArgumentList Wk = block_diag(*Wk_all_users) received_symbols = np.dot(Wk, received_signal) # xxxxxxxxxx Demodulate the filtered symbols xxxxxxxxxxxxxxxxxxxxxx decoded_symbols = self.modulator.demodulate(received_symbols) # xxxxxxxxxx Calculates the Symbol Error Rate xxxxxxxxxxxxxxxxxxxxx num_symbol_errors = np.sum(decoded_symbols != input_data, 1) # num_symbol_errors = sum_user_data(num_symbol_errors, # Ns_all_users) num_symbols = np.ones(Ns_total) * input_data.shape[1] # xxxxxxxxxx Calculates the Bit Error Rate xxxxxxxxxxxxxxxxxxxxxxxx num_bit_errors = misc.count_bit_errors(decoded_symbols, input_data, 1) # num_bit_errors = sum_user_data(num_bit_errors, # Ns_all_users) num_bits = num_symbols * np.log2(current_parameters['M']) # xxxxxxxxxx Calculates the Package Error Rate xxxxxxxxxxxxxxxxxxxx ber = num_bit_errors / num_bits per = 1. - ((1. - ber)**current_parameters['packet_length']) num_packages = num_bits / current_parameters['packet_length'] num_package_errors = per * num_packages # xxxxxxxxxx Calculates the Spectral Efficiency xxxxxxxxxxxxxxxxxxx # nominal spectral Efficiency per stream nominal_spec_effic = self.modulator.K effective_spec_effic = (1 - per) * nominal_spec_effic # xxxxx Map the per stream metric to a global metric xxxxxxxxxxxxxx num_bit_errors = np.sum(num_bit_errors) num_bits = np.sum(num_bits) num_symbol_errors = np.sum(num_symbol_errors) num_symbols = np.sum(num_symbols) num_package_errors = np.sum(num_package_errors) num_packages = np.sum(num_packages) effective_spec_effic = np.sum(effective_spec_effic) # xxxxx Calculate teh SINR xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Uk_all_users = np.empty(Wk_all_users.size, dtype=np.ndarray) for ii in range(Wk_all_users.size): Uk_all_users[ii] = Wk_all_users[ii].conjugate().T SINR_all_k = self.multiuser_channel.calc_JP_SINR( MsPk_all_users, Uk_all_users) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # None metric ber_result = Result.create('ber_{0}'.format(metric_name), Result.RATIOTYPE, num_bit_errors, num_bits) ser_result = Result.create('ser_{0}'.format(metric_name), Result.RATIOTYPE, num_symbol_errors, num_symbols) per_result = Result.create('per_{0}'.format(metric_name), Result.RATIOTYPE, num_package_errors, num_packages) spec_effic_result = Result.create('spec_effic_{0}'.format(metric_name), Result.RATIOTYPE, effective_spec_effic, 1) sinr_result = Result('sinr_{0}'.format(metric_name), Result.RATIOTYPE, accumulate_values=True) for k in range(Wk_all_users.size): sinr_k = SINR_all_k[k] for value in sinr_k: sinr_result.update(value, 1) return (ber_result, ser_result, per_result, spec_effic_result, sinr_result) # def _keep_going(self, current_sim_results, current_rep): # ber_result = current_sim_results['ber'][-1] # num_bit_errors = ber_result._value # return num_bit_errors < self.max_bit_errors @staticmethod def _calc_transmit_power(SNR_dB, N0_dBm, cell_radius, path_loss_obj): """ Calculates the required transmit power (in linear scale) to achieve the desired mean SNR value at the cell border. This method calculates the path loss at the cell border and then finds the transmit power that gives the desired mean SNR at the cell border. Parameters ---------- SNR_dB : float SNR value (in dB) N0_dBm : float Noise power (in dBm) cell_radius : float Cell radius (in Km) path_loss_obj : Path Loss object Object of a pathloss class used to calculate the path loss (see `comm.pathloss`. Returns ------- transmit_power : float Desired transmit power (in linear scale). """ # Path loss (in linear scale) from the cell center to path_loss_border = path_loss_obj.calc_path_loss(cell_radius) snr = dB2Linear(SNR_dB) pt = snr * dBm2Linear(N0_dBm) / path_loss_border return pt
class BDSimulationRunner(SimulationRunner): # pylint: disable=R0902 """ Simulation runner for a Block Diagonalization transmission. """ 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) # 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 _create_users_according_to_scenario(self, current_params): """ Create the users according to the current_params['user_positioning_method'] parameter. This method will call one of the "_create*_scenario" methods. """ scenario = current_params['user_positioning_method'] if scenario == 'Symmetric Far Away': self._create_symmetric_far_away_users_scenario(current_params) elif scenario == 'Random': self._create_random_users_scenario(current_params) else: raise RuntimeError( "Invalid scenario: {0}".format(scenario)) def _create_random_users_scenario(self, current_params): """Run this method to set variables specific to the 'RandomUsers' scenario. The 'RandomUsers' scenario places a user at a random location in each cell. """ cluster0 = self.cell_grid.get_cluster_from_index(0) cell_ids = np.arange(1, current_params['num_cells'] + 1) cluster0.remove_all_users() cluster0.add_random_users(cell_ids) def _create_symmetric_far_away_users_scenario(self, current_params): """Run this method to set variables specific to the 'FarAwayUsers' scenario. The 'FarAwayUsers70%' scenario place a user in each cell at a the angle further away from the cell center in a distance from the cell center to the cell border equivalent to 70% of the cell radius. """ cluster0 = self.cell_grid.get_cluster_from_index(0) cell_ids = np.arange(1, current_params['num_cells'] + 1) angles = np.array([210, -30, 90]) cluster0.delete_all_users() cluster0.add_border_users(cell_ids, angles, 0.7) def _create_users_channels(self, current_params): """Create the channels of all the users. The users must have already been created. """ cluster0 = self.cell_grid.get_cluster_from_index(0) # xxxxx Distances between each transmitter and each receiver xxxxxx # This `dists` matrix may be indexed as dists[user, cell]. dists = cluster0.calc_dist_all_users_to_each_cell() # Path loss from each base station to each user pathloss = self.path_loss_obj.calc_path_loss(dists) # xxx Distances between each receiver and the ext. int. source xxxx # Calculates the distance of each user to the cluster center # # Note: Because we are using the cluster0.get_all_users() method # THIS CODE ONLY WORKS when there is a single user at each cell. distance_users_to_cluster_center = np.array( [cluster0.calc_dist(i) for i in cluster0.get_all_users()]) pathlossInt = self.path_loss_obj.calc_path_loss( cluster0.external_radius - distance_users_to_cluster_center) # The number of rows is equal to the number of receivers, while the # cumber of columns is equal to the number of external interference # sources. pathlossInt.shape = (current_params['num_cells'], 1) # Generate a random channel and set the path loss self.multiuser_channel.randomize(current_params['Nr'], current_params['Nt'], current_params['num_cells'], current_params['ext_int_rank']) self.multiuser_channel.set_pathloss(pathloss, pathlossInt) def _on_simulate_current_params_start(self, current_params): """This method is called once for each combination of transmit parameters. """ # pylint: disable=W0201 # IMPORTANT: Re-seed the channel and the noise RandomState # objects. Without this, when you perform the simulation in # parallel (call the simulate_in_parallel method(from the # SimulationRunner class) you will get the same channel samples and # noise for all parallel process. self.multiuser_channel.re_seed() # xxxxx Calculates the transmit power at each base station. xxxxxxx # Because this value does not change in the different iterations of # _run_simulation, but only when the parameters change the # calculation is performed here in the # _on_simulate_current_params_start. transmit_power = BDSimulationRunner._calc_transmit_power( current_params['SNR'], current_params['N0'], current_params['cell_radius'], self.path_loss_obj) # External interference power self.pe = dBm2Linear(current_params['Pe_dBm']) # xxxxx Create the BD object with the None metric xxxxxxxxxxxxxxxxx self.bd_obj_None = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_None.set_ext_int_handling_metric( "None", {'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1}) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with the Naive metric xxxxxxxxxxxxxxxx self.bd_obj_naive = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_naive.set_ext_int_handling_metric( "naive", {'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1}) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with the fixed metric xxxxxxxxxxxxxxxx self.bd_obj_fixed = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_fixed.set_ext_int_handling_metric( "fixed", {'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1}) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with the capacity metric xxxxxxxxxxxxx self.bd_obj_capacity = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_capacity.set_ext_int_handling_metric( "capacity", {'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1}) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xx Create the BD object with the effective_throughput metric xxxx self.bd_obj_effec_throughput = EnhancedBD( current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_effec_throughput.set_ext_int_handling_metric( "effective_throughput", {'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1}) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with whitening xxxxxxxxxxxxxxxxxxxxxxx self.bd_obj_whitening = WhiteningBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx def _run_simulation(self, current_parameters): # pylint: disable=R0914 """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. Parameters ---------- current_parameters : SimulationParameters object SimulationParameters object with the parameters for the simulation. The self.params variable is not used directly. It is first unpacked (in the SimulationRunner.simulate method which then calls _run_simulation) for each combination. """ # xxxxxxxxxx Prepare the scenario for this iteration. xxxxxxxxxxxxx # This will place the users at the locations specified by the # scenario (random locations or not), calculate the path loss and # generate a new random channel (in the self.multiuser_channel # variable). self._create_users_according_to_scenario(current_parameters) # This will calculate pathloss and generate random channels from # all transmitters to all receivers as well as from the external # interference sources to all receivers. This method must be called # after the _create_users_according_to_scenario method so that the # users are already created (we need their positions for the # pathloss) self._create_users_channels(current_parameters) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Perform the block diagonalization for each metric xxxxxxxxx # None Metric (MsPk_all_users_None, Wk_all_users_None, Ns_all_users_None) \ = self.bd_obj_None.block_diagonalize_no_waterfilling( self.multiuser_channel) # Naive Metric (MsPk_all_users_naive, Wk_all_users_naive, Ns_all_users_naive) \ = self.bd_obj_naive.block_diagonalize_no_waterfilling( self.multiuser_channel) # Fixed Metric (MsPk_all_users_fixed, Wk_all_users_fixed, Ns_all_users_fixed) \ = self.bd_obj_fixed.block_diagonalize_no_waterfilling( self.multiuser_channel) # Capacity Metric (MsPk_all_users_capacity, Wk_all_users_capacity, Ns_all_users_capacity) \ = self.bd_obj_capacity.block_diagonalize_no_waterfilling( self.multiuser_channel) # effective_throughput Metric (MsPk_all_users_effec_throughput, Wk_all_users_effec_throughput, Ns_all_users_effec_throughput) \ = self.bd_obj_effec_throughput.block_diagonalize_no_waterfilling( self.multiuser_channel) (Ms_all_users_Whitening, Wk_all_users_Whitening, Ns_all_users_Whitening) \ = self.bd_obj_whitening.block_diagonalize_no_waterfilling( self.multiuser_channel) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Since we will use the same data for the external interference no # matter which metric is used, lets create that data here. external_int_data_all_metrics = ( np.sqrt(self.pe) * misc.randn_c_RS( self.ext_data_RS, current_parameters['ext_int_rank'], current_parameters['NSymbs'])) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxx Run the Simulation and get the results for each metric xxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # None metric (ber_result_None, ser_result_None, per_result_None, spec_effic_result_None, sinr_result_None) = self.__simulate_for_one_metric( Ns_all_users_None, external_int_data_all_metrics, MsPk_all_users_None, Wk_all_users_None, 'None', current_parameters) # naive metric (ber_result_naive, ser_result_naive, per_result_naive, spec_effic_result_naive, sinr_result_naive) = self.__simulate_for_one_metric( Ns_all_users_naive, external_int_data_all_metrics, MsPk_all_users_naive, Wk_all_users_naive, 'naive', current_parameters) # fixed metric (ber_result_fixed, ser_result_fixed, per_result_fixed, spec_effic_result_fixed, sinr_result_fixed) = self.__simulate_for_one_metric( Ns_all_users_fixed, external_int_data_all_metrics, MsPk_all_users_fixed, Wk_all_users_fixed, 'fixed', current_parameters) # capacity metric (ber_result_capacity, ser_result_capacity, per_result_capacity, spec_effic_result_capacity, sinr_result_capacity) = self.__simulate_for_one_metric( Ns_all_users_capacity, external_int_data_all_metrics, MsPk_all_users_capacity, Wk_all_users_capacity, 'capacity', current_parameters) # effective throughput metric (ber_result_effec_throughput, ser_result_effec_throughput, per_result_effec_throughput, spec_effic_result_effec_throughput, sinr_result_effec_throughput) = self.__simulate_for_one_metric( Ns_all_users_effec_throughput, external_int_data_all_metrics, MsPk_all_users_effec_throughput, Wk_all_users_effec_throughput, 'effec_throughput', current_parameters) # Whitening BD (ber_result_Whitening, ser_result_Whitening, per_result_Whitening, spec_effic_result_Whitening, sinr_result_Whitening) = self.__simulate_for_one_metric( Ns_all_users_Whitening, external_int_data_all_metrics, Ms_all_users_Whitening, Wk_all_users_Whitening, 'Whitening', current_parameters) simResults = SimulationResults() # Add the 'None' results simResults.add_result(ber_result_None) simResults.add_result(ser_result_None) simResults.add_result(per_result_None) simResults.add_result(spec_effic_result_None) simResults.add_result(sinr_result_None) # Add the naive results simResults.add_result(ber_result_naive) simResults.add_result(ser_result_naive) simResults.add_result(per_result_naive) simResults.add_result(spec_effic_result_naive) simResults.add_result(sinr_result_naive) # Add the fixed results simResults.add_result(ber_result_fixed) simResults.add_result(ser_result_fixed) simResults.add_result(per_result_fixed) simResults.add_result(spec_effic_result_fixed) simResults.add_result(sinr_result_fixed) # Add the capacity results simResults.add_result(ber_result_capacity) simResults.add_result(ser_result_capacity) simResults.add_result(per_result_capacity) simResults.add_result(spec_effic_result_capacity) simResults.add_result(sinr_result_capacity) # Add the effective thoughput results simResults.add_result(ber_result_effec_throughput) simResults.add_result(ser_result_effec_throughput) simResults.add_result(per_result_effec_throughput) simResults.add_result(spec_effic_result_effec_throughput) simResults.add_result(sinr_result_effec_throughput) # Add the 'Whitening' results simResults.add_result(ber_result_Whitening) simResults.add_result(ser_result_Whitening) simResults.add_result(per_result_Whitening) simResults.add_result(spec_effic_result_Whitening) simResults.add_result(sinr_result_Whitening) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx return simResults def __simulate_for_one_metric(self, Ns_all_users, external_int_data_all_metrics, MsPk_all_users, Wk_all_users, metric_name, current_parameters): """ This method is only called inside the _run_simulation method. This method has the common code that is execute for each metric inside the _run_simulation method. Parameters ---------- Ns_all_users : 1D numpy array of size K. Number of streams for each user. This variable controls how many data streams will be generated for each user of the K users. external_int_data_all_metrics : 2D numpy array The data of the external interference sources. MsPk_all_users : 1D numpy array of 2D numpy arrays The precoders of all users returned by the block diagonalize method for the given metric. Wk_all_users : 1D numpy array of 2D numpy arrays The receive filter for all users. metric_name : string Metric name. This string will be appended to each result name. Returns ------- TODO: Write the rest of the docstring """ # pylint: disable=R0914 Ns_total = np.sum(Ns_all_users) self.data_RS = np.random.RandomState(self.data_gen_seed) input_data = self.data_RS.randint( 0, current_parameters['M'], [Ns_total, current_parameters['NSymbs']]) symbols = self.modulator.modulate(input_data) # Prepare the transmit data. That is, the precoded_data as well as # the external interferece sources' data. precoded_data = np.dot(np.hstack(MsPk_all_users), symbols) # external_int_data_all_metrics = ( # np.sqrt(self.pe) # * misc.randn_c_RS( # self.ext_data_RS, self.ext_int_rank, self.NSymbs)) all_data = np.vstack([precoded_data, external_int_data_all_metrics]) # xxxxxxxxxx Pass the precoded data through the channel xxxxxxxxxxx self.multiuser_channel.set_noise_seed(self.noise_seed) received_signal = self.multiuser_channel.corrupt_concatenated_data( all_data ) # xxxxxxxxxx Filter the received data xxxxxxxxxxxxxxxxxxxxxxxxxxxxx # noinspection PyArgumentList Wk = block_diag(*Wk_all_users) received_symbols = np.dot(Wk, received_signal) # xxxxxxxxxx Demodulate the filtered symbols xxxxxxxxxxxxxxxxxxxxxx decoded_symbols = self.modulator.demodulate(received_symbols) # xxxxxxxxxx Calculates the Symbol Error Rate xxxxxxxxxxxxxxxxxxxxx num_symbol_errors = np.sum(decoded_symbols != input_data, 1) # num_symbol_errors = sum_user_data(num_symbol_errors, # Ns_all_users) num_symbols = np.ones(Ns_total) * input_data.shape[1] # xxxxxxxxxx Calculates the Bit Error Rate xxxxxxxxxxxxxxxxxxxxxxxx num_bit_errors = misc.count_bit_errors(decoded_symbols, input_data, 1) # num_bit_errors = sum_user_data(num_bit_errors, # Ns_all_users) num_bits = num_symbols * np.log2(current_parameters['M']) # xxxxxxxxxx Calculates the Package Error Rate xxxxxxxxxxxxxxxxxxxx ber = num_bit_errors / num_bits per = 1. - ((1. - ber) ** current_parameters['packet_length']) num_packages = num_bits / current_parameters['packet_length'] num_package_errors = per * num_packages # xxxxxxxxxx Calculates the Spectral Efficiency xxxxxxxxxxxxxxxxxxx # nominal spectral Efficiency per stream nominal_spec_effic = self.modulator.K effective_spec_effic = (1 - per) * nominal_spec_effic # xxxxx Map the per stream metric to a global metric xxxxxxxxxxxxxx num_bit_errors = np.sum(num_bit_errors) num_bits = np.sum(num_bits) num_symbol_errors = np.sum(num_symbol_errors) num_symbols = np.sum(num_symbols) num_package_errors = np.sum(num_package_errors) num_packages = np.sum(num_packages) effective_spec_effic = np.sum(effective_spec_effic) # xxxxx Calculate teh SINR xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Uk_all_users = np.empty(Wk_all_users.size, dtype=np.ndarray) for ii in range(Wk_all_users.size): Uk_all_users[ii] = Wk_all_users[ii].conjugate().T SINR_all_k = self.multiuser_channel.calc_JP_SINR(MsPk_all_users, Uk_all_users) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # None metric ber_result = Result.create( 'ber_{0}'.format(metric_name), Result.RATIOTYPE, num_bit_errors, num_bits) ser_result = Result.create( 'ser_{0}'.format(metric_name), Result.RATIOTYPE, num_symbol_errors, num_symbols) per_result = Result.create( 'per_{0}'.format(metric_name), Result.RATIOTYPE, num_package_errors, num_packages) spec_effic_result = Result.create( 'spec_effic_{0}'.format(metric_name), Result.RATIOTYPE, effective_spec_effic, 1) sinr_result = Result( 'sinr_{0}'.format(metric_name), Result.RATIOTYPE, accumulate_values=True) for k in range(Wk_all_users.size): sinr_k = SINR_all_k[k] for value in sinr_k: sinr_result.update(value, 1) return (ber_result, ser_result, per_result, spec_effic_result, sinr_result) # def _keep_going(self, current_sim_results, current_rep): # ber_result = current_sim_results['ber'][-1] # num_bit_errors = ber_result._value # return num_bit_errors < self.max_bit_errors @staticmethod def _calc_transmit_power(SNR_dB, N0_dBm, cell_radius, path_loss_obj): """ Calculates the required transmit power (in linear scale) to achieve the desired mean SNR value at the cell border. This method calculates the path loss at the cell border and then finds the transmit power that gives the desired mean SNR at the cell border. Parameters ---------- SNR_dB : float SNR value (in dB) N0_dBm : float Noise power (in dBm) cell_radius : float Cell radius (in Km) path_loss_obj : Path Loss object Object of a pathloss class used to calculate the path loss (see `comm.pathloss`. Returns ------- transmit_power : float Desired transmit power (in linear scale). """ # Path loss (in linear scale) from the cell center to path_loss_border = path_loss_obj.calc_path_loss(cell_radius) snr = dB2Linear(SNR_dB) pt = snr * dBm2Linear(N0_dBm) / path_loss_border return pt
def _on_simulate_current_params_start(self, current_params): """This method is called once for each combination of transmit parameters. """ # pylint: disable=W0201 # IMPORTANT: Re-seed the channel and the noise RandomState # objects. Without this, when you perform the simulation in # parallel (call the simulate_in_parallel method(from the # SimulationRunner class) you will get the same channel samples and # noise for all parallel process. self.multiuser_channel.re_seed() # xxxxx Calculates the transmit power at each base station. xxxxxxx # Because this value does not change in the different iterations of # _run_simulation, but only when the parameters change the # calculation is performed here in the # _on_simulate_current_params_start. transmit_power = BDSimulationRunner._calc_transmit_power( current_params['SNR'], current_params['N0'], current_params['cell_radius'], self.path_loss_obj) # External interference power self.pe = dBm2Linear(current_params['Pe_dBm']) # xxxxx Create the BD object with the None metric xxxxxxxxxxxxxxxxx self.bd_obj_None = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_None.set_ext_int_handling_metric( "None", { 'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1 }) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with the Naive metric xxxxxxxxxxxxxxxx self.bd_obj_naive = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_naive.set_ext_int_handling_metric( "naive", { 'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1 }) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with the fixed metric xxxxxxxxxxxxxxxx self.bd_obj_fixed = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_fixed.set_ext_int_handling_metric( "fixed", { 'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1 }) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with the capacity metric xxxxxxxxxxxxx self.bd_obj_capacity = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_capacity.set_ext_int_handling_metric( "capacity", { 'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1 }) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xx Create the BD object with the effective_throughput metric xxxx self.bd_obj_effec_throughput = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_effec_throughput.set_ext_int_handling_metric( "effective_throughput", { 'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1 }) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with whitening xxxxxxxxxxxxxxxxxxxxxxx self.bd_obj_whitening = WhiteningBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe)
def _on_simulate_current_params_start(self, current_params): """This method is called once for each combination of transmit parameters. """ # pylint: disable=W0201 # IMPORTANT: Re-seed the channel and the noise RandomState # objects. Without this, when you perform the simulation in # parallel (call the simulate_in_parallel method(from the # SimulationRunner class) you will get the same channel samples and # noise for all parallel process. self.multiuser_channel.re_seed() # xxxxx Calculates the transmit power at each base station. xxxxxxx # Because this value does not change in the different iterations of # _run_simulation, but only when the parameters change the # calculation is performed here in the # _on_simulate_current_params_start. transmit_power = BDSimulationRunner._calc_transmit_power( current_params['SNR'], current_params['N0'], current_params['cell_radius'], self.path_loss_obj) # External interference power self.pe = dBm2Linear(current_params['Pe_dBm']) # xxxxx Create the BD object with the None metric xxxxxxxxxxxxxxxxx self.bd_obj_None = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_None.set_ext_int_handling_metric( "None", {'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1}) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with the Naive metric xxxxxxxxxxxxxxxx self.bd_obj_naive = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_naive.set_ext_int_handling_metric( "naive", {'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1}) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with the fixed metric xxxxxxxxxxxxxxxx self.bd_obj_fixed = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_fixed.set_ext_int_handling_metric( "fixed", {'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1}) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with the capacity metric xxxxxxxxxxxxx self.bd_obj_capacity = EnhancedBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_capacity.set_ext_int_handling_metric( "capacity", {'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1}) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xx Create the BD object with the effective_throughput metric xxxx self.bd_obj_effec_throughput = EnhancedBD( current_params['num_cells'], transmit_power, self.noise_var, self.pe) self.bd_obj_effec_throughput.set_ext_int_handling_metric( "effective_throughput", {'modulator': self.modulator, 'packet_length': current_params['packet_length'], 'num_streams': 1}) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Create the BD object with whitening xxxxxxxxxxxxxxxxxxxxxxx self.bd_obj_whitening = WhiteningBD(current_params['num_cells'], transmit_power, self.noise_var, self.pe)