Ejemplo n.º 1
0
  def test_eff_height_within3km(self):
    profile = [4, 500, 1, 2, 3, 4, 5]
    eff_tx_m = ehata.CbsdEffectiveHeights(50, profile)
    self.assertEqual(50, eff_tx_m)

    eff_tx_m = ehata.CbsdEffectiveHeights(19, profile)
    self.assertEqual(20, eff_tx_m)
Ejemplo n.º 2
0
  def test_eff_height_over15km(self):
    profile = [9, 2000, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    eff_tx_m = ehata.CbsdEffectiveHeights(50, profile)
    self.assertEqual(45.5, eff_tx_m)

    profile = [12, 2000, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40]
    eff_tx_m = ehata.CbsdEffectiveHeights(50, profile)
    self.assertEqual(45.5, eff_tx_m)
Ejemplo n.º 3
0
  def test_eff_height_within15km(self):
    profile = [9, 1000, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    eff_tx_m = ehata.CbsdEffectiveHeights(50, profile)
    self.assertEqual(47, eff_tx_m)

    eff_tx_m = ehata.CbsdEffectiveHeights(21, profile)
    self.assertEqual(20, eff_tx_m)

    eff_tx_m = ehata.CbsdEffectiveHeights(19, profile)
    self.assertEqual(20, eff_tx_m)

    profile = [5, 800, 12, 2, 3, 4, 5, 9]
    eff_tx_m = ehata.CbsdEffectiveHeights(50, profile)
    self.assertEqual(50+((12-7)*1/12.), eff_tx_m)
Ejemplo n.º 4
0
  def test_eff_height_at3km(self):
    profile = [6, 500, 1, 2, 3, 4, 5, 6, 7]
    eff_tx_m = ehata.CbsdEffectiveHeights(50, profile)
    self.assertEqual(50, eff_tx_m)

    profile = [6, 505, 1, 2, 3, 4, 5, 6, 7]
    eff_tx_m = ehata.CbsdEffectiveHeights(50, profile)
    self.assertEqual(50-(6*30/12.e3), eff_tx_m)

    profile = [6, 500.000000000001, 1, 2, 3, 4, 5, 6, 7]
    eff_tx_m = ehata.CbsdEffectiveHeights(50, profile)
    #self.assertAlmostEqual(50, eff_tx_m, 7)
    self.assertEqual(50, eff_tx_m)

    profile = [6, 499.99999999999507, 1, 2, 3, 4, 5, 6, 7]
    eff_tx_m = ehata.CbsdEffectiveHeights(50, profile)
    self.assertEqual(50, eff_tx_m)
Ejemplo n.º 5
0
def CalcHybridPropagationLoss(lat_cbsd,
                              lon_cbsd,
                              height_cbsd,
                              lat_rx,
                              lon_rx,
                              height_rx,
                              cbsd_indoor=False,
                              reliability=-1,
                              freq_mhz=3625.,
                              region='RURAL',
                              is_height_cbsd_amsl=False,
                              return_internals=False):
    """Implements the Hybrid ITM/eHata NTIA propagation model.

  As specified by Winforum, see:
    R2-SGN-03, R2-SGN-04 through R2-SGN-10 and NTIA TR 15-517 Appendix A.

  Note that contrary to the ITM model, this function does not provide the
  possibility to retrieve a CDF of path losses, as it is not required in the
  intended use of that model (it shall be used currently only for protecting
  zones using average aggregated interference).

  Warning: Only 'reliability' values 0.5 (median) and -1 (average) are currently
  fully supported, as other values will not return the quantile when using
  internally the eHata model. Workaround is to apply it afterwards when the
  returned opcode=4, and using the standard deviation obtained with the
  'GetEHataStdev()' routine.

  Inputs:
    lat_cbsd, lon_cbsd, height_cbsd: Lat/lon (deg) and height AGL (m) of CBSD
    lat_rx, lon_rx, height_rx:       Lat/lon (deg) and height AGL (m) of Rx point
    cbsd_indoor:        CBSD indoor status - Default=False.
    freq_mhz:           Frequency (MHz). Default is mid-point of band.
    reliability:        Reliability. Default is -1 (average value).
                        Options:
                          Value in [0,1]: returns the CDF quantile
                          -1: returns the mean path loss
    region:             Region type among 'URBAN', 'SUBURBAN, 'RURAL'
    is_height_cbsd_amsl: If True, the CBSD height shall be considered as AMSL (Average
                         mean sea level).

  Returns:
    A namedtuple of:
      db_loss:          Path Loss in dB.

      incidence_angles: A namedtuple of angles (degrees)
          hor_cbsd:       Horizontal departure angle (bearing) from CBSD to Rx
          ver_cbsd:       Vertical departure angle at CBSD
          hor_rx:         Horizontal incidence angle (bearing) from Rx to CBSD
          ver_rx:         Vertical incidence angle at Rx

      internals:        A dictionary of internal data for advanced analysis
                        (only if return_internals=True):
          hybrid_opcode:  Opcode from HybridCode - See GetInfoOnHybridCodes()
          effective_height_cbsd: Effective CBSD antenna height
          itm_db_loss:    Loss in dB for the ITM model.
          itm_err_num:    ITM error code (see wf_itm module).
          itm_str_mode:   Description (string) of dominant prop mode in ITM.
          dist_km:        Distance between end points (km)
          prof_d_km       ndarray of distances (km) - x values to plot terrain.
          prof_elev       ndarray of terrain heightsheights (m) - y values to plot terrain,

  Raises:
    Exception if input parameters invalid or out of range.
  """
    # Case of same points
    if (lat_cbsd == lat_rx and lon_cbsd == lon_rx):
        return _PropagResult(db_loss=0,
                             incidence_angles=_IncidenceAngles(0, 0, 0, 0),
                             internals=None)

    # Sanity checks on input parameters
    if freq_mhz < 40 or freq_mhz > 10000:
        raise Exception('Frequency outside range [40MHz - 10GHz].')
    if region not in ['RURAL', 'URBAN', 'SUBURBAN']:
        raise Exception('Region %s not allowed' % region)
    if reliability not in (-1, 0.5):
        raise Exception('Hybrid model only computes the median or the mean.')

    if is_height_cbsd_amsl:
        altitude_cbsd = drive.terrain_driver.GetTerrainElevation(
            lat_cbsd, lon_cbsd)
        height_cbsd = height_cbsd - altitude_cbsd

    # Get the terrain profile, using Vincenty great circle route, and WF
    # standard (bilinear interp; 1501 pts for all distances over 45 km)
    its_elev = drive.terrain_driver.TerrainProfile(lat1=lat_cbsd,
                                                   lon1=lon_cbsd,
                                                   lat2=lat_rx,
                                                   lon2=lon_rx,
                                                   target_res_meter=30.,
                                                   do_interp=True,
                                                   max_points=1501)

    # Structural CBSD and mobile height corrections
    height_cbsd = max(height_cbsd, 20.)
    height_rx = 1.5

    # Calculate the predicted ITM loss
    # and get the distance and profile for use in further logic
    db_loss_itm, incidence_angles, internals = wf_itm.CalcItmPropagationLoss(
        lat_cbsd,
        lon_cbsd,
        height_cbsd,
        lat_rx,
        lon_rx,
        height_rx,
        False,
        reliability,
        freq_mhz,
        its_elev,
        return_internals=True)
    internals['itm_db_loss'] = db_loss_itm

    # Calculate the effective heights of the tx
    height_cbsd_eff = ehata.CbsdEffectiveHeights(height_cbsd, its_elev)
    internals['effective_height_cbsd'] = height_cbsd_eff

    # Use ITM if CBSD effective height greater than 200 m
    if height_cbsd_eff >= 200:
        return _BuildOutput(db_loss_itm, incidence_angles, internals,
                            HybridMode.ITM_HIGH_HEIGHT, cbsd_indoor)

    # Set the environment code number.
    if region == 'URBAN':
        region_code = 23
    elif region == 'SUBURBAN':
        region_code = 22
    else:  # 'RURAL': use ITM
        if not return_internals: return_internals = None
        return _BuildOutput(db_loss_itm, incidence_angles, internals,
                            HybridMode.ITM_RURAL, cbsd_indoor)

    # The eHata offset to apply (only in case the mean is requested)
    offset_median_to_mean = _GetMedianToMeanOffsetDb(freq_mhz,
                                                     region == 'URBAN')

    # Now process the different cases
    dist_km = internals['dist_km']
    if not return_internals: return_internals = None

    if dist_km <= 0.1:  # Use Free Space Loss
        db_loss = CalcFreeSpaceLoss(dist_km, freq_mhz, height_cbsd, height_rx)
        return _BuildOutput(db_loss, incidence_angles, internals,
                            HybridMode.FSL, cbsd_indoor)

    elif dist_km > 0.1 and dist_km < 1:  # Use E-Hata Median Basic Prop Loss
        fsl_100m = CalcFreeSpaceLoss(0.1, freq_mhz, height_cbsd, height_rx)
        median_basic_loss = ehata.MedianBasicPropLoss(freq_mhz, height_cbsd,
                                                      height_rx, 1,
                                                      region_code)
        alpha = 1. + math.log10(dist_km)
        db_loss = fsl_100m + alpha * (median_basic_loss - fsl_100m)

        # TODO: validate the following approach with WinnForum participants:
        # Weight the offset as well from 0 (100m) to 1.0 (1km).
        if reliability == -1:
            db_loss += alpha * offset_median_to_mean
        return _BuildOutput(db_loss, incidence_angles, internals,
                            HybridMode.EHATA_FSL_INTERP, cbsd_indoor)

    elif dist_km >= 1 and dist_km <= 80:  # Use best of E-Hata / ITM
        ehata_loss_med = ehata.ExtendedHata(its_elev, freq_mhz, height_cbsd,
                                            height_rx, region_code)
        if reliability == 0.5:
            ehata_loss = ehata_loss_med
            itm_loss_med = db_loss_itm
        else:
            ehata_loss = ehata_loss_med + offset_median_to_mean
            itm_loss_med = wf_itm.CalcItmPropagationLoss(
                lat_cbsd, lon_cbsd, height_cbsd, lat_rx, lon_rx, height_rx,
                False, 0.5, freq_mhz, its_elev).db_loss

        if itm_loss_med >= ehata_loss_med:
            return _BuildOutput(db_loss_itm, incidence_angles, internals,
                                HybridMode.ITM_DOMINANT, cbsd_indoor)
        else:
            return _BuildOutput(ehata_loss, incidence_angles, internals,
                                HybridMode.EHATA_DOMINANT, cbsd_indoor)

    elif dist_km > 80:  # Use the ITM with correction from E-Hata @ 80km
        # Calculate the ITM median and eHata median losses at 80km
        bearing = incidence_angles.hor_cbsd

        lat_80km, lon_80km, _ = vincenty.GeodesicPoint(lat_cbsd, lon_cbsd, 80.,
                                                       bearing)
        its_elev_80km = drive.terrain_driver.TerrainProfile(
            lat_cbsd,
            lon_cbsd,
            lat_80km,
            lon_80km,
            target_res_meter=30.,
            do_interp=True,
            max_points=1501)
        ehata_loss_80km = ehata.ExtendedHata(its_elev_80km, freq_mhz,
                                             height_cbsd, height_rx,
                                             region_code)
        itm_loss_80km = wf_itm.CalcItmPropagationLoss(lat_cbsd, lon_cbsd,
                                                      height_cbsd, lat_80km,
                                                      lon_80km, height_rx,
                                                      False, 0.5, freq_mhz,
                                                      its_elev_80km).db_loss

        J = max(ehata_loss_80km - itm_loss_80km, 0)
        db_loss = db_loss_itm + J

        return _BuildOutput(db_loss, incidence_angles, internals,
                            HybridMode.ITM_CORRECTED, cbsd_indoor)