def test_computeFssBlocking(self):
        # Mock things propag and FSS antenna. -70dBm at 30km
        wf_itm.CalcItmPropagationLoss = testutils.FakePropagationPredictor(
            dist_type='REAL', factor=1.0, offset=70 - 30.0)
        antenna.GetFssAntennaGains = mock.create_autospec(
            antenna.GetFssAntennaGains, return_value=2.8)
        # Create FSS and a CBSD at 30km
        fss_point, fss_info, _ = data.getFssInfo(TestAggInterf.fss_record)
        fss_freq_range = (3650e6, 3750e6)
        cbsd_lat, cbsd_lon, _ = vincenty.GeodesicPoint(fss_point[1],
                                                       fss_point[0], 30, 0)
        cbsd = entities.CBSD_TEMPLATE_CAT_A_OUTDOOR._replace(
            latitude=cbsd_lat, longitude=cbsd_lon)
        grant = entities.ConvertToCbsdGrantInfo([cbsd], 3640, 3680)[0]
        constraint = data.ProtectionConstraint(
            fss_point[1], fss_point[0], 3550e6, fss_freq_range[0],
            data.ProtectedEntityType.FSS_BLOCKING)

        itf = interf.computeInterferenceFssBlocking(grant, constraint,
                                                    fss_info, grant.max_eirp)
        self.assertAlmostEqual(
            itf,
            20 +  # EIRP/MHZ
            10 +  # 10MHz effective bandwidth
            -70  # pathloss
            + 2.8  # FSS antenna gain
            - 3.1634,  # FSS mask loss for adjacent 10MHz
            4)
Exemplo n.º 2
0
def getDpaNeighborGrants(grants, protection_points, dpa_geometry, low_freq,
                         high_freq, neighbor_distances):
    """Gets the list of actual neighbor grants of a DPA, for a given channel.

  This looks at the total keep list considering a bunch of protected points.

  Args:
    grants:  A list of CBSD |data.CbsdGrantInfo| active grants.
    protection_points: A list of protection point locations defining the DPA, each one
      having attributes 'latitude' and 'longitude'.
    dpa_geometry: The DPA |shapely.geometry| for detection of inside grants.
    low_freq: The low frequency of protection constraint (Hz).
    high_freq: The high frequency of protection constraint (Hz).
    neighbor_distances: The neighborhood distances (km) as a sequence:
      [cata_dist, catb_dist, cata_oob_dist, catb_oob_dist]

  Returns:
    A set of |CbsdGrantInfo| neighbor grants.
  """
    dpa_type = findDpaType(low_freq, high_freq)

    neighbor_grants = set()
    if dpa_geometry and not isinstance(dpa_geometry, sgeo.Point):
        inside_grants = set(
            g for g in grants
            if sgeo.Point(g.longitude, g.latitude).intersects(dpa_geometry))
        neighbor_grants = set(
            filterGrantsForFreqRange(inside_grants, low_freq, high_freq))

    for point in protection_points:
        # Assign values to the protection constraint
        constraint = data.ProtectionConstraint(
            latitude=point.latitude,
            longitude=point.longitude,
            low_frequency=low_freq,
            high_frequency=high_freq,
            entity_type=data.ProtectedEntityType.DPA)

        # Identify CBSD grants in the neighborhood of the protection constraint
        nbors, _ = findGrantsInsideNeighborhood(grants, constraint, dpa_type,
                                                neighbor_distances)
        neighbor_grants.update(nbors)

    return neighbor_grants
Exemplo n.º 3
0
def calcAggregatedInterference(protection_point,
                               low_freq,
                               high_freq,
                               grants,
                               inc_ant_height,
                               num_iter,
                               beamwidth,
                               neighbor_distances,
                               min_azimuth=0,
                               max_azimuth=360,
                               do_max=False):
    """Computes the 95% aggregated interference quantile on a protected point.

  Inputs:
    protection_point:  A protection point location, having attributes 'latitude' and
                       'longitude'.
    low_freq:          The low frequency of protection constraint (Hz).
    high_freq:         The high frequency of protection constraint (Hz).
    grants:            A list of CBSD |data.CbsdGrantInfo| active grants.
    inc_ant_height:    The reference incumbent antenna height (meters).
    num_iter:          The number of Monte Carlo iterations.
    beamwidth:         The protection antenna beamwidth (degree).
    min_azimuth:       The minimum azimuth (degrees) for incumbent transmission.
    max_azimuth:       The maximum azimuth (degrees) for incumbent transmission.
    neighbor_distances: The neighborhood distances (km) as a sequence:
      [cata_dist, catb_dist, cata_oob_dist, catb_oob_dist]
    do_max:            If True, returns the maximum interference over all radar azimuth.

  Returns:
    The 95% aggregated interference (dB) either:
      - as a vector (ndarray) of length N, where the element k corresponds to
          azimuth k * (beamwith/2). The length N is thus equal to 2 * 360 / beamwith,
          (or 2 * azimuth_range / beamwidth if using a smaller azimuth range than
           360 degrees, as specified by min_azimuth/max_azimuth).
      - or the maximum over all radar azimuth, if `do_max` is set to True.
  """
    dpa_type = findDpaType(low_freq, high_freq)
    if not beamwidth: beamwidth = 360

    # Assign values to the protection constraint
    constraint = data.ProtectionConstraint(
        latitude=protection_point.latitude,
        longitude=protection_point.longitude,
        low_frequency=low_freq,
        high_frequency=high_freq,
        entity_type=data.ProtectedEntityType.DPA)

    # DPA Purge algorithm for OOB
    if dpa_type is DpaType.OUT_OF_BAND:
        cbsds_grants_map = defaultdict(list)
        for grant in grants:
            key = grant.uniqueCbsdKey()
            _addMinFreqGrantToFront(cbsds_grants_map[key], grant)
        # Reset the grants to the minimum frequency grant for each CBSDs.
        grants = [cbsd_grants[0] for cbsd_grants in cbsds_grants_map.values()]

    # Identify CBSD grants in the neighborhood of the protection constraint
    neighbor_grants, _ = findGrantsInsideNeighborhood(grants, constraint,
                                                      dpa_type,
                                                      neighbor_distances)
    if not neighbor_grants:
        return np.asarray(-1000)
    interf_matrix = np.zeros((num_iter, len(neighbor_grants)))
    bearings = np.zeros(len(neighbor_grants))
    for k, grant in enumerate(neighbor_grants):
        interf, _ = computeInterference(grant, constraint, inc_ant_height,
                                        num_iter, dpa_type)
        interf_matrix[:, k] = interf.randomInterference
        bearings[k] = interf.bearing_c_cbsd

    interf_matrix = 10**(interf_matrix / 10.)
    azimuths = findAzimuthRange(min_azimuth, max_azimuth, beamwidth)

    agg_interf = np.zeros(len(azimuths))
    for k, azi in enumerate(azimuths):
        dpa_gains = antenna.GetRadarNormalizedAntennaGains(
            bearings, azi, beamwidth)
        dpa_interf = interf_matrix * 10**(dpa_gains / 10.0)
        agg_interf[k] = np.percentile(np.sum(dpa_interf, axis=1),
                                      PROTECTION_PERCENTILE,
                                      interpolation='lower')
    agg_interf = 10 * np.log10(agg_interf)
    return np.max(agg_interf) if do_max else agg_interf
Exemplo n.º 4
0
def moveListConstraint(protection_point,
                       low_freq,
                       high_freq,
                       grants,
                       inc_ant_height,
                       num_iter,
                       threshold,
                       beamwidth,
                       neighbor_distances,
                       min_azimuth=0,
                       max_azimuth=360):
    """Returns the move list for a given protection constraint.

  Note that the returned indexes corresponds to the grant.grant_index

  Inputs:
    protection_point:  A protection point location, having attributes
                      'latitude' and 'longitude'.
    low_freq:          The low frequency of protection constraint (Hz).
    high_freq:         The high frequency of protection constraint (Hz).
    grants:            A list of CBSD |data.CbsdGrantInfo| grants.
    inc_ant_height:    The reference incumbent antenna height (meters).
    num_iter:          The number of Monte Carlo iterations.
    threshold:         The protection threshold (dBm/10 MHz).
    beamwidth:         The protection antenna beamwidth (degree).
    neighbor_distances: The neighborhood distances (km) as a sequence:
      [cata_dist, catb_dist, cata_oob_dist, catb_oob_dist]
    min_azimuth:       The minimum azimuth (degrees) for incumbent transmission.
    max_azimuth:       The maximum azimuth (degrees) for incumbent transmission.

  Returns:
    A tuple of (move_list_grants, neighbor_list_grants) for that protection constraint:
      + the grants on the move list.
      + the grants in the neighborhood list.
  """
    logging.debug(
        'DPA Create move list for point (%s), freq (%s, %s), threshold (%s), neighborhood distance (%r)',
        protection_point, low_freq, high_freq, threshold, neighbor_distances)
    if not grants:
        return [], []

    dpa_type = findDpaType(low_freq, high_freq)
    if not beamwidth: beamwidth = 360

    # Assign values to the protection constraint
    constraint = data.ProtectionConstraint(
        latitude=protection_point.latitude,
        longitude=protection_point.longitude,
        low_frequency=low_freq,
        high_frequency=high_freq,
        entity_type=data.ProtectedEntityType.DPA)

    # DPA Purge algorithm for OOB
    if dpa_type is DpaType.OUT_OF_BAND:
        cbsds_grants_map = defaultdict(list)
        for grant in grants:
            key = grant.uniqueCbsdKey()
            _addMinFreqGrantToFront(cbsds_grants_map[key], grant)
        # Reset the grants to the minimum frequency grant for each CBSDs.
        grants = [cbsd_grants[0] for cbsd_grants in cbsds_grants_map.values()]

    # Identify CBSD grants in the neighborhood of the protection constraint
    neighbor_grants, neighbor_idxs = findGrantsInsideNeighborhood(
        grants, constraint, dpa_type, neighbor_distances)

    movelist_grants = []
    if len(neighbor_grants):  # Found CBSDs in the neighborhood
        # Form the matrix of interference contributions
        I, sorted_neighbor_idxs, bearings = formInterferenceMatrix(
            neighbor_grants, neighbor_idxs, constraint, inc_ant_height,
            num_iter, dpa_type)

        # Find the index (nc) of the grant in the ordered list of grants such that
        # the protection percentile of the interference from the first nc grants is below
        # the threshold for all azimuths of the receiver antenna.
        nc = find_nc(I, bearings, threshold, beamwidth, min_azimuth,
                     max_azimuth)

        # Determine the associated move list (Mc)
        movelist_grants = [grants[k] for k in sorted_neighbor_idxs[nc:]]

        # DPA Purge Algorithm for OOB - reintegrated in move list
        if dpa_type is DpaType.OUT_OF_BAND:
            # Add back all purged list with state of main one
            extra_grants = []
            for grant in movelist_grants:
                cbsd_extra_grants = cbsds_grants_map[grant.uniqueCbsdKey()][1:]
                if cbsd_extra_grants:
                    extra_grants.extend(cbsd_extra_grants)

            movelist_grants.extend(extra_grants)
            # Note: the following update on neighbor list is optional, the whole
            # code would run the same if we were including only the main grant in
            # the neighbor list. But for sake of consistency, we keep them.
            extra_grants = []
            for grant in neighbor_grants:
                cbsd_extra_grants = cbsds_grants_map[grant.uniqueCbsdKey()][1:]
                if cbsd_extra_grants:
                    extra_grants.extend(cbsd_extra_grants)

            neighbor_grants.extend(extra_grants)

    logging.debug('DPA Returning movelist_grants=(%s), neighbor_grants=(%s)',
                  movelist_grants, neighbor_grants)
    return (movelist_grants, neighbor_grants)
Exemplo n.º 5
0
def iapPointConstraint(protection_point, channels, low_freq, high_freq, grants,
                       fss_info, esc_antenna_info, region_type, threshold,
                       protection_ent_type):
    """Computes aggregate interference(Ap and ASASp) from authorized grants.

  This routine is applicable for FSS Co-Channel and ESC Sensor protection points,
  and PPA/GWPZ protection areas. It calculates aggregate interference over all
  5MHz channels, and feeds post-IAP assessment of allowed interference margins.

  Args:
    protection_point: A protection point as a tuple (longitude, latitude).
    channels: The 5MHz channels as a list of (low_freq, high_freq) tuples.
    low_freq: low frequency of protection constraint (Hz)
    high_freq: high frequency of protection constraint (Hz)
    grants: An iterable of |data.CbsdGrantInfo| grants.
    fss_info: The FSS information of type |data.FssInformation|.
    esc_antenna_info: ESC antenna information of type |data.EscInformation|.
    region_type: Region type of the protection point: 'URBAN', 'SUBURBAN' or 'RURAL'.
    threshold: The protection threshold (mW).
    protection_ent_type: The entity type (|data.ProtectedEntityType|).

  Returns:
    A tuple (latitude, longitude, asas_interference, agg_interference) where:
      asas_interference: a list of interference (per channel) for managing SAS.
      agg_interference: a list of total interference (per channel).
  """
    # Get protection constraint of protected entity
    protection_constraint = data.ProtectionConstraint(
        latitude=protection_point[1],
        longitude=protection_point[0],
        low_frequency=low_freq,
        high_frequency=high_freq,
        entity_type=protection_ent_type)

    # Get all the grants inside neighborhood of the protection entity
    grants_inside = interf.findGrantsInsideNeighborhood(
        grants, protection_point, protection_ent_type)

    # Get all the grants inside neighborhood of the protection entity, and
    # with frequency overlap to the protection point.
    neighbor_grants = interf.findOverlappingGrants(grants_inside,
                                                   protection_constraint)

    if not neighbor_grants:
        return (protection_point[1], protection_point[0], [0] * len(channels),
                [0] * len(channels))

    # Get number of grants, IAP protection threshold and fairshare per channel.
    num_unsatisfied_grants = len(neighbor_grants)

    # Initialize list of aggregate interference from all the grants
    # (including grants from managing and peer SAS )
    aggr_interf = [0] * len(channels)
    # Initialize list of aggregate interference from managing SAS grants.
    asas_interf = [0] * len(channels)

    # Algorithm to calculate interference within IAPBW using EIRP obtained for all
    # the grants through application of IAP
    num_unsatisfied_grants_channels = []
    iap_threshold_channels = []
    fairshare_channels = []

    for index, channel in enumerate(channels):
        # Get protection constraint over 5MHz channel range
        channel_constraint = data.ProtectionConstraint(
            latitude=protection_point[1],
            longitude=protection_point[0],
            low_frequency=channel[0],
            high_frequency=channel[1],
            entity_type=protection_ent_type)

        # Identify CBSD grants overlapping with frequency range of the protection entity
        # in the neighborhood of the protection point and channel
        channel_neighbor_grants = interf.findOverlappingGrants(
            neighbor_grants, channel_constraint)
        num_unsatisfied_grants_channel = len(channel_neighbor_grants)

        # Computes interference quota for this protection_point and channel.
        iap_threshold = threshold

        # Calculate the fair share per channel based on unsatisfied grants
        fairshare_channel = 0
        if num_unsatisfied_grants_channel > 0:
            fairshare_channel = float(
                iap_threshold) / num_unsatisfied_grants_channel

        num_unsatisfied_grants_channels.append(num_unsatisfied_grants_channel)
        iap_threshold_channels.append(iap_threshold)
        fairshare_channels.append(fairshare_channel)

    # List of grants initialized with max EIRP
    grants_eirp = [grant.max_eirp for grant in neighbor_grants]

    # Initialize list of grants_satisfied to False
    grants_satisfied = [False] * num_unsatisfied_grants

    # Initialize list of grants_removed to False
    grants_removed = [False] * num_unsatisfied_grants

    # Initialize grant overlap and interference per channel dictionary
    # Values will be stored in the format of key as tuple (grant_id, channel_id)
    # and respective value as:
    #   overlap_flag: True/False based on grant overlaps with channel
    #   interference: respective interference value for the key
    grants_overlap_flag = {}
    grants_interference = {}

    with cache.CacheManager(wf_hybrid.CalcHybridPropagationLoss):
        # Using memoizing cache manager only for lengthy calculation (hybrid on PPA/GWPZ).
        while num_unsatisfied_grants > 0:
            for g_idx, grant in enumerate(neighbor_grants):

                if grants_satisfied[g_idx]:
                    continue

                for idx, channel in enumerate(channels):
                    # Check if grant overlaps with protection point, channel
                    grant_overlap_check = interf.grantFrequencyOverlapCheck(
                        grant, channel[0], channel[1], protection_ent_type)

                    grants_overlap_flag[(g_idx, idx)] = grant_overlap_check
                    if not grant_overlap_check:
                        continue
                    # Get protection constraint over 5MHz channel range
                    channel_constraint = data.ProtectionConstraint(
                        latitude=protection_point[1],
                        longitude=protection_point[0],
                        low_frequency=channel[0],
                        high_frequency=channel[1],
                        entity_type=protection_ent_type)

                    # Compute interference that grant causes to protection point over channel
                    interference = interf.dbToLinear(
                        interf.computeInterference(grant, grants_eirp[g_idx],
                                                   channel_constraint,
                                                   fss_info, esc_antenna_info,
                                                   region_type))

                    # If calculated interference is more than fair share of interference
                    # to which the grants are entitled then grant is considered unsatisfied
                    if interference < fairshare_channels[idx]:
                        # Add the interference caused by all the grants in a 5MHz channel
                        grants_interference[(g_idx, idx)] = interference
                        grants_satisfied[g_idx] = True
                    else:
                        grants_satisfied[g_idx] = False
                        break

            num_grants_good_overall_channels = 0

            for gr_idx, grant in enumerate(neighbor_grants):
                if grants_removed[gr_idx]:
                    continue
                if not grants_satisfied[gr_idx]:
                    continue
                if num_unsatisfied_grants > 0:
                    num_unsatisfied_grants -= 1
                for ch_idx, channel in enumerate(channels):
                    # Grant interferes with protection point over channel
                    if grants_overlap_flag[(gr_idx, ch_idx)]:
                        iap_threshold_channels[ch_idx] = (
                            iap_threshold_channels[ch_idx] -
                            grants_interference[(gr_idx, ch_idx)])
                        num_unsatisfied_grants_channels[ch_idx] -= 1
                        # Re-calculate fairshare for a channel
                        if num_unsatisfied_grants_channels[ch_idx] > 0:
                            fairshare_channels[ch_idx] = (
                                float(iap_threshold_channels[ch_idx]) /
                                num_unsatisfied_grants_channels[ch_idx])
                        aggr_interf[ch_idx] += grants_interference[(gr_idx,
                                                                    ch_idx)]
                        if grant.is_managed_grant:
                            asas_interf[ch_idx] += grants_interference[(
                                gr_idx, ch_idx)]

                    # Removing grants from future consideration
                    grants_removed[gr_idx] = True

                    # Increase number of grants good over all channels
                    num_grants_good_overall_channels += 1

            if num_grants_good_overall_channels == 0:
                for grant_idx, grant in enumerate(neighbor_grants):
                    # Reduce power level of all the unsatisfied grants
                    if not grants_satisfied[grant_idx]:
                        grants_eirp[grant_idx] -= 1

    logging.debug('IAP point_constraint @ point %s: %s',
                  (protection_point[1], protection_point[0]),
                  zip(asas_interf, aggr_interf))

    # Return the computed data
    return protection_point[1], protection_point[0], asas_interf, aggr_interf
def aggregateInterferenceForPoint(protection_point, channels, grants, fss_info,
                                  esc_antenna_info, protection_ent_type,
                                  region_type):
    """Computes the aggregate interference for a protection point.

  This routine is invoked to calculate aggregate interference for ESC sensor,
  FSS Co-channel/Blocking and PPA/GWPZ protection areas.

  Args:
    protection_point: The location of a protected entity as (longitude, latitude) tuple.
    channels: A sequence of channels as tuple (low_freq_hz, high_freq_hz).
    grants: An iterable of CBSD grants of type |data.CbsdGrantInfo|.
    fss_info: The FSS information of type |data.FssInformation| (optional).
    esc_antenna_info: ESC antenna information of type |data.EscInformation| (optional).
    protection_ent_type: The entity type (|data.ProtectedEntityType|).
    region: Region type of the protection point: 'URBAN', 'SUBURBAN' or 'RURAL'.

  Returns:
    A tuple (latitude, longitude, interferences) where interferences is a list
    of interference per channel.
  """

    # Get all the grants inside neighborhood of the protection entity
    grants_inside = interf.findGrantsInsideNeighborhood(
        grants, protection_point, protection_ent_type)

    if not grants_inside:
        # We need one entry per channel, even if they're all zero.
        return protection_point[1], protection_point[0], [0] * len(channels)

    interferences = []
    with cache.CacheManager(wf_hybrid.CalcHybridPropagationLoss):
        # Using memoizing cache manager only for lengthy calculation (hybrid on PPA/GWPZ).
        for channel in channels:
            # Get protection constraint over 5MHz channel range
            protection_constraint = data.ProtectionConstraint(
                latitude=protection_point[1],
                longitude=protection_point[0],
                low_frequency=channel[0],
                high_frequency=channel[1],
                entity_type=protection_ent_type)

            # Identify CBSD grants overlapping with frequency range of the protection entity
            # in the neighborhood of the protection point and channel
            neighborhood_grants = interf.findOverlappingGrants(
                grants_inside, protection_constraint)

            if not neighborhood_grants:
                interferences.append(0)
                continue

            cbsd_interferences = [
                interf.computeInterference(grant, grant.max_eirp,
                                           protection_constraint, fss_info,
                                           esc_antenna_info, region_type)
                for grant in neighborhood_grants
            ]

            total_interference = convertAndSumInterference(cbsd_interferences)
            interferences.append(total_interference)

    logging.debug('Agg Interf @ point %s: %s',
                  (protection_point[1], protection_point[0]), interferences)
    return protection_point[1], protection_point[0], interferences