Exemplo n.º 1
0
    def N_wet(self, lat, lon):
        if not self._N_wet:
            vals = load_data(os.path.join(dataset_dir, '453/v12_ESANWET.txt'))
            lats = load_data(os.path.join(dataset_dir, '453/v12_ESALAT.txt'))
            lons = load_data(os.path.join(dataset_dir, '453/v12_ESALON.txt'))
            self._N_wet = bilinear_2D_interpolator(lats, lons, vals)

        return self._N_wet(np.array([lat.ravel(),
                                     lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 2
0
    def Pclw(self, lat, lon):
        if not self._Pclw:
            vals = load_data(os.path.join(dataset_dir, '840/v6_Pclw.txt'))
            lats = load_data(os.path.join(dataset_dir, '840/v6_Lat.txt'))
            lons = load_data(os.path.join(dataset_dir, '840/v6_Lon.txt'))
            self._Pclw = bilinear_2D_interpolator(lats, lons, vals)

        return self._Pclw(
            np.array([lat.ravel(), lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 3
0
    def temperature(self, lat, lon):
        if not self._temperature:
            vals = load_data(os.path.join(dataset_dir, '1510/v0_Temp.txt'))
            lats = load_data(os.path.join(dataset_dir, '1510/v0_Lat.txt'))
            lons = load_data(os.path.join(dataset_dir, '1510/v0_Lon.txt'))
            self._temperature = bicubic_2D_interpolator(np.flipud(lats), lons,
                                                        np.flipud(vals))

        return self._temperature(
            np.array([lat.ravel(), lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 4
0
    def sigma(self, lat, lon):
        if not self._sigma:
            vals = load_data(os.path.join(dataset_dir,
                                          '840/v4_WRED_LOGNORMAL_STDEV.txt'))
            lats = load_data(os.path.join(dataset_dir, '840/v6_Lat.txt'))
            lons = load_data(os.path.join(dataset_dir, '840/v6_Lon.txt'))
            self._sigma = bilinear_2D_interpolator(lats, lons, vals)

        return self._sigma(
            np.array([lat.ravel(), lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 5
0
    def temperature(self, lat, lon):
        if not self._temperature:
            vals = load_data(os.path.join(dataset_dir, '1510/v1_T_Annual.txt'))
            lats = load_data(os.path.join(dataset_dir, '1510/v1_Lat.txt'))
            lons = load_data(os.path.join(dataset_dir, '1510/v1_Lon.txt'))
            self._temperature = bilinear_2D_interpolator(
                    np.flipud(lats), lons, np.flipud(vals))

        lon[lon > 180] = lon[lon > 180] - 360
        return self._temperature(
            np.array([lat.ravel(), lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 6
0
    def altitude(self, lat, lon):
        if not self._altitude:
            vals = load_data(
                os.path.join(dataset_dir, '1511/v1_TOPO_0DOT5.txt'))
            lats = load_data(os.path.join(dataset_dir, '1511/v1_Lat.txt'))
            lons = load_data(os.path.join(dataset_dir, '1511/v1_Lon.txt'))
            self._altitude = bicubic_2D_interpolator(np.flipud(lats), lons,
                                                     np.flipud(vals))

        return self._altitude(np.array([lat.ravel(),
                                        lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 7
0
    def topo_alt(self, lat, lon):
        if self._topo_alt is None:
            d_dir = os.path.join(dataset_dir, '836/v6_TOPO_0DOT5.txt')
            lats = load_data(os.path.join(dataset_dir, '836/v6_TOPOLAT.txt'))
            lons = load_data(os.path.join(dataset_dir, '836/v6_TOPOLON.txt'))
            vals = load_data(d_dir)
            self._topo_alt = bicubic_2D_interpolator(np.flipud(lats), lons,
                                                     np.flipud(vals))

        return self._topo_alt(
                np.array([lat.ravel(), lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 8
0
    def Beta(self, lat, lon):
        if not self._Beta:
            vals = load_data(
                os.path.join(dataset_dir, '837/ESARAIN_BETA_v5.txt'))
            lats = load_data(
                os.path.join(dataset_dir, '837/ESARAIN_LAT_v5.txt'))
            lons = load_data(
                os.path.join(dataset_dir, '837/ESARAIN_LON_v5.txt'))
            self._Beta = bilinear_2D_interpolator(lats, lons, vals)

        return self._Beta(np.array([lat.ravel(),
                                    lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 9
0
    def isoterm_0(self, lat, lon):
        if not self._zero_isoterm_data:
            vals = load_data(os.path.join(dataset_dir,
                                          '839/v4_ESA0HEIGHT.txt'))
            lats = load_data(os.path.join(dataset_dir, '839/v4_ESALAT.txt'))
            lons = load_data(os.path.join(dataset_dir, '839/v4_ESALON.txt'))
            self._zero_isoterm_data = bilinear_2D_interpolator(
                lats, lons, vals)

        return self._zero_isoterm_data(np.array([lat.ravel(),
                                                 lon.ravel()
                                                 ]).T).reshape(lat.shape)
Exemplo n.º 10
0
    def R001(self, lat, lon):
        if not self._R001:
            lats = load_data(os.path.join(dataset_dir, '837/v7_LAT_R001.txt'))
            lons = load_data(os.path.join(dataset_dir, '837/v7_LON_R001.txt'))
            vals = load_data(os.path.join(dataset_dir, '837/v7_R001.txt'))
            self._R001 = bilinear_2D_interpolator(np.flipud(lats), lons,
                                                  np.flipud(vals))

        # In this recommendation the longitude is encoded with format -180 to
        # 180 whereas we always use 0 - 360 encoding
        lon = np.array(lon)
        lon[lon > 180] = lon[lon > 180] - 360
        return self._R001(np.array([lat.ravel(),
                                    lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 11
0
    def rho(self, lat, lon, p):
        if not self._rho:
            ps = [0.1, 0.2, 0.3, 0.5, 1, 2, 3, 5, 10, 20, 30,
                  50, 60, 70, 80, 90, 95, 99]
            d_dir = os.path.join(dataset_dir, '836/v4_RHO_%s.txt')
            lats = load_data(os.path.join(dataset_dir, '836/v4_Lat.txt'))
            lons = load_data(os.path.join(dataset_dir, '836/v4_Lon.txt'))
            for p_loads in ps:
                vals = load_data(d_dir % (str(p_loads).replace('.', '')))
                self._rho[float(p_loads)] =\
                    bilinear_2D_interpolator(lats, lons, vals)

        return self._rho[float(p)](
                np.array([lat.ravel(), lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 12
0
    def month_temperature(self, lat, lon, m):
        if not self._month_temperature:
            lats = load_data(os.path.join(dataset_dir, '1510/v1_Lat.txt'))
            lons = load_data(os.path.join(dataset_dir, '1510/v1_Lon.txt'))
            for _m in self.__months:
                vals = load_data(os.path.join(dataset_dir,
                                              '1510/v1_T_Month{0:02d}.txt')
                                 .format(_m))
                self._month_temperature[_m] = bilinear_2D_interpolator(
                            np.flipud(lats), lons, np.flipud(vals))

        lon[lon > 180] = lon[lon > 180] - 360
        return self._month_temperature[m](
            np.array([lat.ravel(), lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 13
0
    def Lred(self, lat, lon, p):
        if not self._Lred:
            ps = [0.1, 0.2, 0.3, 0.5, 1, 2, 3, 5, 10, 20, 30,
                  50, 60, 70, 80, 90, 95]
            d_dir = os.path.join(dataset_dir, '840/v7_Lred_%s.txt')
            lats = load_data(os.path.join(dataset_dir, '840/v7_Lat.txt'))
            lons = load_data(os.path.join(dataset_dir, '840/v7_Lon.txt'))
            for p_load in ps:
                vals = load_data(d_dir % (str(p_load).replace('.', '')))
                self._Lred[float(p_load)] = bilinear_2D_interpolator(
                    lats, lons, vals)

        return self._Lred[float(p)](
            np.array([lat.ravel(), lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 14
0
    def s_a(self, lat, lon):
        """ Standard deviation of terrain heights (m) within a 110 km × 110 km
        area with a 30 s resolution (e.g. the Globe “gtopo30” data).
        The value for the mid-path may be obtained from an area roughness
        with 0.5 × 0.5 degree resolution of geographical coordinates
        using bi-linear interpolation.
        """
        if not self._s_a:
            vals = load_data(os.path.join(dataset_dir, '530/v16_gtopo_30.txt'))
            lats = load_data(os.path.join(dataset_dir, '530/v16_lat.txt'))
            lons = load_data(os.path.join(dataset_dir, '530/v16_lon.txt'))
            self._Pr6 = bilinear_2D_interpolator(lats, lons, vals)

        return self._Pr6(np.array([lat.ravel(),
                                   lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 15
0
    def Mt(self, lat, lon, m):
        if not self._Mt:
            lats = load_data(os.path.join(dataset_dir, '837/v7_LAT_MT.txt'))
            lons = load_data(os.path.join(dataset_dir, '837/v7_LON_MT.txt'))
            for _m in self.months:
                vals = load_data(
                    os.path.join(dataset_dir,
                                 '837/v7_MT_Month{0:02d}.txt').format(_m))
                self._Mt[_m] = bilinear_2D_interpolator(
                    np.flipud(lats), lons, np.flipud(vals))

        # In this recommendation the longitude is encoded with format -180 to
        # 180 whereas we always use 0 - 360 encoding
        lon = np.array(lon)
        lon[lon > 180] = lon[lon > 180] - 360
        return self._Mt[m](np.array([lat.ravel(),
                                     lon.ravel()]).T).reshape(lat.shape)
Exemplo n.º 16
0
    def N_wet(self, lat, lon, p):
        if not self._N_wet:
            ps = [
                0.1, 0.2, 0.3, 0.5, 1, 2, 3, 5, 10, 20, 30, 50, 60, 70, 80, 90,
                95, 99
            ]
            d_dir = os.path.join(dataset_dir, '453/v13_NWET_Annual_%s.txt')
            lats = load_data(os.path.join(dataset_dir, '453/v13_LAT_N.txt'))
            lons = load_data(os.path.join(dataset_dir, '453/v13_LON_N.txt'))
            for p_loads in ps:
                vals = load_data(d_dir % (str(p_loads).replace('.', '')))
                self._N_wet[float(p_loads)] = bilinear_2D_interpolator(
                    np.flipud(lats), lons, np.flipud(vals))

        lon[lon > 180] = lon[lon > 180] - 360
        return self._N_wet[float(p)](np.array([lat.ravel(),
                                               lon.ravel()
                                               ]).T).reshape(lat.shape)
Exemplo n.º 17
0
    def DN65(self, lat, lon, p):
        if not self._DN65:
            ps = [
                0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95,
                98, 99, 99.5, 99.8, 99.9
            ]
            d_dir = os.path.join(dataset_dir, '453/v12_DN65m_%02dd%02d_v1.txt')
            lats = load_data(os.path.join(dataset_dir, '453/v12_lat0d75.txt'))
            lons = load_data(os.path.join(dataset_dir, '453/v12_lon0d75.txt'))
            for p_loads in ps:
                int_p = p_loads // 1
                frac_p = round((p_loads % 1.0) * 100)
                vals = load_data(d_dir % (int_p, frac_p))
                self._DN65[float(p_loads)] = bilinear_2D_interpolator(
                    lats, lons, vals)

        return self._DN65[float(p)](np.array([lat.ravel(),
                                              lon.ravel()
                                              ]).T).reshape(lat.shape)
Exemplo n.º 18
0
class _ITU676_10():

    tmp = load_data(os.path.join(dataset_dir, '676/v10_lines_oxygen.txt'),
                    skip_header=1)
    f_ox = tmp[:, 0]
    a1 = tmp[:, 1]
    a2 = tmp[:, 2]
    a3 = tmp[:, 3]
    a4 = tmp[:, 4]
    a5 = tmp[:, 5]
    a6 = tmp[:, 6]

    tmp = load_data(os.path.join(dataset_dir,
                                 '676//v10_lines_water_vapour.txt'),
                    skip_header=1)
    f_wv = tmp[:, 0]
    b1 = tmp[:, 1]
    b2 = tmp[:, 2]
    b3 = tmp[:, 3]
    b4 = tmp[:, 4]
    b5 = tmp[:, 5]
    b6 = tmp[:, 6]

    def __init__(self):
        self.__version__ = 10
        self.year = 2013
        self.month = 9
        self.link = 'https://www.itu.int/rec/R-REC-P.676-10-201309-S/en'

    @classmethod
    def gammaw_approx(self, f, P, rho, T):
        rp = P / 1013
        rt = 288 / (T)
        eta1 = 0.955 * rp * rt**0.68 + 0.006 * rho
        eta2 = 0.735 * rp * rt**0.50 + 0.0353 * rt**4 * rho

        def g(f, fi):
            return 1 + ((f - fi) / (f + fi))**2

        gammaw = (
            (3.98 * eta1 * np.exp(2.23 * (1 - rt))) /
            ((f - 22.235)**2 + 9.42 * eta1**2) * g(f, 22.0) +
            (11.96 * eta1 * np.exp(0.70 * (1 - rt))) /
            ((f - 183.310)**2 + 11.14 * eta1**2) +
            (0.081 * eta1 * np.exp(6.44 * (1 - rt))) /
            ((f - 321.226)**2 + 6.29 * eta1**2) +
            (3.660 * eta1 * np.exp(1.60 * (1 - rt))) /
            ((f - 325.153)**2 + 9.22 * eta1**2) +
            (25.37 * eta1 * np.exp(1.09 * (1 - rt))) / ((f - 380.000)**2) +
            (17.40 * eta1 * np.exp(1.46 * (1 - rt))) / ((f - 448.000)**2) +
            (844.6 * eta1 * np.exp(0.17 * (1 - rt))) /
            ((f - 557.000)**2) * g(f, 557.0) +
            (290.0 * eta1 * np.exp(0.41 * (1 - rt))) /
            ((f - 752.000)**2) * g(f, 752.0) +
            (8.3328e4 * eta2 * np.exp(0.99 * (1 - rt))) /
            ((f - 1780.00)**2) * g(f, 1780.0)) * f**2 * rt**2.5 * rho * 1e-4
        return gammaw

    @classmethod
    def gamma0_approx(self, f, P, rho, T):
        rp = P / 1013.0
        rt = 288.0 / (T)

        def phi(rp, rt, a, b, c, d):
            return np.power(rp, a) * np.power(rt, b) * np.exp(c *
                                                              (1 - rp) + d *
                                                              (1 - rt))

        # Dry air attenuation (gamma0) computation as in Section 1 of Annex 2
        # of [1]
        delta = -0.00306 * phi(rp, rt, 3.211, -14.94, 1.583, -16.37)

        xi1 = phi(rp, rt, 0.0717, -1.8132, 0.0156, -1.6515)
        xi2 = phi(rp, rt, 0.5146, -4.6368, -0.1921, -5.7416)
        xi3 = phi(rp, rt, 0.3414, -6.5851, 0.2130, -8.5854)
        xi4 = phi(rp, rt, -0.0112, 0.0092, -0.1033, -0.0009)
        xi5 = phi(rp, rt, 0.2705, -2.7192, -0.3016, -4.1033)
        xi6 = phi(rp, rt, 0.2445, -5.9191, 0.0422, -8.0719)
        xi7 = phi(rp, rt, -0.1833, 6.5589, -0.2402, 6.131)

        gamma54 = 2.192 * phi(rp, rt, 1.8286, -1.9487, 0.4051, -2.8509)
        gamma58 = 12.59 * phi(rp, rt, 1.0045, 3.5610, 0.1588, 1.2834)
        gamma60 = 15.00 * phi(rp, rt, 0.9003, 4.1335, 0.0427, 1.6088)
        gamma62 = 14.28 * phi(rp, rt, 0.9886, 3.4176, 0.1827, 1.3429)
        gamma64 = 6.819 * phi(rp, rt, 1.4320, 0.6258, 0.3177, -0.5914)
        gamma66 = 1.908 * phi(rp, rt, 2.0717, -4.1404, 0.4910, -4.8718)

        def fcn_le_54():
            return (((7.2 * rt**2.8) / (f**2 + 0.34 * rp**2 * rt**1.6) +
                     (0.62 * xi3) / ((54 - f)**(1.16 * xi1) + 0.83 * xi2)) *
                    f**2 * rp**2 * 1e-3)

        def fcn_le_60():
            return (np.exp(
                np.log(gamma54) / 24.0 * (f - 58) * (f - 60) -
                np.log(gamma58) / 8.0 * (f - 54) * (f - 60) +
                np.log(gamma60) / 12.0 * (f - 54) * (f - 58)))

        def fcn_le_62():
            return (gamma60 + (gamma62 - gamma60) * (f - 60) / 2.0)

        def fcn_le_66():
            return (np.exp(
                np.log(gamma62) / 8.0 * (f - 64) * (f - 66) -
                np.log(gamma64) / 4.0 * (f - 62) * (f - 66) +
                np.log(gamma66) / 8.0 * (f - 62) * (f - 64)))

        def fcn_le_120():
            return ((3.02e-4 * rt**3.5 + (0.283 * rt**3.8) /
                     ((f - 118.75)**2 + 2.91 * rp**2 * rt**1.6) +
                     (0.502 * xi6 * (1 - 0.0163 * xi7 * (f - 66))) /
                     ((f - 66)**(1.4346 * xi4) + 1.15 * xi5)) * f**2 * rp**2 *
                    1e-3)

        def fcn_rest():
            return (((3.02e-4) / (1 + 1.9e-5 * f**1.5) + (0.283 * rt**0.3) /
                     ((f - 118.75)**2 + 2.91 * rp**2 * rt**1.6)) * f**2 *
                    rp**2 * rt**3.5 * 1e-3 + delta)

        gamma0 = \
            np.where(
                f <= 54, fcn_le_54(),
                np.where(
                    np.logical_and(54 < f, f <= 60), fcn_le_60(),
                    np.where(
                        np.logical_and(60 < f, f <= 62), fcn_le_62(),
                        np.where(
                            np.logical_and(62 < f, f <= 66), fcn_le_66(),
                            np.where(
                                np.logical_and(66 < f, f <= 120),
                                fcn_le_120(),
                                fcn_rest())))))

        return gamma0

    @classmethod
    def gamma0_exact(self, f, p, rho, T):
        return __gamma0_exact__676_9_11__(self, f, p, rho, T)

    @classmethod
    def gammaw_exact(self, f, p, rho, T):
        return __gammaw_exact__676_9_11__(self, f, p, rho, T)

    @classmethod
    def gamma_exact(self, f, p, rho, T):
        return (self.gamma0_exact(f, p, rho, T) +
                self.gammaw_exact(f, p, rho, T))

    @classmethod
    def gaseous_attenuation_approximation(self, f, el, rho, P, T):
        """
        T goes in Kelvin
        """
        if np.any(f > 350):
            warnings.warn(
                RuntimeWarning(
                    'The approximated method to computes '
                    'the gaseous attenuation in recommendation ITU-P 676-11 '
                    'is only recommended for frequencies below 350GHz'))

        if np.any(5 > el) or np.any(np.mod(el, 90) < 5):
            warnings.warn(
                RuntimeWarning(
                    'The approximated method to compute '
                    'the gaseous attenuation in recommendation ITU-P 676-11 '
                    'is only recommended for elevation angles between'
                    '5 and 90 degrees'))

        # Water vapour attenuation (gammaw) computation as in Section 1 of
        # Annex 2 of [1]
        gamma0 = self.gamma0_approx(f, P, rho, T)
        gammaw = self.gammaw_approx(f, P, rho, T)

        return gamma0, gammaw

    @classmethod
    def slant_inclined_path_equivalent_height(self, f, p):
        """
        """
        rp = p / 1013.0
        t1 = (4.64) / (1 + 0.066 * rp**-2.3) * \
            np.exp(- ((f - 59.7) / (2.87 + 12.4 * np.exp(-7.9 * rp)))**2)
        t2 = (0.14 * np.exp(2.21 * rp)) / \
            ((f - 118.75)**2 + 0.031 * np.exp(2.2 * rp))
        t3 = (0.0114) / (1 + 0.14 * rp**-2.6) * f * \
             (-0.0247 + 0.0001 * f + 1.61e-6 * f**2) / \
             (1 - 0.0169 * f + 4.1e-5 * f**2 + 3.2e-7 * f**3)

        h0 = (6.1) / (1 + 0.17 * rp**-1.1) * (1 + t1 + t2 + t3)

        h0 = np.where(f < 70, np.minimum(h0, 10.7 * rp**0.3), h0)

        sigmaw = (1.013) / (1 + np.exp(-8.6 * (rp - 0.57)))
        hw = 1.66 * (1 + (1.39 * sigmaw) / ((f - 22.235)**2 + 2.56 * sigmaw) +
                     (3.37 * sigmaw) / ((f - 183.31)**2 + 4.69 * sigmaw) +
                     (1.58 * sigmaw) / ((f - 325.1)**2 + 2.89 * sigmaw))

        return h0, hw

    @classmethod
    def gaseous_attenuation_terrestrial_path(self,
                                             r,
                                             f,
                                             el,
                                             rho,
                                             P,
                                             T,
                                             mode='approx'):
        """
        """
        if mode == 'approx':
            gamma0, gammaw = self.gaseous_attenuation_approximation(
                f, el, rho, P, T)
            return (gamma0 + gammaw) * r
        else:
            gamma = self.gamma_exact(f, P, rho, T)
            return gamma * r

    @classmethod
    def gaseous_attenuation_slant_path(self,
                                       f,
                                       el,
                                       rho,
                                       P,
                                       T,
                                       V_t=None,
                                       h=None,
                                       mode='approx'):
        """
        """
        if mode == 'approx':
            gamma0, gammaw = self.gaseous_attenuation_approximation(
                f, el, rho, P, T)
            e = rho * T / 216.7
            h0, hw = self.slant_inclined_path_equivalent_height(f, P + e)

            # Use the zenit water-vapour method if the values of V_t
            # and h are provided
            if V_t is not None and h is not None:
                Aw = self.zenit_water_vapour_attenuation(
                    None, None, None, f, V_t, h)
            else:
                Aw = gammaw * hw

            A0 = gamma0 * h0
            return (A0 + Aw) / np.sin(np.deg2rad(el))

        else:
            delta_h = 0.0001 * np.exp((np.arange(1, 923) - 1) / 100)
            h_n = np.cumsum(delta_h)
            T_n = standard_temperature(h_n).to(u.K).value
            press_n = standard_pressure(h_n).value
            rho_n = standard_water_vapour_density(h_n, rho_0=rho).value

            e = rho * T / 216.7
            n_n = radio_refractive_index(press_n, e, T).value
            n_ratio = np.pad(n_n[1:], (0, 1), mode='edge') / n_n
            r_n = 6371 + h_n

            b = np.pi / 2 - np.deg2rad(el)
            Agas = 0
            for t, press, rho, r, delta, n_r in zip(T_n, press_n, rho_n, r_n,
                                                    delta_h, n_ratio):
                a = -r * np.cos(b) + 0.5 * np.sqrt(
                    4 * r**2 * np.cos(b)**2 + 8 * r * delta + 4 * delta**2)
                a_cos_arg = np.clip((-a**2 - 2 * r * delta - delta**2) /
                                    (2 * a * r + 2 * a * delta), -1, 1)
                alpha = np.pi - np.arccos(a_cos_arg)
                gamma = self.gamma_exact(f, press, rho, t)
                Agas += a * gamma
                b = np.arcsin(n_r * np.sin(alpha))

            return Agas

    @classmethod
    def gaseous_attenuation_inclined_path(self,
                                          f,
                                          el,
                                          rho,
                                          P,
                                          T,
                                          h1,
                                          h2,
                                          mode='approx'):
        """
        """
        if h1 > 10 or h2 > 10:
            raise ValueError('Both the transmitter and the receiver must be at'
                             'altitude of less than 10 km above the sea level.'
                             'Current altitude Tx: %.2f km, Rx: %.2f km' %
                             (h1, h2))

        if mode == 'approx':
            rho = rho * np.exp(h1 / 2)
            gamma0, gammaw = self.gaseous_attenuation_approximation(
                f, el, rho, P, T)
        else:
            gamma0 = self.gamma_exact(f, P, rho, T)
            gammaw = 0

        e = rho * T / 216.7
        h0, hw = self.slant_inclined_path_equivalent_height(f, P + e)

        if 5 < el and el < 90:
            h0_p = h0 * (np.exp(-h1 / h0) - np.exp(-h2 / h0))
            hw_p = hw * (np.exp(-h1 / hw) - np.exp(-h2 / hw))
            return (gamma0 * h0_p + gammaw * hw_p) / np.sin(np.deg2rad(el))
        else:

            def F(x):
                return 1 / (0.661 * x + 0.339 * np.sqrt(x**2 + 5.51))

            el1 = el
            el2 = -el
            Re = 8500  # TODO: change to ITU-R P 834

            def xi(eli, hi):
                return np.tan(np.deg2rad(eli) * np.sqrt((Re + hi) / h0))

            def xi_p(eli, hi):
                return np.tan(np.deg2rad(eli) * np.sqrt((Re + hi) / hw))

            def eq_33(h_num, h_den, el, x):
                return np.sqrt(Re + h_num) * F(x) * \
                    np.exp(-h_num / h_den) / np.cos(np.deg2rad(el))

            A = gamma0 * np.sqrt(h0) * (eq_33(h1, h0, el1, xi(el1, h1)) -
                                        eq_33(h2, h0, el2, xi(el2, h2))) +\
                gammaw * np.sqrt(hw) * (eq_33(h1, hw, el1, xi_p(el1, h1)) -
                                        eq_33(h2, hw, el2, xi_p(el2, h2)))
            return A

    @classmethod
    def zenit_water_vapour_attenuation(self, lat, lon, p, f, V_t=None, h=None):
        f_ref = 20.6  # [GHz]
        p_ref = 780  # [hPa]
        if V_t is None:
            V_t = total_water_vapour_content(lat, lon, p, h).value
        rho_ref = V_t / 4  # [g/m3]
        t_ref = 14 * np.log(0.22 * V_t / 4) + 3  # [Celsius]

        gammaw_approx_vect = np.vectorize(self.gammaw_approx)
        return (0.0173 * V_t *
                gammaw_approx_vect(f, p_ref, rho_ref, t_ref + 273) /
                gammaw_approx_vect(f_ref, p_ref, rho_ref, t_ref + 273))
Exemplo n.º 19
0
class _ITU676_11():

    tmp = load_data(os.path.join(dataset_dir, '676/v11_lines_oxygen.txt'),
                    skip_header=1)
    f_ox = tmp[:, 0]
    a1 = tmp[:, 1]
    a2 = tmp[:, 2]
    a3 = tmp[:, 3]
    a4 = tmp[:, 4]
    a5 = tmp[:, 5]
    a6 = tmp[:, 6]

    tmp = load_data(os.path.join(dataset_dir,
                                 '676//v11_lines_water_vapour.txt'),
                    skip_header=1)
    f_wv = tmp[:, 0]
    b1 = tmp[:, 1]
    b2 = tmp[:, 2]
    b3 = tmp[:, 3]
    b4 = tmp[:, 4]
    b5 = tmp[:, 5]
    b6 = tmp[:, 6]

    idx_approx = np.zeros_like(b1, dtype=bool).squeeze()
    asterisk_rows = [0, 3, 4, 5, 7, 12, 20, 24, 34]
    idx_approx[np.array(asterisk_rows)] = True

    def __init__(self):
        self.__version__ = 11
        self.year = 2017
        self.month = 12
        self.link = 'https://www.itu.int/rec/R-REC-P.676-11-201712-S/en'

    @classmethod
    def gammaw_approx(self, f, p, rho, T):
        # T in Kelvin
        # e : water vapour partial pressure in hPa (total barometric pressure
        # ptot = p + e)
        theta = 300 / T
        e = rho * T / 216.7

        f_wv = self.f_wv[self.idx_approx]
        b1 = self.b1[self.idx_approx]
        b2 = self.b2[self.idx_approx]
        b3 = self.b3[self.idx_approx]
        b4 = self.b4[self.idx_approx]
        b5 = self.b5[self.idx_approx]
        b6 = self.b6[self.idx_approx]

        D_f_wv = b3 * 1e-4 * (p * theta**b4 + b5 * e * theta**b6)

        F_i_wv = f / f_wv * ((D_f_wv) / ((f_wv - f)**2 + D_f_wv**2) +
                             (D_f_wv) / ((f_wv + f)**2 + D_f_wv**2))

        Si_wv = b1 * 1e-1 * e * theta**3.5 * np.exp(b2 * (1 - theta))

        N_pp_wv = Si_wv * F_i_wv

        N_pp = N_pp_wv.sum()

        gamma = 0.1820 * f * N_pp  # Eq. 1 [dB/km]
        return gamma

    @classmethod
    def gamma0_approx(self, f, p, rho, T):
        # T in Kelvin
        # e : water vapour partial pressure in hPa (total barometric pressure
        # ptot = p + e)
        theta = 300 / T
        e = rho * T / 216.7

        f_ox = self.f_ox

        D_f_ox = self.a3 * 1e-4 * (p *
                                   (theta**(0.8 - self.a4)) + 1.1 * e * theta)

        delta_ox = (self.a5 + self.a6 * theta) * 1e-4 * (p + e) * theta**0.8

        F_i_ox = f / f_ox * ((D_f_ox - delta_ox *
                              (f_ox - f)) / ((f_ox - f)**2 + D_f_ox**2) +
                             (D_f_ox - delta_ox *
                              (f_ox + f)) / ((f_ox + f)**2 + D_f_ox**2))

        Si_ox = self.a1 * 1e-7 * p * theta**3 * np.exp(self.a2 * (1 - theta))

        N_pp_ox = Si_ox * F_i_ox

        d = 5.6e-4 * (p + e) * theta**0.8

        N_d_pp = f * p * theta**2 * \
            (6.14e-5 / (d * (1 + (f / d)**2)) +
             1.4e-12 * p * theta**1.5 / (1 + 1.9e-5 * f**1.5))

        N_pp = N_pp_ox.sum() + N_d_pp

        gamma = 0.1820 * f * N_pp  # Eq. 1 [dB/km]
        return gamma

    @classmethod
    def gamma0_exact(self, f, p, rho, T):
        return __gamma0_exact__676_9_11__(self, f, p, rho, T)

    @classmethod
    def gammaw_exact(self, f, p, rho, T):
        return __gammaw_exact__676_9_11__(self, f, p, rho, T)

    @classmethod
    def gamma_exact(self, f, p, rho, T):
        return (self.gamma0_exact(f, p, rho, T) +
                self.gammaw_exact(f, p, rho, T))

    @classmethod
    def gaseous_attenuation_approximation(self, f, el, rho, P, T):
        """
        T goes in Kelvin
        """
        if np.any(f > 350):
            warnings.warn(
                RuntimeWarning(
                    'The approximated method to computes '
                    'the gaseous attenuation in recommendation ITU-P 676-11 '
                    'is only recommended for frequencies below 350GHz'))

        if np.any(5 > el) or np.any(np.mod(el, 90) < 5):
            warnings.warn(
                RuntimeWarning(
                    'The approximated method to compute '
                    'the gaseous attenuation in recommendation ITU-P 676-11 '
                    'is only recommended for elevation angles between'
                    '5 and 90 degrees'))

        # Water vapour attenuation (gammaw) computation as in Section 1 of
        # Annex 2 of [1]
        gamma0 = self.gamma0_approx(f, P, rho, T)
        gammaw = self.gammaw_approx(f, P, rho, T)

        return gamma0, gammaw

    @classmethod
    def slant_inclined_path_equivalent_height(self, f, p):
        """
        """
        rp = p / 1013.25
        t1 = 4.64 / (1 + 0.066 * rp**-2.3) * \
            np.exp(- ((f - 59.7) / (2.87 + 12.4 * np.exp(-7.9 * rp)))**2)
        t2 = (0.14 * np.exp(2.12 * rp)) / \
            ((f - 118.75)**2 + 0.031 * np.exp(2.2 * rp))
        t3 = 0.0114 / (1 + 0.14 * rp**-2.6) * f * \
            (-0.0247 + 0.0001 * f + 1.61e-6 * f**2) / \
            (1 - 0.0169 * f + 4.1e-5 * f**2 + 3.2e-7 * f**3)

        h0 = 6.1 / (1 + 0.17 * rp**-1.1) * (1 + t1 + t2 + t3)

        h0 = np.where(f < 70, np.minimum(h0, 10.7 * rp**0.3), h0)

        sigmaw = 1.013 / (1 + np.exp(-8.6 * (rp - 0.57)))
        hw = 1.66 * (1 + (1.39 * sigmaw) / ((f - 22.235)**2 + 2.56 * sigmaw) +
                     (3.37 * sigmaw) / ((f - 183.31)**2 + 4.69 * sigmaw) +
                     (1.58 * sigmaw) / ((f - 325.1)**2 + 2.89 * sigmaw))

        return h0, hw

    @classmethod
    def gaseous_attenuation_terrestrial_path(self,
                                             r,
                                             f,
                                             el,
                                             rho,
                                             P,
                                             T,
                                             mode='approx'):
        """
        """
        if mode == 'approx':
            gamma0, gammaw = self.gaseous_attenuation_approximation(
                f, el, rho, P, T)
            return (gamma0 + gammaw) * r
        else:
            gamma = self.gamma_exact(f, P, rho, T)
            return gamma * r

    @classmethod
    def gaseous_attenuation_slant_path(self,
                                       f,
                                       el,
                                       rho,
                                       P,
                                       T,
                                       V_t=None,
                                       h=None,
                                       mode='approx'):
        """
        """
        if mode == 'approx':
            gamma0, gammaw = self.gaseous_attenuation_approximation(
                f, el, rho, P, T)

            e = rho * T / 216.7
            h0, hw = self.slant_inclined_path_equivalent_height(f, P + e)

            # Use the zenit water-vapour method if the values of V_t
            # and h are provided
            if V_t is not None and h is not None:
                Aw = self.zenit_water_vapour_attenuation(
                    None, None, None, f, V_t, h)
            else:
                Aw = gammaw * hw

            A0 = gamma0 * h0
            return (A0 + Aw) / np.sin(np.deg2rad(el))

        else:
            delta_h = 0.0001 * np.exp((np.arange(0, 923)) / 100)
            h_n = np.cumsum(delta_h)
            T_n = standard_temperature(h_n).to(u.K).value
            press_n = standard_pressure(h_n).value
            rho_n = standard_water_vapour_density(h_n, rho_0=rho).value

            e = rho * T / 216.7
            n_n = radio_refractive_index(press_n, e, T).value
            n_ratio = np.pad(n_n[1:], (0, 1), mode='edge') / n_n
            r_n = 6371 + h_n

            b = np.pi / 2 - np.deg2rad(el)
            Agas = 0
            for t, press, rho, r, delta, n_r in zip(T_n, press_n, rho_n, r_n,
                                                    delta_h, n_ratio):
                a = -r * np.cos(b) + 0.5 * np.sqrt(
                    4 * r**2 * np.cos(b)**2 + 8 * r * delta + 4 * delta**2)
                a_cos_arg = np.clip((-a**2 - 2 * r * delta - delta**2) /
                                    (2 * a * r + 2 * a * delta), -1, 1)
                alpha = np.pi - np.arccos(a_cos_arg)
                gamma = self.gamma_exact(f, press, rho, t)
                Agas += a * gamma
                b = np.arcsin(n_r * np.sin(alpha))

            return Agas

    @classmethod
    def gaseous_attenuation_inclined_path(self,
                                          f,
                                          el,
                                          rho,
                                          P,
                                          T,
                                          h1,
                                          h2,
                                          mode='approx'):
        """
        """
        if h1 > 10 or h2 > 10:
            raise ValueError('Both the transmitter and the receiver must be at'
                             'altitude of less than 10 km above the sea level.'
                             'Current altitude Tx: %.2f km, Rx: %.2f km' %
                             (h1, h2))

        if mode == 'approx':
            rho = rho * np.exp(h1 / 2)
            gamma0, gammaw = self.gaseous_attenuation_approximation(
                f, el, rho, P, T)
        else:
            gamma0 = self.gamma0_exact(f, P, rho, T)
            gammaw = 0

        e = rho * T / 216.7
        h0, hw = self.slant_inclined_path_equivalent_height(f, P + e)

        if 5 < el and el < 90:
            h0_p = h0 * (np.exp(-h1 / h0) - np.exp(-h2 / h0))
            hw_p = hw * (np.exp(-h1 / hw) - np.exp(-h2 / hw))
            return (gamma0 * h0_p + gammaw * hw_p) / np.sin(np.deg2rad(el))
        else:

            def F(x):
                return 1 / (0.661 * x + 0.339 * np.sqrt(x**2 + 5.51))

            el1 = el
            el2 = -el
            Re = 8500  # TODO: change to ITU-R P 834

            def xi(eli, hi):
                return np.tan(np.deg2rad(eli) * np.sqrt((Re + hi) / h0))

            def xi_p(eli, hi):
                return np.tan(np.deg2rad(eli) * np.sqrt((Re + hi) / hw))

            def eq_33(h_num, h_den, el, x):
                return np.sqrt(Re + h_num) * F(x) * \
                    np.exp(-h_num / h_den) / np.cos(np.deg2rad(el))

            A = gamma0 * np.sqrt(h0) * (eq_33(h1, h0, el1, xi(el1, h1)) -
                                        eq_33(h2, h0, el2, xi(el2, h2))) +\
                gammaw * np.sqrt(hw) * (eq_33(h1, hw, el1, xi_p(el1, h1)) -
                                        eq_33(h2, hw, el2, xi_p(el2, h2)))
            return A

    @classmethod
    def zenit_water_vapour_attenuation(self, lat, lon, p, f, V_t=None, h=None):
        f_ref = 20.6  # [GHz]
        p_ref = 815  # [hPa]

        if h is None:
            h = topographic_altitude(lat, lon).value

        if V_t is None:
            V_t = total_water_vapour_content(lat, lon, p, h).value

        rho_ref = V_t / 3.67
        t_ref = 14 * np.log(0.22 * V_t / 3.67) + 3  # [Celsius]

        a = (0.2048 * np.exp(-((f - 22.43) / 3.097)**2) +
             0.2236 * np.exp(-((f - 183.5) / 4.096)**2) +
             0.2073 * np.exp(-((f - 325) / 3.651)**2) - 0.113)

        b = 8.741e4 * np.exp(-0.587 * f) + 312.2 * f**(-2.38) + 0.723
        h = np.minimum(h, 4)

        gammaw_approx_vect = np.vectorize(self.gammaw_approx)

        Aw_term1 = (0.0176 * V_t *
                    gammaw_approx_vect(f, p_ref, rho_ref, t_ref + 273.15) /
                    gammaw_approx_vect(f_ref, p_ref, rho_ref, t_ref + 273.15))

        return np.where(f < 20, Aw_term1, Aw_term1 * (a * h**b + 1))
Exemplo n.º 20
0
class _ITU676_9():

    tmp = load_data(os.path.join(dataset_dir, '676//v9_lines_oxygen.txt'),
                    skip_header=1)
    f_ox = tmp[:, 0]
    a1 = tmp[:, 1]
    a2 = tmp[:, 2]
    a3 = tmp[:, 3]
    a4 = tmp[:, 4]
    a5 = tmp[:, 5]
    a6 = tmp[:, 6]

    tmp = load_data(os.path.join(dataset_dir,
                                 '676//v9_lines_water_vapour.txt'),
                    skip_header=1)
    f_wv = tmp[:, 0]
    b1 = tmp[:, 1]
    b2 = tmp[:, 2]
    b3 = tmp[:, 3]
    b4 = tmp[:, 4]
    b5 = tmp[:, 5]
    b6 = tmp[:, 6]

    def __init__(self):
        self.__version__ = 9
        self.year = 2012
        self.month = 2
        self.link = 'https://www.itu.int/rec/R-REC-P.676-9-201202-S/en'

    # Recommendation ITU-P R.676-9 has most of the methods similar to those
    # in Recommendation ITU-P R.676-10.
    def gammaw_approx(self, *args, **kwargs):
        return _ITU676_10.gammaw_approx(*args, **kwargs)

    def gamma0_approx(self, *args, **kwargs):
        return _ITU676_10.gamma0_approx(*args, **kwargs)

    def gaseous_attenuation_inclined_path(self, *args, **kwargs):
        return _ITU676_10.gaseous_attenuation_inclined_path(*args, **kwargs)

    def zenit_water_vapour_attenuation(self, *args, **kwargs):
        return _ITU676_10.zenit_water_vapour_attenuation(*args, **kwargs)

    def gaseous_attenuation_approximation(self, *args, **kwargs):
        return _ITU676_10.gaseous_attenuation_approximation(*args, **kwargs)

    def slant_inclined_path_equivalent_height(self, *args, **kwargs):
        return _ITU676_10.slant_inclined_path_equivalent_height(
            *args, **kwargs)

    def gaseous_attenuation_terrestrial_path(self, *args, **kwargs):
        return _ITU676_10.gaseous_attenuation_terrestrial_path(*args, **kwargs)

    def gaseous_attenuation_slant_path(self, *args, **kwargs):
        return _ITU676_10.gaseous_attenuation_slant_path(*args, **kwargs)

    def gamma0_exact(self, f, p, rho, T):
        return __gamma0_exact__676_9_11__(self, f, p, rho, T)

    def gammaw_exact(self, f, p, rho, T):
        return __gammaw_exact__676_9_11__(self, f, p, rho, T)

    def gamma_exact(self, f, p, rho, T):
        return (self.gamma0_exact(f, p, rho, T) +
                self.gammaw_exact(f, p, rho, T))