from throughput_model import ThroughputModel from scipy import spatial import numpy as np import tensorflow as tf import matplotlib.pyplot as plt from tqdm import tqdm import pandas as pd import seaborn as sns import warnings import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' warnings.filterwarnings('ignore') def generate_scenario(N_Cells, N_UEs, pathloss_exponent=3): cell_positions = np.random.uniform(-1e3, 1e3, size=(N_Cells, 2)) user_positions = np.random.uniform(-1e3, 1e3, size=(N_UEs, 2)) distance_matrix = spatial.distance_matrix(user_positions, cell_positions) distance_matrix[distance_matrix < 1] = 1 PL_matrix = 10 * pathloss_exponent * np.log10(distance_matrix) return cell_positions, user_positions, PL_matrix ''' Generate a random network configuration, with simple distance based pathloss ''' if __name__ == "__main__": N_cells = 25 N_UEs = 1500 print(f"Generating random network deployment with {N_cells} cells and {N_UEs} users") cell_positions, user_positions, PL_matrix = generate_scenario(N_cells, N_UEs, pathloss_exponent=3) ''' Set the optimization parameters ''' p_min, p_max = -15, 15 #Minimum and maximum transmit power in dBm demand = "high" #Current level of demand for [low, medium, high] noise_level = -120.0 #Noise Level in dBm throughput_target = 10 #Lower Optimization Target in MBits ''' Start the transmit power optimization ''' throughput_model = ThroughputModel(resource_blocks=100, resource_block_bw=180e3, noise_level=noise_level, demand=demand) optimizer = tf.keras.optimizers.Adam(learning_rate=1e-2) gamma_latent = tf.Variable(np.random.uniform(0, 1, size=len(cell_positions)), dtype='float32') gamma = tf.math.sigmoid((gamma_latent - 0.5) * 10) loss_hist = [] throughput_shared_hist = [] throughput_violations_hist = [] sinr_hist = [] transmit_power_hist = [] connected_UEs_hist = [] for _ in tqdm(range(100), desc=f"Optimizing transmit power"): with tf.GradientTape() as tape: gamma = tf.math.sigmoid((gamma_latent - 0.5) * 10) p = p_min + gamma * (p_max - p_min) R_matrix = tf.cast(p - PL_matrix, tf.float32) throughput_shared, _, SINR, connected_UEs_vector = throughput_model(R_matrix, extended=True) throughput = throughput_shared throughput_violations = tf.math.sigmoid(throughput_target - throughput*1e-6) loss = tf.math.reduce_mean( throughput_violations ) grads = tape.gradient(loss, [gamma_latent]) optimizer.apply_gradients(zip(grads, [gamma_latent])) loss_hist.append(loss) throughput_shared_hist.append(throughput_shared.numpy()) throughput_violations_hist.append(throughput_violations.numpy()) sinr_hist.append(SINR.numpy()) transmit_power_hist.append(p.numpy()) connected_UEs_hist.append(connected_UEs_vector.numpy()) throughput_shared_hist = pd.DataFrame(throughput_shared_hist) plt.figure() plt.plot(loss_hist, label="Learning Curve") plt.ylabel("Ratio of throughput violations") plt.xlabel("Gradient descent iterations") plt.legend() plt.show() fig, (ax0, ax1) = plt.subplots(nrows=1, ncols=2, figsize=(14, 6)) fig.suptitle("Transmit Power Configuration --- Before and After Optimization") ax0.stem(transmit_power_hist[0], label="Transmit Power Configuration") ax0.set_ylim(p_min, p_max) ax0.set_title("Before Optimization") ax1.stem(transmit_power_hist[-1], label="Transmit Power Configuration") ax1.set_ylim(p_min, p_max) ax1.set_title("After Optimization") for ax in [ax0, ax1]: ax.set_xlabel("Cells") ax.set_ylabel("Transmit Power, [dBm]") plt.show() fig, (ax0, ax1) = plt.subplots(nrows=1, ncols=2, figsize=(14, 6)) fig.suptitle("Number of connected UEs per Cell --- Before and After Optimization") ax0.stem(connected_UEs_hist[0], label="Number of connected UEs") ax0.set_ylim(0, np.max(connected_UEs_hist[0]) * 1.1) ax0.set_title("Before Optimization") ax1.stem(connected_UEs_hist[-1], label="Number of connected UEs") ax1.set_ylim(0, np.max(connected_UEs_hist[0]) * 1.1) ax1.set_title("After Optimization") for ax in [ax0, ax1]: ax.set_xlabel("Cells") ax.set_ylabel("Number of connected UEs, [#]") plt.show() fig, (ax0, ax1) = plt.subplots(nrows=1, ncols=2, figsize=(14, 6)) fig.suptitle("Violated Throughput Target --- Before and After Optimization") clb = ax0.scatter(user_positions[:, 0], user_positions[:, 1], c=throughput_violations_hist[0], label="UE Positions", vmin=0, vmax=1) plt.colorbar(clb, label="Throughput Target Violations", shrink=0.85) ax0.scatter(cell_positions[:, 0], cell_positions[:, 1], color="red", label="Cell Positions") ax0.set_title("Before Optimization") clb = ax1.scatter(user_positions[:, 0], user_positions[:, 1], c=throughput_violations_hist[-1], label="UE Positions", vmin=0, vmax=1) plt.colorbar(clb, label="Throughput Target Violations", shrink=0.85) ax1.scatter(cell_positions[:, 0], cell_positions[:, 1], color="red", label="Cell Positions") ax1.set_title("After Optimization") for ax in [ax0, ax1]: ax.set_xlabel("x [m]") ax.set_ylabel("y [m]") ax.set_aspect("equal") plt.show() fig, (ax0, ax1) = plt.subplots(nrows=1, ncols=2, figsize=(14, 6)) fig.suptitle("Shared Throughput --- Before and After Optimization") clb = ax0.scatter(user_positions[:, 0], user_positions[:, 1], c=throughput_shared_hist.iloc[0]*1e-6, label="UE Positions", vmin=0, vmax=25) plt.colorbar(clb, label="UE Shared Throughput, [MBit/s]", shrink=0.85) ax0.scatter(cell_positions[:, 0], cell_positions[:, 1], color="red", label="Cell Positions") ax0.set_title("Before Optimization") clb = ax1.scatter(user_positions[:, 0], user_positions[:, 1], c=throughput_shared_hist.iloc[-1]*1e-6, label="UE Positions", vmin=0, vmax=25) plt.colorbar(clb, label="UE Shared Throughput, [MBit/s]", shrink=0.85) ax1.scatter(cell_positions[:, 0], cell_positions[:, 1], color="red", label="Cell Positions") ax1.set_title("After Optimization") for ax in [ax0, ax1]: ax.set_xlabel("x [m]") ax.set_ylabel("y [m]") ax.set_aspect("equal") plt.show() plt.figure() sns.ecdfplot(throughput_shared_hist.iloc[0]*1e-6, label="Before Optimization") sns.ecdfplot(throughput_shared_hist.iloc[-1]*1e-6, label="After Optimization") plt.vlines(throughput_target, 0, 1, label="Threshold", linestyles="dashed", color="gray") plt.legend() plt.xlabel("UE Shared Throughput, [MBit/s]") plt.ylabel("ECDF") plt.show()