Source code for comyx.stats.moments

from __future__ import annotations

from typing import Any, Tuple

import numpy as np
import numpy.typing as npt
from scipy.special import gamma

NDArrayFloat = npt.NDArray[np.floating[Any]]


[docs] def fun_mu_naka( p: int, m: float, omega: NDArrayFloat, ) -> NDArrayFloat: """Computes the p-th moment of the Nakagami-m distribution. Args: p: Order of the moment to compute. m: Shape parameter of the distribution. omega: Scale parameter of the distribution. Returns: The p-th moment of the Nakagami-m distribution. """ return np.array((gamma(m + p / 2) / gamma(m)) * (m / omega) ** (-p / 2))
[docs] def fun_mu_gamma( p: int, k: float, theta: NDArrayFloat, ) -> NDArrayFloat: """Computes the p-th moment of the Gamma distribution. Args: p: Order of the moment to compute. k: Shape parameter of the distribution. theta: Scale parameter of the distribution. Returns: The p-th moment of the Gamma distribution. """ return np.array((gamma(k + p) / gamma(k)) * (k / theta) ** (-p))
[docs] def fun_mu_doublenaka( p: int, m: float, k: float, omega: NDArrayFloat, theta: NDArrayFloat, c: float, N: int, ) -> NDArrayFloat: r"""Computes the p-th moment of the sum of two independent Nakagami-m RVs. .. math:: G = \sqrt{c} \sum_{n=1}^{N} |{h_1}||{h_2}| , where :math:`h_1 \sim Nakagami(m, \Omega)` and :math:`h_2 \sim Nakagami(k, \theta)`. Args: p: Order of the moment to compute. m: Shape parameter of the first distribution :math:`h_1`. k: Shape parameter of the second distribution :math:`h_2`. omega: Scale parameter of the first distribution :math:`h_1`. theta: Scale parameter of the second distribution :math:`h_2`. c: Summation constant. N: Number of summation terms. Returns: The p-th moment of the sum of two independent Nakagami-m random variables. """ return np.array( ( gamma(m + (p / 2)) * (np.sqrt(c) * N) ** p * gamma(k + (p / 2)) * ((k * m) / (omega * theta)) ** (-p / 2) ) / (gamma(k) * gamma(m)) )
[docs] def fun_mu_effective( p: int, m_h: float, m_Ga: float, m_Gb: float, omega_h: NDArrayFloat, omega_Ga: NDArrayFloat, omega_Gb: NDArrayFloat, c: float, N: int, ): r"""Computes the p-th moment of the effective channel distribution. .. math:: Z = |H|^2 = (h + G)^2 , where :math:`h \sim Nakagami(m, \Omega)` and :math:`G \sim \Gamma(k_G, \theta_G)`. Furthermore, :math:`G` is defined as: .. math:: G = \sqrt{c} \sum_{n=1}^{N} |{h_1}||{h_2}| Args: p: Order of the moment to compute. Only p = 1 and p = 2 are supported. m_h: Shape parameter of h distribution. m_Ga: Shape parameter of the first distribution of :math:`G`. m_Gb: Shape parameter of the second distribution of :math:`G`. omega_h: Scale parameter of h distribution. omega_Ga: Scale parameter of the first distribution of :math:`G`. omega_Gb: Scale parameter of the second distribution of :math:`G`. c: Summation constant. N: Number of summation terms. Returns: The p-th moment of the effective channel distribution. """ assert p in [1, 2], "p must be 1 or 2, higher moments are not supported." if p == 1: return ( fun_mu_doublenaka(2, m_Ga, m_Gb, omega_Ga, omega_Gb, c, N) + fun_mu_naka(2, m_h, omega_h) + ( 2 * fun_mu_doublenaka(1, m_Ga, m_Gb, omega_Ga, omega_Gb, c, N) * fun_mu_naka(1, m_h, omega_h) ) ) else: return ( fun_mu_doublenaka(4, m_Ga, m_Gb, omega_Ga, omega_Gb, c, N) + fun_mu_naka(4, m_h, omega_h) + ( 6 * fun_mu_doublenaka(2, m_Ga, m_Gb, omega_Ga, omega_Gb, c, N) * fun_mu_naka(2, m_h, omega_h) ) + ( 4 * fun_mu_naka(3, m_h, omega_h) * fun_mu_doublenaka(1, m_Ga, m_Gb, omega_Ga, omega_Gb, c, N) ) + ( 4 * fun_mu_naka(1, m_h, omega_h) * fun_mu_doublenaka(3, m_Ga, m_Gb, omega_Ga, omega_Gb, c, N) ) )
[docs] def approx_gamma_params( mu_1: NDArrayFloat, mu_2: NDArrayFloat, const: NDArrayFloat = np.array([1.0]), ) -> Tuple[NDArrayFloat, NDArrayFloat]: r"""Approximates the shape and scale of the Gamma distribution. Approximates the shape and scale parameters of the Gamma distribution given the first two moments of a non-negative RV. The approximation is based on the method of moments, given by: .. math:: k = \frac{\mu^2}{\mu^{(2)} - \mu^2} .. math:: \theta = \frac{\mu^{(2)} - \mu^2}{\mu} , where :math:`\mu` and :math:`\mu^{(2)}` are the first and second moments, respectively. Args: mu_1: First moment of the RV. mu_2: Second moment of the RV. const: Constant to multiply the scale parameter by. Defaults to 1.0. Returns: Shape and scale parameters of the Gamma distribution. """ k = (mu_1**2) / (mu_2 - mu_1**2) theta = (mu_2 - mu_1**2) / mu_1 return np.repeat(k, len(const)), theta * const
__all__ = [ "fun_mu_naka", "fun_mu_gamma", "fun_mu_doublenaka", "fun_mu_effective", "approx_gamma_params", ]