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): # 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.multiUserChannel.re_seed() if current_params['scenario'] == 'NoPathLoss': self.noise_var = 1.0 self.multiUserChannel.noise_var = self.noise_var else: self.noise_var = dBm2Linear(self.params['N0']) self.multiUserChannel.noise_var = self.noise_var self.ia_solver.max_iterations = current_params['max_iterations'] # Parameter choosing the stream selection method. The value can be # either 'greedy' or 'brute'. The value 'none' is also accepted, in # which case no stream selection is performed. alg = current_params['stream_sel_method'] # Create the 'top' IA solver object: either "greedy" or the "brute # force" depending on the value of the 'stream_sel_method' # parameter. This object will use the basic IA solver object. Note # that if 'stream_sel_method' is equal to 'none' then no IA # top object will be used and self.ia_top_object is set to # self.ia_solver so that we run the regular IA algorithm. if alg == 'greedy': self.ia_top_object = algorithms.GreedStreamIASolver(self.ia_solver) elif alg == 'brute': self.ia_top_object = algorithms.BruteForceStreamIASolver( self.ia_solver) elif alg == 'none': # For the no stream selection case the IA top object will be # the same as the IA basic object self.ia_top_object = self.ia_solver else: raise ValueError( "Invalid stream selection method: '{0}'".format(alg))
def _on_simulate_current_params_start(self, current_params): # 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.multiUserChannel.re_seed() if current_params["scenario"] == "NoPathLoss": self.noise_var = 1.0 self.multiUserChannel.noise_var = self.noise_var else: self.noise_var = dBm2Linear(self.params["N0"]) self.multiUserChannel.noise_var = self.noise_var self.ia_solver.max_iterations = current_params["max_iterations"] # Parameter choosing the stream selection method. The value can be # either 'greedy' or 'brute'. The value 'none' is also accepted, in # which case no stream selection is performed. alg = current_params["stream_sel_method"] # Create the 'top' IA solver object: either "greedy" or the "brute # force" depending on the value of the 'stream_sel_method' # parameter. This object will use the basic IA solver object. Note # that if 'stream_sel_method' is equal to 'none' then no IA # top object will be used and self.ia_top_object is set to # self.ia_solver so that we run the regular IA algorithm. if alg == "greedy": self.ia_top_object = algorithms.GreedStreamIASolver(self.ia_solver) elif alg == "brute": self.ia_top_object = algorithms.BruteForceStreamIASolver(self.ia_solver) elif alg == "none": # For the no stream selection case the IA top object will be # the same as the IA basic object self.ia_top_object = self.ia_solver else: raise ValueError("Invalid stream selection method: '{0}'".format(alg))
# External Interference Parameters Pe_dBm = -10000 # transmit power (in dBm) of the ext. interference ext_int_rank = 1 # Rank of the external interference # xxxxxxxxxx General Parameters xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx rep_max = 20000 # Maximum number of repetitions for each pbar = progressbar.ProgressbarText(rep_max, message="Simulating for SNR: {0}".format(SNR_dB)) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Dependent parameters (don't change these) xxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Path loss (in linear scale) from the cell center to path_loss_border = path_loss_obj.calc_path_loss(cell_radius) noise_var = conversion.dBm2Linear(N0_dBm) snr = conversion.dB2Linear(SNR_dB) transmit_power = snr * noise_var / path_loss_border # External interference power pe = conversion.dBm2Linear(Pe_dBm) # Cell Grid cell_grid = cell.Grid() cell_grid.create_clusters(num_clusters, num_cells, cell_radius) # noinspection PyProtectedMember cluster0 = cell_grid._clusters[0] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Create the scenario xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
def perform_simulation_SINR_heatmap(scenario_params, power_params): # pylint: disable=R0914 """ Perform the simulation. """ # xxxxxxxxxx Simulation Scenario Configuration xxxxxxxxxxxxxxxxxxxxxxxx # The size of the side of each square room side_length = scenario_params["side_length"] # How much (in dB) is lost for each wall teh signal has to pass single_wall_loss_dB = scenario_params["single_wall_loss_dB"] # Square of 12 x 12 square rooms num_rooms_per_side = scenario_params["num_rooms_per_side"] # Total number of rooms in the grid num_rooms = num_rooms_per_side ** 2 # 1 means 1 ap every room. 2 means 1 ap every 2 rooms and so on. Valid # values are: 1, 2, 4 and 9. ap_decimation = scenario_params["ap_decimation"] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Simulation Power Configuration xxxxxxxxxxxxxxxxxxxxxxxxxxx # Transmit power of each access point Pt_dBm = power_params["Pt_dBm"] noise_power_dBm = power_params["noise_power_dBm"] Pt = dBm2Linear(Pt_dBm) # 20 dBm transmit power noise_var = dBm2Linear(noise_power_dBm) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Discretization of the possible positions xxxxxxxxxxxxxxxxx num_discrete_positions_per_room = 15 # Number of discrete positions step = 1.0 / num_discrete_positions_per_room aux = np.linspace(-(1.0 - step), (1.0 - step), num_discrete_positions_per_room) aux = np.meshgrid(aux, aux, indexing="ij") user_relative_positions = aux[1] + 1j * aux[0][::-1] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate the positions of all rooms xxxxxxxxxxxxxxxxxxxxx room_positions = calc_room_positions_square(side_length, num_rooms) room_positions.shape = (num_rooms_per_side, num_rooms_per_side) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Create the path loss object xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx pl_3gpp_obj = pathloss.PathLoss3GPP1() pl_free_space_obj = pathloss.PathLossFreeSpace() pl_3gpp_obj.handle_small_distances_bool = True pl_free_space_obj.handle_small_distances_bool = True pl_metis_ps7_obj = pathloss.PathLossMetisPS7() pl_metis_ps7_obj.handle_small_distances_bool = True # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxx Add one user in each discrete position of each room xxxxxxxxxx user_relative_positions2 = user_relative_positions * side_length / 2.0 user_positions = ( room_positions[:, :, np.newaxis, np.newaxis] + user_relative_positions2[np.newaxis, np.newaxis, :, :] ) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx AP Allocation xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # 1 AP in each room ap_positions = get_ap_positions(room_positions, ap_decimation) num_aps = ap_positions.size # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate distances: each user to each AP xxxxxxxxxxxxxxxx # Dimension: (romm_row, room_c, user_row, user_col, num_APs) dists_m = np.abs(user_positions[:, :, :, :, np.newaxis] - ap_positions.reshape([1, 1, 1, 1, -1])) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate AP association xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Determine with which AP each user is associated with. # Each user will associate with the CLOSEST access point. ap_assoc = np.argmin(dists_m, axis=-1) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate wall losses xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # We want to calculate the number walls from each room to the rooms # which have an access point. # Dimension is (num_rooms, num_aps) num_walls = calc_num_walls(side_length, room_positions, ap_positions) # Reshape it to (num_rooms_per_side, num_rooms_per_side, 1, 1, num_aps) num_walls_extended = num_walls.reshape([num_rooms_per_side, num_rooms_per_side, 1, 1, num_aps]) # And finally broadcast the (1, 1) dimensions to the number of users # per room. This will make num_walls_extended have the same dimension # as dists_m. num_walls_extended, _ = np.broadcast_arrays(num_walls_extended, dists_m) wall_losses_dB = num_walls_extended * single_wall_loss_dB # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate the path losses xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # The METIS PS7 path loss model require distance values in meters, # while the others are in Kms. All distances were calculates in meters # and, therefore, we divide the distance in by 1000 for 3GPP and free # space. pl_3gpp = pl_3gpp_obj.calc_path_loss(dists_m / 1000.0) pl_free_space = pl_free_space_obj.calc_path_loss(dists_m / 1000.0) pl_nothing = np.ones( [ num_rooms_per_side, num_rooms_per_side, num_discrete_positions_per_room, num_discrete_positions_per_room, num_aps, ], dtype=float, ) # We need to know the number of walls the signal must pass to reach the # receiver to calculate the path loss for the METIS PS7 model. pl_metis_ps7 = pl_metis_ps7_obj.calc_path_loss(dists_m, num_walls=num_walls_extended) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate the SINRs for each path loss model xxxxxxxxxxxxx sinr_array_pl_nothing_dB = simulate_for_a_given_ap_assoc(pl_nothing, ap_assoc, wall_losses_dB, Pt, noise_var) sinr_array_pl_3gpp_dB = simulate_for_a_given_ap_assoc(pl_3gpp, ap_assoc, wall_losses_dB, Pt, noise_var) sinr_array_pl_free_space_dB = simulate_for_a_given_ap_assoc(pl_free_space, ap_assoc, wall_losses_dB, Pt, noise_var) sinr_array_pl_metis_ps7_dB = simulate_for_a_given_ap_assoc(pl_metis_ps7, ap_assoc, wall_losses_dB, Pt, noise_var) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx out = (sinr_array_pl_nothing_dB, sinr_array_pl_3gpp_dB, sinr_array_pl_free_space_dB, sinr_array_pl_metis_ps7_dB) return out
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 _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 perform_simulation( scenario_params, # pylint: disable=R0914 power_params, plot_results_bool=True): """ Run the simulation. """ # xxxxxxxxxx Simulation Scenario Configuration xxxxxxxxxxxxxxxxxxxxxxxx # The size of the side of each square room side_length = scenario_params['side_length'] # How much (in dB) is lost for each wall teh signal has to pass single_wall_loss_dB = scenario_params['single_wall_loss_dB'] # Square of 12 x 12 square rooms num_rooms_per_side = scenario_params['num_rooms_per_side'] # Total number of rooms in the grid num_rooms = num_rooms_per_side**2 # 1 means 1 ap every room. 2 means 1 ap every 2 rooms and so on. Valid # values are: 1, 2, 4 and 9. ap_decimation = scenario_params['ap_decimation'] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Simulation Power Configuration xxxxxxxxxxxxxxxxxxxxxxxxxxx # Transmit power of each access point Pt_dBm = power_params['Pt_dBm'] noise_power_dBm = power_params['noise_power_dBm'] Pt = dBm2Linear(Pt_dBm) # 20 dBm transmit power noise_var = dBm2Linear(noise_power_dBm) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate the positions of all rooms xxxxxxxxxxxxxxxxxxxxx room_positions = calc_room_positions_square(side_length, num_rooms) room_positions.shape = (num_rooms_per_side, num_rooms_per_side) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Create the path loss object xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx pl_metis_ps7_obj = pathloss.PathLossMetisPS7() pl_metis_ps7_obj.handle_small_distances_bool = True # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Add users in random positions in the 2D grid xxxxxxxxxxxxx num_users = 100 # We will create this many users in the 2D grid users_positions = (num_rooms_per_side * side_length * (np.random.random_sample(num_users) + 1j * np.random.random_sample(num_users) - 0.5 - 0.5j)) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx AP Allocation xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # 1 AP in each room ap_positions = get_ap_positions(room_positions, ap_decimation) num_aps = ap_positions.size # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate distances: each user to each AP xxxxxxxxxxxxxxxx # Dimension: (num_users, num_APs) dists_m = np.abs(users_positions[:, np.newaxis] - ap_positions[np.newaxis, :]) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate AP association xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # INPUTS # Find in which room each user is users_rooms = np.argmin(np.abs( room_positions.reshape([-1, 1]) - users_positions[np.newaxis, :]), axis=0) # Number of walls from each room to each other room num_walls_all_rooms = calc_num_walls(side_length, room_positions, ap_positions) # Number of walls from each room that has at least one user to each # room with an AP num_walls_rooms_with_users = num_walls_all_rooms[users_rooms] # Path loss from each user to each AP (no matter if it will be a # transmitting AP or not, since we still have to perform the AP # association) pl_all = pl_metis_ps7_obj.calc_path_loss( dists_m, num_walls=num_walls_rooms_with_users) # Calculate wall losses from each user to each AP (no matter if it will # be a transmitting AP or not, since we still have to perform the AP # association) wall_losses_dB_all = num_walls_rooms_with_users * single_wall_loss_dB # Calculate path loss plus wall losses (we multiply the linear values) # from each user to each AP (no matter if it will be a transmitting AP # or not, since we still have to perform the AP association) pl_all_plus_wl = pl_all * dB2Linear(-wall_losses_dB_all) # OUTPUTS # Determine with which AP each user is associated with. # Each user will associate with the CLOSEST access point. ap_assoc = find_ap_assoc_best_channel(pl_all_plus_wl) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Find which Access Points should stay on xxxxxxxxxxxxxxxxxx # Indexes of the active APs transmitting_aps, users_count = np.unique(ap_assoc, return_counts=True) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate the SINRs for each path loss model xxxxxxxxxxxxx # Take the path loss plus wall losses only for the transmitting aps pl_all_plus_wall_losses_tx_aps = pl_all_plus_wl.take(transmitting_aps, axis=1) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate the SINRs and capacity xxxxxxxxxxxxxxxxxxxxxxxxx sinr_array_pl_metis_ps7_dB, capacity_metis_ps7 \ = simulate_for_a_given_ap_assoc( pl_all_plus_wall_losses_tx_aps, ap_assoc, transmitting_aps, Pt, noise_var) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Plot the results xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx if plot_results_bool is True: print(("\nMin/Mean/Max SINR value (METIS PS7):" "\n {0}\n {1}\n {2}").format( sinr_array_pl_metis_ps7_dB.min(), sinr_array_pl_metis_ps7_dB.mean(), sinr_array_pl_metis_ps7_dB.max())) print(("\nMin/Mean/Max Capacity value (METIS PS7):" "\n {0}\n {1}\n {2}").format(capacity_metis_ps7.min(), capacity_metis_ps7.mean(), capacity_metis_ps7.max())) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxx Plot the results xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Create a mask for the active APs transmitting_aps_mask = np.zeros(num_aps, dtype=bool) transmitting_aps_mask[transmitting_aps] = True # Save how many users are associated with each AP users_per_ap = np.zeros(num_aps, dtype=int) users_per_ap[transmitting_aps_mask] = users_count # xxxxxxxxxx Plot all rooms and users xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx all_rooms = [ shapes.Rectangle(pos - side_length / 2. - side_length * 1j / 2., pos + side_length / 2. + side_length * 1j / 2.) for pos in room_positions.flatten() ] # Plot all Rooms and save the axis where they were plotted plt.figure(figsize=(10, 10)) gs = gridspec.GridSpec(2, 1, height_ratios=[4, 1]) # ax1 is where we will plot everything ax1 = plt.subplot(gs[0]) ax1.set_xlabel("Position X coordinate") ax1.set_ylabel("Position Y coordinate") ax1.set_title("Plot of all Rooms") ax1.set_ylim([-60, 60]) ax1.set_xlim([-60, 60]) ax1 = plot_all_rooms(all_rooms, ax1) ax1.hold(True) # ax2 will be used for annotations ax2 = plt.subplot(gs[1]) plt.setp(ax2.get_xticklabels(), visible=False) plt.setp(ax2.get_yticklabels(), visible=False) ax2.set_ylim([0, 10]) ax2.set_xlim([0, 10]) details = ax2.text(5, 5, 'Details', verticalalignment='center', horizontalalignment='center', family='monospace') # Set the an array with colors for the access points. Transmitting APs # will be blue, while inactive APs will be gray ap_colors = np.empty(ap_positions.shape, dtype='U4') ap_colors[transmitting_aps_mask] = 'b' ap_colors[np.logical_not(transmitting_aps_mask)] = 'gray' # Plot the access points. We set linewidth to 0.0 so that there is no # border. We set the size ('s' keyword) to 50 to make it larger. The # colors are set according to the ap_colors array. # Note that we set a 5 points tolerance for the pick event. aps_plt = ax1.scatter(ap_positions.real, ap_positions.imag, marker='^', c=ap_colors, linewidths=0.1, s=50, picker=3) # Plot the users # Note that we set a 5 points tolerance for the pick event. users_plt = ax1.scatter(users_positions.real, users_positions.imag, marker='*', c='r', linewidth=0.1, s=50, picker=3) # xxxxxxxxxx Define a function to call for the pick_event Circle used # to select an AP. We will set its visibility to False here. When an AP # is selected, we move this circle to its position and set its # visibility to True. selected_ap_circle = ax1.plot([0], [0], 'o', ms=12, alpha=0.4, color='yellow', visible=False)[0] # Define the callback function for the pick event def on_pick(event): """Callback for the pick event in the matplotlib plot.""" # We will reset users colors on each pick users_colors = np.empty(ap_assoc.size, dtype='U1') users_colors[:] = 'r' # Index of the point clicked ind = event.ind[0] if event.artist == aps_plt: # Disable the circle in the AP selected_ap_circle.set_visible(False) if ind not in ap_assoc: # Text information for the disabled AP text = "AP {0} (Disabled)".format(ind) else: # Text information for the selected AP text = "AP {0} with {1} user(s)\nTotal throughput: {2:7.4f}" text = text.format( ind, users_per_ap[ind], np.sum(capacity_metis_ps7[ap_assoc == ind])) # Change the colors of the users associated with the # current AP to green users_colors[ap_assoc == ind] = 'g' elif event.artist == users_plt: # Text information for the selected user text = "User {0}\n SINR: {1:7.4f}\nCapacity: {2:7.4f}".format( ind, sinr_array_pl_metis_ps7_dB[ind], capacity_metis_ps7[ind]) # If there other users are associated with the same AP of the # current user if users_per_ap[ap_assoc[ind]] > 1: text = "{0}\nShares AP with {1} other user(s)".format( text, users_per_ap[ap_assoc[ind]] - 1) users_AP = ap_assoc[ind] # Plot a yellow circle in the user's AP ap_pos = ap_positions[users_AP] # CHange the collor of other users in the same AP to green and # the current user to cyan users_colors[ap_assoc == users_AP] = 'g' users_colors[ind] = 'c' selected_ap_circle.set_visible(True) selected_ap_circle.set_data([ap_pos.real], [ap_pos.imag]) # Set users colors users_plt.set_color(users_colors) # Set the details text details.set_text(text) ax1.figure.canvas.draw() # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Connect the on_pick function with the pick event ax1.figure.canvas.mpl_connect('pick_event', on_pick) plt.show() # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Return the results xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx return sinr_array_pl_metis_ps7_dB, capacity_metis_ps7
def perform_simulation_SINR_heatmap( scenario_params, # pylint: disable=R0914 power_params): """ Perform the simulation. Parameters ---------- scenario_params : dict Dictionary with the scenario parameters. power_params : dict Dictionary with the power related parameters. Returns ------- tuple[np.ndarray] Tuple with 4 numpy arrays with the results. """ # xxxxxxxxxx Simulation Scenario Configuration xxxxxxxxxxxxxxxxxxxxxxxx # The size of the side of each square room side_length = scenario_params['side_length'] # How much (in dB) is lost for each wall teh signal has to pass single_wall_loss_dB = scenario_params['single_wall_loss_dB'] # Square of 12 x 12 square rooms num_rooms_per_side = scenario_params['num_rooms_per_side'] # Total number of rooms in the grid num_rooms = num_rooms_per_side**2 # 1 means 1 ap every room. 2 means 1 ap every 2 rooms and so on. Valid # values are: 1, 2, 4 and 9. ap_decimation = scenario_params['ap_decimation'] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Simulation Power Configuration xxxxxxxxxxxxxxxxxxxxxxxxxxx # Transmit power of each access point Pt_dBm = power_params['Pt_dBm'] noise_power_dBm = power_params['noise_power_dBm'] Pt = dBm2Linear(Pt_dBm) # 20 dBm transmit power noise_var = dBm2Linear(noise_power_dBm) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Discretization of the possible positions xxxxxxxxxxxxxxxxx num_discrete_positions_per_room = 15 # Number of discrete positions step = 1. / num_discrete_positions_per_room aux = np.linspace(-(1. - step), (1. - step), num_discrete_positions_per_room) aux = np.meshgrid(aux, aux, indexing='ij') ":type: np.ndarray" user_relative_positions = aux[1] + 1j * aux[0][::-1] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate the positions of all rooms xxxxxxxxxxxxxxxxxxxxx room_positions = calc_room_positions_square(side_length, num_rooms) room_positions.shape = (num_rooms_per_side, num_rooms_per_side) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Create the path loss object xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx pl_3gpp_obj = pathloss.PathLoss3GPP1() pl_free_space_obj = pathloss.PathLossFreeSpace() pl_3gpp_obj.handle_small_distances_bool = True pl_free_space_obj.handle_small_distances_bool = True pl_metis_ps7_obj = pathloss.PathLossMetisPS7() pl_metis_ps7_obj.handle_small_distances_bool = True # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxx Add one user in each discrete position of each room xxxxxxxxxx user_relative_positions2 = user_relative_positions * side_length / 2. user_positions = (room_positions[:, :, np.newaxis, np.newaxis] + user_relative_positions2[np.newaxis, np.newaxis, :, :]) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx AP Allocation xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # 1 AP in each room ap_positions = get_ap_positions(room_positions, ap_decimation) num_aps = ap_positions.size # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate distances: each user to each AP xxxxxxxxxxxxxxxx # Dimension: (room_row, room_c, user_row, user_col, num_APs) dists_m = np.abs(user_positions[:, :, :, :, np.newaxis] - ap_positions.reshape([1, 1, 1, 1, -1])) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate AP association xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Determine with which AP each user is associated with. # Each user will associate with the CLOSEST access point. ap_assoc = np.argmin(dists_m, axis=-1) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate wall losses xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # We want to calculate the number walls from each room to the rooms # which have an access point. # Dimension is (num_rooms, num_aps) num_walls = calc_num_walls(side_length, room_positions, ap_positions) # Reshape it to (num_rooms_per_side, num_rooms_per_side, 1, 1, num_aps) num_walls_extended = num_walls.reshape( [num_rooms_per_side, num_rooms_per_side, 1, 1, num_aps]) # And finally broadcast the (1, 1) dimensions to the number of users # per room. This will make num_walls_extended have the same dimension # as dists_m. num_walls_extended, _ = np.broadcast_arrays(num_walls_extended, dists_m) wall_losses_dB = num_walls_extended * single_wall_loss_dB # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate the path losses xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # The METIS PS7 path loss model require distance values in meters, # while the others are in Kms. All distances were calculates in meters # and, therefore, we divide the distance in by 1000 for 3GPP and free # space. pl_3gpp = pl_3gpp_obj.calc_path_loss(dists_m / 1000.) pl_free_space = pl_free_space_obj.calc_path_loss(dists_m / 1000.) pl_nothing = np.ones([ num_rooms_per_side, num_rooms_per_side, num_discrete_positions_per_room, num_discrete_positions_per_room, num_aps ], dtype=float) # We need to know the number of walls the signal must pass to reach the # receiver to calculate the path loss for the METIS PS7 model. pl_metis_ps7 = pl_metis_ps7_obj.calc_path_loss( dists_m, num_walls=num_walls_extended) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate the SINRs for each path loss model xxxxxxxxxxxxx sinr_array_pl_nothing_dB = simulate_for_a_given_ap_assoc( pl_nothing, ap_assoc, wall_losses_dB, Pt, noise_var) sinr_array_pl_3gpp_dB = simulate_for_a_given_ap_assoc( pl_3gpp, ap_assoc, wall_losses_dB, Pt, noise_var) sinr_array_pl_free_space_dB = simulate_for_a_given_ap_assoc( pl_free_space, ap_assoc, wall_losses_dB, Pt, noise_var) sinr_array_pl_metis_ps7_dB = simulate_for_a_given_ap_assoc( pl_metis_ps7, ap_assoc, wall_losses_dB, Pt, noise_var) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx out = (sinr_array_pl_nothing_dB, sinr_array_pl_3gpp_dB, sinr_array_pl_free_space_dB, sinr_array_pl_metis_ps7_dB) return out
# External Interference Parameters Pe_dBm = -10000 # transmit power (in dBm) of the ext. interference ext_int_rank = 1 # Rank of the external interference # xxxxxxxxxx General Parameters xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx rep_max = 20000 # Maximum number of repetitions for each pbar = progressbar.ProgressbarText( rep_max, message="Simulating for SNR: {0}".format(SNR_dB)) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Dependent parameters (don't change these) xxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Path loss (in linear scale) from the cell center to path_loss_border = path_loss_obj.calc_path_loss(cell_radius) noise_var = conversion.dBm2Linear(N0_dBm) snr = conversion.dB2Linear(SNR_dB) transmit_power = snr * noise_var / path_loss_border # External interference power pe = conversion.dBm2Linear(Pe_dBm) # Cell Grid cell_grid = cell.Grid() cell_grid.create_clusters(num_clusters, num_cells, cell_radius) # noinspection PyProtectedMember cluster0 = cell_grid._clusters[0] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Create the scenario xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
def test_dBm2Linear(self): self.assertAlmostEqual(conversion.dBm2Linear(60), 1000.0)
def perform_simulation(scenario_params, power_params, plot_results_bool=True): # pylint: disable=R0914 """ Run the simulation. """ # xxxxxxxxxx Simulation Scenario Configuration xxxxxxxxxxxxxxxxxxxxxxxx # The size of the side of each square room side_length = scenario_params["side_length"] # How much (in dB) is lost for each wall teh signal has to pass single_wall_loss_dB = scenario_params["single_wall_loss_dB"] # Square of 12 x 12 square rooms num_rooms_per_side = scenario_params["num_rooms_per_side"] # Total number of rooms in the grid num_rooms = num_rooms_per_side ** 2 # 1 means 1 ap every room. 2 means 1 ap every 2 rooms and so on. Valid # values are: 1, 2, 4 and 9. ap_decimation = scenario_params["ap_decimation"] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Simulation Power Configuration xxxxxxxxxxxxxxxxxxxxxxxxxxx # Transmit power of each access point Pt_dBm = power_params["Pt_dBm"] noise_power_dBm = power_params["noise_power_dBm"] Pt = dBm2Linear(Pt_dBm) # 20 dBm transmit power noise_var = dBm2Linear(noise_power_dBm) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate the positions of all rooms xxxxxxxxxxxxxxxxxxxxx room_positions = calc_room_positions_square(side_length, num_rooms) room_positions.shape = (num_rooms_per_side, num_rooms_per_side) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Create the path loss object xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx pl_metis_ps7_obj = pathloss.PathLossMetisPS7() pl_metis_ps7_obj.handle_small_distances_bool = True # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Add users in random positions in the 2D grid xxxxxxxxxxxxx num_users = 100 # We will create this many users in the 2D grid users_positions = ( num_rooms_per_side * side_length * (np.random.random_sample(num_users) + 1j * np.random.random_sample(num_users) - 0.5 - 0.5j) ) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx AP Allocation xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # 1 AP in each room ap_positions = get_ap_positions(room_positions, ap_decimation) num_aps = ap_positions.size # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate distances: each user to each AP xxxxxxxxxxxxxxxx # Dimension: (num_users, num_APs) dists_m = np.abs(users_positions[:, np.newaxis] - ap_positions[np.newaxis, :]) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate AP association xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # INPUTS # Find in which room each user is users_rooms = np.argmin(np.abs(room_positions.reshape([-1, 1]) - users_positions[np.newaxis, :]), axis=0) # Number of walls from each room to each other room num_walls_all_rooms = calc_num_walls(side_length, room_positions, ap_positions) # Number of walls from each room that has at least one user to each # room with an AP num_walls_rooms_with_users = num_walls_all_rooms[users_rooms] # Path loss from each user to each AP (no matter if it will be a # transmitting AP or not, since we still have to perform the AP # association) pl_all = pl_metis_ps7_obj.calc_path_loss(dists_m, num_walls=num_walls_rooms_with_users) # Calculate wall losses from each user to each AP (no matter if it will # be a transmitting AP or not, since we still have to perform the AP # association) wall_losses_dB_all = num_walls_rooms_with_users * single_wall_loss_dB # Calculate path loss plus wall losses (we multiply the linear values) # from each user to each AP (no matter if it will be a transmitting AP # or not, since we still have to perform the AP association) pl_all_plus_wl = pl_all * dB2Linear(-wall_losses_dB_all) # OUTPUTS # Determine with which AP each user is associated with. # Each user will associate with the CLOSEST access point. ap_assoc = find_ap_assoc_best_channel(pl_all_plus_wl) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Find which Access Points should stay on xxxxxxxxxxxxxxxxxx # Indexes of the active APs transmitting_aps, users_count = np.unique(ap_assoc, return_counts=True) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate the SINRs for each path loss model xxxxxxxxxxxxx # Take the path loss plus wall losses only for the transmitting aps pl_all_plus_wall_losses_tx_aps = pl_all_plus_wl.take(transmitting_aps, axis=1) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculate the SINRs and capacity xxxxxxxxxxxxxxxxxxxxxxxxx sinr_array_pl_metis_ps7_dB, capacity_metis_ps7 = simulate_for_a_given_ap_assoc( pl_all_plus_wall_losses_tx_aps, ap_assoc, transmitting_aps, Pt, noise_var ) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Plot the results xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx if plot_results_bool is True: print( ("\nMin/Mean/Max SINR value (METIS PS7):" "\n {0}\n {1}\n {2}").format( sinr_array_pl_metis_ps7_dB.min(), sinr_array_pl_metis_ps7_dB.mean(), sinr_array_pl_metis_ps7_dB.max() ) ) print( ("\nMin/Mean/Max Capacity value (METIS PS7):" "\n {0}\n {1}\n {2}").format( capacity_metis_ps7.min(), capacity_metis_ps7.mean(), capacity_metis_ps7.max() ) ) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxx Plot the results xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Create a mask for the active APs transmitting_aps_mask = np.zeros(num_aps, dtype=bool) transmitting_aps_mask[transmitting_aps] = True # Save how many users are associated with each AP users_per_ap = np.zeros(num_aps, dtype=int) users_per_ap[transmitting_aps_mask] = users_count # xxxxxxxxxx Plot all rooms and users xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx all_rooms = [ shapes.Rectangle( pos - side_length / 2.0 - side_length * 1j / 2.0, pos + side_length / 2.0 + side_length * 1j / 2.0 ) for pos in room_positions.flatten() ] # Plot all Rooms and save the axis where they were plotted plt.figure(figsize=(10, 10)) gs = gridspec.GridSpec(2, 1, height_ratios=[4, 1]) # ax1 is where we will plot everything ax1 = plt.subplot(gs[0]) ax1.set_xlabel("Position X coordinate") ax1.set_ylabel("Position Y coordinate") ax1.set_title("Plot of all Rooms") ax1.set_ylim([-60, 60]) ax1.set_xlim([-60, 60]) ax1 = plot_all_rooms(all_rooms, ax1) ax1.hold(True) # ax2 will be used for annotations ax2 = plt.subplot(gs[1]) plt.setp(ax2.get_xticklabels(), visible=False) plt.setp(ax2.get_yticklabels(), visible=False) ax2.set_ylim([0, 10]) ax2.set_xlim([0, 10]) details = ax2.text( 5, 5, "Details", verticalalignment="center", horizontalalignment="center", family="monospace" ) # Set the an array with colors for the access points. Transmitting APs # will be blue, while inactive APs will be gray ap_colors = np.empty(ap_positions.shape, dtype="U4") ap_colors[transmitting_aps_mask] = "b" ap_colors[np.logical_not(transmitting_aps_mask)] = "gray" # Plot the access points. We set linewidth to 0.0 so that there is no # border. We set the size ('s' keyword) to 50 to make it larger. The # colors are set according to the ap_colors array. # Note that we set a 5 points tolerance for the pick event. aps_plt = ax1.scatter( ap_positions.real, ap_positions.imag, marker="^", c=ap_colors, linewidths=0.1, s=50, picker=3 ) # Plot the users # Note that we set a 5 points tolerance for the pick event. users_plt = ax1.scatter( users_positions.real, users_positions.imag, marker="*", c="r", linewidth=0.1, s=50, picker=3 ) # xxxxxxxxxx Define a function to call for the pick_event Circle used # to select an AP. We will set its visibility to False here. When an AP # is selected, we move this circle to its position and set its # visibility to True. selected_ap_circle = ax1.plot([0], [0], "o", ms=12, alpha=0.4, color="yellow", visible=False)[0] # Define the callback function for the pick event def on_pick(event): """Callback for the pick event in the matplotlib plot.""" # We will reset users colors on each pick users_colors = np.empty(ap_assoc.size, dtype="U1") users_colors[:] = "r" # Index of the point clicked ind = event.ind[0] if event.artist == aps_plt: # Disable the circle in the AP selected_ap_circle.set_visible(False) if ind not in ap_assoc: # Text information for the disabled AP text = "AP {0} (Disabled)".format(ind) else: # Text information for the selected AP text = "AP {0} with {1} user(s)\nTotal throughput: {2:7.4f}" text = text.format(ind, users_per_ap[ind], np.sum(capacity_metis_ps7[ap_assoc == ind])) # Change the colors of the users associated with the # current AP to green users_colors[ap_assoc == ind] = "g" elif event.artist == users_plt: # Text information for the selected user text = "User {0}\n SINR: {1:7.4f}\nCapacity: {2:7.4f}".format( ind, sinr_array_pl_metis_ps7_dB[ind], capacity_metis_ps7[ind] ) # If there other users are associated with the same AP of the # current user if users_per_ap[ap_assoc[ind]] > 1: text = "{0}\nShares AP with {1} other user(s)".format(text, users_per_ap[ap_assoc[ind]] - 1) users_AP = ap_assoc[ind] # Plot a yellow circle in the user's AP ap_pos = ap_positions[users_AP] # CHange the collor of other users in the same AP to green and # the current user to cyan users_colors[ap_assoc == users_AP] = "g" users_colors[ind] = "c" selected_ap_circle.set_visible(True) selected_ap_circle.set_data([ap_pos.real], [ap_pos.imag]) # Set users colors users_plt.set_color(users_colors) # Set the details text details.set_text(text) ax1.figure.canvas.draw() # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Connect the on_pick function with the pick event ax1.figure.canvas.mpl_connect("pick_event", on_pick) plt.show() # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Return the results xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx return sinr_array_pl_metis_ps7_dB, capacity_metis_ps7
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 _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)