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