Source code for ran.phy.numpy.pusch.post_eq_noisevar_sinr

# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Post-equalization noise variance and SINR (NumPy translation).

Implements the post-eq block from detPusch.m:
- Optionally average Ree cumulatively over DMRS positions in sub-slot processing
- For each UE, average 1./Ree over allocated REs and convert to dB
"""

import numpy as np

from ran.types import FloatArrayNP, FloatNP, IntArrayNP
from ran.utils import db


[docs] def post_eq_noisevar_sinr( ree: FloatArrayNP, layer2ue: IntArrayNP, n_ue: int, ) -> tuple[FloatArrayNP, FloatArrayNP]: """ Compute post-equalization noise variance and SINR in dB. Args: ree: Per-layer, per-tone, per-DMRS Ree over the allocated band; shape (nl, n_f_alloc, n_sym) layer2ue: mapping from layer index to UE index (0-based), shape (nl,) n_ue: number of UEs Returns ------- post_eq_noise_var_db: shape (n_sym, n_ue) post_eq_sinr_db: shape (n_sym, n_ue) """ _, n_f, n_sym = ree.shape if n_f == 0: zeros = np.zeros((n_sym, n_ue), dtype=FloatNP) return zeros, zeros # Vectorized aggregation across tones and layers alloc_ree = np.maximum(np.real(ree), np.finfo(FloatNP).tiny) inv_snr_mean_tones = (1.0 / alloc_ree).mean(axis=1) # (nl, n_sym) # Map layers -> UEs and average per UE using bincount nl = inv_snr_mean_tones.shape[0] sum_per_ue = np.zeros((n_ue, n_sym), dtype=FloatNP) np.add.at(sum_per_ue, layer2ue[:nl], inv_snr_mean_tones) counts = np.bincount(layer2ue[:nl], minlength=n_ue).astype(FloatNP) nonzero = counts > 0 if np.any(nonzero): sum_per_ue[nonzero, :] /= counts[nonzero, None] post_eq_noise_var_db = -db(sum_per_ue).T # (n_sym, n_ue) post_eq_sinr_db = -post_eq_noise_var_db return post_eq_noise_var_db, post_eq_sinr_db
__all__ = ["post_eq_noisevar_sinr"]