def FindOrBuildDpa(dpas, options, grants): """Find or build DPA for simulation purpose. If several DPA, select the one with most grants around (but DPA simulation options always override the logic). """ if options.dpa: dpa_kml_file = options.dpa_kml or None dpa = dpa_mgr.BuildDpa(options.dpa, None, portal_dpa_filename=dpa_kml_file) else: if not dpas: raise ValueError( 'Config file not defining a DPA and no --dpa option used.') if len(dpas) == 1: dpa = dpas[0] else: # Roughly find the DPA wth most CBSD within 200km all_cbsds = sgeo.MultiPoint([(g.longitude, g.latitude) for g in grants]) num_cbsds_inside = [ len(dpa.geometry.buffer(2.5).intersection(all_cbsds)) for dpa in dpas ] dpa = dpas[np.argmax(num_cbsds_inside)] try: dpa.margin_db except AttributeError: dpa.margin_db = 'linear(1.5)' try: dpa.geometry except AttributeError: try: dpa_geometry = zones.GetCoastalDpaZones()[dpa.name] except KeyError: dpa_geometry = zones.GetPortalDpaZones( kml_path=dpa_kml_file)[dpa.name] dpa.geometry = dpa_geometry.geometry if options.dpa_builder: dpa.protected_points = dpa_builder.DpaProtectionPoints( dpa.name, dpa.geometry, options.dpa_builder) if options.margin_db: # Override `movelistMargin` directive. try: dpa.margin_db = float(options.margin_db) except ValueError: dpa.margin_db = options.margin_db return dpa
def DpaSimulate(config_file, options): """Performs the DPA simulation.""" if options.seed is not None: # reset the random seed np.random.seed(options.seed) logging.getLogger().setLevel(logging.WARNING) # Read the input config file into ref model entities. grants, dpas = sim_utils.ReadTestHarnessConfigFile(config_file) # Select appropriate DPA or buid one from options. dpa = FindOrBuildDpa(dpas, options, grants) # Setup the simulator processor: number of processor and cache. num_workers = SetupSimProcessor(options.num_process, options.size_tile_cache, grants) # Simulation start print( 'Simulation with DPA `%s` (ref: %d pts):\n' ' %d granted CBSDs: %d CatB - %d CatA_out - %d CatA_in' % (dpa.name, len(dpa.protected_points), len(grants), len([grant for grant in grants if grant.cbsd_category == 'B']), len([ grant for grant in grants if grant.cbsd_category == 'A' and not grant.indoor_deployment ]), len([ grant for grant in grants if grant.cbsd_category == 'A' and grant.indoor_deployment ]))) # Plot the entities. ax, _ = sim_utils.CreateCbrsPlot(grants, dpa=dpa) plt.show(block=False) # Set the grants into DPA. dpa.SetGrantsFromList(grants) # Manages the number of move list to compute. if options.dpa_builder_uut == options.dpa_builder: options.dpa_builder_uut = '' num_ref_ml = options.ref_ml_num or options.num_ml num_uut_ml = options.uut_ml_num or options.num_ml num_base_ml = (num_ref_ml if options.dpa_builder_uut else max( num_ref_ml, num_uut_ml)) if options.do_extensive: num_base_ml = max(num_base_ml, options.num_ml) # Run the move list N times on ref DPA print('Running Move List algorithm (%d workers): %d times' % (num_workers, num_ref_ml)) start_time = time.time() ref_move_list_runs = [] # Save the move list of each run for k in xrange(num_base_ml): dpa.ComputeMoveLists() ref_move_list_runs.append(copy.copy(dpa.move_lists)) sys.stdout.write('.') sys.stdout.flush() # Plot the last move list on map. for channel in dpa._channels: move_list = dpa.GetMoveList(channel) sim_utils.PlotGrants(ax, move_list, color='r') # Now build the UUT dpa and move lists dpa_uut = copy.copy(dpa) uut_move_list_runs = ref_move_list_runs[:num_uut_ml] if options.dpa_builder_uut: dpa_uut.protected_points = dpa_builder.DpaProtectionPoints( dpa_uut.name, dpa_uut.geometry, options.dpa_builder_uut) # If UUT has its own parameters, simulate it by running it, # otherwise reuse the move lists of the ref model. uut_move_list_runs = [] for k in xrange(num_uut_ml): dpa_uut.ComputeMoveLists() uut_move_list_runs.append(copy.copy(dpa_uut.move_lists)) sys.stdout.write('+') sys.stdout.flush() ref_move_list_runs = ref_move_list_runs[:num_ref_ml] print('\n Computation time: %.1fs' % (time.time() - start_time)) # Save data if options.cache_file: SaveDataToCache( options.cache_file, (dpa, ref_move_list_runs, dpa_uut, uut_move_list_runs, options)) # Find a good channel to check: the one with maximum CBSDs. channel, chan_idx = GetMostUsedChannel(dpa) # Plot the move list sizes histogram for that channel. PlotMoveListHistogram(ref_move_list_runs, chan_idx) # Analyze aggregate interference. By default: # + uut: taking smallest move list (ie bigger keep list) # + ref: taking biggest move list (ie smallest keep list) # or taking a median or intersection move list # Hopefully (!) this is a good proxy for worst case scenarios. # # - enable log level - usually 'info' allows concise report. logging.getLogger().setLevel(_LOGGER_MAP[options.log_level]) # - The ref case first dpa.move_lists = SyntheticMoveList(ref_move_list_runs, options.ref_ml_method, options.ref_ml_num, chan_idx) # - The UUT case dpa_uut.move_lists = SyntheticMoveList(uut_move_list_runs, options.uut_ml_method, options.uut_ml_num, chan_idx) uut_keep_list = dpa_uut.GetKeepList(channel) start_time = time.time() print('***** BASIC INTERFERENCE CHECK: size ref_ML=%d vs %d *****' % (len(dpa.move_lists[chan_idx]), len(dpa_uut.move_lists[chan_idx]))) success = dpa.CheckInterference(uut_keep_list, dpa.margin_db, channel=channel, extensive_print=True) print(' Computation time: %.1fs' % (time.time() - start_time)) # Note: disable extensive logging for further extensive interference check logging.getLogger().setLevel(logging.ERROR) # Extensive mode: compare UUT against many ref model move list if options.do_extensive: print('***** EXTENSIVE INTERFERENCE CHECK *****') ExtensiveInterferenceCheck(dpa, uut_keep_list, ref_move_list_runs, options.ref_ml_num, options.ref_ml_method, channel, chan_idx) # Simulation finalization print('') sim_utils.CheckTerrainTileCacheOk() # Cache analysis and report
def BuildDpa(dpa_name, protection_points_method=None, portal_dpa_filename=None): """Builds a DPA parameterized correctly. The DPA special parameters are obtained from the DPA database. The DPA protection points are generated either from a file, or using a provided default method. Args: dpa_name: The DPA official name. protection_points_method: Three methods are supported for getting the protection points: + a path pointing to the file holding the protected points location defined as a geojson MultiPoint or Point geometry. The path can be either absolute or relative to the running script (normally the `harness/` directory). + 'default <parameters>': A simple default method. Parameters is a tuple defining the number of points to use for different part of the DPA: num_pts_front_border: Number of points in the front border num_pts_back_border: Number of points in the back border num_pts_front_zone: Number of points in the front zone num_pts_back_zone: Number of points in the back zone front_us_border_buffer_km: Buffering of US border for delimiting front/back. min_dist_front_border_pts_km: Minimum distance between front border points (km). min_dist_back_border_pts_km: Minimum distance between back border points (km). min_dist_front_zone_pts_km: Minimum distance between front zone points (km). min_dist_back_zone_pts_km: Minimum distance between back zone points (km). Example of encoding: 'default (200,50,20,5)' Note the default values are (25, 10, 10, 5, 40, 0.2, 1, 0.5, 3) Only the passed parameters will be redefined. The result are only approximate (actual distance and number of points may differ). + other 'my_method (p1, p2, ..pk)': The 'my_method` will be checked against registered methods in which case it will be used, and passing to it the parameters p1, p2,... Returns: A Dpa object. Raises: IOError: if the provided file cannot be found. ValueError: in case of other errors, such as invalid file or parameters. """ try: dpa_zone = zones.GetCoastalDpaZones()[dpa_name] monitor_type = 'esc' except KeyError: try: dpa_zone = zones.GetPortalDpaZones( kml_path=portal_dpa_filename)[dpa_name] monitor_type = 'portal' except KeyError: raise ValueError('DPA %s not found in DPA database' % dpa_name) # Get the DPA protection points protection_points = dpa_builder.DpaProtectionPoints( dpa_name, dpa_zone.geometry, protection_points_method) # Set all DPA operational parameters protection_threshold = dpa_zone.protectionCritDbmPer10MHz radar_height = dpa_zone.refHeightMeters radar_beamwidth = dpa_zone.antennaBeamwidthDeg azimuth_range = (dpa_zone.minAzimuthDeg, dpa_zone.maxAzimuthDeg) freq_ranges_mhz = dpa_zone.freqRangeMHz neighbor_distances = (dpa_zone.catANeighborhoodDistanceKm, dpa_zone.catBNeighborhoodDistanceKm, dpa_zone.catAOOBNeighborhoodDistanceKm, dpa_zone.catBOOBNeighborhoodDistanceKm) return Dpa(protection_points, name=dpa_name, threshold=protection_threshold, radar_height=radar_height, beamwidth=radar_beamwidth, azimuth_range=azimuth_range, freq_ranges_mhz=freq_ranges_mhz, neighbor_distances=neighbor_distances, monitor_type=monitor_type)