run_scenario.py 6.68 KB
Newer Older
 Lukas Eller's avatar
Lukas Eller committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
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()