def test_small_height(self):
        lat1, lng1 = 37.756672, -122.508512
        lat2, lng2 = 37.754406, -122.388342

        res_bad = wf_itm.CalcItmPropagationLoss(lat1,
                                                lng1,
                                                0,
                                                lat2,
                                                lng2,
                                                -1,
                                                cbsd_indoor=False,
                                                reliability=0.5,
                                                freq_mhz=3625.)
        res_expected = wf_itm.CalcItmPropagationLoss(lat1,
                                                     lng1,
                                                     1,
                                                     lat2,
                                                     lng2,
                                                     1,
                                                     cbsd_indoor=False,
                                                     reliability=0.5,
                                                     freq_mhz=3625.)
        self.assertEqual(res_bad.db_loss, res_expected.db_loss)
        self.assertEqual(res_bad.incidence_angles,
                         res_expected.incidence_angles)
    def test_op_mode(self):
        lat1, lng1, height1 = 37.756672, -122.508512, 20.0
        lat2, lng2, height2 = 37.754406, -122.388342, 10.0
        reliabilities = [0.1, 0.5, 0.9]
        expected_losses = [213.68, 214.26, 214.62]

        for rel, exp_loss in zip(reliabilities, expected_losses):
            res = wf_itm.CalcItmPropagationLoss(lat1,
                                                lng1,
                                                height1,
                                                lat2,
                                                lng2,
                                                height2,
                                                reliability=rel,
                                                freq_mhz=3625.,
                                                return_internals=True)
            self.assertAlmostEqual(res.db_loss, exp_loss, 2)
            self.assertEqual(res.internals['itm_err_num'],
                             wf_itm.ItmErrorCode.WARNING)  # Double horizon

        # Reliability list input
        res = wf_itm.CalcItmPropagationLoss(lat1,
                                            lng1,
                                            height1,
                                            lat2,
                                            lng2,
                                            height2,
                                            reliability=reliabilities,
                                            freq_mhz=3625.)
        for loss, exp_loss in zip(res.db_loss, expected_losses):
            self.assertAlmostEqual(loss, exp_loss, 2)
 def test_indoor(self):
     lat1, lng1, height1 = 37.756672, -122.508512, 20.0
     lat2, lng2, height2 = 37.754406, -122.388342, 10.0
     # scalar version
     res_outdoor = wf_itm.CalcItmPropagationLoss(lat1,
                                                 lng1,
                                                 height1,
                                                 lat2,
                                                 lng2,
                                                 height2,
                                                 cbsd_indoor=False,
                                                 reliability=0.5,
                                                 freq_mhz=3625.)
     res_indoor = wf_itm.CalcItmPropagationLoss(lat1,
                                                lng1,
                                                height1,
                                                lat2,
                                                lng2,
                                                height2,
                                                cbsd_indoor=True,
                                                reliability=0.5,
                                                freq_mhz=3625.)
     self.assertEqual(res_indoor.db_loss, res_outdoor.db_loss + 15)
     # vector version
     reliabilities = np.arange(0.01, 1.0, 0.01)
     res_outdoor = wf_itm.CalcItmPropagationLoss(lat1,
                                                 lng1,
                                                 height1,
                                                 lat2,
                                                 lng2,
                                                 height2,
                                                 cbsd_indoor=False,
                                                 reliability=reliabilities,
                                                 freq_mhz=3625.)
     res_indoor = wf_itm.CalcItmPropagationLoss(lat1,
                                                lng1,
                                                height1,
                                                lat2,
                                                lng2,
                                                height2,
                                                cbsd_indoor=True,
                                                reliability=reliabilities,
                                                freq_mhz=3625.)
     self.assertEqual(
         np.max(
             np.abs(
                 np.array(res_indoor.db_loss) -
                 np.array(res_outdoor.db_loss) - 15)), 0)
 def test_angles_vs_legacy(self):
     # More extensive testing of the vertical incidence angle
     # obtained from C module vs legacy python-only method used prior to April 2017
     np.random.seed(12345)
     n_links = 500
     pairs = testutils.MakeLatLngPairs(n_links,
                                       10,
                                       50000,
                                       lat_min=37,
                                       lat_max=38,
                                       lng_min=-123,
                                       lng_max=-122)
     height_tx = 20
     height_rx = 10
     for pair in pairs:
         profile = drive.terrain_driver.TerrainProfile(*pair,
                                                       target_res_meter=30.,
                                                       do_interp=True,
                                                       max_points=1501)
         # Compute angles the legacy way
         a_tx, a_rx, _, _ = _GetHorizonAnglesLegacy(profile, height_tx,
                                                    height_rx, 314)
         # Get angle from he ITM model
         _, inc_angles, _ = wf_itm.CalcItmPropagationLoss(pair[0],
                                                          pair[1],
                                                          height_tx,
                                                          pair[2],
                                                          pair[3],
                                                          height_rx,
                                                          its_elev=profile)
         self.assertAlmostEqual(inc_angles.ver_cbsd, a_tx, 14)
         self.assertAlmostEqual(inc_angles.ver_rx, a_rx, 14)
    def test_average_itm(self):
        lat1, lng1, height1 = 37.756672, -122.508512, 20.0
        lat2, lng2, height2 = 37.754406, -122.388342, 1.5
        reliabilities = np.arange(0.01, 1.0, 0.01)
        losses = []
        for rel in reliabilities:
            res = wf_itm.CalcItmPropagationLoss(lat1,
                                                lng1,
                                                height1,
                                                lat2,
                                                lng2,
                                                height2,
                                                reliability=rel,
                                                freq_mhz=3625.)
            losses.append(res.db_loss)

        avg_res = wf_hybrid.CalcHybridPropagationLoss(lat1,
                                                      lng1,
                                                      height1,
                                                      lat2,
                                                      lng2,
                                                      height2,
                                                      reliability=-1,
                                                      freq_mhz=3625.,
                                                      region='SUBURBAN',
                                                      return_internals=True)
        self.assertEqual(avg_res.internals['hybrid_opcode'],
                         wf_hybrid.HybridMode.ITM_DOMINANT)
        self.assertAlmostEqual(
            avg_res.db_loss,
            -10 * np.log10(np.mean(10**(-np.array(losses) / 10.))), 5)
Example #6
0
def get_im_point(cbsd1, cbsd2):
    """
    Call ITM propagation model to calculate Interference Metric of CBSD1 that is interferred by CBSD2
    Using Point Coordination

    Input:
            cbsd1:  CBSD object that is interferred.
                :type cbsd1:    CBSD

            cbsd2:  CBSD object that is interferring (as noise).
                :type cbsd2:    CBSD

    Returns:
            Interference Metrics as float
    """
    # Call ITM Propagation Model to calculate signal loss from cbsd2 at the location of cbsd1
    loss = wf_itm.CalcItmPropagationLoss(cbsd2.latitude,
                                         cbsd2.longitude,
                                         cbsd2.height,
                                         cbsd1.latitude,
                                         cbsd1.longitude,
                                         cbsd1.height,
                                         cbsd_indoor=cbsd2.indoor,
                                         reliability=0.5)

    # Calculate Signal Strength by substracting loss from the transmitter power
    Ix = cbsd2.TxPower - loss[0]

    # Use Global I_min, I_max to calculate the Interference Metric
    if Ix < I_min:
        return 0
    elif Ix > I_max:
        return 1.0
    else:
        return float(Ix - I_min) / (I_max - I_min)
Example #7
0
def get_rx_signal_point((cbsd, location)):
    """
    This Method returns the Rx Signal Strength of a CBSD to a location using ITM Model

    Input:
            cbsd:  a cbsd object
                :type cbsd CBSD

            location, the coordinate of the location
                :type location Tuple[float, float]
    Returns:
            Rx_Signal:  The signal strength, float
    """
    lat_rx = location[0]  # latitude of the location
    lon_rx = location[1]  # longitude of the location
    height_rx = 0  # Default AGL of the Rx location is set to 0

    # call the method in wf_itm (itm model) to calculate the propagation loss from the CBSD to the location
    loss = wf_itm.CalcItmPropagationLoss(cbsd.latitude,
                                         cbsd.longitude,
                                         cbsd.height,
                                         lat_rx,
                                         lon_rx,
                                         height_rx,
                                         cbsd_indoor=cbsd.indoor,
                                         reliability=0.5)

    # Calculate Signal Strength by substracting loss from the transmitter power
    Rx_Signal = cbsd.TxPower - loss[0]

    return Rx_Signal
Example #8
0
def computeInterferenceFssBlocking(cbsd_grant, constraint, fss_info, max_eirp):
    """Computes interference that a grant causes to a FSS protection point.

  Routine to compute interference neighborhood grant causes to FSS protection
  point for blocking passband

  Args:
    cbsd_grant: A CBSD grant of type |data.CbsdGrantInfo|.
    constraint: The protection constraint of type |data.ProtectionConstraint|.
    fss_info: The FSS information of type |data.FssInformation|.
    max_eirp: The maximum EIRP allocated to the grant during IAP procedure.

  Returns:
    The interference contribution(dBm).
  """
    # Get the propagation loss and incident angles for FSS entity
    # blocking channels
    db_loss, incidence_angles, _ = wf_itm.CalcItmPropagationLoss(
        cbsd_grant.latitude,
        cbsd_grant.longitude,
        cbsd_grant.height_agl,
        constraint.latitude,
        constraint.longitude,
        fss_info.height_agl,
        cbsd_grant.indoor_deployment,
        reliability=-1,
        freq_mhz=FREQ_PROP_MODEL_MHZ)

    # Compute CBSD antenna gain in the direction of protection point
    ant_gain = antenna.GetStandardAntennaGains(incidence_angles.hor_cbsd,
                                               cbsd_grant.antenna_azimuth,
                                               cbsd_grant.antenna_beamwidth,
                                               cbsd_grant.antenna_gain)

    # Compute FSS antenna gain in the direction of CBSD
    fss_ant_gain = antenna.GetFssAntennaGains(incidence_angles.hor_rx,
                                              incidence_angles.ver_rx,
                                              fss_info.pointing_azimuth,
                                              fss_info.pointing_elevation,
                                              fss_info.max_gain_dbi)

    # Get the total antenna gain by summing the antenna gains from CBSD to FSS
    # and FSS to CBSD
    effective_ant_gain = ant_gain + fss_ant_gain

    # Compute EIRP of CBSD grant inside the frequency range of
    # protection constraint
    eff_bandwidth = (
        min(cbsd_grant.high_frequency, constraint.high_frequency) -
        cbsd_grant.low_frequency)
    if eff_bandwidth <= 0:
        raise ValueError(
            'Computing FSS blocking on grant fully inside FSS passband')
    eirp = getEffectiveSystemEirp(max_eirp, cbsd_grant.antenna_gain,
                                  effective_ant_gain, eff_bandwidth)
    # Calculate the interference contribution
    interference = eirp - getFssMaskLoss(cbsd_grant, constraint) - db_loss

    return interference
 def test_average(self):
     lat1, lng1, height1 = 37.756672, -122.508512, 20.0
     lat2, lng2, height2 = 37.754406, -122.388342, 10.0
     reliabilities = np.arange(0.01, 1.0, 0.01)
     # vector call
     results = wf_itm.CalcItmPropagationLoss(lat1,
                                             lng1,
                                             height1,
                                             lat2,
                                             lng2,
                                             height2,
                                             reliability=reliabilities,
                                             freq_mhz=3625.)
     # Scalar call
     for rel, exp_loss in zip(reliabilities, results.db_loss):
         res = wf_itm.CalcItmPropagationLoss(lat1,
                                             lng1,
                                             height1,
                                             lat2,
                                             lng2,
                                             height2,
                                             reliability=rel,
                                             freq_mhz=3625.)
         self.assertEqual(res.db_loss, exp_loss)
     # Internal average
     avg_res = wf_itm.CalcItmPropagationLoss(lat1,
                                             lng1,
                                             height1,
                                             lat2,
                                             lng2,
                                             height2,
                                             reliability=-1,
                                             freq_mhz=3625.)
     self.assertAlmostEqual(
         avg_res.db_loss,
         -10 * np.log10(np.mean(10**(-np.array(results.db_loss) / 10.))), 5)
def calculateOobeInterference(grants_cbsds_oobe_info, fss_point, fss_info):
  """Calculates the OOBE interference value (MCBSDi,ch + GCBSDi + PLinvi + GFSSi).

  The interference values are calculated based on the grant with the highest
  highFrequency value, and added back into the grant object under key:
     'oobe_interference'.

  Args:
    grants_cbsds_oobe_info : List of dictionaries containing the highest grant
      of their CBSD and a reference to the CBSD.
    fss_point: The FSS location as a (longitude, latitude) tuple.
    fss_info: The |data.FssInformation| of the FSS.
  """
  # Get values of MCBSD,GCBSD,GFSS and LCBSD for each CBSD.
  for grant in grants_cbsds_oobe_info:
    if not grant['cbsd']['grants']:
      continue
    cbsd = data.constructCbsdGrantInfo(grant['cbsd']['registration'], None)
    # Get the MCBSD (ie the conducted OOBE power)
    mcbsd = grant['mcbsd']
    # Computes the path loss
    lcbsd, incidence_angle, _ = wf_itm.CalcItmPropagationLoss(
        cbsd.latitude,
        cbsd.longitude,
        cbsd.height_agl,
        fss_point[1],
        fss_point[0],
        fss_info.height_agl,
        cbsd.indoor_deployment,
        reliability=-1,
        freq_mhz=interf.FREQ_PROP_MODEL_MHZ)
    # The CBSD antenna gain towards FSS
    gcbsd = antenna.GetStandardAntennaGains(
        incidence_angle.hor_cbsd,
        cbsd.antenna_azimuth,
        cbsd.antenna_beamwidth,
        cbsd.antenna_gain)
    # The FSS antenna gain
    gfss = antenna.GetFssAntennaGains(
        incidence_angle.hor_rx,
        incidence_angle.ver_rx,
        fss_info.pointing_azimuth,
        fss_info.pointing_elevation,
        fss_info.max_gain_dbi)
    # The OOBE interference
    oobe_interference = mcbsd + gcbsd - lcbsd + gfss - interf.IN_BAND_INSERTION_LOSS
    grant['oobe_interference'] = oobe_interference
Example #11
0
def computeInterferenceEsc(cbsd_grant, constraint, esc_antenna_info, max_eirp):
    """Computes interference that a grant causes to a ESC protection point.

  Routine to compute interference neighborhood grant causes to ESC protection
  point.

  Args:
    cbsd_grant: A CBSD grant of type |data.CbsdGrantInfo|.
    constraint: The protection constraint of type |data.ProtectionConstraint|.
    esc_antenna_info: ESC antenna information of type |data.EscInformation|.
    max_eirp: The maximum EIRP allocated to the grant during IAP procedure
  Returns:
    The interference contribution(dBm).
  """
    # Get the propagation loss and incident angles for ESC entity
    db_loss, incidence_angles, _ = wf_itm.CalcItmPropagationLoss(
        cbsd_grant.latitude,
        cbsd_grant.longitude,
        cbsd_grant.height_agl,
        constraint.latitude,
        constraint.longitude,
        esc_antenna_info.antenna_height,
        cbsd_grant.indoor_deployment,
        reliability=-1,
        freq_mhz=FREQ_PROP_MODEL_MHZ)

    # Compute CBSD antenna gain in the direction of protection point
    ant_gain = antenna.GetStandardAntennaGains(incidence_angles.hor_cbsd,
                                               cbsd_grant.antenna_azimuth,
                                               cbsd_grant.antenna_beamwidth,
                                               cbsd_grant.antenna_gain)

    # Compute ESC antenna gain in the direction of CBSD
    esc_ant_gain = antenna.GetAntennaPatternGains(
        incidence_angles.hor_rx, esc_antenna_info.antenna_azimuth,
        esc_antenna_info.antenna_gain_pattern)

    # Get the total antenna gain by summing the antenna gains from CBSD to ESC
    # and ESC to CBSD
    effective_ant_gain = ant_gain + esc_ant_gain

    # Compute the interference value for ESC entity
    eirp = getEffectiveSystemEirp(max_eirp, cbsd_grant.antenna_gain,
                                  effective_ant_gain)
    interference = eirp - db_loss - getEscMaskLoss(constraint)
    return interference
 def test_los_mode(self):
     lat1, lng1, height1 = 37.756672, -122.508512, 20.0
     lat2, lng2, height2 = 37.756559, -122.507882, 10.0
     reliability = 0.5
     res = wf_itm.CalcItmPropagationLoss(lat1,
                                         lng1,
                                         height1,
                                         lat2,
                                         lng2,
                                         height2,
                                         reliability=reliability,
                                         freq_mhz=3625.,
                                         return_internals=True)
     self.assertAlmostEqual(res.db_loss, 78.7408, 4)
     self.assertAlmostEqual(res.incidence_angles.ver_cbsd,
                            -res.incidence_angles.ver_rx, 3)
     self.assertEqual(res.internals['itm_err_num'],
                      wf_itm.ItmErrorCode.OTHER)  # LOS mode
Example #13
0
    rels = [-1, 0.5]
    rt = "RURAL"

    lat2 = 32.74049506692264
    lng2 = -117.14025198345544
    agl2 = 1.5

    for rel in rels:
        loss_hybrid = wf_hybrid.CalcHybridPropagationLoss(lat1,
                                                          lng1,
                                                          agl1,
                                                          lat2,
                                                          lng2,
                                                          agl2,
                                                          cbsd_indoor=indoor,
                                                          region=rt,
                                                          reliability=rel)
        loss_itm = wf_itm.CalcItmPropagationLoss(lat1,
                                                 lng1,
                                                 agl1,
                                                 lat2,
                                                 lng2,
                                                 agl2,
                                                 cbsd_indoor=indoor,
                                                 reliability=rel)

        print "Reliablity: ", rel
        print "Hybrid Loss:", loss_hybrid[0], "dbm:", 26 - loss_hybrid[0]
        print "ITM Loss:", loss_itm[0], "dbm", 26 - loss_itm[0]
        print
Example #14
0
def computePropagationAntennaModel(request):
    reliability_level = request['reliabilityLevel']
    if reliability_level not in [-1, 0.05, 0.95]:
        raise ValueError('reliability_level not in [-1, 0.05, 0.95]')

    tx = request['cbsd']
    if ('fss' in request) and ('ppa' in request):
        raise ValueError('fss and ppa in request')
    elif 'ppa' in request:
        rx = {}
        rx['height'] = 1.5
        isfss = False
        coordinates = []
        ppa = request['ppa']

        arcsec = 1
        ppa_points = geoutils.GridPolygon(ppa['geometry'], arcsec)
        if len(ppa_points) == 1:
            rx['longitude'] = ppa_points[0][0]
            rx['latitude'] = ppa_points[0][1]
        elif len(ppa_points) == 0:
            raise ValueError('ppa boundary contains no protection point')
        else:
            raise ValueError(
                'ppa boundary contains more than a single protection point')

        region_val = drive.nlcd_driver.RegionNlcdVote(
            [[rx['latitude'], rx['longitude']]])

    elif 'fss' in request:
        isfss = True
        rx = request['fss']
    else:
        raise ValueError('Neither fss nor ppa in request')

    # ITM pathloss (if receiver type is FSS) or the hybrid model pathloss (if receiver type is PPA) and corresponding antenna gains.
    # The test specification notes that the SAS UUT shall use default values for w1 and w2 in the ITM model.
    result = {}
    if isfss:
        path_loss = wf_itm.CalcItmPropagationLoss(
            tx['latitude'],
            tx['longitude'],
            tx['height'],
            rx['latitude'],
            rx['longitude'],
            rx['height'],
            cbsd_indoor=tx['indoorDeployment'],
            reliability=reliability_level,
            freq_mhz=3625.,
            is_height_cbsd_amsl=(tx['heightType'] == 'AMSL'))

        result['pathlossDb'] = path_loss.db_loss
        gain_tx_rx = antenna.GetStandardAntennaGains(
            path_loss.incidence_angles.hor_cbsd,
            ant_azimuth=tx['antennaAzimuth'],
            ant_beamwidth=tx['antennaBeamwidth'],
            ant_gain=tx['antennaGain'])
        result['txAntennaGainDbi'] = gain_tx_rx
        if 'rxAntennaGainRequired' in rx:
            hor_dirs = path_loss.incidence_angles.hor_rx
            ver_dirs = path_loss.incidence_angles.ver_rx
            gain_rx_tx = antenna.GetFssAntennaGains(hor_dirs, ver_dirs,
                                                    rx['antennaAzimuth'],
                                                    rx['antennaElevation'],
                                                    rx['antennaGain'])
            result['rxAntennaGainDbi'] = gain_rx_tx
    else:

        path_loss = wf_hybrid.CalcHybridPropagationLoss(
            tx['latitude'],
            tx['longitude'],
            tx['height'],
            rx['latitude'],
            rx['longitude'],
            rx['height'],
            cbsd_indoor=tx['indoorDeployment'],
            reliability=-1,
            freq_mhz=3625.,
            region=region_val,
            is_height_cbsd_amsl=(tx['heightType'] == 'AMSL'))
        result['pathlossDb'] = path_loss.db_loss
        gain_tx_rx = antenna.GetStandardAntennaGains(
            path_loss.incidence_angles.hor_cbsd,
            ant_azimuth=tx['antennaAzimuth'],
            ant_beamwidth=tx['antennaBeamwidth'],
            ant_gain=tx['antennaGain'])
        result['txAntennaGainDbi'] = gain_tx_rx

    return result
      base_fss.latitude, base_fss.longitude,
      cbsd.latitude, cbsd.longitude)
  if distance_km <= 150:
    cbsds.append(cbsd)

#  - then calculate all path losses and received RSSI at FSS
#    (without FSS antenna taken into account)
cbsd_rssi = np.zeros(len(cbsds))
cbsd_incidence_angles = []

for k, cbsd in enumerate(cbsds):
  if not (k%10):
    sys.stdout.write('*')
    sys.stdout.flush()
  db_loss, incidence_angles, _ = wf_itm.CalcItmPropagationLoss(
      cbsd.latitude, cbsd.longitude, cbsd.height_agl,
      base_fss.latitude, base_fss.longitude, base_fss.height_agl,
      cbsd.is_indoor, reliability=-1)

  cbsd_effective_eirp = antenna.GetStandardAntennaGains(
      incidence_angles.hor_cbsd,
      cbsd.antenna_azimuth, cbsd.antenna_beamwidth,
      cbsd.eirp_dbm_mhz)

  cbsd_rssi[k] = cbsd_effective_eirp - db_loss
  cbsd_incidence_angles.append(incidence_angles)

#  - then compute the aggregate average interference for each FSS entity
#    (ie each different possible FSS antenna pointing)
fss_total_rssi = []
for fss_entity in fss_entities:
  hor_dirs = [inc_angle.hor_rx for inc_angle in cbsd_incidence_angles]
def computeInterference(grant, constraint, inc_ant_height, num_iteration,
                        dpa_type):
    """Calculate interference contribution of each grant in the neighborhood to
  the protection constraint c.

  Inputs:
    cbsd_grant:     a |data.CbsdGrantInfo| grant
    constraint:     protection constraint of type |data.ProtectionConstraint|
    inc_ant_height: reference incumbent antenna height (in meters)
    num_iteration:  a number of Monte Carlo iterations
    dpa_type:       an enum member of class DpaType

  Returns:
    A tuple of
      interference: 	interference contribution, a tuple with named fields
         'randomInterference' (K random interference contributions
         of the grant to protection constraint c), and 'bearing_c_cbsd'
         (bearing from c to CBSD grant location).
      medianInterference: the median interference.
  """
    # Get frequency information
    low_freq_cbsd = grant.low_frequency
    high_freq_cbsd = grant.high_frequency
    low_freq_c = constraint.low_frequency
    high_freq_c = constraint.high_frequency

    # Compute median and K random realizations of path loss/interference contribution
    # based on ITM model as defined in [R2-SGN-03] (in dB)
    reliabilities = np.random.uniform(0.001, 0.999,
                                      num_iteration)  # get K random
    # reliability values from an uniform distribution over [0.001,0.999)
    reliabilities = np.append(reliabilities,
                              [0.5])  # add 0.5 (for median loss) as
    # a last value to reliabilities array
    results = wf_itm.CalcItmPropagationLoss(grant.latitude,
                                            grant.longitude,
                                            grant.height_agl,
                                            constraint.latitude,
                                            constraint.longitude,
                                            inc_ant_height,
                                            grant.indoor_deployment,
                                            reliability=reliabilities,
                                            freq_mhz=FREQ_PROP_MODEL)
    path_loss = np.array(results.db_loss)

    # Compute CBSD antenna gain in the direction of protection point
    ant_gain = antenna.GetStandardAntennaGains(
        results.incidence_angles.hor_cbsd, grant.antenna_azimuth,
        grant.antenna_beamwidth, grant.antenna_gain)

    # Compute EIRP of CBSD grant inside the frequency range of protection constraint
    if dpa_type is not DpaType.OUT_OF_BAND:  # For co-channel offshore/inland DPAs

        # CBSD co-channel bandwidth overlapping with
        # frequency range of protection constraint
        co_channel_bw = min(high_freq_cbsd, high_freq_c) - max(
            low_freq_cbsd, low_freq_c)

        # Compute EIRP within co-channel bandwidth
        eirp_cbsd = ((grant.max_eirp - grant.antenna_gain) + ant_gain +
                     10 * np.log10(co_channel_bw / 1.e6))

    else:  # For out-of-band inland DPAs

        # Compute out-of-band conducted power
        oob_power = ComputeOOBConductedPower(low_freq_cbsd, low_freq_c,
                                             high_freq_c)
        # Compute out-of-band EIRP
        eirp_cbsd = oob_power + ant_gain

    # Calculate the interference contributions
    interf = eirp_cbsd - path_loss
    median_interf = interf[-1]  # last element is the median interference
    K_interf = interf[:-1]  # first 'K' interference

    # Store interference contributions
    interference = InterferenceContribution(
        randomInterference=K_interf,
        bearing_c_cbsd=results.incidence_angles.hor_rx)
    return interference, median_interf
  def test_WINNF_FT_S_BPR_2(self, config_filename):
    """[Configurable] Grant Request from CBSDs within the Shared Zone adjacent
      the Canadian border.
    """
    config = loadConfig(config_filename)
    # Very light checking of the config file.
    self.assertValidConfig(
        config, {
            'registrationRequests': list,
            'conditionalRegistrationData': list,
            'grantRequests': list
        })
    self.assertEqual(
        len(config['registrationRequests']), len(config['grantRequests']))

    # Whitelist FCC ID and User ID.
    for device in config['registrationRequests']:
      self._sas_admin.InjectFccId({'fccId': device['fccId']})
      self._sas_admin.InjectUserId({'userId': device['userId']})

    # Pre-load conditional registration data.
    if config['conditionalRegistrationData']:
      self._sas_admin.PreloadRegistrationData({
          'registrationData': config['conditionalRegistrationData']
      })

    # Register CBSDs.
    request = {'registrationRequest': config['registrationRequests']}
    responses = self._sas.Registration(request)['registrationResponse']

    # Check registration response.
    self.assertEqual(len(responses), len(config['registrationRequests']))
    grant_request = []
    index_of_devices_with_success_registration_response = []
    for i, response in enumerate(responses):
      if response['response']['responseCode'] == 0:
        self.assertTrue('cbsdId' in response)
        index_of_devices_with_success_registration_response.append(i)
        config['grantRequests'][i]['cbsdId'] = response['cbsdId']
        grant_request.append(config['grantRequests'][i])
    del request, responses

    if not grant_request:
      return  # SAS passes immediately, since none of the registration requests
      # succeeded in this case.

    # For CBSDs successfully registered in Step 1, Send grant request
    request = {'grantRequest': grant_request}
    responses = self._sas.Grant(request)['grantResponse']
    # Check grant response
    self.assertEqual(len(responses), len(grant_request))
    self.assertEqual(
        len(responses),
        len(index_of_devices_with_success_registration_response))

    for i, index in enumerate(
        index_of_devices_with_success_registration_response):
      logging.info('Looking at Grant response number: %d', i)
      if (config['grantRequests'][i]['operationParam']
          ['operationFrequencyRange']['highFrequency'] <= 3650e6):
        logging.info(
            'Grant is not subject to Arrangement R because it does not overlap '
            'with 3650-3700 MHz.')
        continue

      if 'installationParam' in config['registrationRequests'][index]:
        cbsd_information = config['registrationRequests'][index]
      else:
        for conditional in config['conditionalRegistrationData']:
          if (config['registrationRequests'][index]['fccId'] ==
              conditional['fccId']) and (
                  config['registrationRequests'][index]['cbsdSerialNumber'] ==
                  conditional['cbsdSerialNumber']):
            cbsd_information = conditional
      cbsd_lat = cbsd_information['installationParam']['latitude']
      cbsd_lon = cbsd_information['installationParam']['longitude']
      cbsd_ant_azi = cbsd_information['installationParam']['antennaAzimuth']
      cbsd_ant_beamwidth = cbsd_information['installationParam'][
          'antennaBeamwidth']
      # Check if CBSD is in the Border Sharing Zone, Get the closest point.
      (is_in_sharing_zone, closest_point_lat,
       closest_point_lon) = utils.CheckCbsdInBorderSharingZone(
           cbsd_lat, cbsd_lon, cbsd_ant_azi, cbsd_ant_beamwidth)
      logging.info('CBSD is in Border Sharing Zone?: %s', is_in_sharing_zone)
      if not is_in_sharing_zone:
        continue  # CBSD not in the sharing zone; no PFD check is required.

      # Proceed with PFD calculation
      logging.info('Closest point in the border: Lat is %f', closest_point_lat)
      logging.info('Closest point in the border: Long is %f', closest_point_lon)
      # requested_eirp (p)
      p = config['grantRequests'][index]['operationParam']['maxEirp']
      # Calculate PL
      cbsd_height = cbsd_information['installationParam']['height']
      cbsd_height_type = cbsd_information['installationParam']['heightType']
      is_cbsd_indoor = cbsd_information['installationParam']['indoorDeployment']
      closest_point_height = 1.5  # According to the spec
      freq_mhz = 3625.  # Always in all SAS
      propagation = wf_itm.CalcItmPropagationLoss(
          cbsd_lat,
          cbsd_lon,
          cbsd_height,
          closest_point_lat,
          closest_point_lon,
          closest_point_height,
          reliability=0.5,
          cbsd_indoor=is_cbsd_indoor,
          freq_mhz=freq_mhz,
          is_height_cbsd_amsl=(cbsd_height_type == 'AMSL'))
      pl = propagation.db_loss
      logging.info('Propagation - db_loss: %f', propagation.db_loss)
      bearing = propagation.incidence_angles.hor_cbsd
      logging.info('Bearing: %f', propagation.incidence_angles.hor_cbsd)
      # Calculate effective antenna gain
      max_ant_gain = cbsd_information['installationParam']['antennaGain']
      ant_gain = antenna.GetStandardAntennaGains(
          bearing, cbsd_ant_azi, cbsd_ant_beamwidth,
          max_ant_gain)
      logging.info('Effective Antenna Gain: %f', ant_gain)
      # Calculate PFD where:
      # p = requested_eirp
      # effective_eirp = p - maxAntGain + antGain
      # PFD = effective_eirp - pl + 32.6
      pfd = p - max_ant_gain + ant_gain - pl + 32.6
      logging.info('Power Flex Density: %f dBm/m2/MHz', pfd)
      if pfd > -80:
        self.assertTrue(responses[i]['response']['responseCode'] == 400)
Example #18
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)
Example #19
0
def CalcItm(rel, rx_lat, rx_lng):
    res = wf_itm.CalcItmPropagationLoss(cbsd_lat, cbsd_lon, 10, rx_lat, rx_lng,
                                        1.5, False, rel, freq_mhz)
    return res
    def test_WINNF_FT_S_QPR_5(self, config_filename):
        """[Configurable] Unsuccessful Grant Request from CBSDs within Coordination
    Area around Table Mountain Quiet Zone (QZ) with Multiple Grants.
    """
        config = loadConfig(config_filename)
        self.assertValidConfig(
            config, {
                'registrationRequests': list,
                'conditionalRegistrationData': list,
                'grantRequestsN1': list,
                'grantRequestsN2': list
            })
        self.assertEqual(len(config['registrationRequests']),
                         len(config['grantRequestsN1']))
        self.assertEqual(len(config['grantRequestsN1']),
                         len(config['grantRequestsN2']))

        # Whitelist FCC ID and User ID.
        for device in config['registrationRequests']:
            self._sas_admin.InjectFccId({'fccId': device['fccId']})
            self._sas_admin.InjectUserId({'userId': device['userId']})

        # Pre-load conditional registration data.
        if config['conditionalRegistrationData']:
            self._sas_admin.PreloadRegistrationData(
                {'registrationData': config['conditionalRegistrationData']})

        # Step 1: Register CBSDs.
        request = {'registrationRequest': config['registrationRequests']}
        responses = self._sas.Registration(request)['registrationResponse']

        # Check registration response.
        self.assertEqual(len(responses), len(config['registrationRequests']))
        grant_request_n1 = []
        grant_request_n2 = []
        successful_reg_requests = []
        for i, response in enumerate(responses):
            if response['response']['responseCode'] == 0:
                self.assertTrue('cbsdId' in response)
                successful_reg_requests.append(
                    config['registrationRequests'][i])
                config['grantRequestsN1'][i]['cbsdId'] = response['cbsdId']
                grant_request_n1.append(config['grantRequestsN1'][i])
                config['grantRequestsN2'][i]['cbsdId'] = response['cbsdId']
                grant_request_n2.append(config['grantRequestsN2'][i])
        del request, responses

        if not successful_reg_requests:
            return  # SAS passes immediately, since none of the registration requests
            # succeeded in this case.

        # Step 2: For CBSDs successfully registered in Step 1, Send grant request 1
        request1 = {'grantRequest': grant_request_n1}
        grant_responses1 = self._sas.Grant(request1)['grantResponse']
        # Check grant response 1
        self.assertEqual(len(grant_responses1), len(grant_request_n1))

        # Step 3: For CBSDs successfully registered in Step 1, Send grant request 2
        request2 = {'grantRequest': grant_request_n2}
        grant_responses2 = self._sas.Grant(request2)['grantResponse']
        # Check grant response 2
        self.assertEqual(len(grant_responses2), len(grant_request_n2))

        for i, device in enumerate(successful_reg_requests):
            if 'installationParam' in device:
                cbsd_information = device
            else:
                for conditional in config['conditionalRegistrationData']:
                    if (device['fccId'] == conditional['fccId']) and (
                            device['cbsdSerialNumber']
                            == conditional['cbsdSerialNumber']):
                        cbsd_information = conditional
            logging.info(
                'Looking at device with FccID: %s / CbsdSerialNumber: %s',
                cbsd_information['fccId'],
                cbsd_information['cbsdSerialNumber'])
            grant_response1 = grant_responses1[i]
            grant_response2 = grant_responses2[i]
            if not (grant_response1['response']['responseCode'] == 0
                    or grant_response2['response']['responseCode'] == 0):
                logging.info(
                    'Both grant requests were rejected for this device.')
                continue  # Skip further calculation for this device.

            # Calculate PL
            logging.info(
                'Calculating PL for device with FccID: %s / CbsdSerialNumber: %s',
                cbsd_information['fccId'],
                cbsd_information['cbsdSerialNumber'])
            cbsd_lat = cbsd_information['installationParam']['latitude']
            cbsd_lon = cbsd_information['installationParam']['longitude']
            cbsd_ant_azi = cbsd_information['installationParam'][
                'antennaAzimuth']
            cbsd_ant_beamwidth = cbsd_information['installationParam'][
                'antennaBeamwidth']
            cbsd_height = cbsd_information['installationParam']['height']
            cbsd_height_type = cbsd_information['installationParam'][
                'heightType']
            is_cbsd_indoor = cbsd_information['installationParam'][
                'indoorDeployment']
            freq_mhz = 3625.  # Always in all SAS
            table_mountain_quiet_zone_lat = 40.130660
            table_mountain_quiet_zone_long = -105.244596
            table_mountain_quiet_zone_height = 9  # 9 m: According to the spec
            propagation = wf_itm.CalcItmPropagationLoss(
                cbsd_lat,
                cbsd_lon,
                cbsd_height,
                table_mountain_quiet_zone_lat,
                table_mountain_quiet_zone_long,
                table_mountain_quiet_zone_height,
                cbsd_indoor=is_cbsd_indoor,
                reliability=0.5,
                freq_mhz=freq_mhz,
                is_height_cbsd_amsl=(cbsd_height_type == 'AMSL'))
            pl = propagation.db_loss
            logging.info('Propagation:db_loss: %f', pl)
            bearing = propagation.incidence_angles.hor_cbsd
            logging.info('Bearing: %f', bearing)
            # Calculate effective antenna gain
            max_ant_gain_dbi = cbsd_information['installationParam'][
                'antennaGain']
            ant_gain_dbi = antenna.GetStandardAntennaGains(
                bearing, cbsd_ant_azi, cbsd_ant_beamwidth, max_ant_gain_dbi)
            logging.info('Effective Antenna Gain: %f', ant_gain_dbi)

            # Gather values required for calculating Total Interference
            grant1_eirp = 0
            if grant_response1['response']['responseCode'] == 0:
                p1 = grant_request_n1[i]['operationParam']['maxEirp']
                logging.info('Grant 1 Max Eirp: %f dBm/MHz', p1)
                bw1 = (grant_request_n1[i]['operationParam']
                       ['operationFrequencyRange']['highFrequency'] -
                       grant_request_n1[i]['operationParam']
                       ['operationFrequencyRange']['lowFrequency']) / 1.e6
                logging.info('Grant 1 Bandwidth: %f', bw1)
                grant1_eirp = (10**(p1 / 10.0)) * bw1
                logging.info('Grant 1 EIRP is %f', grant1_eirp)

            grant2_eirp = 0
            if grant_response2['response']['responseCode'] == 0:
                p2 = grant_request_n2[i]['operationParam']['maxEirp']
                logging.info('Grant 2 Max Eirp: %f dBm/MHz', p2)
                bw2 = (grant_request_n2[i]['operationParam']
                       ['operationFrequencyRange']['highFrequency'] -
                       grant_request_n2[i]['operationParam']
                       ['operationFrequencyRange']['lowFrequency']) / 1.e6
                logging.info('Grant 2 Bandwidth: %f', bw2)
                grant2_eirp = (10**(p2 / 10.0)) * bw2
                logging.info('Grant 2 EIRP is %f', grant2_eirp)

            # Step 4: Calculate Total Interference
            total_interference_dbm = ant_gain_dbi - max_ant_gain_dbi + (
                10 * np.log10(grant1_eirp + grant2_eirp)) - pl
            logging.info('Total Interference is %f dBm',
                         total_interference_dbm)

            # CHECK: Total Interference from all approved grants is <= -88.4 dBm
            self.assertLessEqual(total_interference_dbm, -88.4)
 def test_same_location(self):
     result = wf_itm.CalcItmPropagationLoss(45, -80, 10, 45, -80, 10)
     self.assertEqual(result.db_loss, 0)
     self.assertTupleEqual(result.incidence_angles, (0, 0, 0, 0))