def calculateAggregateInterferenceForFssCochannel(fss_record, grants): """Calculates per-channel aggregate interference for FSS co-channel. Args: fss_record: A FSS record (dict). grants: An iterable of CBSD grants of type |data.CbsdGrantInfo|. Returns: Aggregate interference to FSS co-channel in the nested dictionary format: {latitude : {longitude: [aggr_interf1(mW), ..., aggr_interfK(mW)]}} The list contains the value per protected channel. """ # 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') protection_channels = interf.getProtectedChannels(fss_low_freq, interf.CBRS_HIGH_FREQ_HZ) logging.info( 'Computing aggregateInterferenceForPoint for FSS Coch: channels (%s), ' 'point (%s), grants (%s), fss_info (%s)', protection_channels, fss_point, grants, fss_info) interferences = aggregateInterferenceForPoint( fss_point, protection_channels, grants, fss_info, None, data.ProtectedEntityType.FSS_CO_CHANNEL, None) return InterferenceDict(interferences)
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)
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
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
def fssPurgeReferenceModel(sas_uut_fad, sas_test_harness_fads, fss_records): """Performs FSS purge model as described in R2-SGN-29. The FSS purge list model removes grants from the CBSD records of the FAD (Full Activity Dump) objects for both SAS UUT and SAS Test Harness. Args: sas_uut_fad: A |FullActivityDump| object containing the FAD records of SAS UUT. sas_test_harness_fads: A list of |FullActivityDump| objects containing the FAD records from SAS test harnesses. fss_records: A list of FSS record dictionary. """ # Get the CBSD list from the FAD Object. cbsds = sas_uut_fad.getCbsdRecords() for fad in sas_test_harness_fads: cbsds.extend(fad.getCbsdRecords()) grants_to_purged_for_all_fss = [] ids_to_purge = set() for fss_record in fss_records: fss_point, fss_info, freq_range = data.getFssInfo(fss_record) _, fss_high_freq = freq_range # If the FSS is of TT&C type and the FSS high frequency is above 3700 MHz then perform the FSS purge model for the FSS. if fss_record['ttc'] and fss_high_freq > interf.FSS_TTC_LOW_FREQ_HZ: logging.info('Running purge list for FSS record (%s).', fss_record) neighboring_cbsds_with_grants = pre_iap_util.getFssNeighboringCbsdsWithGrants( cbsds, fss_point, 40) if neighboring_cbsds_with_grants: grants_to_purge_for_fss = generatePurgeListForFssPoint( neighboring_cbsds_with_grants, fss_point, fss_info) # Grants to be purged is updated checking against the cbsd id and grant id # to eliminate the duplicate entries grants_to_purged_for_all_fss.extend( purge_data for purge_data in grants_to_purge_for_fss if (purge_data.grant['id'], purge_data.cbsd['id']) not in ids_to_purge) ids_to_purge.update([ (purge_data.grant['id'], purge_data.cbsd['id']) for purge_data in grants_to_purge_for_fss ]) # Removing grant requests that are in the grants to purge list from the CBSDs. logging.info( 'As a result of all FSS purge list calculations, purging the following: %s', grants_to_purged_for_all_fss) for purge_data in grants_to_purged_for_all_fss: purge_data.cbsd['grants'].remove(purge_data.grant)
def calculateAggregateInterferenceForFssBlocking(fss_record, grants): """Calculates per-channel aggregate interference for FSS blocking. Args: fss_record: A FSS record (dict). grants: An iterable of CBSD grants of type |data.CbsdGrantInfo|. Returns: Aggregate interference to FSS blocking in the nested dictionary format. {latitude : {longitude: [aggr_interf1(mW), ..., aggr_interfK(mW)]}} The list contains the value per protected channel. """ 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( "AggInterf for FSS not applied for FSS Pass band 3700 to 4200 " "and TT&C flag set to false, please check the inputs.") # 5MHz channelization is not required for Blocking protection # FSS TT&C Blocking Algorithm protection_channels = [(interf.CBRS_LOW_FREQ_HZ, fss_low_freq)] logging.info( 'Computing aggregateInterferenceForPoint for FSS Blocking: channels (%s), ' 'point (%s), grants (%s), fss_info (%s)', protection_channels, fss_point, grants, fss_info) interferences = aggregateInterferenceForPoint( fss_point, protection_channels, grants, fss_info, None, data.ProtectedEntityType.FSS_BLOCKING, None) return InterferenceDict(interferences)
def zonePurgeReferenceModel(sas_uut_fad, sas_test_harness_fads, ppa_records, pal_records, gwpz_records, fss_records): """Executes the Zone PPA, GWPZ and FSS+GWBL purge reference model. CBSDs from the FAD objects of SAS UUT and SAS test harnesses that lie within the PPA area or GWPZ area or within 150 KMs from the FSS site will have their grant purged if the grant overlaps with frequency range of the protected entities. A frequency range of 3650-3700 MHz is considered for all the FSSs. It is assumed that the FSS records passed as input have a GWBL station within 150 KMs and thus the FSS exclusion zone is activated. Grants are purged directly from the input FADs. Args: sas_uut_fad: A |FullActivityDump| object containing the FAD records of SAS UUT. sas_test_harness_fads: A list of |FullActivityDump| objects containing the FAD records from SAS test harnesses. ppa_records: List of PPA record dictionaries. pal_records: List of PAL record dictionaries. gwpz_records: List of GWPZ record dictionaries. fss_records: List of FSS record dictionaries. All the FSSs in this list should have at least one GWBL within 150KMs. """ logging.info('Performing zone purge with PPA (%s), PAL (%s), GWPZ (%s), and FSS with GWBL (%s)', ppa_records, pal_records, gwpz_records, fss_records) # Get the list of all CBSDs from the FAD objects of UUT and test harness cbsds = sas_uut_fad.getCbsdRecords() for fad in sas_test_harness_fads: cbsds.extend(fad.getCbsdRecords()) # Perform purge for each PPA for ppa_record in ppa_records: logging.info('Purging in PPA (%s)', ppa_record) # Get all the CBSDs within the PPA polygon cbsds_within_ppa = pre_iap_util.getCbsdsWithinPolygon(cbsds, ppa_record['zone']) logging.info('CBSDs within PPA: %s', cbsds_within_ppa) if cbsds_within_ppa: # Get all the cbsds that are not part of the PPA cluster list cbsds_not_part_of_ppa_cluster = data.getCbsdsNotPartOfPpaCluster( cbsds_within_ppa, ppa_record) logging.info('CBSDs which are not part of the PPA cluster list: %s', cbsds_not_part_of_ppa_cluster) if cbsds_not_part_of_ppa_cluster: # Get the frequency of the PPA ppa_frequency_range = pre_iap_util.getPpaFrequencyRange(ppa_record, pal_records) logging.info('PPA frequency range: %s', ppa_frequency_range) # Purge the grants of CBSDs that are overlapping PPA frequency pre_iap_util.purgeOverlappingGrants(cbsds_not_part_of_ppa_cluster, ppa_frequency_range) # Perform purge for each GWPZ for gwpz_record in gwpz_records: logging.info('Purging in GWPZ (%s)', gwpz_record) # Get the CBSDs that are witin the GWPZ polygon cbsds_within_gwpz = pre_iap_util.getCbsdsWithinPolygon(cbsds, gwpz_record['zone']) logging.info('CBSDs within GWPZ: %s', cbsds_within_gwpz) if cbsds_within_gwpz: # Purge the overlapping grants pre_iap_util.purgeOverlappingGrants(cbsds_within_gwpz, gwpz_record['record']['deploymentParam'][0] ['operationParam']['operationFrequencyRange']) # Perform GWBL+FSS purge for each FSS for fss_record in fss_records: logging.info('Purging near FSS (%s)', fss_record) fss_point, fss_info, _ = data.getFssInfo(fss_record) # Get the CBSDs that are present within 150kms of FSS entity cbsds_neighboring_fss = pre_iap_util.getFssNeighboringCbsdsWithGrants( cbsds, fss_point, pre_iap_util.FSS_GWBL_PROTECTION_DISTANCE_KM) logging.info('CBSDs near the FSS: %s', cbsds_neighboring_fss) if cbsds_neighboring_fss: # Purge the overlapping grants pre_iap_util.purgeOverlappingGrants(cbsds_neighboring_fss, pre_iap_util.FSS_GWBL_PROTECTION_FREQ_RANGE)