Пример #1
0
def estimate_accuracy(lat, lon, points, minimum):
    if len(points) == 1:
        accuracy = points[0].range
    else:
        # Terrible approximation, but hopefully better
        # than the old approximation, "worst-case range":
        # this one takes the maximum distance from location
        # to any of the provided points.
        accuracy = max([distance(to_degrees(lat),
                                 to_degrees(lon),
                                 to_degrees(p.lat),
                                 to_degrees(p.lon)) * 1000
                        for p in points])
    return max(accuracy, minimum)
Пример #2
0
def _nearest_tower(missing_lat, missing_lon, centroids):
    """
    We just need the closest cell, so we can approximate
    using the haversine formula.
    """
    lat1 = to_degrees(missing_lat)
    lon1 = to_degrees(missing_lon)

    min_dist = None
    for pt in centroids:
        lat2 = to_degrees(pt['lat'])
        lon2 = to_degrees(pt['lon'])
        dist = distance(lat1, lon1, lat2, lon2)
        if min_dist is None or min_dist['dist'] > dist:
            min_dist = {'dist': dist, 'pt': pt}
    if min_dist['dist'] <= NEAREST_DISTANCE:
        return min_dist
Пример #3
0
def _nearest_tower(missing_lat, missing_lon, centroids):
    """
    We just need the closest cell, so we can approximate
    using the haversine formula.
    """
    lat1 = to_degrees(missing_lat)
    lon1 = to_degrees(missing_lon)

    min_dist = None
    for pt in centroids:
        lat2 = to_degrees(pt['lat'])
        lon2 = to_degrees(pt['lon'])
        dist = distance(lat1, lon1, lat2, lon2)
        if min_dist is None or min_dist['dist'] > dist:
            min_dist = {'dist': dist, 'pt': pt}
    if min_dist['dist'] <= NEAREST_DISTANCE:
        return min_dist
Пример #4
0
def update_lac(self, radio, mcc, mnc, lac):

    with self.db_session() as session:

        # Select all the cells in this LAC that aren't the virtual
        # cell itself, and derive a bounding box for them.

        q = session.query(Cell).filter(Cell.radio == radio).filter(
            Cell.mcc == mcc).filter(Cell.mnc == mnc).filter(
                Cell.lac == lac).filter(Cell.cid != CELLID_LAC)

        cells = q.all()
        points = [(to_degrees(c.lat), to_degrees(c.lon)) for c in cells]
        min_lat = to_degrees(min([c.min_lat for c in cells]))
        min_lon = to_degrees(min([c.min_lon for c in cells]))
        max_lat = to_degrees(max([c.max_lat for c in cells]))
        max_lon = to_degrees(max([c.max_lon for c in cells]))

        bbox_points = [(min_lat, min_lon), (min_lat, max_lon),
                       (max_lat, min_lon), (max_lat, max_lon)]

        ctr = centroid(points)
        rng = range_to_points(ctr, bbox_points)

        # switch units back to DB preferred centimicrodegres angle
        # and meters distance.
        ctr_lat = from_degrees(ctr[0])
        ctr_lon = from_degrees(ctr[1])
        rng = int(round(rng * 1000.0))

        # Now create or update the LAC virtual cell

        q = session.query(Cell).filter(Cell.radio == radio).filter(
            Cell.mcc == mcc).filter(Cell.mnc == mnc).filter(
                Cell.lac == lac).filter(Cell.cid == CELLID_LAC)

        lac = q.first()

        if lac is None:
            lac = Cell(radio=radio,
                       mcc=mcc,
                       mnc=mnc,
                       lac=lac,
                       cid=CELLID_LAC,
                       lat=ctr_lat,
                       lon=ctr_lon,
                       range=rng)
        else:
            lac.new_measures = 0
            lac.lat = ctr_lat
            lac.lon = ctr_lon
            lac.range = rng

        session.commit()
Пример #5
0
def update_lac(self, radio, mcc, mnc, lac):

    with self.db_session() as session:

        # Select all the cells in this LAC that aren't the virtual
        # cell itself, and derive a bounding box for them.

        q = session.query(Cell).filter(
            Cell.radio == radio).filter(
            Cell.mcc == mcc).filter(
            Cell.mnc == mnc).filter(
            Cell.lac == lac).filter(
            Cell.cid != CELLID_LAC).filter(
            Cell.new_measures == 0).filter(
            Cell.lat.isnot(None)).filter(
            Cell.lon.isnot(None))

        cells = q.all()
        if len(cells) == 0:
            return

        points = [(to_degrees(c.lat),
                   to_degrees(c.lon)) for c in cells]
        min_lat = to_degrees(min([c.min_lat for c in cells]))
        min_lon = to_degrees(min([c.min_lon for c in cells]))
        max_lat = to_degrees(max([c.max_lat for c in cells]))
        max_lon = to_degrees(max([c.max_lon for c in cells]))

        bbox_points = [(min_lat, min_lon),
                       (min_lat, max_lon),
                       (max_lat, min_lon),
                       (max_lat, max_lon)]

        ctr = centroid(points)
        rng = range_to_points(ctr, bbox_points)

        # switch units back to DB preferred centimicrodegres angle
        # and meters distance.
        ctr_lat = from_degrees(ctr[0])
        ctr_lon = from_degrees(ctr[1])
        rng = int(round(rng * 1000.0))

        # Now create or update the LAC virtual cell

        q = session.query(Cell).filter(
            Cell.radio == radio).filter(
            Cell.mcc == mcc).filter(
            Cell.mnc == mnc).filter(
            Cell.lac == lac).filter(
            Cell.cid == CELLID_LAC)

        lac = q.first()

        if lac is None:
            lac = Cell(radio=radio,
                       mcc=mcc,
                       mnc=mnc,
                       lac=lac,
                       cid=CELLID_LAC,
                       lat=ctr_lat,
                       lon=ctr_lon,
                       range=rng)
        else:
            lac.new_measures = 0
            lac.lat = ctr_lat
            lac.lon = ctr_lon
            lac.range = rng

        session.commit()
Пример #6
0
def calculate_new_position(station, measures, moving_stations,
                           max_dist_km, backfill=True):
    # if backfill is true, we work on older measures for which
    # the new/total counters where never updated
    length = len(measures)
    latitudes = [w[0] for w in measures]
    longitudes = [w[1] for w in measures]
    new_lat = sum(latitudes) // length
    new_lon = sum(longitudes) // length

    if station.lat and station.lon:
        latitudes.append(station.lat)
        longitudes.append(station.lon)
        existing_station = True
    else:
        station.lat = new_lat
        station.lon = new_lon
        existing_station = False

    # calculate extremes of measures, existing location estimate
    # and existing extreme values
    def extreme(vals, attr, function):
        new = function(vals)
        old = getattr(station, attr, None)
        if old is not None:
            return function(new, old)
        else:
            return new

    min_lat = extreme(latitudes, 'min_lat', min)
    min_lon = extreme(longitudes, 'min_lon', min)
    max_lat = extreme(latitudes, 'max_lat', max)
    max_lon = extreme(longitudes, 'max_lon', max)

    # calculate sphere-distance from opposite corners of
    # bounding box containing current location estimate
    # and new measurements; if too big, station is moving
    box_dist = distance(to_degrees(min_lat), to_degrees(min_lon),
                        to_degrees(max_lat), to_degrees(max_lon))

    if existing_station:

        if box_dist > max_dist_km:
            # add to moving list, return early without updating
            # station since it will be deleted by caller momentarily
            moving_stations.add(station)
            return

        if backfill:
            new_total = station.total_measures + length
            old_length = station.total_measures
            # update total to account for new measures
            # new counter never got updated to include the measures
            station.total_measures = new_total
        else:
            new_total = station.total_measures
            old_length = new_total - length

        station.lat = ((station.lat * old_length) +
                       (new_lat * length)) // new_total
        station.lon = ((station.lon * old_length) +
                       (new_lon * length)) // new_total

    if not backfill:
        # decrease new counter, total is already correct
        # in the backfill case new counter was never increased
        station.new_measures = station.new_measures - length

    # update max/min lat/lon columns
    station.min_lat = min_lat
    station.min_lon = min_lon
    station.max_lat = max_lat
    station.max_lon = max_lon

    # give radio-range estimate between extreme values and centroid
    ctr = (to_degrees(station.lat), to_degrees(station.lon))
    points = [(to_degrees(min_lat), to_degrees(min_lon)),
              (to_degrees(min_lat), to_degrees(max_lon)),
              (to_degrees(max_lat), to_degrees(min_lon)),
              (to_degrees(max_lat), to_degrees(max_lon))]

    station.range = range_to_points(ctr, points) * 1000.0
Пример #7
0
def calculate_new_position(station,
                           measures,
                           moving_stations,
                           max_dist_km,
                           backfill=True):
    # if backfill is true, we work on older measures for which
    # the new/total counters where never updated
    length = len(measures)
    latitudes = [w[0] for w in measures]
    longitudes = [w[1] for w in measures]
    new_lat = sum(latitudes) // length
    new_lon = sum(longitudes) // length

    if station.lat and station.lon:
        latitudes.append(station.lat)
        longitudes.append(station.lon)
        existing_station = True
    else:
        station.lat = new_lat
        station.lon = new_lon
        existing_station = False

    # calculate extremes of measures, existing location estimate
    # and existing extreme values
    def extreme(vals, attr, function):
        new = function(vals)
        old = getattr(station, attr, None)
        if old is not None:
            return function(new, old)
        else:
            return new

    min_lat = extreme(latitudes, 'min_lat', min)
    min_lon = extreme(longitudes, 'min_lon', min)
    max_lat = extreme(latitudes, 'max_lat', max)
    max_lon = extreme(longitudes, 'max_lon', max)

    # calculate sphere-distance from opposite corners of
    # bounding box containing current location estimate
    # and new measurements; if too big, station is moving
    box_dist = distance(to_degrees(min_lat), to_degrees(min_lon),
                        to_degrees(max_lat), to_degrees(max_lon))

    if existing_station:

        if box_dist > max_dist_km:
            # add to moving list, return early without updating
            # station since it will be deleted by caller momentarily
            moving_stations.add(station)
            return

        if backfill:
            new_total = station.total_measures + length
            old_length = station.total_measures
            # update total to account for new measures
            # new counter never got updated to include the measures
            station.total_measures = new_total
        else:
            new_total = station.total_measures
            old_length = new_total - length

        station.lat = ((station.lat * old_length) +
                       (new_lat * length)) // new_total
        station.lon = ((station.lon * old_length) +
                       (new_lon * length)) // new_total

    if not backfill:
        # decrease new counter, total is already correct
        # in the backfill case new counter was never increased
        station.new_measures = station.new_measures - length

    # update max/min lat/lon columns
    station.min_lat = min_lat
    station.min_lon = min_lon
    station.max_lat = max_lat
    station.max_lon = max_lon

    # give radio-range estimate between extreme values and centroid
    ctr = (to_degrees(station.lat), to_degrees(station.lon))
    points = [(to_degrees(min_lat), to_degrees(min_lon)),
              (to_degrees(min_lat), to_degrees(max_lon)),
              (to_degrees(max_lat), to_degrees(min_lon)),
              (to_degrees(max_lat), to_degrees(max_lon))]

    station.range = range_to_points(ctr, points) * 1000.0