Скачиваний:
0
Добавлен:
04.05.2025
Размер:
1.63 Mб
Скачать

ГУАП

КАФЕДРА № 41

ОТЧЕТ ЗАЩИЩЕН С ОЦЕНКОЙ

ПРЕПОДАВАТЕЛЬ

старший преподаватель

Н.В. Апанасенко

должность, уч. степень, звание

подпись, дата

инициалы, фамилия

ОТЧЕТ О ЛАБОРАТОРНОЙ РАБОТЕ №2

СТРАТЕГИИ РАСПРЕДЕЛЕНИЯ РЕСУРСНЫХ БЛОКОВ В ЦЕНТРАЛИЗОВАННОЙ СЕТИ СО СЛУЧАЙНЫМ ТРАФИКОМ

по курсу: МОДЕЛИРОВАНИЕ СИСТЕМ РАСПРЕДЕЛЕНИЯ РЕСУРСОВ

РАБОТУ ВЫПОЛНИЛ

СТУДЕНТ гр. №

подпись, дата

инициалы, фамилия

Санкт-Петербург 2025

Цель работы: получение навыков моделирования стандартных сценариев работы телекоммуникационных систем с топологией типа «звезда». Изучение свойств алгоритмов планирования ресурсов нисходящего кадра в подобных системах. Изучение стратегий распределения ресурсных блоков в централизованной сети со случайным трафиком

Вариант 13:

На рисунке 1 представлены параметры сети согласно варианту задания.

Рисунок 1 – Параметры сети по варианту 13

Расчетные формулы для оценки предельно достижимой скорости:

  1. Рассчитаем мощность шума:

(1)

здесь

– полоса пропускания канала связи,

T – абсолютная температура (К),

k – постоянная Больцмана ,

- коэффициент теплового шума приемника .

  1. Рассчитаем потери L:

(2)

где

- частота (МГц),

- высота базовой станции (м), возьмем 40м,

- высота точки приема (м), возьмём средний рост человека 1.7м,

d – расстояние от АБ до БС (км), возьмем максимальное расстояние 2.5км,

,

(3)

Переведем из «дБ» в «разы»:

(4)

  1. Рассчитаем мощность, принятую АБ:

(5)

где

- излучаемая мощность БС (Вт),

L - уровень потерь мощности при преодолении сигналов расстояния от БС к АБ

  1. Рассчитаем отношение сигнал/шум:

(6)

где

PRX – мощность, принятая АБ,

PN - мощность шума.

  1. Рассчитаем пропускную способность канала связи:

(7)

где

- полоса пропускания канала связи,

- отношение сигнал/шум (Signal-to-Noise Ratio, SNR) у абонента с индексом .

Рассмотрим алгоритмы распределения ресурсов.

  1. Equal Blind

Данный алгоритм выравнивает среднюю скорость закачки. Для алгоритма Equal Blind приоритет пользователя i на ресурсный блок j определяется как:

(7)

Соответственно, ресурсный блок отдается тому пользователю, у которого самый высокий приоритет:

(8)

здесь x номер абонента, которому выделен ресурсный блок j в слоте k.

  1. Maximum Throughput

Алгоритм MT «отдает» ресурсный блок тому пользователю, у которого максимальна пропускная канала связи. Приоритет пользователя i на ресурсный блок j определяется как:

(9)

Соответственно, ресурсный блок отдается тому пользователю, у которого самый высокий приоритет:

(10)

здесь x номер абонента, которому отдается ресурсный блок j в слоте k.

  1. Proportional fair (выравнивание ресурсов, отдаваемых пользователям):

(11)

средняя доля ресурса, которую i-ый абонент получил от базовой станции к моменту k. Приоритет пользователя i на ресурсный блок j определяется как:

.

(12)

Соответственно, ресурсный блок отдается тому пользователю, у которого самый высокий приоритет:

(13)

здесь x номер абонента, которому отдан ресурсный блок j в слоте k.

Рассмотрим сглаживающий фильтр для нахождения значения :

Зафиксируем интервал времени y (выраженную в секундах) на котором рассчитаем среднюю скорость, с которой АБ скачивал данные. Тогда количество слотов, на котором рассчитывается средняя скорость находится как:

(14)

Средняя скорость, с которой абонент скачивал, полученная на основе сглаживающего фильтра может быть записана как:

(15)

где .

Пример случайных расположений абонентских станций

Была разработана программа для моделирования и визуализации пространственного распределения абонентов вокруг базовой станции в полярной системе координат (Листинг 1).

Сначала определяется функция place_users, которая принимает количество абонентов N и радиус окружности R как входные параметры. Функция генерирует случайные углы в диапазоне от 0 до 2π с равномерным распределением с помощью метода np.random.uniform, а также случайные радиусы, равномерно распределённые по площади круга. Для получения радиусов используется метод квадратного корня от случайных значений, что обеспечивает равномерную плотность распределения абонентов по всей площади окружности.

С целью обеспечения воспроизводимости результатов устанавливается фиксированное значение зерна генератора случайных чисел с помощью функции np.random.seed.

Далее выполняется визуализация полученного распределения абонентов. В полярной системе координат с использованием библиотеки matplotlib строится диаграмма, где положения абонентов отображаются в виде точек. Центр координат обозначает местоположение базовой станции и выделяется красным маркером. Также задаются параметры отображения: ориентация начального угла по направлению на восток и направление оси углов по часовой стрелке, добавляются сетка и легенда.

В результате работы программы визуализируется схема с размещением 64 абонентов в пределах окружности заданного радиуса, позволяющая наглядно оценить пространственное распределение пользователей относительно базовой станции (Рисунок 1).

Листинг 1- Генерация и визуализация размещения абонентов вокруг БС

# Функция для размещения абонентов внутри окружности

def place_users(N, R):

angles = np.random.uniform(0, 2 * np.pi, N)

radii = np.sqrt(np.random.uniform(0, R**2, N))

return angles, radii

np.random.seed(123) # Зерно рандома для воспроизводимости результатов

# Визуализация распределения абонентов в полярной системе координат

angles, radii = place_users(64, R) # Пример для 64 абонентов

plt.figure(figsize=(8, 8))

ax = plt.subplot(111, projection='polar')

ax.scatter(angles, radii, s=30, label='Абоненты')

ax.plot(0, 0, color='red', marker='o', markersize=10, label='Базовая станция')

ax.set_theta_zero_location('E')

ax.set_theta_direction(1)

ax.grid(True)

ax.set_title('Распределение 64 абонентов вокруг базовой станции', pad=20)

ax.legend(loc='upper right')

plt.show()

Рисунок 1 – Распределение абонентов вокруг БС

Описание разработанной программы:

Была разработана программа для моделирования распределения ресурсов в сети с использованием алгоритмов планирования. Программа симулирует работу радиосети с расчетом пропускной способности, потерь сигнала, отношения сигнал/шум (SNR) и распределения ресурсов между пользователями.

Определяется основная модель симуляции, которая включает несколько компонентов, таких как расчёт потерь по модели Окамура-Хата, вычисление мощности принятого сигнала, а также пропускной способности сети для каждого пользователя. Для каждого абонента выполняются вычисление затухания сигнала, вычисление пропускной способности на основе отношения сигнал/шум (SNR) и распределение ресурсных блоков с использованием различных алгоритмов планирования.

Для выполнения модели используется асинхронное выполнение через библиотеку asyncio, что позволяет параллельно обрабатывать большое количество конфигураций пользователей и интенсивности потока данных, значительно ускоряя процесс моделирования. При таких условиях время выполнения моделирования занимает около 20 минут.

В результате работы программы получаем следующие данные: для каждой конфигурации (разное количество пользователей и интенсивность потока) вычисляются средние значения размера буфера для каждого алгоритма.

В таблице 1 представлены использованные прееменные, в Листинге 2 представлен программный код для моделирования.

Таблица 1 – Исопльзованные переменные

Переменная

Описание

R

Радиус зоны покрытия (метры).

Ptx

Мощность передатчика (Вт).

F0

Несущая частота (МГц).

KN

Коэффициент потерь (единицы измерения зависят от конкретной модели).

N_RB

Количество ресурсных блоков (RB) в сети.

packet_size

Размер пакета в битах.

tau_RB

Длительность одного ресурсного блока (секунды).

delta_f_RB

Полоса частот одного ресурсного блока (Гц).

simulation_slots

Число слотов симуляции.

N2_lambda, N4_lambda, N16_lambda, N32_lambda

Интенсивности потока пакетов для разных конфигураций пользователей.

Hbs

Высота базовой станции (м).

Hrx

Высота абонента (м).

S

Параметр затенения.

K

Постоянная Больцмана (единицы измерения).

T

Абсолютная температура (К).

Pn

Мощность шума (Вт).

distances

Массив расстояний от БС до каждого пользователя (метры).

Li_base

Базовое затухание сигнала для каждого пользователя (дБ).

Li

Общее затухание сигнала для каждого пользователя и ресурсного блока.

C

Пропускная способность для каждого пользователя и ресурсного блока (бит/с).

V

Максимальный объем данных, который может быть передан за один слот (биты).

p_ij_k

Приоритеты для каждого пользователя и ресурсного блока.

buffers

Буферы для разных алгоритмов планирования (бит).

R_avg

Средняя скорость передачи данных для каждого пользователя и алгоритма.

hist

История суммарных размеров буферов для каждого алгоритма.

rb_allocation

Массив, показывающий распределение ресурсных блоков среди пользователей.

transmit_volume

Объем переданных данных для каждого пользователя.

Листинг 2 – Программа для моделирования

import numpy as np

import matplotlib.pyplot as plt

from scipy.stats import poisson, norm

import asyncio

import time

import nest_asyncio

# Параметры

R = 2500                     # радиус зоны покрытия (м)

Ptx = 10                     # мощность передатчика (Вт)

F0 = 900                     # несущая частота (МГц)

KN = 2                       # коэффициент потерь

N_RB = 25                    # количество ресурсных блоков

packet_size = 8*1024         # размер пакета в битах

tau_RB = 0.5*10**(-3)        # длительность слота (0.5 мс)

delta_f_RB = 180*10**3       # полоса частот

simulation_slots = 10**5     # число слотов

N2_lambda = [0, 1, 1.5, 2.0, 2.5]

N4_lambda = [0, 0.5, 0.75, 1.0, 1.5]

N16_lambda = [0, 0.1, 0.15, 0.2, 0.3]

N32_lambda = [0, 0.05, 0.1, 0.2, 0.3]

N_users_values = [2, 4, 16, 32]  # число пользователей, shape: (4,)

# Параметры для модели Окамура-Хата

Hbs = 40                     # Высота БС (м)

Hrx = 1.7                    # Высота абонента (м)

S = 0                        # Параметр затенения

K = 1.38 * 10**(-23)         # Постоянная Больцмана

T = 300                      # Абсолютная температура (К)

Pn = K * T * delta_f_RB * KN # Мощность шума

# Векторизованная функция для расчета потерь по модели Окамура-Хата

def okumura_hata_vectorized(d, f0, hbs, hrx, s):

    # d: distances - shape: (N_users,) - расстояния от БС до каждого пользователя

    # Возвращает: L_db - shape: (N_users,) - потери сигнала в дБ для каждого пользователя

   

    # Преобразуем расстояние в километры

    d_km = d / 1000  # shape: (N_users,)

   

    # Расчет коэффициента a(hrx)

    a_hrx = (1.1 * np.log10(f0) - 0.7) * hrx - (1.56 * np.log10(f0) - 0.8)

   

    # Расчет потерь по модели Окамура-Хата

    L_db = 46.3 + 33.9 * np.log10(f0) - 13.82 * np.log10(hbs) - a_hrx + (44.9 - 6.55 * np.log10(hrx)) * np.log10(d_km) + s  # shape: (N_users,)

   

    return L_db

# Векторизованная функция для расчета мощности принятого сигнала

def calculate_received_power_vectorized(ptx, L_db):

    # L_db: shape (N_users, N_RB) - затухание сигнала в дБ

    # Возвращает: Prx - shape (N_users, N_RB) - мощность принятого сигнала в ваттах

   

    # L_db должен быть уже вычислен и передан

    Prx = ptx / (10 ** (L_db / 10))  # Принятая мощность в ваттах, shape: (N_users, N_RB)

    return Prx

# Векторизованная функция для расчета SNR

def calculate_snr_vectorized(ptx, L_db):

    # L_db: shape (N_users, N_RB) - затухание сигнала в дБ

    # Возвращает: snr - shape (N_users, N_RB) - отношение сигнал/шум

   

    Prx = calculate_received_power_vectorized(ptx, L_db)  # shape: (N_users, N_RB)

    snr = Prx / Pn  # shape: (N_users, N_RB)

    return snr

# Векторизованная функция для расчета пропускной способности (скорости)

def calculate_data_rate_vectorized(snr, DF):

    # snr: shape (N_users, N_RB) - отношение сигнал/шум

    # DF: полоса частот

    # Возвращает: shape (N_users, N_RB) - пропускная способность в бит/с

    return DF * np.log2(1 + snr)  # shape: (N_users, N_RB)

# Функция для размещения абонентов внутри окружности

def place_users(N, R):

    # N: число пользователей

    # R: радиус зоны покрытия

    # Возвращает: radii - shape: (N,) - расстояния от БС до каждого пользователя

   

    radii = np.sqrt(np.random.uniform(0, R**2, N))  # shape: (N,)

    return radii

def model(N_users, lambda_val):

    # N_users: число пользователей

    # lambda_val: интенсивность поступления пакетов

    # Возвращает: кортеж из трех значений - средние размеры буферов для трех алгоритмов

   

    distances = place_users(N_users, R)  # shape: (N_users,) - расстояния от БС до каждого пользователя

   

    # Буферы для каждого алгоритма - словарь с тремя ключами, каждый содержит numpy array

    # shape каждого массива: (N_users,) - размер буфера для каждого пользователя в битах

    buffers = {'Equal Blind': np.zeros(N_users),  

               'Maximum Throughput': np.zeros(N_users),

               'Proportional Fair': np.zeros(N_users)}

   

    # Начальные средние скорости - словарь с тремя ключами, каждый содержит numpy array

    # shape каждого массива: (N_users,) - средняя скорость передачи в бит/с для каждого пользователя

    R_avg = {'Equal Blind': np.ones(N_users)*1e-6,

             'Maximum Throughput': np.ones(N_users)*1e-6,

             'Proportional Fair': np.ones(N_users)*1e-6}

   

    # История буферов - словарь с тремя ключами, каждый содержит пустой список

    # Будет наполняться суммарным размером буфера на каждой итерации

    hist = {'Equal Blind': [], 'Max Throughput': [], 'Proportional Fair': []}

   

    # Предварительно вычисляем базовые потери для всех пользователей

    # shape: (N_users, 1) - базовое затухание сигнала в дБ для каждого пользователя

    Li_base = okumura_hata_vectorized(distances, F0, Hbs, Hrx, S).reshape(N_users, 1)

   

    # Предварительно выделяем память для массивов, которые будут многократно использоваться

    Li = np.zeros((N_users, N_RB))     # shape: (N_users, N_RB) - затухание сигнала для каждого пользователя и ресурсного блока

    C = np.zeros((N_users, N_RB))      # shape: (N_users, N_RB) - пропускная способность для каждого пользователя и ресурсного блока

    V = np.zeros((N_users, N_RB))      # shape: (N_users, N_RB) - максимальный объем данных в битах, который можно передать

    p_ij_k = np.zeros((N_users, N_RB)) # shape: (N_users, N_RB) - приоритеты для алгоритмов планирования

   

    for k in range(simulation_slots):

        # Генерируем случайные затухания (векторизованно)

        # x_ij_k: shape: (N_users, N_RB) - случайная компонента затухания

        x_ij_k = norm.rvs(0, 1, size=(N_users, N_RB))

        # Li: shape: (N_users, N_RB) - полное затухание сигнала для каждого пользователя и ресурсного блока

        Li = np.tile(np.mean(Li_base), (N_users, N_RB)) + x_ij_k

       

        # Генерируем пакеты для всех пользователей сразу

        # packets: shape: (N_users,) - число пакетов для каждого пользователя

        packets = poisson.rvs(lambda_val, size=N_users)

           

        # Вычисляем SNR и пропускную способность (векторизованно)

        # snr_values: shape: (N_users, N_RB) - SNR для каждого пользователя и ресурсного блока

        snr_values = calculate_snr_vectorized(Ptx, Li)

        # C: shape: (N_users, N_RB) - пропускная способность в бит/с для каждого пользователя и ресурсного блока

        C = calculate_data_rate_vectorized(snr_values, delta_f_RB)

        # V: shape: (N_users, N_RB) - максимальный объем данных в битах, который можно передать за один слот

        V = C * tau_RB

       

        # Распределение ресурсов для каждого алгоритма

        for algorithm in buffers:

            # Расчет приоритетов (векторизованно)

            if algorithm == 'Equal Blind':

                # p_ij_k: shape: (N_users, N_RB) - приоритеты для алгоритма Equal Blind

                p_ij_k = np.ones((N_users, N_RB)) / R_avg[algorithm].reshape(N_users, 1)

            elif algorithm == 'Max Throughput':

                # p_ij_k: shape: (N_users, N_RB) - приоритеты для алгоритма Max Throughput (равны пропускной способности)

                p_ij_k = C.copy()

            elif algorithm == 'Proportional Fair':

                # p_ij_k: shape: (N_users, N_RB) - приоритеты для алгоритма Proportional Fair

                p_ij_k = C / R_avg[algorithm].reshape(N_users, 1)

           

            # Инициализация счетчика для отслеживания объема данных

            # transmit_volume: shape: (N_users,) - объем переданных данных для каждого пользователя

            transmit_volume = np.zeros(N_users)

           

            # Добавляем пакеты в буферы (размер каждого пакета в битах умножается на число пакетов)

            buffers[algorithm] += packets * packet_size  # shape: (N_users,)

            # Определяем активных пользователей (тех, у кого буфер не пуст)

            # active_users: shape: (M,) - индексы активных пользователей, где M <= N_users

            active_users = np.where(buffers[algorithm] > 0)[0]

           

            if len(active_users) > 0:

                # Инициализация массива распределения ресурсных блоков

                # rb_allocation: shape: (N_RB,) - массив, показывающий какому пользователю назначен каждый ресурсный блок

                rb_allocation = np.full(N_RB, -1, dtype=int)

               

                # Вычисляем приоритеты только для активных пользователей

                # active_priorities: shape: (M, N_RB) - приоритеты только для активных пользователей

                active_priorities = p_ij_k[active_users]

               

                # Распределяем ресурсные блоки одним проходом

                for rb_index in range(N_RB):

                    if len(active_users) == 0:

                        break

                   

                    # Находим индекс максимального приоритета среди активных пользователей

                    # best_user_local_idx: индекс пользователя с максимальным приоритетом в массиве active_users

                    best_user_local_idx = np.argmax(active_priorities[:, rb_index])

                    # selected_user_id: фактический индекс выбранного пользователя

                    selected_user_id = active_users[best_user_local_idx]

                   

                    # Назначаем ресурсный блок выбранному пользователю

                    rb_allocation[rb_index] = selected_user_id

                   

                    # Вычисляем объем данных для передачи (минимум из пропускной способности и размера буфера)

                    # data_to_transmit: объем данных для передачи в битах

                    data_to_transmit = min(V[selected_user_id, rb_index], buffers[algorithm][selected_user_id])

                   

                    # Обновляем буфер и счетчик переданных данных

                    buffers[algorithm][selected_user_id] -= data_to_transmit

                    transmit_volume[selected_user_id] += data_to_transmit

                   

                    # Если буфер пуст, удаляем пользователя из активных

                    if buffers[algorithm][selected_user_id] <= 0:

                        # Находим индекс в массиве active_users

                        # remove_idx: индекс пользователя в массиве active_users, которого нужно удалить

                        remove_idx = np.where(active_users == selected_user_id)[0][0]

                        # Удаляем пользователя и его приоритеты из соответствующих массивов

                        active_users = np.delete(active_users, remove_idx)  # shape: (M-1,)

                        active_priorities = np.delete(active_priorities, remove_idx, axis=0)  # shape: (M-1, N_RB)

           

            # Сглаживающий фильтр для обновления средних скоростей

            y = 1.

            beta = tau_RB / y  # коэффициент сглаживания

            # Обновляем средние скорости для алгоритма, shape: (N_users,)

            R_avg[algorithm] = (1-beta)*R_avg[algorithm] + beta*(transmit_volume/tau_RB)

           

            # Добавляем текущий суммарный размер буфера в историю

            hist[algorithm].append(np.sum(buffers[algorithm]))  # сумма всех буферов

   

    # Возвращаем средние значения истории буферов для трех алгоритмов

    # Каждое значение - среднее по всем итерациям для данного алгоритма

    return (np.mean(hist['Equal Blind']),

            np.mean(hist['Maximum Throughput']),

            np.mean(hist['Proportional Fair']))

async def model_async(N, lam):

    """Асинхронная обертка для функции model"""

    try:

        if lam == 0:

            print(f"Пропуск моделирования для N={N}, λ={lam} (всегда нули)")

            return (0, 0, 0), N, lam

       

        # Передаем выполнение основной функции, которая может занять много времени

        result = await asyncio.to_thread(model, N, lam)

        print(f"Выполнено моделирование для N={N}, λ={lam}")

        return result, N, lam

    except Exception as e:

        print(f"Ошибка при N={N}, λ={lam}: {str(e)}")

        return (0, 0, 0), N, lam

async def main():

    start_time = time.time()

    results = {N: {'Equal Blind': [], 'Maximum Throughput': [], 'Proportional Fair': []} for N in N_users_values}

   

    # Используем фиксированное начальное значение для воспроизводимости результатов

    np.random.seed(42)

   

    # Создаем список задач для асинхронного выполнения

    tasks = []

    for N in N_users_values:

        if N == 2:

            lambda_values = N2_lambda

        elif N == 4:

            lambda_values = N4_lambda

        elif N == 16:

            lambda_values = N16_lambda

        elif N == 32:

            lambda_values = N32_lambda

        for lam in lambda_values:

            print(f"Запуск моделирования: N={N}, λ={lam}")

            tasks.append(model_async(N, lam))

   

    # Запускаем все задачи параллельно и ждем результаты

    completed_tasks = await asyncio.gather(*tasks)

   

    # Обрабатываем результаты

    for result, N, lam in completed_tasks:

        eb, mt, pf = result

        if N == 2:

            lambda_values = N2_lambda

        elif N == 4:

            lambda_values = N4_lambda

        elif N == 16:

            lambda_values = N16_lambda

        elif N == 32:

            lambda_values = N32_lambda

        lambda_index = list(lambda_values).index(lam)

        results[N]['Equal Blind'].insert(lambda_index, eb)

        results[N]['Maximum Throughput'].insert(lambda_index, mt)

        results[N]['Proportional Fair'].insert(lambda_index, pf)

   

    end_time = time.time()

    print(f"Общее время выполнения: {end_time - start_time} секунд")

    print(f"Моделирование успешно завершено для всех конфигураций!")

   

    return results

nest_asyncio.apply()

results_optimized = asyncio.run(main())

Соседние файлы в предмете Моделирование систем распределения ресурсов