Source code for comyx.network.links

from __future__ import annotations

from typing import TYPE_CHECKING, Any, List, Tuple, Union

import numpy as np
import numpy.typing as npt

from ..fading import get_rvs
from ..propagation import get_pathloss
from ..utils import db2pow, ensure_list, get_distance
from .ris import RIS, STAR_RIS

if TYPE_CHECKING:
    from .transceiver import Transceiver

NDArrayFloat = npt.NDArray[np.floating[Any]]
NDArrayComplex = npt.NDArray[np.complexfloating[Any, Any]]

EPSILON = np.finfo(float).eps






[docs] def cascaded_channel_gain( tR_link: Link, Rr_link: Link, style: str = "sum", ele_idx: int = 0 ) -> NDArrayComplex: r"""Calculate the cascaded channel gain. The cascaded channel gain is the channel gain between the transmitter and the receiver through the RIS. Mathematically, the cascaded channel gain through the RIS is given by .. math:: h_{csc}= \mathbf{h}_{R,r}^T \mathbf{R} \mathbf{h}_{t,R}, where :math:`\mathbf{h}_{t,R}` is the channel gain between the transmitter and the RIS, :math:`\mathbf{h}_{R,r}` is the channel gain between the RIS and the receiver, and :math:`\mathbf{R}` is the reflection matrix of the RIS. The superscript :math:`T` denotes the transpose operator. If channel_gain_tR is of shape (Nt, K, Mc), and channel_gain_Rr is of shape (K, Nr, Mc), where Nt is the number of transmit antennas, K is the number of RIS elements, Nr is the number of receive antennas, and Mc is the number of channel realizations, then the cascaded channel gain is of shape (Nt, Nr, Mc). For SISO links, the cascaded channel gain is of shape (1, 1, Mc). Args: tR_link: Link between the transmitter and the RIS. Rr_link: Link between the RIS and the receiver. style: Formula used to calculate the cascaded channel gain. Possible values are 'sum' and 'matrix'. ele_idx: Index of the elements of RIS in channel gain matrix. Returns: Cascaded channel gain. """ channel_gain_tR = tR_link.channel_gain channel_gain_Rr = Rr_link.channel_gain # RIS object of both links must be the same assert tR_link.rx == Rr_link.tx, ( "The receiver of the first link must be the same as the transmitter of the " + "second link." ) ris = tR_link.rx # or Rr_link.tx assert channel_gain_tR.shape[-1] == channel_gain_Rr.shape[-1], ( "The number of channel realizations must be the same for both channel " + "gains." ) mc = channel_gain_tR.shape[-1] if style == "sum": cascaded_channel_gain = np.zeros( (tR_link.tx.n_antennas, Rr_link.rx.n_antennas, mc), dtype=np.complex128 ) if ele_idx == 0: for i in range(ris.n_elements): cascaded_channel_gain += ( channel_gain_tR[i, :, :] * ris.amplitudes[i] * np.exp(1j * ris.phase_shifts[i]) * channel_gain_Rr[i, :, :] ) elif ele_idx == 1: for i in range(ris.n_elements): cascaded_channel_gain += ( channel_gain_tR[:, i, :] * ris.amplitudes[i] * np.exp(1j * ris.phase_shifts[i]) * channel_gain_Rr[:, i, :] ) else: raise ValueError(f"Element index {ele_idx} not supported.") elif style == "matrix": if channel_gain_tR.ndim != 2 or channel_gain_Rr.ndim != 2: raise NotImplementedError( "The matrix style is only implemented when the channel realization " + "dimension is absent. Use the sum style instead." ) cascaded_channel_gain = ( channel_gain_Rr.T @ ris.reflection_matrix @ channel_gain_tR ) else: raise NotImplementedError( f"Style {style} not implemented. Possible values are 'sum' and 'matrix'." ) return cascaded_channel_gain
[docs] def effective_channel_gain( tr_link: Link, tR_link: Link, Rr_link: Link, style: str = "sum", ele_idx: int = 0, ) -> NDArrayComplex: r"""Calculate the effective channel gain. The effective channel gain is the channel gain between the transceiver and the receiver through the RIS. Mathematically, the effective channel gain through the RIS is given by .. math:: h_{eff}= h_{t,r} + \mathbf{h}_{R,r}^T \mathbf{R} \mathbf{h}_{t,R}, where :math:`\mathbf{h}_{t,R}` is the channel gain between the transmitter and the RIS, :math:`\mathbf{h}_{R,r}` is the channel gain between the RIS and the receiver, :math:`\mathbf{R}` is the reflection matrix of the RIS, and :math:`h_{t,r}` is the channel gain between the transmitter and the receiver. The superscript :math:`T` denotes the transpose operator. Args: tr: Direct link. tR: Link between the transmitter and the RIS. Rr: Link between the RIS and the receiver. style: Formula used to calculate the cascaded channel gain. Possible values are 'sum' and 'matrix'. ele_idx: Index of the elements of RIS in channel gain matrix. Returns: Effective channel gain. """ channel_gain_tr = tr_link.channel_gain effective_channel_gain = channel_gain_tr + cascaded_channel_gain( tR_link, Rr_link, style=style ) return effective_channel_gain
__all__ = ["Link", "cascaded_channel_gain", "effective_channel_gain"]