throughput_model.py 3.9 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
import numpy as np
import tensorflow as tf
from helpers import mappings
from helpers.utils import logsumexp10

class ThroughputModel():
    def __init__(self, resource_blocks=100, resource_block_bw=180e3, noise_level=-120.0, demand="medium"):
        self._noise_level = noise_level
        self._resource_blocks = resource_blocks
        self._resource_block_bw = resource_block_bw

        self._act_ues_mapping = mappings.Active_UEs_from_Connected(demand=demand)
        self._cell_load_mapping = mappings.Cell_Load_from_Active_UEs()
        self._cqi_mapping = mappings.CQI_from_SINR()
        self._spectral_efficiency_mapping =  mappings.Spectral_Efficiency_from_CQI()

    @tf.function
    def get_cell_assignment(self, R_matrix, softmax_temperature=3):
        R_sorted = tf.cast(tf.sort(R_matrix, axis=1), tf.float32)
        R_max = R_sorted[:, -1]
        delta_R = tf.reshape(R_max, (-1, 1)) - R_matrix
        soft_assignment = tf.math.softmax(-delta_R / softmax_temperature)

        return soft_assignment

    @tf.function
    def get_act_ues(self, number_ues_soft):
        return self._act_ues_mapping.map(number_ues_soft)

    @tf.function
    def get_cell_load(self, number_ues_soft):
        return self._cell_load_mapping.map(number_ues_soft)

    @tf.function
    def get_SINR_matrix(self, R_matrix, cell_load_vector):
        I_matrix = []
        for j in range(R_matrix.shape[1]):
            indices = list(range(R_matrix.shape[1]))
            indices.remove(j)

            relevant_interferers = tf.gather(R_matrix, indices, axis=1)
            relevant_cell_load = tf.gather(cell_load_vector, indices)

            noise_vector = tf.fill((relevant_interferers.shape[0], 1), tf.cast(self._noise_level, tf.float32))

            additive_terms = tf.concat((relevant_interferers, noise_vector), axis=1)
            scaling_factors = tf.concat((relevant_cell_load, tf.constant([1.], dtype=tf.float32)), axis=0)

            I_matrix.append(
                logsumexp10(additive_terms, alpha=scaling_factors)
            )

        SINR_matrix = R_matrix - tf.cast(tf.stack(I_matrix, axis=1), tf.float32)

        return SINR_matrix

    @tf.function
    def get_achievable_throughput(self, SINR_matrix):
        cqi_matrix = self._cqi_mapping.map(tf.reshape(SINR_matrix, (-1,)))
        achievable_throughput_matrix = tf.cast(
            self._resource_block_bw * self._spectral_efficiency_mapping.map(cqi_matrix), tf.float32
        )
        achievable_throughput_matrix = tf.reshape(achievable_throughput_matrix, SINR_matrix.shape)

        return achievable_throughput_matrix

    @tf.function
    def __call__(self, R_matrix, extended=False):
        soft_assignment_matrix = self.get_cell_assignment(R_matrix)
        connected_UEs_vector = tf.reduce_sum(soft_assignment_matrix, axis=0)

        #Compute the number of active UEs and the cell load
        active_UEs_vector = self.get_act_ues(connected_UEs_vector)
        cell_load_vector = self.get_cell_load(active_UEs_vector)

        #Compute the SINR and subsequently the RATE
        SINR_matrix = self.get_SINR_matrix(R_matrix, cell_load_vector)
        achievable_throughput_matrix = self.get_achievable_throughput(SINR_matrix)

        load_aware_throughput_vector = tf.reduce_sum(
            (self._resource_blocks / (active_UEs_vector + 1.0)) * soft_assignment_matrix * achievable_throughput_matrix, axis=1
        )

        #Compute the SINR and the theoretical empty cell rate per UE
        SINR_vector = tf.reduce_sum(soft_assignment_matrix * SINR_matrix, axis=1)
        load_unaware_throughput_vector = tf.reduce_sum(
            (self._resource_blocks / (1 + self.get_act_ues(R_matrix.shape[0] / R_matrix.shape[1])) ) * soft_assignment_matrix * achievable_throughput_matrix, axis=1
        )
        if extended:
            return load_aware_throughput_vector, load_unaware_throughput_vector, SINR_vector, connected_UEs_vector
        else:
            return load_aware_throughput_vector