Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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