def calc_path_loss_dB(self, d, **kargs): """ Calculates the Path Loss (in dB) for a given distance (in Km). Note that the returned value is positive, but should be understood as "a loss". Parameters ---------- d : float or numpy array Distance (in Km) kargs : dict Optional parameters for use in subclasses if required. Other Parameters ---------------- kwargs : dict Additional keywords that might be necessary in a subclass. Returns ------- PL : float or numpy array Path loss (in dB) for the given distance(s). """ PL = self._calc_deterministic_path_loss_dB(d, **kargs) if self.use_shadow_bool is True: # pragma: no cover if isinstance(d, Iterable): # If 'd' is a numpy array (or something similar such as a # list), shadow must be a numpy array with the same shape shadow = conversion.dB2Linear( np.random.standard_normal(np.size(d)) * self.sigma_shadow) shadow.shape = np.shape(d) else: # If 'd' is not an array but add a scalar shadowing shadow = conversion.dB2Linear( np.random.standard_normal() * self.sigma_shadow) PL += shadow # The calculated path loss (in dB) must be positive. If it is not # positive that means that the distance 'd' is too small. if np.any(np.array(PL) < 0): if self.handle_small_distances_bool is True: if isinstance(PL, Iterable): # If PL is the path loss for multiple distance values # and one (or more) of the path loss values is (are) # negative, set them to to zero (no path loss). PL[PL < 0] = 0.0 else: # If PL is the path loss for a single distance value # and it is negative (the distance is too small), let's # assume the path loss is equal to 0dB PL = 0.0 else: msg = ("The distance is too small to calculate a valid" " path loss.") raise RuntimeError(msg.format(d)) return PL
def _calcTheoreticalSingleCarrierErrorRate(self, SNR): """ Calculates the theoretical (approximation) error rate of a single carrier in the QAM system (QAM has two carriers). Parameters ---------- SNR : float | np.ndarray Signal-to-noise-value (in dB). Returns ------- Psc : float | np.ndarray The theoretical single carrier error rate. Notes ----- This method is used in the :meth:`calcTheoreticalSER` implementation. See also -------- calcTheoreticalSER """ snr = dB2Linear(SNR) # Probability of error of each carrier in a square QAM # $P_{sc} = 2\left(1 - \frac{1}{\sqrt M}\right)Q\left(\sqrt{\frac{3}{M-1}\frac{E_s}{N_0}}\right)$ sqrtM = np.sqrt(self._M) Psc = (2. * (1. - (1. / sqrtM)) * qfunc(np.sqrt(snr * 3. / (self._M - 1.)))) return Psc
def _calc_transmit_power(SNR_dB, noise_var, path_loss=1.0): """ 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) noise_var : float Noise variance path_loss : float Path loss (in linear scale) to consider in the transmit power calculation. The case without considering path loss corresponds to path_loss=1. Returns ------- transmit_power : float Desired transmit power (in linear scale). """ snr = dB2Linear(SNR_dB) pt = snr * noise_var / path_loss return pt
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 simulate_for_a_given_ap_assoc(pl, ap_assoc, wall_losses_dB, Pt, noise_var): """ Simulate and return the SINR for a given path loss and AP associations. This is an internal function called inside `perform_simulation_SINR_heatmap` Parameters ---------- pl : 5D numpy float array The path loss (in LINEAR SCALE) from each discrete position in each room to each access point. Dimension: (n, n, d, d, a) where 'n' is the number of rooms per dimension, 'd' is the number of discrete positions in one room (per dimension) and 'a' is the number of access points. ap_assoc : 4D numpy int array The index of the access point that each discrete point in each room is associated with. Dimension: (n, n, d, d) wall_losses_dB : 5D numpy int array The wall losses (in dB) from each discrete user in each room to each access point. Dimension: (n, n, d, d, a) Pt : float Transmit power. noise_var : float Noise variance (power) Returns ------- sinr_array_dB : 4D numpy array The SINR (in dB) of each discrete point of each room. """ wall_losses = dB2Linear(-wall_losses_dB) # Number of APs is the last dimension in the path loss array num_aps = pl.shape[-1] # Output variable sinr_array = np.empty(ap_assoc.shape, dtype=float) for ap_idx in range(num_aps): # Mask of the users associated with the current access point mask = (ap_assoc == ap_idx) # # Mask of the users NOT associated with the current access point # mask_n = np.logical_not(mask) # Mask with all APs except the current one (that is, the # interfering APs) mask_i_aps = np.arange(num_aps) != ap_idx # Each element in desired_power is the desired power of one user # associated with the current access point desired_power = Pt * wall_losses[mask, ap_idx] * pl[mask, ap_idx] undesired_power = np.sum(Pt * wall_losses[mask][:, mask_i_aps] * pl[mask][:, mask_i_aps], axis=-1) sinr_array[mask] = (desired_power / (undesired_power + noise_var)) return linear2dB(sinr_array)
def simulate_and_compute_Rxx_U0(M, N, SNR, beam_sep): """ Simulate and generate Rxx and U0 considering that three wavefronts were sent. M : int N : int SNR : float beam_sep : float Normalized beamwidth separation between the wavefronts. This separation is normalized by the beamwidth. """ qpsk = modulators.QPSK() d = 3 # Number of inpinging waves mu_b = 2 * np.pi / M mu = np.array([-beam_sep * mu_b, 0, beam_sep * mu_b]) # Standard beamwidth data = np.random.randint(4, size=(d, N)) modulated_data = qpsk.modulate(data) / sqrt(d) noise_power = 1. / dB2Linear(SNR) noise = sqrt(noise_power) * randn_c(M, N) steering_vec = calc_a_phi_vect(M, mu) received_data = steering_vec @ modulated_data + noise # Covariance matrix of the received Data Rxx = received_data @ received_data.T.conj() U, S, V_H = np.linalg.svd(Rxx) U0 = U[:, d:] return Rxx, U0
def simulate_for_a_given_ap_assoc(pl, ap_assoc, wall_losses_dB, Pt, noise_var): """ Simulate and return the SINR for a given path loss and AP associations. This is an internal function called inside `perform_simulation_SINR_heatmap` Parameters ---------- pl : 5D numpy float array The path loss (in LINEAR SCALE) from each discrete position in each room to each access point. Dimension: (n, n, d, d, a) where 'n' is the number of rooms per dimension, 'd' is the number of discrete positions in one room (per dimension) and 'a' is the number of access points. ap_assoc : 4D numpy int array The index of the access point that each discrete point in each room is associated with. Dimension: (n, n, d, d) wall_losses_dB : 5D numpy int array The wall losses (in dB) from each discrete user in each room to each access point. Dimension: (n, n, d, d, a) Pt : float Transmit power. noise_var : float Noise variance (power) Returns ------- sinr_array_dB : 4D numpy array The SINR (in dB) of each discrete point of each room. """ wall_losses = dB2Linear(-wall_losses_dB) # Number of APs is the last dimension in the path loss array num_aps = pl.shape[-1] # Output variable sinr_array = np.empty(ap_assoc.shape, dtype=float) for ap_idx in range(num_aps): # Mask of the users associated with the current access point mask = ap_assoc == ap_idx # # Mask of the users NOT associated with the current access point # mask_n = np.logical_not(mask) # Mask with all APs except the current one (that is, the # interfering APs) mask_i_aps = np.arange(num_aps) != ap_idx # Each element in desired_power is the desired power of one user # associated with the current access point desired_power = Pt * wall_losses[mask, ap_idx] * pl[mask, ap_idx] undesired_power = np.sum(Pt * wall_losses[mask][:, mask_i_aps] * pl[mask][:, mask_i_aps], axis=-1) sinr_array[mask] = desired_power / (undesired_power + noise_var) return linear2dB(sinr_array)
def test_calc_effective_throughput(self): psk_obj = fundamental.PSK(8) packet_length = 60 SINRs_dB = np.array([11.4, 20.3]) sinrs_linear = dB2Linear(SINRs_dB) expected_spectral_efficiency = np.sum( psk_obj.calcTheoreticalSpectralEfficiency(SINRs_dB, packet_length)) spectral_efficiency = blockdiagonalization._calc_effective_throughput( sinrs_linear, psk_obj, packet_length) np.testing.assert_array_almost_equal(spectral_efficiency, expected_spectral_efficiency)
def calc_path_loss(self, d, **kargs): """ Calculates the path loss (linear scale) for a given distance (in Km). Parameters ---------- d : float or numpy array Distance (in Km) kargs : dict Additional keywords that might be necessary in a subclass. Returns ------- pl : float or numpy array Path loss (in linear scale) for the given distance(s). """ pl = conversion.dB2Linear(-self.calc_path_loss_dB(d)) return pl
def calcTheoreticalSER(self, SNR): """Calculates the theoretical (approximation) symbol error rate for the BPSK scheme. Parameters ---------- SNR : float or array like Signal-to-noise-value (in dB). Returns ------- SER : float or array like The theoretical symbol error rate. """ snr = dB2Linear(SNR) # $P_b = Q\left(\sqrt{\frac{2E_b}{N_0}}\right)$ # Alternative formula (same result) # $P_b = \frac{1}{2}erfc \left ( \sqrt{\frac{E_b}{N_0}} \right )$ ser = qfunc(np.sqrt(2 * snr)) return ser
def calcTheoreticalSER(self, SNR): """ Calculates the theoretical (approximation) symbol error rate for the BPSK scheme. Parameters ---------- SNR : float | np.ndarray Signal-to-noise-value (in dB). Returns ------- SER : float | np.ndarray The theoretical symbol error rate. """ snr = dB2Linear(SNR) # $P_b = Q\left(\sqrt{\frac{2E_b}{N_0}}\right)$ # Alternative formula (same result) # $P_b = \frac{1}{2}erfc \left ( \sqrt{\frac{E_b}{N_0}} \right )$ ser = qfunc(np.sqrt(2 * snr)) return ser
def calcTheoreticalSER(self, SNR): """Calculates the theoretical (approximation for high M and high SNR) symbol error rate for the M-PSK scheme. Parameters ---------- SNR : float | np.ndarray Signal-to-noise-value (in dB). Returns ------- SER : float | np.ndarray The theoretical symbol error rate. """ snr = dB2Linear(SNR) # $P_s \approx 2Q\left(\sqrt{2\gamma_s}\sin\frac{\pi}{M}\right)$ # Alternative formula (same result) # $P_s = erfc \left ( \sqrt{\gamma_s} \sin(\frac{\pi}{M}) \right )$ ser = 2. * qfunc(np.sqrt(2. * snr) * math.sin(PI / self._M)) return ser
def calc_path_loss(self, d, **kargs): # pragma: no cover """ Calculates the path loss (linear scale) for a given distance (in Km). Parameters ---------- d : float or numpy array Distance (in Km) kargs : dict Extra named parameters. This is used in subclasses for extra parameters for the path loss calculation. Other Parameters ---------------- kwargs : dict Additional keywords that might be necessary in a subclass. Returns ------- pl : float or numpy array Path loss (in linear scale) for the given distance(s). """ pl = conversion.dB2Linear(-self.calc_path_loss_dB(d, **kargs)) return pl
def _run_simulation(self, current_parameters): # To make sure that this function does not modify the object state, # we sobrescibe self to None. #self = None # xxxxx Input parameters (set in the constructor) xxxxxxxxxxxxxxxxx NSymbs = current_parameters["NSymbs"] M = current_parameters["M"] SNR = current_parameters["SNR"] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Input Data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx inputData = np.random.randint(0, M, NSymbs) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Modulate input data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx modulatedData = self.modulator.modulate(inputData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Pass through the channel xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx noiseVar = 1 / dB2Linear(SNR) noise = ((np.random.standard_normal(NSymbs) + 1j * np.random.standard_normal(NSymbs)) * np.sqrt(noiseVar / 2)) receivedData = modulatedData + noise # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Demodulate received data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx demodulatedData = self.modulator.demodulate(receivedData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Calculates the symbol and bit error rates xxxxxxxxxxxxxxxxx symbolErrors = sum(inputData != demodulatedData) bitErrors = misc.count_bit_errors(inputData, demodulatedData) numSymbols = inputData.size numBits = inputData.size * mod.level2bits(M) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Return the simulation results xxxxxxxxxxxxxxxxxxxxxxxxxxxxx symbolErrorsResult = Result.create( "symbol_errors", Result.SUMTYPE, symbolErrors) numSymbolsResult = Result.create( "num_symbols", Result.SUMTYPE, numSymbols) bitErrorsResult = Result.create("bit_errors", Result.SUMTYPE, bitErrors) numBitsResult = Result.create("num_bits", Result.SUMTYPE, numBits) berResult = Result.create("ber", Result.RATIOTYPE, bitErrors, numBits) serResult = Result.create( "ser", Result.RATIOTYPE, symbolErrors, numSymbols) simResults = SimulationResults() simResults.add_result(symbolErrorsResult) simResults.add_result(numSymbolsResult) simResults.add_result(bitErrorsResult) simResults.add_result(numBitsResult) simResults.add_result(berResult) simResults.add_result(serResult) return simResults
# 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 cell_ids = np.arange(1, num_cells + 1)
codebook_size = 5 dimension = 4 C = gen_codebook(codebook_size, dimension) Nt = 2 Nr = 2 K = 3 H = misc.randn_c(Nr * K, Nt * K) Hquant = my_quant_func(H, Nr, Nt, K, C) if __name__ == '__main__': SNR = 15.0 noise_var = 1 / dB2Linear(SNR) M = 2 NSymbs = 50 rep_max = 300 modulator = fundamental.BPSK() K = 3 Nr = np.ones(K, dtype=int) * 2 Nt = np.ones(K, dtype=int) * 2 Ns = np.ones(K, dtype=int) * 1 multi_user_channel = pyphysim.channels.multiuser.MultiUserChannelMatrix() multi_user_channel_quant = pyphysim.channels.multiuser.MultiUserChannelMatrix() multi_user_channel.noise_var = noise_var multi_user_channel_quant.noise_var = noise_var ia_solver = algorithms.MaxSinrIASolver(multi_user_channel_quant) ia_solver.max_iterations = 120
def test_dB2Linear(self): self.assertAlmostEqual(conversion.dB2Linear(30), 1000.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
from pyphysim.channels.multiuser import MultiUserChannelMatrix from pyphysim.ia import algorithms from pyphysim.modulators.fundamental import PSK from pyphysim.util.conversion import dB2Linear if __name__ == '__main__': K = 3 Nr = np.ones(K) * 4 Nt = np.ones(K) * 4 Ns = np.array([2, 2, 2]) # np.ones(K) * 2 multiuserchannel = MultiUserChannelMatrix() modulator = PSK(4) SNR = 40 noise_var = 1 / dB2Linear(SNR) print("SNR: {0}".format(SNR)) print("noise_var: {0}".format(noise_var)) multiuserchannel.randomize(Nr, Nt, K) multiuserchannel.noise_var = noise_var ia_solver = algorithms.AlternatingMinIASolver(multiuserchannel) ia_solver2 = algorithms.MMSEIASolver(multiuserchannel) ia_solver3 = algorithms.MaxSinrIASolver(multiuserchannel) ia_solver4 = algorithms.AlternatingMinIASolver(multiuserchannel) # ia_solver.initialize_with_closed_form = True # ia_solver2.initialize_with_closed_form = True # ia_solver3.initialize_with_closed_form = True
def main(): """Main function. """ K = 3 Nr = 4 Nt = 4 Ns = 2 SNR = 30.0 P = 1.0 # Dependent parameters noise_var = 1 / dB2Linear(SNR) RepMax = 1 mmse_sinrs = np.empty([RepMax, K, Ns], dtype=float) max_sinr_sinrs = np.empty([RepMax, K, Ns], dtype=float) mmse_capacity = np.empty(RepMax, dtype=float) max_sinr_capacity = np.empty(RepMax, dtype=float) pbar = ProgressbarText(RepMax, message="Simulating for SNR: {0}".format(SNR)) for rep in range(RepMax): # Creat the channel multiUserChannel = pyphysim.channels.multiuser.MultiUserChannelMatrix() multiUserChannel.randomize(Nr, Nt, K) multiUserChannel.noise_var = noise_var # Creat the IA solver object mmse_ia_solver = algorithms.MMSEIASolver(multiUserChannel) max_sinr_ia_solver = algorithms.MaxSinrIASolver(multiUserChannel) mmse_ia_solver.randomizeF(Ns, P) mmse_ia_solver.initialize_with = "fix" max_sinr_ia_solver.initialize_with = "fix" # noinspection PyProtectedMember max_sinr_ia_solver._F = mmse_ia_solver._F # mmse_ia_solver.initialize_with = 'fix' # We wouldn't need to explicitly set ia_solver.noise_var # variable if the multiUserChannel object had the correct value at # this point. # mmse_ia_solver.noise_var = noise_var mmse_ia_solver.max_iterations = 200 mmse_ia_solver.solve(Ns) # max_sinr_ia_solver.noise_var = noise_var max_sinr_ia_solver.max_iterations = 200 max_sinr_ia_solver.solve(Ns) mmse_sinrs[rep] = list(map(linear2dB, mmse_ia_solver.calc_SINR())) max_sinr_sinrs[rep] = list(map(linear2dB, max_sinr_ia_solver.calc_SINR())) mmse_capacity[rep] = np.sum(calc_capacity(mmse_ia_solver.calc_SINR())) max_sinr_capacity[rep] = np.sum(calc_capacity(max_sinr_ia_solver.calc_SINR())) # print "MMSE Alt. SINRs:\n{0}".format(np.vstack(mmse_sinrs[rep])) # print "Max SINR Alg. SINRs:\n{0}".format(np.vstack(max_sinr_sinrs[rep])) # print "MMSE Alt. Capacity: {0}".format(np.sum(calc_capacity(mmse_sinrs[rep]))) # print "Max SINR Alg. Capacity: {0}".format(np.sum(calc_capacity(max_sinr_sinrs[rep]))) # print pbar.progress(rep) print("MMSE Average SINRs:\n{0}".format(mmse_sinrs.mean(0))) print("Max SINR Average SINRs:\n{0}".format(max_sinr_sinrs.mean(0))) print("MMSE Average Capacity: {0}".format(mmse_capacity.mean())) print("Max SINR Average Capacity: {0}".format(max_sinr_capacity.mean())) print("\nEnd!")
def _run_simulation(self, current_parameters): """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. """ # xxxxx Input parameters (set in the constructor) xxxxxxxxxxxxxxxxx NSymbs = current_parameters['NSymbs'] modulator = current_parameters['modulator'] M = modulator.M SNR = current_parameters["SNR"] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Input Data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx inputData = np.random.randint(0, M, NSymbs) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Modulate input data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx modulatedData = modulator.modulate(inputData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Pass through the channel xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx noiseVar = 1. / dB2Linear(SNR) noise = misc.randn_c(NSymbs) * np.sqrt(noiseVar) receivedData = modulatedData + noise # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Demodulate received data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx demodulatedData = modulator.demodulate(receivedData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Calculates the symbol and bit error rates xxxxxxxxxxxxxxxxx symbolErrors = sum(inputData != demodulatedData) bitErrors = misc.count_bit_errors(inputData, demodulatedData) numSymbols = inputData.size numBits = inputData.size * fundamental.level2bits(M) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Return the simulation results xxxxxxxxxxxxxxxxxxxxxxxxxxxxx symbolErrorsResult = Result.create( "symbol_errors", Result.SUMTYPE, symbolErrors) numSymbolsResult = Result.create( "num_symbols", Result.SUMTYPE, numSymbols) bitErrorsResult = Result.create( "bit_errors", Result.SUMTYPE, bitErrors) numBitsResult = Result.create("num_bits", Result.SUMTYPE, numBits) berResult = Result.create("ber", Result.RATIOTYPE, bitErrors, numBits) serResult = Result.create( "ser", Result.RATIOTYPE, symbolErrors, numSymbols) simResults = SimulationResults() simResults.add_result(symbolErrorsResult) simResults.add_result(numSymbolsResult) simResults.add_result(bitErrorsResult) simResults.add_result(numBitsResult) simResults.add_result(berResult) simResults.add_result(serResult) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx return simResults
def _run_simulation(self, current_parameters): # xxxxx Input parameters (set in the constructor) xxxxxxxxxxxxxxxxx NSymbs = current_parameters["NSymbs"] M = self.modulator.M Nr = current_parameters["Nr"] Nt = current_parameters["Nt"] SNR = current_parameters["SNR"] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Create the channel xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx channel = misc.randn_c(Nr, Nt) self.mimo_object.set_channel_matrix(channel) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Input Data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx num_layers = self.mimo_object.getNumberOfLayers() inputData = np.random.randint(0, M, NSymbs * num_layers) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Modulate input data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx modulatedData = self.modulator.modulate(inputData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Encode with the MIMO scheme xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx transmit_signal = self.mimo_object.encode(modulatedData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Pass through the channel xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx noiseVar = 1 / dB2Linear(SNR) awgn_noise = (misc.randn_c(Nr, NSymbs) * np.sqrt(noiseVar)) received_signal = np.dot(channel, transmit_signal) + awgn_noise # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Decode with the MIMO Scheme xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx mimo_decoded_data = self.mimo_object.decode(received_signal) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Demodulate received data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx demodulatedData = self.modulator.demodulate(mimo_decoded_data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Calculates the symbol and bit error rates xxxxxxxxxxxxxxxxx symbolErrors = sum(inputData != demodulatedData) bitErrors = misc.count_bit_errors(inputData, demodulatedData) numSymbols = inputData.size numBits = inputData.size * fundamental.level2bits(M) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Return the simulation results xxxxxxxxxxxxxxxxxxxxxxxxxxxxx symbolErrorsResult = Result.create( "symbol_errors", Result.SUMTYPE, symbolErrors) numSymbolsResult = Result.create( "num_symbols", Result.SUMTYPE, numSymbols) bitErrorsResult = Result.create("bit_errors", Result.SUMTYPE, bitErrors) numBitsResult = Result.create("num_bits", Result.SUMTYPE, numBits) berResult = Result.create("ber", Result.RATIOTYPE, bitErrors, numBits) serResult = Result.create( "ser", Result.RATIOTYPE, symbolErrors, numSymbols) simResults = SimulationResults() simResults.add_result(symbolErrorsResult) simResults.add_result(numSymbolsResult) simResults.add_result(bitErrorsResult) simResults.add_result(numBitsResult) simResults.add_result(berResult) simResults.add_result(serResult) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx return simResults
def _run_simulation(self, current_parameters): # To make sure that this function does not modify the object state, # we sobrescibe self to None. #self = None # xxxxx Input parameters (set in the constructor) xxxxxxxxxxxxxxxxx NSymbs = current_parameters["NSymbs"] M = current_parameters["M"] SNR = current_parameters["SNR"] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Input Data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx inputData = np.random.randint(0, M, NSymbs) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Modulate input data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx modulatedData = self.modulator.modulate(inputData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Pass through the channel xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx noiseVar = 1 / dB2Linear(SNR) noise = ((np.random.standard_normal(NSymbs) + 1j * np.random.standard_normal(NSymbs)) * np.sqrt(noiseVar / 2)) receivedData = modulatedData + noise # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Demodulate received data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx demodulatedData = self.modulator.demodulate(receivedData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Calculates the symbol and bit error rates xxxxxxxxxxxxxxxxx symbolErrors = sum(inputData != demodulatedData) bitErrors = misc.count_bit_errors(inputData, demodulatedData) numSymbols = inputData.size numBits = inputData.size * mod.level2bits(M) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Return the simulation results xxxxxxxxxxxxxxxxxxxxxxxxxxxxx symbolErrorsResult = Result.create("symbol_errors", Result.SUMTYPE, symbolErrors) numSymbolsResult = Result.create("num_symbols", Result.SUMTYPE, numSymbols) bitErrorsResult = Result.create("bit_errors", Result.SUMTYPE, bitErrors) numBitsResult = Result.create("num_bits", Result.SUMTYPE, numBits) berResult = Result.create("ber", Result.RATIOTYPE, bitErrors, numBits) serResult = Result.create("ser", Result.RATIOTYPE, symbolErrors, numSymbols) simResults = SimulationResults() simResults.add_result(symbolErrorsResult) simResults.add_result(numSymbolsResult) simResults.add_result(bitErrorsResult) simResults.add_result(numBitsResult) simResults.add_result(berResult) simResults.add_result(serResult) return simResults
def _run_simulation(self, # pylint: disable=R0914,R0915 current_parameters): # xxxxx Input parameters (set in the constructor) xxxxxxxxxxxxxxxxx M = self.modulator.M NSymbs = current_parameters["NSymbs"] K = current_parameters["K"] Nr = current_parameters["Nr"] Nt = current_parameters["Nt"] Ns = current_parameters["Ns"] SNR = current_parameters["SNR"] # Dependent parameters noise_var = 1 / dB2Linear(SNR) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Calc. precoders and receive filters for IA xxxxxxxxxxxxxxxx # We need to perform IA before generating any data so that we know # how many streams we need to send (and thus generate data. Note # that it is not always equal to Ns. It can be lower for some user # if the IA algorithm chooses a precoder that sends zero energy in # some stream. self.multiUserChannel.randomize(Nr, Nt, K) self.multiUserChannel.noise_var = noise_var self.ia_solver.clear() self.ia_solver.solve(Ns) # If any of the Nr, Nt or Ns variables were integers (meaning all # users have the same value) we will convert them by numpy arrays # with correct size (K). # Nr = self.ia_solver.Nr # Nt = self.ia_solver.Nt Ns = self.ia_solver.Ns cumNs = np.cumsum(self.ia_solver.Ns) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Input Data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # inputData has the data of all users (vertically stacked) inputData = np.random.randint(0, M, [np.sum(Ns), NSymbs]) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Modulate input data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # modulatedData has the data of all users (vertically stacked) modulatedData = self.modulator.modulate(inputData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Perform the Interference Alignment xxxxxxxxxxxxxxxxxxx # Split the data. transmit_signal will be a list and each element # is a numpy array with the data of a user transmit_signal = np.split(modulatedData, cumNs[:-1]) transmit_signal_precoded = map( np.dot, self.ia_solver.full_F, transmit_signal) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Pass through the channel xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # noinspection PyProtectedMember multi_user_channel = self.ia_solver._multiUserChannel # received_data is an array of matrices, one matrix for each receiver. received_data = multi_user_channel.corrupt_data( transmit_signal_precoded) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Perform the Interference Cancellation xxxxxxxxxxxxxxxxxxxxx received_data_no_interference = map( np.dot, self.ia_solver.full_W_H, received_data) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Demodulate Data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx received_data_no_interference = np.vstack( received_data_no_interference) demodulated_data = self.modulator.demodulate( received_data_no_interference) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Calculates the symbol and bit error rates xxxxxxxxxxxxxxxxx symbolErrors = np.sum(inputData != demodulated_data) bitErrors = misc.count_bit_errors(inputData, demodulated_data) numSymbols = inputData.size numBits = inputData.size * fundamental.level2bits(M) ia_cost = self.ia_solver.get_cost() # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Calculates the Sum Capacity xxxxxxxxxxxxxxxxxxxxxxxxxx sirn_all_k = self.ia_solver.calc_SINR() calc_capacity = lambda sirn: np.sum(np.log2(1 + sirn)) # Array with the sum capacity of each user sum_capacity = np.array(list(map(calc_capacity, sirn_all_k))) # Total sum capacity total_sum_capacity = np.sum(sum_capacity) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxx Number of iterations of the IA algorithm xxxxxxxxxxxxx ia_runned_iterations = self.ia_solver.runned_iterations # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Return the simulation results xxxxxxxxxxxxxxxxxxxxxxxxxxxxx symbolErrorsResult = Result.create( "symbol_errors", Result.SUMTYPE, symbolErrors) numSymbolsResult = Result.create( "num_symbols", Result.SUMTYPE, numSymbols) bitErrorsResult = Result.create( "bit_errors", Result.SUMTYPE, bitErrors) numBitsResult = Result.create("num_bits", Result.SUMTYPE, numBits) berResult = Result.create("ber", Result.RATIOTYPE, bitErrors, numBits, accumulate_values=False) serResult = Result.create("ser", Result.RATIOTYPE, symbolErrors, numSymbols, accumulate_values=False) ia_costResult = Result.create( "ia_cost", Result.RATIOTYPE, ia_cost, 1, accumulate_values=False) sum_capacityResult = Result.create( "sum_capacity", Result.RATIOTYPE, total_sum_capacity, 1, accumulate_values=False) ia_runned_iterationsResult = Result.create( "ia_runned_iterations", Result.RATIOTYPE, ia_runned_iterations, 1, accumulate_values=False) simResults = SimulationResults() simResults.add_result(symbolErrorsResult) simResults.add_result(numSymbolsResult) simResults.add_result(bitErrorsResult) simResults.add_result(numBitsResult) simResults.add_result(berResult) simResults.add_result(serResult) simResults.add_result(ia_costResult) simResults.add_result(sum_capacityResult) simResults.add_result(ia_runned_iterationsResult) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx return simResults
def _run_simulation(self, current_parameters): """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. """ # xxxxx Input parameters (set in the constructor) xxxxxxxxxxxxxxxxx NSymbs = current_parameters['NSymbs'] modulator = current_parameters['modulator'] M = modulator.M SNR = current_parameters["SNR"] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Input Data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx inputData = np.random.randint(0, M, NSymbs) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Modulate input data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx modulatedData = modulator.modulate(inputData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Pass through the channel xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx noiseVar = 1. / dB2Linear(SNR) noise = misc.randn_c(NSymbs) * np.sqrt(noiseVar) receivedData = modulatedData + noise # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Demodulate received data xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx demodulatedData = modulator.demodulate(receivedData) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Calculates the symbol and bit error rates xxxxxxxxxxxxxxxxx symbolErrors = sum(inputData != demodulatedData) bitErrors = misc.count_bit_errors(inputData, demodulatedData) numSymbols = inputData.size numBits = inputData.size * fundamental.level2bits(M) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Return the simulation results xxxxxxxxxxxxxxxxxxxxxxxxxxxxx symbolErrorsResult = Result.create("symbol_errors", Result.SUMTYPE, symbolErrors) numSymbolsResult = Result.create("num_symbols", Result.SUMTYPE, numSymbols) bitErrorsResult = Result.create("bit_errors", Result.SUMTYPE, bitErrors) numBitsResult = Result.create("num_bits", Result.SUMTYPE, numBits) berResult = Result.create("ber", Result.RATIOTYPE, bitErrors, numBits) serResult = Result.create("ser", Result.RATIOTYPE, symbolErrors, numSymbols) simResults = SimulationResults() simResults.add_result(symbolErrorsResult) simResults.add_result(numSymbolsResult) simResults.add_result(bitErrorsResult) simResults.add_result(numBitsResult) simResults.add_result(berResult) simResults.add_result(serResult) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx return simResults
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 cell_ids = np.arange(1, num_cells + 1)
def main(): """Main function. """ K = 3 Nr = 4 Nt = 4 Ns = 2 SNR = 30.0 P = 1.0 # Dependent parameters noise_var = 1 / dB2Linear(SNR) RepMax = 1 mmse_sinrs = np.empty([RepMax, K, Ns], dtype=float) max_sinr_sinrs = np.empty([RepMax, K, Ns], dtype=float) mmse_capacity = np.empty(RepMax, dtype=float) max_sinr_capacity = np.empty(RepMax, dtype=float) pbar = ProgressbarText(RepMax, message="Simulating for SNR: {0}".format(SNR)) for rep in range(RepMax): # Creat the channel multiUserChannel = pyphysim.channels.multiuser.MultiUserChannelMatrix() multiUserChannel.randomize(Nr, Nt, K) multiUserChannel.noise_var = noise_var # Creat the IA solver object mmse_ia_solver = algorithms.MMSEIASolver(multiUserChannel) max_sinr_ia_solver = algorithms.MaxSinrIASolver(multiUserChannel) mmse_ia_solver.randomizeF(Ns, P) mmse_ia_solver.initialize_with = 'fix' max_sinr_ia_solver.initialize_with = 'fix' # noinspection PyProtectedMember max_sinr_ia_solver._F = mmse_ia_solver._F #mmse_ia_solver.initialize_with = 'fix' # We wouldn't need to explicitly set ia_solver.noise_var # variable if the multiUserChannel object had the correct value at # this point. # mmse_ia_solver.noise_var = noise_var mmse_ia_solver.max_iterations = 200 mmse_ia_solver.solve(Ns) # max_sinr_ia_solver.noise_var = noise_var max_sinr_ia_solver.max_iterations = 200 max_sinr_ia_solver.solve(Ns) mmse_sinrs[rep] = list(map(linear2dB, mmse_ia_solver.calc_SINR())) max_sinr_sinrs[rep] = list(map(linear2dB, max_sinr_ia_solver.calc_SINR())) mmse_capacity[rep] = np.sum(calc_capacity(mmse_ia_solver.calc_SINR())) max_sinr_capacity[rep] = np.sum(calc_capacity(max_sinr_ia_solver.calc_SINR())) # print "MMSE Alt. SINRs:\n{0}".format(np.vstack(mmse_sinrs[rep])) # print "Max SINR Alg. SINRs:\n{0}".format(np.vstack(max_sinr_sinrs[rep])) # print "MMSE Alt. Capacity: {0}".format(np.sum(calc_capacity(mmse_sinrs[rep]))) # print "Max SINR Alg. Capacity: {0}".format(np.sum(calc_capacity(max_sinr_sinrs[rep]))) # print pbar.progress(rep) print("MMSE Average SINRs:\n{0}".format(mmse_sinrs.mean(0))) print("Max SINR Average SINRs:\n{0}".format(max_sinr_sinrs.mean(0))) print("MMSE Average Capacity: {0}".format(mmse_capacity.mean())) print("Max SINR Average Capacity: {0}".format(max_sinr_capacity.mean())) print("\nEnd!")
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