Android How to calclulate the movement speed witho

2019-09-05 07:12发布

问题:

As we all know GPS system is far from perfect and when you go around with your app using the gps when the GPS loses the signal and it starts calculating again. And if you try to calculate the distance correctly it will start calculating and for example if you were 30 meters away from your destination it will calculate for example 130 meters. Which messes my how calculation of the distance up. So I found some suggestion that I should filter the GPS coordination using the speed.

I want to calculate the speed without the location.getSpeed() I want to calculate the speed by comparing the distance from the last known coordinates to the coordinates at some given point and I get the speed of the device moving. And if the speed is for example greater than 15 m/h coordinates are invalid and don't re-calculate the distance.

回答1:

It is as simple as V = (Distance) / (Elapsed time). So lets say you read your location1 at time X. Than at some point after X lets say at time Y you read your location again. Than you'll have

float distance = location1.distanceTo(location2); 

which is float in meters (see this http://developer.android.com/reference/android/location/Location.html#distanceTo(android.location.Location)

To have your velocity as in meters per seconds if you calculate X - Y as

float X = System.currentTimeMillis(); //When you get the first location
float Y = System.currentTimeMillis(); //When you get the second location
//...
//Than when calculating
float timeElapsed= (Y - X)/1000; //In seconds

Than the velocity in meters per second will be

float V = distance/timeElapsed;

If you want to calculate average velocity, you need to store the velocities in a list lets say, and than calculate average from all those velocities calculated between each two points. So if you have location l1, l2, l3, l4 ..... ln, V1 will be velocity between l1 and l2, V2 will be between l2 and l3, and Vn-1 will be between ln-1 and ln. You will store all Vn in a list (for example) than you caluclate the average as

Vavg = (V1 + V2 + V3 ... + Vn)/n

UPDATE: In your activity

Location previousLocation = null;
float previousTime = 0;
float velocity = 0;

Than:

public void onLocationChanged(Location loc) {
  boolean hasPrevious = true;
  if (previousLocation == null || previousTime == 0) {
      hasPrevious = false;
  }
  float currentTime = System.currentTimeMillis();
  if (hasPrevious) {
     float timeElapsed = (currentTime - previousTime)/1000;
     velocity = loc.distanceTo(previousLocation)/timeElapsed;
  } 
  storeToPrevious(loc, currentTime);
}

In a different function

private void storeToPrevious(Location l, float time) {
   previousLocation = new Location(l);
   previousTime = time;
}


回答2:

This may do what you want. It is written in Kotlin. It applies a weighted moving average. Most recent locations have a heavier weight. It can "smooth" out the speed, at the cost of adding more lag. This was to get around a bug in certain situations that I could not use getSpeed(). But normally if you use "Fused" location on Android, the speed is quite stable and accurate on a typical modern, ACTIVE phone.

var recentGPSLocationSegments = listOf<Pair<android.location.Location, android.location.Location>>()

fun applyWeightedMovingAverageSpeed(location: android.location.Location, previous: android.location.Location): Double
{
    recentGPSLocationSegments += Pair(location, previous)
    val cachedLocationsNs = location.elapsedRealtimeNanos - 4500000000 // 4.5 seconds, This will typically get 4 entries (1 second apart)
    val targetZeroWeightNs = location.elapsedRealtimeNanos - 5000000000 // 5.0 seconds, Weights will be approx 5000000000, 4000000000, 3000000000, 1000000000

    // Toss old locations
    recentGPSLocationSegments = recentGPSLocationSegments.filter { it -> it.first.elapsedRealtimeNanos > cachedLocationsNs }

    // Total up all the weights. Weight is based on age, younger has higher weight
    val weights = recentGPSLocationSegments.map { it.first.elapsedRealtimeNanos - targetZeroWeightNs }.sum()

    // Apply the weights and get average speed in meters/second
    return recentGPSLocationSegments.map { speedFromGPS(it.first, it.second) * (it.first.elapsedRealtimeNanos - targetZeroWeightNs) }.sum() / weights
}

fun speedFromGPS(location: android.location.Location, previous: android.location.Location): Double
{
    val dist = location.distanceTo(previous)
    val time = (location.elapsedRealtimeNanos - previous.elapsedRealtimeNanos) / 1000000000.0
    return dist / time
}

val locationManagerExample: LocationListener = object : LocationListener
{
    var lastLocation: android.location.Location? = null
    var lastPreviousLocation: android.location.Location? = null

    override fun onLocationChanged(location: android.location.Location?)
    {
        if (location != null)
        {
            if (lastPreviousLocation != null)
            {
                currentSpeed = applyWeightedMovingAverageSpeed(location, lastPreviousLocation!!)

                lastPreviousLocation = lastLocation
            }

            lastLocation = location

            if (currentSpeed < 0.0)
            {
                currentSpeed = 0.0
            }
        }
    }

    override fun onStatusChanged(provider: String, status: Int, extras: Bundle)
    {
    }

    override fun onProviderEnabled(provider: String)
    {
    }

    override fun onProviderDisabled(provider: String)
    {
    }
}


回答3:

Try this

@Override
public void onLocationChanged(Location location) {

    try {
        if (location != null) {

            if (current_lat != null && current_lat > 0) {
                latitude = current_lat;
            }
            if (current_long != null && current_long > 0) {
                longitude = current_long;
            }
            current_lat = location.getLatitude();
            current_long = location.getLongitude();
            distanceBetweenTwoPoint = getDistance(latitude, longitude, current_lat, current_long);
            if ((current_lat > 0 && current_long > 0) && distanceBetweenTwoPoint > IjoomerApplicationConfiguration.track_DistanceBetweenPoints_IN_METERS) {
                if (location.hasSpeed()) {
                    speedInKm = location.getSpeed() * 3.6;
                } else {
                    speedInKm = 0.0;
                }
                row = new HashMap<String, String>();
                row.put(TRACKID, IN_TRACKID + "");
                row.put(LATITUDE, current_lat.toString());
                row.put(LONGITUDE, current_long.toString());
                row.put(SPEED, speedInKm + "");
                row.put(TIMESTAMP, System.currentTimeMillis() + "");
                row.put(STATUS, status);

                distance = distance + (distanceBetweenTwoPoint / 1000);
                row.put(DISTANCE, "" + distance);
                dataProvider.InsertRow("TrackDetail", row);
                row.put(LASTKNOWNLATITUDE, latitude.toString());
                row.put(LASTKNOWNLONGITUDE, longitude.toString());
                int seconds = (int) ((System.currentTimeMillis() - trackStartTime) / 1000) % 60;
                int minutes = (int) (((System.currentTimeMillis() - trackStartTime) / (1000 * 60)) % 60);
                int hours = (int) (((System.currentTimeMillis() - trackStartTime) / (1000 * 60 * 60)) % 24);

                row.put(DURATION, String.valueOf(hours) + " : " + String.valueOf(minutes) + " : " + String.valueOf(seconds));
                setNotification(speedInKm, String.valueOf(hours) + " : " + String.valueOf(minutes) + " : " + String.valueOf(seconds));
                if (status.equalsIgnoreCase("1")) {

                    builder.append("|" + current_lat + "," + current_long);
                    trackDuration = String.valueOf(hours) + " : " + String.valueOf(minutes) + " : " + String.valueOf(seconds);
                    if (speedInKm > maxSpeed) {
                        maxSpeed = speedInKm;
                    }
                    totalSpeed = totalSpeed + speedInKm;
                    ++totalTrackPoint;
                    sendBrodcastToActivity();
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

}