# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
from astropy import units as u
from itur.utils import prepare_quantity
class __ITU838__():
"""Specific attenuation model for rain for use in prediction methods
Available versions include:
* P.838-0 (03/92) (Superseded)
* P.838-1 (10/99) (Superseded)
* P.838-2 (04/03) (Superseded)
* P.838-3 (03/05) (Current version)
"""
# This is an abstract class that contains an instance to a version of the
# ITU-R P.838 recommendation.
def __init__(self, version=3):
if version == 3:
self.instance = _ITU838_3_()
elif version == 2:
self.instance = _ITU838_2_()
elif version == 1:
self.instance = _ITU838_1_()
elif version == 0:
self.instance = _ITU838_0_()
else:
raise ValueError(
'Version ' +
str(version) +
' is not implemented' +
' for the ITU-R P.838 model.')
@property
def __version__(self):
return self.instance.__version__
def rain_specific_attenuation_coefficients(self, f, el, tau):
# Abstract method to compute the rain height
fcn = np.vectorize(self.instance.rain_specific_attenuation_coefficients,
excluded=[1], otypes=[np.ndarray])
return np.array(fcn(f, el, tau).tolist())
def rain_specific_attenuation(self, R, f, el, tau):
# Abstract method to compute the zero isoterm height
k, alpha = self.rain_specific_attenuation_coefficients(f, el, tau)
return k * R**alpha
class _ITU838_3_():
def __init__(self):
self.__version__ = 3
self.year = 2005
self.month = 3
self.link = 'https://www.itu.int/rec/R-REC-P.838-3-200503-I/en'
@staticmethod
def rain_specific_attenuation_coefficients(f, el, tau):
"""
"""
kh = {'aj': [-5.33980, -0.35351, -0.23789, -0.94158],
'bj': [-0.10008, 1.2697, 0.86036, 0.64552],
'cj': [1.13098, 0.454, 0.15354, 0.16817],
'mk': -0.18961,
'ck': 0.71147}
kv = {'aj': [-3.80595, -3.44965, -0.39902, 0.50167],
'bj': [0.56934, -0.22911, 0.73042, 1.07319],
'cj': [0.81061, 0.51059, 0.11899, 0.27195],
'mk': -0.16398,
'ck': 0.63297}
alphah = {'aj': [-0.14318, 0.29591, 0.32177, -5.37610, 16.1721],
'bj': [1.82442, 0.77564, 0.63773, -0.96230, -3.29980],
'cj': [-0.55187, 0.19822, 0.13164, 1.47828, 3.4399],
'ma': 0.67849,
'ca': -1.95537}
alphav = {'aj': [-0.07771, 0.56727, -0.20238, -48.2991, 48.5833],
'bj': [2.3384, 0.95545, 1.1452, 0.791669, 0.791459],
'cj': [-0.76284, 0.54039, 0.26809, 0.116226, 0.116479],
'ma': -0.053739,
'ca': 0.83433}
def curve_fcn(f, a, b, c):
return (a * np.exp(-((np.log10(f) - b) / c)**2))
KH = np.power(10, sum([curve_fcn(f, kh['aj'][j], kh['bj'][j], kh['cj'][j])
for j in range(4)]) + kh['mk'] * np.log10(f) + kh['ck'])
KV = np.power(10, sum([curve_fcn(f, kv['aj'][j], kv['bj'][j], kv['cj'][j])
for j in range(4)]) + kv['mk'] * np.log10(f) + kv['ck'])
alphaH = sum([curve_fcn(f, alphah['aj'][j], alphah['bj'][j], alphah['cj'][j])
for j in range(5)]) + alphah['ma'] * np.log10(f) + alphah['ca']
alphaV = sum([curve_fcn(f, alphav['aj'][j], alphav['bj'][j], alphav['cj'][j])
for j in range(5)]) + alphav['ma'] * np.log10(f) + alphav['ca']
k = (KH + KV + (KH - KV) * np.cos(np.deg2rad(el))**2
* np.cos(np.deg2rad(2 * tau))) / 2.0
alpha = (KH * alphaH + KV * alphaV + (KH * alphaH - KV * alphaV) *
np.cos(np.deg2rad(el))**2 * np.cos(np.deg2rad(2 * tau))) / (2.0 * k)
return k, alpha
class _ITU838_2_():
def __init__(self):
self.__version__ = 2
self.year = 2003
self.month = 4
self.link = 'https://www.itu.int/rec/R-REC-P.838-2-200304-S/en'
@staticmethod
def rain_specific_attenuation_coefficients(f, el, tau):
"""
"""
kh = {'aj': [0.3364, 0.7520, -0.9466],
'bj': [1.1274, 1.6644, 2.8496],
'cj': [0.2916, 0.5175, 0.4315],
'mk': 1.9925,
'ck': -4.4123}
kv = {'aj': [0.3023, 0.7790, -1.0022],
'bj': [1.1402, 1.6723, 2.9400],
'cj': [0.2826, 0.5694, 0.4823],
'mk': 1.9710,
'ck': -4.4535}
alphah = {'aj': [0.5564, 0.2237, -0.1961, -0.02219],
'bj': [0.7741, 1.4023, 0.5769, 2.2959],
'cj': [0.4011, 0.3475, 0.2372, 0.2801],
'ma': -0.08016,
'ca': 0.8993}
alphav = {'aj': [0.5463, 0.2158, -0.1693, -0.01895],
'bj': [0.8017, 1.4080, 0.6353, 2.3105],
'cj': [0.3657, 0.3636, 0.2155, 0.2938],
'ma': -0.07059,
'ca': 0.8756}
def curve_fcn(f, a, b, c):
return a * np.exp(-((np.log10(f) - b) / c)**2)
KH = np.power(10, sum([curve_fcn(f, kh['aj'][j], kh['bj'][j], kh['cj'][j])
for j in range(3)]) + kh['mk'] * np.log10(f) + kh['ck'])
KV = np.power(10, sum([curve_fcn(f, kv['aj'][j], kv['bj'][j], kv['cj'][j])
for j in range(3)]) + kv['mk'] * np.log10(f) + kv['ck'])
alphaH = sum([curve_fcn(f, alphah['aj'][j], alphah['bj'][j], alphah['cj'][j])
for j in range(4)]) + alphah['ma'] * np.log10(f) + alphah['ca']
alphaV = sum([curve_fcn(f, alphav['aj'][j], alphav['bj'][j], alphav['cj'][j])
for j in range(4)]) + alphav['ma'] * np.log10(f) + alphav['ca']
k = (KH + KV + (KH - KV) * np.cos(np.deg2rad(el))**2
* np.cos(np.deg2rad(2 * tau))) / 2.0
alpha = (KH * alphaH + KV * alphaV + (KH * alphaH - KV * alphaV) *
np.cos(np.deg2rad(el))**2 *
np.cos(np.deg2rad(2 * tau))) / (2.0 * k)
return k, alpha
class _ITU838_1_():
def __init__(self):
self.__version__ = 1
self.year = 1999
self.month = 10
self.link = 'https://www.itu.int/rec/R-REC-P.838-1-199910-S/en'
@staticmethod
def rain_specific_attenuation_coefficients(f, el, tau):
"""
The frequency-dependent coefficients k and α are given in Table 1 for
linear polarizations (horizontal: H, vertical: V) and horizontal paths.
Values of k and α at frequencies other than those in Table 1 can be
obtained by interpolator using a logarithmic scale for frequency,
a logarithmic scale for k and a linear scale for α.
The values in Table 1 have been tested and found to be sufficiently
accurate for attenuation predictions up to frequencies of 55 GHz.
"""
_f = [1, 2, 4, 6, 7, 8, 10, 12, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70,
80, 90, 100, 120, 150, 200, 300, 400]
_kH = [0.0000387, 0.000154, 0.00065, 0.00175, 0.00301, 0.00454, 0.0101,
0.0188, 0.0367, 0.0751, 0.124, 0.187, 0.263, 0.35, 0.442, 0.536,
0.707, 0.851, 0.975, 1.06, 1.12, 1.18, 1.31, 1.45, 1.36, 1.32]
_kV = [0.0000352, 0.000138, 0.000591, 0.00155, 0.00265, 0.00395,
0.00887, 0.0168, 0.0335, 0.0691, 0.113, 0.167, 0.233, 0.31,
0.393, 0.479, 0.642, 0.784, 0.906, 0.999, 1.06, 1.13, 1.27,
1.42, 1.35, 1.31]
_alphaH = [0.912, 0.963, 1.121, 1.308, 1.332, 1.327, 1.276, 1.217,
1.154, 1.099, 1.061, 1.021, 0.979, 0.939, 0.903, 0.873,
0.826, 0.793, 0.769, 0.753, 0.743, 0.731, 0.71, 0.689,
0.688, 0.683]
_alphaV = [0.88, 0.923, 1.075, 1.265, 1.312, 1.31, 1.264, 1.2, 1.128,
1.065, 1.03, 1, 0.963, 0.929, 0.897, 0.868, 0.824, 0.793,
0.769, 0.754, 0.744, 0.732, 0.711, 0.69, 0.689, 0.684]
KH = np.exp(np.interp(np.log(f), np.log(_f), np.log(_kH)))
KV = np.exp(np.interp(np.log(f), np.log(_f), np.log(_kV)))
alphaH = np.interp(np.log(f), np.log(_f), _alphaH)
alphaV = np.interp(np.log(f), np.log(_f), _alphaV)
k = (KH + KV + (KH - KV) * np.cos(np.deg2rad(el))**2 *
np.cos(np.deg2rad(2 * tau))) / 2.0
alpha = (KH * alphaH + KV * alphaV + (KH * alphaH - KV * alphaV) *
np.cos(np.deg2rad(el))**2 *
np.cos(np.deg2rad(2 * tau))) / (2.0 * k)
return k, alpha
class _ITU838_0_():
def __init__(self):
self.__version__ = 0
self.year = 1992
self.month = 8
self.link = 'https://www.itu.int/rec/R-REC-P.838-0-199203-S/en'
@staticmethod
def rain_specific_attenuation_coefficients(*args, **kwargs):
return _ITU838_1_.rain_specific_attenuation_coefficients(*args,
**kwargs)
__model = __ITU838__()
[docs]def change_version(new_version):
"""
Change the version of the ITU-R P.838 recommendation currently being used.
This function changes the model used for the ITU-R P.838 recommendation
to a different version.
Parameters
----------
new_version : int
Number of the version to use.
Valid values are:
* 3: Activates recommendation ITU-R P.838-3 (03/05) (Current version)
* 2: Activates recommendation ITU-R P.838-2 (04/03) (Superseded)
* 1: Activates recommendation ITU-R P.838-1 (10/99) (Superseded)
* 0: Activates recommendation ITU-R P.838-0 (03/92) (Superseded)
"""
global __model
__model = __ITU838__(new_version)
[docs]def get_version():
"""
Obtain the version of the ITU-R P.838 recommendation currently being used.
Returns
-------
version: int
Version currently being used.
"""
return __model.__version__
[docs]def rain_specific_attenuation_coefficients(f, el, tau):
"""Compute the values for the coefficients k and α.
A method to compute the values for the coefficients k and α to compute
the rain specific attenuation :math:`\\gamma_R` (dB/km) (dB/km)
Parameters
----------
f : number or Quantity
Frequency (GHz)
el : number, sequence, or numpy.ndarray
Elevation angle of the receiver points
tau : number, sequence, or numpy.ndarray
Polarization tilt angle relative to the horizontal (degrees). Tau = 45
deg for circular polarization)
Returns
-------
k: number
Coefficient k (non-dimensional)
α: number
Coefficient α (non-dimensional)
References
----------
[1] Rain height model for prediction methods:
https://www.itu.int/rec/R-REC-P.838/en
"""
f = prepare_quantity(f, u.GHz, 'Frequency')
return __model.rain_specific_attenuation_coefficients(f, el, tau)
[docs]def rain_specific_attenuation(R, f, el, tau):
"""Compute the specific attenuation γ_R (dB/km) given the rainfall rate.
A method to compute the specific attenuation γ_R (dB/km) from rain. The
value is obtained from the rainfall rate R (mm/h) using a power law
relationship.
.. math::
\\gamma_R = k R^\\alpha
Parameters
----------
R : number, sequence, numpy.ndarray or Quantity
Rain rate (mm/h)
f : number or Quantity
Frequency (GHz)
el : number, sequence, or numpy.ndarray
Elevation angle of the receiver points
tau : number, sequence, or numpy.ndarray
Polarization tilt angle relative to the horizontal (degrees). Tau = 45
deg for circular polarization)
Returns
-------
γ_R: numpy.ndarray
Specific attenuation from rain (dB/km)
References
----------
[1] Rain height model for prediction methods:
https://www.itu.int/rec/R-REC-P.838/en
"""
R = prepare_quantity(R, u.mm / u.hr, 'Rain rate')
f = prepare_quantity(f, u.GHz, 'Frequency')
return __model.rain_specific_attenuation(R, f, el, tau) * u.dB / u.km