Source code for pytwinnet.scheduling.pf_scheduler

from __future__ import annotations
from typing import Dict, List
from ..core.digital_twin import DigitalTwin
from ..physics.link_budget import rx_power_dbm, noise_power_dbm, sinr_db, shannon_throughput_bps

def _est_throughput_bps(twin: DigitalTwin, tx_id: str, ue_id: str,
                        bandwidth_hz: float, noise_figure_db: float) -> float:
    pm = twin.propagation_model; env = twin.environment
    tx = twin.network.get_node_by_id(tx_id); ue = twin.network.get_node_by_id(ue_id)
    pl_db = pm.calculate_path_loss(tx, ue, env)
    prx_dbm = rx_power_dbm(
        tx.transceiver_properties.transmit_power_dbm,
        tx.transceiver_properties.antenna_gain_dbi,
        ue.transceiver_properties.antenna_gain_dbi,
        pl_db,
    )
    n_dbm = noise_power_dbm(290.0, bandwidth_hz, noise_figure_db)
    s = sinr_db(prx_dbm, interferers_dbm=None, noise_dbm=n_dbm)
    return shannon_throughput_bps(bandwidth_hz, s, efficiency=0.75)

[docs] def proportional_fair_allocation( twin: DigitalTwin, association: Dict[str, str], rb_count: int = 50, rb_bandwidth_hz: float = 180e3, noise_figure_db: float = 7.0, avg_throughput_bps: Dict[str, float] | None = None, ) -> Dict[str, List[str]]: """Greedy PF: per TX, for each RB pick UE maximizing inst_rate / avg_rate.""" if avg_throughput_bps is None: avg_throughput_bps = {} eps = 1e-6 # group UEs per TX per_tx: Dict[str, List[str]] = {} for ue_id, tx_id in association.items(): per_tx.setdefault(tx_id, []).append(ue_id) schedule: Dict[str, List[str]] = {tx_id: [] for tx_id in per_tx.keys()} for tx_id, ues in per_tx.items(): if not ues: continue for _ in range(rb_count): best_ue, best_metric = None, float("-inf") for ue_id in ues: inst = _est_throughput_bps(twin, tx_id, ue_id, rb_bandwidth_hz, noise_figure_db) avg = avg_throughput_bps.get(ue_id, inst) # cold-start metric = inst / max(avg, eps) if metric > best_metric: best_metric, best_ue = metric, ue_id schedule[tx_id].append(best_ue) return schedule