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
예제 #3
0
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)