def test_grid_point_and_null(self):
     poly = sgeo.Polygon([(1.9, 0.9), (2.1, 0.9), (2.1, 1.1), (1.9, 1.1)])
     exp_pts = [(2.0, 1.0)]
     pts = utils.GridPolygon(poly, res_arcsec=900.)
     self.assertListEqual(pts, exp_pts)
     pts = utils.GridPolygon(poly, res_arcsec=7200.)
     self.assertListEqual(pts, [])
    def test_grid_complex(self):
        with open(os.path.join(TEST_DIR, 'test_geocollection.json'),
                  'r') as fd:
            json_geo = json.load(fd)

        shape_geo = utils.ToShapely(json_geo)
        exp_pts = {(-95, 40), (-95.5, 40.5), (-95.5, 40), (-96, 40),
                   (-96.5, 40.5), (-96.5, 40)}
        pts = utils.GridPolygon(json_geo, res_arcsec=1800)
        self.assertSetEqual(set(pts), exp_pts)

        pts = utils.GridPolygon(shape_geo, res_arcsec=1800)
        self.assertSetEqual(set(pts), exp_pts)

        pts = utils.GridPolygon(ops.unary_union(shape_geo), res_arcsec=1800)
        self.assertSetEqual(set(pts), exp_pts)
 def test_grid_simple(self):
     poly = sgeo.Polygon([(1.9, 3.9), (3.1, 3.9), (3.1, 4.4), (2.5, 4.5),
                          (2.4, 5.1), (1.9, 5.1)])
     exp_pts = {(2.0, 4.0), (2.5, 4.0), (3.0, 4.0), (2.0, 4.5), (2.5, 4.5),
                (2.0, 5.0)}
     pts = utils.GridPolygon(poly, res_arcsec=1800.)
     self.assertSetEqual(set(pts), exp_pts)
 def test_grid_border_included(self):
     poly = sgeo.Polygon([(-108.05, 42.25), (-107.90, 42.25),
                          (-107.90, 42.20), (-108.05, 42.20),
                          (-108.05, 42.25)])
     pts = utils.GridPolygon(poly, res_arcsec=2.)
     self.assertEqual(len(pts), (1800 * 0.15 + 1) * (1800 * 0.05 + 1))
     self.assertAlmostEqual(pts[0][0], -108.05, 10)
     self.assertAlmostEqual(pts[0][1], 42.20, 10)
     self.assertAlmostEqual(pts[-1][0], -107.90, 10)
     self.assertAlmostEqual(pts[-1][1], 42.25, 10)
def calculateAggregateInterferenceForGwpz(gwpz_record, grants):
    """Calculates per-channel aggregate interference for GWPZ.

  Args:
    gwpz_record: A GWPZ record dict.
    grants: An iterable of CBSD grants of type |data.CbsdGrantInfo|.

  Returns:
    Aggregate interference to GWPZ in the nested dictionary format.
      {latitude : {longitude: [aggr_interf1(mW), ..., aggr_interfK(mW)]}}
    The list contains the value per protected channel.
  """
    gwpz_region = gwpz_record['landCategory']

    # 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']

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

    # Calculate aggregate interference from each protection constraint with a
    # pool of parallel processes.
    logging.info(
        'Computing aggregateInterferenceForPoint for PPA (%s), channels (%s), '
        'nPoints (%d), grants (%s), region_type (%s)', gwpz_record,
        protection_channels, len(protection_points), grants, gwpz_region)
    logging.debug('  points: %s', protection_points)

    interfCalculator = partial(
        aggregateInterferenceForPoint,
        channels=protection_channels,
        grants=grants,
        fss_info=None,
        esc_antenna_info=None,
        protection_ent_type=data.ProtectedEntityType.GWPZ_AREA,
        region_type=gwpz_region)

    pool = mpool.Pool()
    interferences = pool.map(interfCalculator, protection_points)
    return InterferenceDict(interferences)
def _DefaultProtectionPoints(dpa_name,
                             dpa_geometry,
                             num_pts_front_border=25,
                             num_pts_back_border=10,
                             num_pts_front_zone=10,
                             num_pts_back_zone=5,
                             front_us_border_buffer_km=40,
                             min_dist_front_border_pts_km=0.2,
                             min_dist_back_border_pts_km=1.,
                             min_dist_front_zone_pts_km=0.5,
                             min_dist_back_zone_pts_km=3.):
    """Returns a default list of DPA protection points.

  This creates a default set of points by regular sampling of the contour and gridding
  the interior of the DPA zone. The contour and zone are separated in front and back,
  using the US border (with a buffer) as the delimitation.
  Approximate minimum distance can be specified to avoid too many points for small
  inland DPAs. Single point DPA are obviously protected by a single point.

  Args:
    dpa_geometry: The DPA geometry as a |shapely.Polygon/MultiPolygon or Point|.
    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).
  """
    def SampleLine(line, num_points, min_step_arcsec):
        step = line.length / float(num_points)
        min_step = min_step_arcsec / 3600.
        if step < min_step:
            num_points = max(1, int(line.length / min_step))
            step = line.length / float(num_points)
        return [
            line.interpolate(dist)
            for dist in np.arange(0, line.length - step / 2., step)
        ]

    def CvtKmToArcSec(dist_km, ref_geo):
        EQUATORIAL_RADIUS_KM = 6378.
        return dist_km / (EQUATORIAL_RADIUS_KM * 2 * np.pi / 360. *
                          np.cos(ref_geo.centroid.y * np.pi / 180.)) * 3600.

    # Case of DPA points
    if isinstance(dpa_geometry, sgeo.Point):
        return [
            ProtectionPoint(longitude=dpa_geometry.x, latitude=dpa_geometry.y)
        ]

    # Sanity checks
    num_pts_front_border = max(num_pts_front_border, 1)  # at least one

    # Case of Polygon/MultiPolygon
    global _us_border_ext
    global _us_border_ext_buffer
    if _us_border_ext is None or _us_border_ext_buffer != front_us_border_buffer_km:
        us_border = zones.GetUsBorder()
        _us_border_ext = us_border.buffer(
            CvtKmToArcSec(front_us_border_buffer_km, us_border) / 3600.)
        _us_border_ext_buffer = front_us_border_buffer_km

    front_border = dpa_geometry.boundary.intersection(_us_border_ext)
    back_border = dpa_geometry.boundary.difference(_us_border_ext)
    front_zone = dpa_geometry.intersection(_us_border_ext)
    back_zone = dpa_geometry.difference(_us_border_ext)

    # Obtain an approximate grid step, insuring a minimum separation between zone points
    step_front_dpa_arcsec = CvtKmToArcSec(min_dist_front_zone_pts_km,
                                          dpa_geometry)
    if num_pts_front_zone != 0:
        step_front_dpa_arcsec = max(
            np.sqrt(front_zone.area / num_pts_front_zone) * 3600.,
            step_front_dpa_arcsec)
    step_back_dpa_arcsec = CvtKmToArcSec(min_dist_back_zone_pts_km,
                                         dpa_geometry)
    if num_pts_back_zone != 0:
        step_back_dpa_arcsec = max(
            np.sqrt(back_zone.area / num_pts_back_zone) * 3600.,
            step_back_dpa_arcsec)

    # Obtain the number of points in the border, insuring a minimum separation
    min_step_front_border = CvtKmToArcSec(min_dist_front_border_pts_km,
                                          dpa_geometry)
    min_step_back_border = CvtKmToArcSec(min_dist_back_border_pts_km,
                                         dpa_geometry)

    front_border_pts = [] if not front_border else [
        ProtectionPoint(longitude=pt.x, latitude=pt.y) for pt in SampleLine(
            front_border, num_pts_front_border, min_step_front_border)
    ]
    back_border_pts = [] if (
        not back_border or num_pts_back_border == 0) else [
            ProtectionPoint(longitude=pt.x, latitude=pt.y) for pt in
            SampleLine(back_border, num_pts_back_border, min_step_back_border)
        ]
    front_zone_pts = [] if (not front_zone or num_pts_front_zone == 0) else [
        ProtectionPoint(longitude=pt[0], latitude=pt[1])
        for pt in utils.GridPolygon(front_zone, step_front_dpa_arcsec)
    ]
    back_zone_pts = [] if (not back_zone or num_pts_back_zone == 0) else [
        ProtectionPoint(longitude=pt[0], latitude=pt[1])
        for pt in utils.GridPolygon(back_zone, step_back_dpa_arcsec)
    ]

    return front_border_pts + front_zone_pts + back_border_pts + back_zone_pts
示例#7
0
def computePropagationAntennaModel(request):
    reliability_level = request['reliabilityLevel']
    if reliability_level not in [-1, 0.05, 0.95]:
        raise ValueError('reliability_level not in [-1, 0.05, 0.95]')

    tx = request['cbsd']
    if ('fss' in request) and ('ppa' in request):
        raise ValueError('fss and ppa in request')
    elif 'ppa' in request:
        rx = {}
        rx['height'] = 1.5
        isfss = False
        coordinates = []
        ppa = request['ppa']

        arcsec = 1
        ppa_points = geoutils.GridPolygon(ppa['geometry'], arcsec)
        if len(ppa_points) == 1:
            rx['longitude'] = ppa_points[0][0]
            rx['latitude'] = ppa_points[0][1]
        elif len(ppa_points) == 0:
            raise ValueError('ppa boundary contains no protection point')
        else:
            raise ValueError(
                'ppa boundary contains more than a single protection point')

        region_val = drive.nlcd_driver.RegionNlcdVote(
            [[rx['latitude'], rx['longitude']]])

    elif 'fss' in request:
        isfss = True
        rx = request['fss']
    else:
        raise ValueError('Neither fss nor ppa in request')

    # ITM pathloss (if receiver type is FSS) or the hybrid model pathloss (if receiver type is PPA) and corresponding antenna gains.
    # The test specification notes that the SAS UUT shall use default values for w1 and w2 in the ITM model.
    result = {}
    if isfss:
        path_loss = wf_itm.CalcItmPropagationLoss(
            tx['latitude'],
            tx['longitude'],
            tx['height'],
            rx['latitude'],
            rx['longitude'],
            rx['height'],
            cbsd_indoor=tx['indoorDeployment'],
            reliability=reliability_level,
            freq_mhz=3625.,
            is_height_cbsd_amsl=(tx['heightType'] == 'AMSL'))

        result['pathlossDb'] = path_loss.db_loss
        gain_tx_rx = antenna.GetStandardAntennaGains(
            path_loss.incidence_angles.hor_cbsd,
            ant_azimuth=tx['antennaAzimuth'],
            ant_beamwidth=tx['antennaBeamwidth'],
            ant_gain=tx['antennaGain'])
        result['txAntennaGainDbi'] = gain_tx_rx
        if 'rxAntennaGainRequired' in rx:
            hor_dirs = path_loss.incidence_angles.hor_rx
            ver_dirs = path_loss.incidence_angles.ver_rx
            gain_rx_tx = antenna.GetFssAntennaGains(hor_dirs, ver_dirs,
                                                    rx['antennaAzimuth'],
                                                    rx['antennaElevation'],
                                                    rx['antennaGain'])
            result['rxAntennaGainDbi'] = gain_rx_tx
    else:

        path_loss = wf_hybrid.CalcHybridPropagationLoss(
            tx['latitude'],
            tx['longitude'],
            tx['height'],
            rx['latitude'],
            rx['longitude'],
            rx['height'],
            cbsd_indoor=tx['indoorDeployment'],
            reliability=-1,
            freq_mhz=3625.,
            region=region_val,
            is_height_cbsd_amsl=(tx['heightType'] == 'AMSL'))
        result['pathlossDb'] = path_loss.db_loss
        gain_tx_rx = antenna.GetStandardAntennaGains(
            path_loss.incidence_angles.hor_cbsd,
            ant_azimuth=tx['antennaAzimuth'],
            ant_beamwidth=tx['antennaBeamwidth'],
            ant_gain=tx['antennaGain'])
        result['txAntennaGainDbi'] = gain_tx_rx

    return result
示例#8
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
示例#9
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 calculateAggregateInterferenceForPpa(ppa_record, pal_records, grants):
    """Calculates per-channel aggregate interference for PPA.

  Args:
    ppa_record: A PPA record dict.
    pal_records: PAL records associated with a PPA protection area
    grants: An iterable of CBSD grants of type |data.CbsdGrantInfo|.

  Returns:
    Aggregate interference to PPA in the nested dictionary format.
      {latitude : {longitude: [aggr_interf1(mW), ..., aggr_interfK(mW)]}}
    The list contains the value per protected channel.
  """
    # 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(
            'AggInterf: 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)

    logging.info(
        'Computing aggregateInterferenceForPoint for PPA (%s), channels (%s), '
        'nPoints (%d), grants (%s), region_type (%s)', ppa_record,
        protection_channels, len(protection_points), grants, ppa_region)
    logging.debug('  points: %s', protection_points)

    # Calculate aggregate interference from each protection constraint with a
    # pool of parallel processes.
    interfCalculator = partial(
        aggregateInterferenceForPoint,
        channels=protection_channels,
        grants=grants,
        fss_info=None,
        esc_antenna_info=None,
        protection_ent_type=data.ProtectedEntityType.PPA_AREA,
        region_type=ppa_region)

    pool = mpool.Pool()
    interferences = pool.map(interfCalculator, protection_points)
    return InterferenceDict(interferences)