Esempio n. 1
0
def performIapForFssBlocking(fss_record, sas_uut_fad_object,
                             sas_th_fad_objects):
    """Computes post IAP interference margin for FSS Blocking incumbent.

  FSS protection is provided over blocking pass band.

  Args:
    fss_record: A FSS record (dict).
    sas_uut_fad_object: FAD object from SAS UUT
    sas_th_fad_object: a list of FAD objects from SAS Test Harness
  Returns:
    ap_iap_ref: The post-IAP allowed interference, as a dict formatted as:
        {latitude : {longitude : [interference(mW/IAPBW), .., interference(mW/IAPBW)]}}
      where the list holds all values per channel of that protection point.
  """
    # Actual protection threshold used for IAP - calculated by applying
    # a pre-defined Pre-IAP headroom (Mg) at each protection threshold(Q)
    fss_blocking_iap_threshold = interf.dbToLinear(
        THRESH_FSS_BLOCKING_DBM_PER_RBW - MARGIN_FSS_BLOCKING_DB)

    grants = data.getGrantObjectsFromFAD(sas_uut_fad_object,
                                         sas_th_fad_objects)

    # Get number of SAS
    num_sas = len(sas_th_fad_objects) + 1

    # Get FSS T&C Flag value
    fss_ttc_flag = fss_record['ttc']

    # Get the FSS infos
    fss_point, fss_info, fss_freq_range = data.getFssInfo(fss_record)
    fss_low_freq, fss_high_freq = fss_freq_range

    # FSS Passband is between 3700 and 4200 and TT&C flag is set to FALSE
    if (fss_low_freq >= interf.FSS_TTC_LOW_FREQ_HZ
            and fss_high_freq <= interf.FSS_TTC_HIGH_FREQ_HZ
            and fss_ttc_flag is False):
        raise Exception(
            "IAP for FSS not applied for FSS Pass band 3700 to 4200 "
            "and TT&C flag set to false, please check the inputs.")

    logging.debug('$$$$ Calling FSS blocking Protection $$$$')
    # 5MHz channelization is not required for Blocking protection
    protection_channels = [(interf.CBRS_LOW_FREQ_HZ, fss_low_freq)]

    iap_interfs = iapPointConstraint(fss_point, protection_channels,
                                     interf.CBRS_LOW_FREQ_HZ, fss_low_freq,
                                     grants, fss_info, None, None,
                                     fss_blocking_iap_threshold,
                                     data.ProtectedEntityType.FSS_BLOCKING)

    ap_iap_ref = calculatePostIapAggregateInterference(
        interf.dbToLinear(THRESH_FSS_BLOCKING_DBM_PER_RBW), num_sas,
        iap_interfs)
    return ap_iap_ref
Esempio n. 2
0
def performIapForFssCochannel(fss_record, sas_uut_fad_object,
                              sas_th_fad_objects):
    """Computes post IAP interference margin for FSS Co-channel incumbent.

  FSS protection is provided over co-channel pass band.

  Args:
    fss_record: A FSS record (dict).
    sas_uut_fad_object: A FAD object from SAS UUT
    sas_th_fad_object: A list of FAD objects from SAS Test Harness
  Returns:
    ap_iap_ref: The post-IAP allowed interference, as a dict formatted as:
        {latitude : {longitude : [interference(mW/IAPBW), .., interference(mW/IAPBW)]}}
      where the list holds all values per channel of that protection point.
  """
    fss_cochannel_thresh_q = THRESH_FSS_CO_CHANNEL_DBM_PER_IAPBW

    # Actual protection threshold used for IAP - calculated by applying
    # a pre-defined Pre-IAP headroom (Mg) at each protection threshold(Q)
    fss_cochannel_iap_threshold = interf.dbToLinear(fss_cochannel_thresh_q -
                                                    MARGIN_FSS_CO_CHANNEL_DB)

    grants = data.getGrantObjectsFromFAD(sas_uut_fad_object,
                                         sas_th_fad_objects)

    # Get number of SAS
    num_sas = len(sas_th_fad_objects) + 1

    # Get the FSS infos
    fss_point, fss_info, fss_freq_range = data.getFssInfo(fss_record)
    fss_low_freq, fss_high_freq = fss_freq_range

    # Get channels for co-channel CBSDs
    if fss_high_freq < interf.CBRS_HIGH_FREQ_HZ:
        raise ValueError(
            'FSS high frequency should not be less than CBRS high frequency(Hz)'
        )
    protection_channels = interf.getProtectedChannels(fss_low_freq,
                                                      interf.CBRS_HIGH_FREQ_HZ)

    # FSS Co-channel algorithm
    logging.debug('$$$$ Calling FSS co-channel Protection $$$$')
    iap_interfs = iapPointConstraint(fss_point, protection_channels,
                                     fss_low_freq, interf.CBRS_HIGH_FREQ_HZ,
                                     grants, fss_info, None, None,
                                     fss_cochannel_iap_threshold,
                                     data.ProtectedEntityType.FSS_CO_CHANNEL)

    ap_iap_ref = calculatePostIapAggregateInterference(
        interf.dbToLinear(fss_cochannel_thresh_q), num_sas, iap_interfs)

    return ap_iap_ref
Esempio n. 3
0
def performIapForEsc(esc_record, sas_uut_fad_object, sas_th_fad_objects):
    """Computes post IAP interference margin for ESC.

  IAP algorithm is run over ESC passband 3550-3660MHz for Category A CBSDs and
  3550-3680MHz for Category B CBSDs.

  Args:
    esc_record: An ESC record (dict of schema |EscSensorRecord|).
    sas_uut_fad_object: FAD object from SAS UUT
    sas_th_fad_objects: A list of FAD objects from SAS Test Harness
  Returns:
    ap_iap_ref: The post-IAP allowed interference, as a dict formatted as:
        {latitude : {longitude : [interference(mW/IAPBW), .., interference(mW/IAPBW)]}}
      where the list holds all values per channel of that protection point.
  """
    esc_thresh_q = THRESH_ESC_DBM_PER_IAPBW

    # Actual protection threshold used for IAP - calculated by applying
    # a pre-defined Pre-IAP headroom (Mg) at each protection threshold(Q)
    esc_iap_threshold = interf.dbToLinear(esc_thresh_q - MARGIN_ESC_DB)

    grants = data.getGrantObjectsFromFAD(sas_uut_fad_object,
                                         sas_th_fad_objects)

    # Get number of SAS
    num_sas = len(sas_th_fad_objects) + 1

    # Get the ESC infos
    protection_point, esc_antenna_info = data.getEscInfo(esc_record)

    # Get ESC passband 3550-3680 MHz protection channels
    protection_channels = interf.getProtectedChannels(interf.ESC_LOW_FREQ_HZ,
                                                      interf.ESC_HIGH_FREQ_HZ)

    logging.debug('$$$$ Calling ESC Protection $$$$')
    # ESC algorithm
    iap_interfs = iapPointConstraint(protection_point, protection_channels,
                                     interf.ESC_LOW_FREQ_HZ,
                                     interf.ESC_HIGH_FREQ_HZ, grants, None,
                                     esc_antenna_info, None, esc_iap_threshold,
                                     data.ProtectedEntityType.ESC)

    ap_iap_ref = calculatePostIapAggregateInterference(
        interf.dbToLinear(esc_thresh_q), num_sas, iap_interfs)
    return ap_iap_ref
Esempio n. 4
0
def generatePurgeListForFssPoint(cbsds, fss_point, fss_info):
    """Generates the FSS purge list.

  Implementation of algorithm described in R2-SGN-29.
  The list of grants to be purged based on the interference caused by their
  out of band emission are identified and returned.

  Args:
    cbsds: The list of |CbsdData| objects that are in the neighborhood to an FSS.
    fss_point: The FSS location as a (longitude, latitude) tuple.
    fss_info: The |data.FssInformation| of the FSS.

  Returns:
    A list of dictionaries, each holding keys:
      'grant': the grants to be purged
      'cbsd': the corresponding |CbsdData| object.

    A list of multiple key-value pairs with keys "grantData", "cbsd" and values as grants to be
    purged and corresponding cbsd data object respectively.
  """
    # List of grants to be purged for the fss entity.
    final_purge_list = []

    # List of dictionaries containing the grant_info based on the highest grant
    # from FSS OOBE calculation
    grants_cbsds_info_for_oobe_calculation = getGrantInfoListForFssOobeCalculation(
        cbsds)

    # Calculate the threshold value in dBm for the OOBE interference
    oobe_threshold_value = -129 + 10 * np.log10(
        REF_BW / interf.MHZ) - FSS_OOBE_MARGIN

    while True:
        logging.info(
            'Starting another loop of the FSS purge list; current purge list: %s',
            final_purge_list)

        # Calculate the OOBE interference value for each grant.
        calculateOobeInterference(grants_cbsds_info_for_oobe_calculation,
                                  fss_point, fss_info)

        # Sort the grants based on the calculated interference value.
        sorted_grants_cbsds_info = sorted(
            grants_cbsds_info_for_oobe_calculation,
            key=lambda grant: grant['oobe_interference'])
        # Find the largest index such that aggregation of the interferences are not equal
        # to or higher than the OOBE threshold.
        oobe_interferences = [
            interf.dbToLinear(grant['oobe_interference'])
            for grant in sorted_grants_cbsds_info
        ]
        cumulated_interference = np.cumsum(oobe_interferences)
        index = np.searchsorted(cumulated_interference,
                                interf.dbToLinear(oobe_threshold_value))
        grants_to_purge = sorted_grants_cbsds_info[index:]
        grants_cbsds_info_for_oobe_calculation = sorted_grants_cbsds_info[:
                                                                          index]

        # If no grants are identified for purging in this iteration then break the loop
        if not grants_to_purge:
            logging.info('No grants to purge.')
            break
        # Otherwise update purge list
        for purged_grant in grants_to_purge:
            remaining_grants = []
            for grant in purged_grant['cbsd']['grants']:
                # Find the grants matching mcbsd value and add it to the purge list
                if purged_grant['mcbsd'] == getMcbsdValue(grant):
                    final_purge_list.append(
                        grants_cbsds_namedtuple(grant, purged_grant['cbsd']))
                elif purged_grant['mcbsd'] > getMcbsdValue(grant):
                    # Find the grants with mcbsd value less than the max_grant mcbsd value
                    # and add it to the remaining grants list
                    remaining_grants.append(grant)

            # Identify the grant with the highest highFrequency value among the remaining
            # grants for the CBSD and add it to the grants_cbsds_info_for_oobe_calculation
            # list for next iteration.
            if remaining_grants:
                max_grant = max(remaining_grants,
                                key=lambda x: x['operationParam']
                                ['operationFrequencyRange']['highFrequency'])
                grants_cbsds_info_for_oobe_calculation.append({
                    'mcbsd':
                    getMcbsdValue(max_grant),
                    'cbsd':
                    purged_grant['cbsd']
                })

    return final_purge_list
Esempio 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
Esempio n. 6
0
def performIapForPpa(ppa_record, sas_uut_fad_object, sas_th_fad_objects,
                     pal_records):
    """Computes post IAP interference margin for PPA incumbents.

  Routine to get protection points within PPA protection area and perform
  IAP algorithm on each protection point.

  Args:
    ppa_record: A PPA record dict.
    sas_uut_fad_object: A FAD object from SAS UUT.
    sas_th_fad_object: A list of FAD objects from SAS Test Harness
    pal_records: PAL records associated with a PPA protection area
  Returns:
    ap_iap_ref: The post-IAP allowed interference, as a dict formatted as:
        {latitude : {longitude : [interference(mW/IAPBW), .., interference(mW/IAPBW)]}}
      where the list holds all values per channel of that protection point.
  """
    ppa_thresh_q = THRESH_PPA_DBM_PER_IAPBW

    # Actual protection threshold used for IAP - calculated by applying
    # a pre-defined Pre-IAP headroom (Mg) at each protection threshold(Q)
    ppa_iap_threshold = interf.dbToLinear(ppa_thresh_q - MARGIN_PPA_DB)

    grants = data.getGrantObjectsFromFAD(sas_uut_fad_object,
                                         sas_th_fad_objects, ppa_record)

    # Get number of SAS
    num_sas = len(sas_th_fad_objects) + 1

    logging.debug('$$$$ Getting GRID points for PPA Protection Area $$$$')

    # Get Fine Grid Points for a PPA protection area
    protection_points = utils.GridPolygon(
        ppa_record['zone']['features'][0]['geometry'], PPA_GRID_RES_ARCSEC)

    # Get the region type of the PPA protection area
    ppa_region = ppa_record['ppaInfo']['ppaRegionType']

    # Find the PAL records for the PAL_IDs defined in PPA records
    ppa_pal_ids = ppa_record['ppaInfo']['palId']

    matching_pal_records = [
        pr for pr in pal_records if pr['palId'] == ppa_pal_ids[0]
    ]
    if not matching_pal_records:
        raise ValueError('No matching PAL record, please check input')

    pal_record = matching_pal_records[0]

    # Get the frequencies from the PAL records
    ppa_freq_range = pal_record['channelAssignment']['primaryAssignment']
    ppa_low_freq = ppa_freq_range['lowFrequency']
    ppa_high_freq = ppa_freq_range['highFrequency']

    # Get channels over which area incumbent needs partial/full protection
    protection_channels = interf.getProtectedChannels(ppa_low_freq,
                                                      ppa_high_freq)

    # Apply IAP for each protection constraint with a pool of parallel
    # processes.
    logging.debug('$$$$ Calling PPA Protection $$$$')
    iapPoint = partial(iapPointConstraint,
                       channels=protection_channels,
                       low_freq=ppa_low_freq,
                       high_freq=ppa_high_freq,
                       grants=grants,
                       fss_info=None,
                       esc_antenna_info=None,
                       region_type=ppa_region,
                       threshold=ppa_iap_threshold,
                       protection_ent_type=data.ProtectedEntityType.PPA_AREA)

    pool = mpool.Pool()
    iap_interfs = pool.map(iapPoint, protection_points)

    ap_iap_ref = calculatePostIapAggregateInterference(
        interf.dbToLinear(ppa_thresh_q), num_sas, iap_interfs)

    return ap_iap_ref
Esempio n. 7
0
def performIapForGwpz(gwpz_record, sas_uut_fad_object, sas_th_fad_objects):
    """Computes post IAP interference margin for GWPZ incumbents.

  Routine to get protection points within GWPZ protection area and perform
  IAP algorithm on each protection point.

  Args:
    gwpz_record: A GWPZ record dict.
    sas_uut_fad_object: FAD object from SAS UUT
    sas_th_fad_objects: A list of FAD objects from SAS Test Harness
  Returns:
    ap_iap_ref: The post-IAP allowed interference, as a dict formatted as:
        {latitude : {longitude : [interference(mW/IAPBW), .., interference(mW/IAPBW)]}}
      where the list holds all values per channel of that protection point.
  """
    gwpz_thresh_q = THRESH_GWPZ_DBM_PER_IAPBW

    # Actual protection threshold used for IAP - calculated by applying
    # a pre-defined Pre-IAP headroom (Mg) at each protection threshold(Q)
    gwpz_iap_threshold = interf.dbToLinear(gwpz_thresh_q - MARGIN_GWPZ_DB)

    grants = data.getGrantObjectsFromFAD(sas_uut_fad_object,
                                         sas_th_fad_objects)

    # Get number of SAS
    num_sas = len(sas_th_fad_objects) + 1

    logging.debug('$$$$ Getting GRID points for GWPZ Protection Area $$$$')
    # Get Fine Grid Points for a GWPZ protection area
    protection_points = utils.GridPolygon(
        gwpz_record['zone']['features'][0]['geometry'], GWPZ_GRID_RES_ARCSEC)

    gwpz_freq_range = gwpz_record['record']['deploymentParam'][0]\
                                 ['operationParam']['operationFrequencyRange']
    gwpz_low_freq = gwpz_freq_range['lowFrequency']
    gwpz_high_freq = gwpz_freq_range['highFrequency']
    gwpz_region = gwpz_record['landCategory']

    # Get channels over which area incumbent needs partial/full protection
    protection_channels = interf.getProtectedChannels(gwpz_low_freq,
                                                      gwpz_high_freq)

    logging.debug('$$$$ Calling GWPZ Protection $$$$')
    iapPoint = partial(iapPointConstraint,
                       channels=protection_channels,
                       low_freq=gwpz_low_freq,
                       high_freq=gwpz_high_freq,
                       grants=grants,
                       fss_info=None,
                       esc_antenna_info=None,
                       region_type=gwpz_region,
                       threshold=gwpz_iap_threshold,
                       protection_ent_type=data.ProtectedEntityType.GWPZ_AREA)

    pool = mpool.Pool()
    iap_interfs = pool.map(iapPoint, protection_points)

    ap_iap_ref = calculatePostIapAggregateInterference(
        interf.dbToLinear(gwpz_thresh_q), num_sas, iap_interfs)

    return ap_iap_ref
def convertAndSumInterference(cbsd_interference_list):
    """Converts interference in dBm to mW to calculate aggregate interference"""
    interferences_in_dbm = np.array(cbsd_interference_list)
    return np.sum(interf.dbToLinear(interferences_in_dbm))