HCKalmanFilter icon indicating copy to clipboard operation
HCKalmanFilter copied to clipboard

NaN latitude and longitude

Open tdimeco opened this issue 6 years ago • 6 comments

Hello,

I have an issue with the filter. Sometimes, the algorithm returns a location with both latitude and longitude NaN:

(lldb) po location
<nan,nan> +/- 65.00m (speed -1.00 mps / course -1.00) @ 01/10/2018 18:07:54 UTC+02:00

Usually, everything works fine and locations are smoothed correctly, but in certain circumstances the output location is NaN.

In case this can help you: the issue occurs indoor, the GPS signal is low, the phone is not moving on a table and the app fetches location in background every second. The problem starts sometimes after 3 minutes, sometimes after 1+ hour. Feel free to ask me if you need further information.

Thank you!

Thomas

tdimeco avatar Oct 01 '18 16:10 tdimeco

Hey Thomas thanks for bringing up this issue, Can you suggest any best way to overcome this issue,? I mean instead using bunch of if let's or guard statements.

yashbedi avatar Feb 06 '19 09:02 yashbedi

Hey Yash,

I am not using the library anymore, but in the past, I temporary "solved" the issue by resetting the Kalman filter when it was dirty. Here is some parts of the code:

class LocationDataProvider: CLLocationManagerDelegate {
    
    // ...
    
    private var locationManager: CLLocationManager?
    private var kalmanAlgorithm: HCKalmanAlgorithm?
    
    // ...
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        
        let location = locations.last!
        var correctedLocation: CLLocation!
        
        // Use the kalman algorithm to smooth location data
        if self.kalmanAlgorithm == nil {
            self.kalmanAlgorithm = HCKalmanAlgorithm(initialLocation: location)
            correctedLocation = location
        } else {
            correctedLocation = self.kalmanAlgorithm!.processState(currentLocation: location)
        }
        
        correctedLocation = self.tempFixForNaNLocations(location: location, correctedLocation: correctedLocation)
        
        // ... <Use correctedLocation>
    }
    
    // FIX: Temporary fix to avoid NaN locations: https://github.com/Hypercubesoft/HCKalmanFilter/issues/19
    private func tempFixForNaNLocations(location: CLLocation, correctedLocation: CLLocation) -> CLLocation {
        if correctedLocation.coordinate.latitude.isNaN || correctedLocation.coordinate.longitude.isNaN || correctedLocation.altitude.isNaN {
            self.kalmanAlgorithm = HCKalmanAlgorithm(initialLocation: location)
            return location
        } else {
            return correctedLocation
        }
    }
}

Hope this can help you. Cheers.

tdimeco avatar Feb 06 '19 10:02 tdimeco

Hey, Thomas

Yeah, I too figured out a way something like that. Though Really appreciate you taking out time to write the snippet. Thank you.

yashbedi avatar Feb 11 '19 07:02 yashbedi

We've had the same problem. It seems that the problem is the value of timeInterval. It's 0 when calculating velocityXComponent, velocityYComponent and velocityZComponent.

See lines 197, 198 and 199:
https://github.com/Hypercubesoft/HCKalmanFilter/blob/master/HCKalmanFilter/HCKalmanAlgorithm.swift#L197

After calculating the velocity, the outcome is:

velocityXComponent = (Double) -Inf
velocityYComponent = (Double) NaN
velocityZComponent = (Double) NaN

What's the best approach? Should we skip the location? Or should the KalmanFilter be altered to devide by 1 instead of zero?

Gerharbo avatar Apr 09 '19 10:04 Gerharbo

Hey guys, I found this library right now and didn't test it yet but looked into this issue.

For me it sounds as if you are using cached locations which you receive in your didUpdateLocations method because the timestamp of the new and previous location must be the same if these three values are 0.

In my own app, I skip cached locations in my didUpdateLocations method when they are older than 10 seconds (however, you should test how many seconds fit to your case). I also skip locations which are invalid (horizontalAccuracy < 0) and those with an horizontalAccuracy over 30 meters.

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    
        guard let mostRecentLocation = locations.last else {
            return
        }
        
        let age = -mostRecentLocation.timestamp.timeIntervalSinceNow
        
        // Filter cached locations, invalid ones and ones with accuracy over 30 meters
        if age > 10 || mostRecentLocation.horizontalAccuracy < 0 || mostRecentLocation.horizontalAccuracy > 30 {
            return
        }

        // ... Use your location 
}

This will not fix the library code which doesn't test for division by zero, but maybe this will help anyway.

Mike1707 avatar May 20 '19 10:05 Mike1707

Hello,

Just if some one else got this error. I have done some investigation and i find that i have a NaN error when my location (previous and current one) have the same timestamp.

If they have the same timestamps some we do a division by 0 and we got a NaN. To prevent it you can just check your locations timestamps before use Kalman or update KalmanAlgo to set value to 0 if the interval between locations is 0

PguOrange avatar Jun 22 '22 09:06 PguOrange