Exemplo n.º 1
0
 def mid_latitude_pressure_winter(self, h):
     """Section 3.2 of Recommendation ITU-R P.835-6
     """
     P10 = standard_pressure(10).to(u.hPa).value
     P72 = standard_pressure(72).to(u.hPa).value
     return np.where(np.logical_and((0 <= h), (h <= 10)),
                 1018.8627 - 124.2954 * h + 4.8307 * h**2,
            np.where(np.logical_and((10 < h), (h <= 72)),
                 P10 * np.exp(-0.147 * (h - 10.)),
            np.where(np.logical_and((72 < h), (h <= 100)),
                 P72 * np.exp(-0.155 * (h - 72.)), np.nan)))
Exemplo n.º 2
0
 def high_latitude_pressure_summer(self, h):
     """Section 4.1 of Recommendation ITU-R P.835-5
     """
     P10 = standard_pressure([10]).to(u.hPa).value
     P72 = standard_pressure([72]).to(u.hPa).value
     return np.where(np.logical_and((0 <= h), (h <= 10)),
                 1008.0278 - 113.2494 * h + 3.9408 * h**2,
            np.where(np.logical_and((10 < h), (h <= 72)),
                 P10 * np.exp(-0.140 * (h - 10.)),
            np.where(np.logical_and((72 < h), (h <= 100)),
                 P72 * np.exp(-0.165 * (h - 72.)), np.nan)))
Exemplo n.º 3
0
 def high_latitude_pressure_winter(self, h):
     """Section 4.2 of Recommendation ITU-R P.835-5
     """
     P10 = standard_pressure([10]).to(u.hPa).value
     P72 = standard_pressure([72]).to(u.hPa).value
     return np.where(np.logical_and((0 <= h), (h <= 10)),
                 1010.8828 - 122.2411 * h + 4.554 * h**2,
            np.where(np.logical_and((10 < h), (h <= 72)),
                 P10 * np.exp(-0.147 * (h - 10.)),
            np.where(np.logical_and((72 < h), (h <= 100)),
                 P72 * np.exp(-0.150 * (h - 72.)), np.nan)))
Exemplo n.º 4
0
 def low_latitude_pressure(self, h):
     """Section 2 of Recommendation ITU-R P.835-5
     """
     P10 = standard_pressure([10]).to(u.hPa).value
     P72 = standard_pressure([72]).to(u.hPa).value
     return np.where(np.logical_and((0 <= h), (h <= 10)),
                 1012.0306 - 109.0338 * h + 3.6316 * h**2,
            np.where(np.logical_and((10 < h), (h <= 72)),
                 P10 * np.exp(-0.147 * (h - 10.)),
            np.where(np.logical_and((72 < h), (h <= 100)),
                 P72 * np.exp(-0.165 * (h - 72.)), np.nan)))
Exemplo n.º 5
0
 def mid_latitude_pressure_summer(self, h):
     """Section 3.1 of Recommendation ITU-R P.835-5
     """
     P10 = standard_pressure([10]).to(u.hPa).value
     P72 = standard_pressure([72]).to(u.hPa).value
     return np.where(np.logical_and((0 <= h), (h <= 10)),
                 1012.8186 - 111.5569 * h + 3.8646 * h**2,
            np.where(np.logical_and((10 < h), (h <= 72)),
                 P10 * np.exp(-0.147 * (h - 10.)),
            np.where(np.logical_and((72 < h), (h <= 100)),
                 P72 * np.exp(-0.165 * (h - 72.)),
                 np.nan)))
Exemplo n.º 6
0
def atmospheric_attenuation_slant_path(lat,
                                       lon,
                                       f,
                                       el,
                                       p,
                                       D,
                                       tau,
                                       eta,
                                       hs=None,
                                       rho=None,
                                       R001=None,
                                       T=None,
                                       H=None,
                                       P=None,
                                       hL=1e3,
                                       V_t=None,
                                       mode='approx',
                                       return_contributions=False,
                                       include_rain=True,
                                       include_gas=True,
                                       include_scintillation=True,
                                       include_clouds=True):
    """ Calculation of long-term atmospheric attenuation statistics.
    The following procedure provides estimates of the long-term statistics of
    the slant-path atmospheric attenuation at a given location for
    frequencies up to 55 GHz and percentages of time 0.001 % < p < 50 %.


    Parameters
    -------------
    - lat : number, sequence, or numpy.ndarray
            Latitudes of the receiver points
    - lon : number, sequence, or numpy.ndarray
            Longitudes of the receiver points
    - f : number or Quantity
            Frequency (GHz)
    - el : sequence, number or Quantity
            Elevation angle (degrees)
    - p : number
            Percetage of the time the rain attenuation value is exceeded.
    - D: number or Quantity
            Physical diameter of the earth-station antenna (m)
    - tau : number
            Polarization tilt angle relative to the horizontal (degrees)
            (tau = 45 deg for circular polarization).
    - eta: number
            Antenna efficiency.
    - hs : number, sequence, or numpy.ndarray, optional
            Heigh above mean sea level of the earth station (km). If local data for
            the earth station height above mean sea level is not available, an
            estimate is obtained from the maps of topographic altitude
            given in Recommendation ITU-R P.1511.
    - rho : number or Quantity, optional
            Water vapor density (g/m3). If not provided, an estimate is obtained
            from Recommendation Recommendation ITU-R P.836.
    - R001: number  or Quantity, optional
            Point rainfall rate for the location for 0.01% of an average year \
            (mm/h). If not provided, an estimate is obtained from Recommendation
            ITU-R P.837. Some useful values:
                * 0.25 mm/h : Drizzle
                * 2.5  mm/h : Light rain
                * 12.5 mm/h : Medium rain
                * 25.0 mm/h : Heavy rain
                * 50.0 mm/h : Downpour
                * 100  mm/h : Tropical
                * 150  mm/h : Monsoon
    - T: number, sequence, or numpy.ndarray, optional
            Average surface ambient temperature (°C) at the site. If None, uses the
            ITU-R P.453 to estimate the wet term of the radio refractivity.
    - H: number, sequence, or numpy.ndarray, optional
            Average surface relative humidity (%) at the site. If None, uses the
            ITU-R P.453 to estimate the wet term of the radio refractivity.
    - P: number, sequence, or numpy.ndarray, optional
            Average surface pressure (hPa) at the site. If None, uses the
            ITU-R P.453 to estimate the wet term of the radio refractivity.
    - hL : number, optional
            Height of the turbulent layer (m). Default value 1000 m
    - V_t : number or Quantity, optional
            Integrated water vapour content along the path (kg/m2 or mm).
            If not provided this value is estimated using Recommendation
            ITU-R P.836. Default value None
    - mode : string, optional
            Mode for the calculation of gaseous attenuation. Valid values are
            'approx', 'exact'. If 'approx' Uses the method in Annex 2 of
            Recommendation ITU-R P.676, else uses the method described in
            Section 1. Default, 'approx'
    - return_contributions: bool, optional
            Determines whether individual contributions from gases, rain, clouds
            and scintillation are returned in addition ot the total attenuation
            (True), or just the total atmospheric attenuation (False).
            Default is False
    - include_rain: bool, optional
            Determines whether to include the rain contribution in the total
            atmospheric attenuation calculation or not. Default is True
    - include_gas: bool, optional
            Determines whether to include the gaseous contribution in the total
            atmospheric attenuation calculation or not. Default is True
    - include_scintillation: bool, optional
            Determines whether to include the scintillation contribution in the
            total atmospheric attenuation calculation or not. Default is True
    - include_clouds: bool, optional
            Determines whether to include the clouds contribution in the total
            atmospheric attenuation calculation or not. Default is True


    Returns
    ---------
    - A : Quantity
            Total atmospheric attenuation (dB)

    - Ag, Ac, Ar, As, A : tuple
            Gaseous, Cloud, Rain, Scintillation contributions to total attenuation,
            and total attenuation (dB)



    References
    -------------
    [1] Propagation data and prediction methods required for the design of
    Earth-space telecommunication systems:
    https://www.p.int/dms_pubrec/itu-r/rec/p/R-REC-P.618-12-201507-I!!PDF-E.pdf


    """
    if np.logical_or(p < 0.001, p > 50).any():
        warnings.warn(
            RuntimeWarning(
                'The method to compute the total '
                'atmospheric attenuation in recommendation ITU-P 618-13 '
                'is only recommended for unavailabilities (p) between '
                '0.001 % and 50 %'))

    # This takes account of the fact that a large part of the cloud attenuation
    # and gaseous attenuation is already included in the rain attenuation
    # prediction for time percentages below 1%. Eq. 61 and Eq. 62 in
    # Recommendation ITU 618-13
    p_c_g = np.maximum(1, p)

    # Estimate the ground station altitude
    if hs is None:
        hs = topographic_altitude(lat, lon)

    # Surface mean temperature
    if T is None:
        T = surface_mean_temperature(lat, lon)

    # Estimate the surface Pressure
    if P is None:
        P = standard_pressure(hs)

    # Estimate the surface Pressure
    if V_t is None:
        V_t = total_water_vapour_content(lat, lon, p_c_g, alt=hs)

    # Estimate the surface water vapour density
    if rho is None:
        rho = surface_water_vapour_density(lat, lon, p_c_g, alt=hs)

    # Compute the attenuation components
    if include_rain:
        Ar = rain_attenuation(lat, lon, f, el, p, tau, hs=hs, R001=R001)
    else:
        Ar = 0 * u.dB

    if include_gas:
        Ag = gaseous_attenuation_slant_path(f,
                                            el,
                                            rho,
                                            P,
                                            T,
                                            V_t=V_t,
                                            h=hs,
                                            mode=mode)
    else:
        Ag = 0 * u.dB

    if include_clouds:
        Ac = cloud_attenuation(lat, lon, el, f, p_c_g)
    else:
        Ac = 0 * u.dB

    if include_scintillation:
        As = scintillation_attenuation(lat,
                                       lon,
                                       f,
                                       el,
                                       p,
                                       D,
                                       eta,
                                       T=T,
                                       H=H,
                                       P=P,
                                       hL=hL)
    else:
        As = 0 * u.dB

    # Compute the total attenuation according to
    A = Ag + np.sqrt((Ar + Ac)**2 + As**2)

    if return_contributions:
        return Ag, Ac, Ar, As, A
    else:
        return A
Exemplo n.º 7
0
    def total_attenuation_synthesis(self,
                                    lat,
                                    lon,
                                    f,
                                    el,
                                    p,
                                    D,
                                    Ns,
                                    tau,
                                    eta,
                                    Ts=1,
                                    hs=None,
                                    rho=None,
                                    H=None,
                                    P=None,
                                    hL=1000,
                                    return_contributions=False):
        t_disc = int(5e6)
        # Step A Correlation coefficients:
        C_RC = 1
        C_CV = 0.8

        # Step B Scintillation polynomials
        def a_Fade(p):
            return -0.061 * np.log10(p)**3 + 0.072 * \
                np.log10(p)**2 - 1.71 * np.log10(p) + 3

        def a_Enhanc(p):
            return -0.0597 * np.log10(p)**3 - 0.0835 * \
                np.log10(p)**2 - 1.258 * np.log10(p) + 2.672

        # Step C1-C3:
        n_R = np.random.normal(0, 1, int((Ns * Ts + t_disc)))
        n_L0 = np.random.normal(0, 1, int((Ns * Ts + t_disc)))
        n_V0 = np.random.normal(0, 1, int((Ns * Ts + t_disc)))

        # Step C4-C5:
        n_L = C_RC * n_R + np.sqrt(1 - C_RC**2) * n_L0
        n_V = C_CV * n_L + np.sqrt(1 - C_CV**2) * n_V0

        # Step C6: Compute the rain attenuation time series
        if hs is None:
            hs = topographic_altitude(lat, lon)
        Ar = rain_attenuation_synthesis(lat,
                                        lon,
                                        f,
                                        el,
                                        tau,
                                        Ns,
                                        hs=hs,
                                        Ts=1,
                                        n=n_R).value
        Ar = Ar[t_disc:]

        # Step C7: Compute the cloud integrated liquid water content time
        # series
        L = cloud_liquid_water_synthesis(lat, lon, Ns, Ts=1, n=n_L).value
        L = L[t_disc:]
        Ac = L * \
            specific_attenuation_coefficients(f, T=0) / np.sin(np.deg2rad(el))
        Ac = Ac.flatten()

        # Step C9: Identify time stamps where A_R > 0 L > 1
        idx = np.where(np.logical_and(Ar > 0, L > 1))[0]
        idx_no = np.where(np.logical_not(np.logical_and(Ar > 0, L > 1)))[0]

        # Step C10: Discard the previous values of Ac and re-compute them by
        # linear interpolation vs. time starting from the non-discarded cloud
        # attenuations values
        Ac[idx] = np.interp(idx, idx_no, Ac[idx_no])

        # Step C11: Compute the integrated water vapour content time series
        V = integrated_water_vapour_synthesis(lat, lon, Ns, Ts=1, n=n_V).value
        V = V[t_disc:]

        # Step C12: Convert the integrated water vapour content time series
        # V into water vapour attenuation time series AV(kTs)
        Av = zenith_water_vapour_attenuation(lat, lon, p, f, V_t=V).value

        # Step C13: Compute the mean annual temperature Tm for the location of
        # interest using experimental values if available.
        Tm = surface_mean_temperature(lat, lon).value

        # Step C14: Convert the mean annual temperature Tm into mean annual
        # oxygen attenuation AO following the method recommended in
        # Recommendation ITU-R P.676.
        if P is None:
            P = standard_pressure(hs).value

        if rho is None:
            rho = standard_water_vapour_density(hs).value

        e = Tm * rho / 216.7
        go = gamma0_exact(f, P, rho, Tm).value
        ho, hw = slant_inclined_path_equivalent_height(f, P).value
        Ao = ho * go * np.ones_like(Ar)

        # Step C15: Synthesize unit variance scintillation time series
        sci_0 = scintillation_attenuation_synthesis(Ns, Ts=1).value

        # Step C16: Compute the correction coefficient time series Cx(kTs) in
        # order to distinguish between scintillation fades and enhancements:
        Q_sci = 100 * stats.norm.sf(sci_0)
        C_x = np.where(sci_0 > 0, a_Fade(Q_sci) / a_Enhanc(Q_sci), 1)

        # Step C17: Transform the integrated water vapour content time series
        # V(kTs) into the Gamma distributed time series Z(kTs) as follows:
        kappa, lambd = integrated_water_vapour_coefficients(lat, lon, None)
        Z = stats.gamma.ppf(np.exp(-(V / lambd)**kappa), 10, scale=0.1)

        # Step C18: Compute the scintillation standard deviation σ following
        # the method recommended in Recommendation ITU-R P.618.
        sigma = scintillation_attenuation_sigma(lat, lon, f, el, D, eta, Tm, H,
                                                P, hL).value

        # Step C19: Compute the scintillation time series sci:
        As = np.where(Ar > 1, sigma * sci_0 * C_x * Z * Ar**(5 / 12),
                      sigma * sci_0 * C_x * Z)

        # Step C20: Compute total tropospheric attenuation time series A(kTs)
        # as follows:
        A = Ar + Ac + Av + Ao + As

        if return_contributions:
            return (Ao + Av)[::Ts], Ac[::Ts], Ar[::Ts], As[::Ts], A[::Ts]
        else:
            return A[::Ts]
Exemplo n.º 8
0
    def test_gaseous_attenuation(self):
        # Define atmospheric parameters
        rho_wet = 7.5 * u.g / u.m**3
        rho_dry = 0 * u.g / u.m**3
        P = 1013.25 * u.hPa
        T = 15 * u.deg_C

        # Define frequency logspace parameters
        N_freq = 1000
        fs = np.linspace(0, 1000, N_freq)

        # Compute the attenuation values
        att_wet = gammaw_exact(fs, P, rho_wet, T)

        att_dry = gamma0_exact(fs, P, rho_dry, T)

        # Plot the results
        plt.figure()
        plt.plot(fs, att_wet.value, 'b--', label='Wet atmosphere')
        plt.plot(fs, att_dry.value, 'r', label='Dry atmosphere')
        plt.xlabel('Frequency [GHz]')
        plt.ylabel('Specific attenuation [dB/km]')
        plt.yscale('log')
        plt.xscale('linear')
        plt.xlim(0, 1000)
        plt.ylim(1e-3, 1e5)
        plt.legend()
        plt.grid(which='both',
                 linestyle=':',
                 color='gray',
                 linewidth=0.3,
                 alpha=0.5)
        plt.grid(which='major', linestyle=':', color='black')
        plt.title('FIGURE 1. - Specific attenuation due to atmospheric gases,'
                  '\ncalculated at 1 GHz intervals, including line centres')
        plt.tight_layout()

        #######################################################################
        #               Specific attenuation at different altitudes           #
        #######################################################################

        # Define atmospheric parameters
        hs = np.array([0, 5, 10, 15, 20]) * u.km

        # Define frequency logspace parameters
        N_freq = 2001
        fs = np.linspace(50, 70, N_freq)

        # Plot the results
        plt.figure()

        # Loop over heights and compute values
        for h in hs:
            rho = standard_water_vapour_density(h)
            P = standard_pressure(h)
            T = standard_temperature(h)
            atts_dry = gamma0_exact(fs * u.GHz, P, rho, T).value
            atts_wet = gammaw_exact(fs * u.GHz, P, rho, T).value
            atts = atts_dry + atts_wet
            plt.plot(fs, atts, label='Altitude {0} km'.format(h.value))

        plt.xlabel('Frequency [GHz]')
        plt.ylabel('Specific attenuation [dB/km]')
        plt.yscale('log')
        plt.xscale('linear')
        plt.xlim(50, 70)
        plt.ylim(1e-3, 1e2)
        plt.legend()
        plt.grid(which='both',
                 linestyle=':',
                 color='gray',
                 linewidth=0.3,
                 alpha=0.5)
        plt.grid(which='major', linestyle=':', color='black')
        plt.title('FIGURE 2. - Specific attenuation in the range 50-70 GHz'
                  ' at the\n altitudes indicated, calculated at intervals of'
                  ' 10 MHz\nincluding line centers (0, 5, 10 15, 20) km')
        plt.tight_layout()

        #######################################################################
        #           Comparison of line-by-line and approximate method         #
        #######################################################################
        # Define atmospheric parameters
        el = 90
        rho = 7.5 * u.g / u.m**3
        P = 1013.25 * u.hPa
        T = 15 * u.deg_C
        e = rho.value * T.value / 216.7  # Water vapour partial pressure
        p = P.value - e  # Dry Air Pressure

        # Define frequency logspace parameters
        N_freq = 350
        fs = np.linspace(1, 350, N_freq)  # GHz

        # Initialize result vectors
        atts_approx = []
        atts_exact = []

        # Loop over frequencies and compute values
        atts_approx = gaseous_attenuation_slant_path(fs,
                                                     el,
                                                     rho,
                                                     p,
                                                     T,
                                                     mode='approx')

        atts_exact = gaseous_attenuation_slant_path(fs,
                                                    el,
                                                    rho,
                                                    p,
                                                    T,
                                                    h=0,
                                                    mode='exact')

        # Plot the results
        plt.figure()
        plt.plot(fs,
                 atts_approx.value,
                 'b--',
                 label='Approximate method Annex 2')
        plt.plot(fs, atts_exact.value, 'r', label='Exact line-by-line method')
        plt.xlabel('Frequency [GHz]')
        plt.ylabel('Attenuation [dB]')
        plt.yscale('log')
        plt.xscale('log')
        plt.legend()
        plt.grid(which='both',
                 linestyle=':',
                 color='gray',
                 linewidth=0.3,
                 alpha=0.5)
        plt.grid(which='major', linestyle=':', color='black')
        plt.title('Comparison of line-by-line method to approximate method')
        plt.tight_layout()