Search code examples
c#unity-game-enginebluetoothpositioningcartesian-coordinates

Working with micro changes in floats/doubles


The last couple of days have been full with making calculations and formulas and I'm beginning to lose my mind (a little bit). So now I'm turning to you guys for some insight/help.

Here's the problem; I'm working with bluetooth beacons whom are placed all over an entire floor in a building to make an indoor GPS showcase. You can use your phone to connect with these beacons, which results in receiving your longitude and latitude location from them. These numbers are large float/double variables, looking like this:

  • lat: 52.501288451787076
  • lng: 6.079107635606511

The actual changes happen at the 4th and 5th position after the point. I'm converting these numbers to the Cartesian coordinate system using;

  • x = R * cos(lat) * cos(lon)
  • z = R *sin(lat)

Now the coordinates from this conversion are kind of solid. They are numbers with which I can work with. I use them in a 3d engine (Unity3d) to make a real-time map where you can see where someone is walking.

Now for the actual problem! These beacons are not entirely accurate. These numbers 'jump' up and down even when you lay your phone down. Ranging from, let's assume the same latitude as mentioned above, 52.501280 to 52.501296. If we convert this and use it as coordinates in a 3d engine, the 'avatar' for a user jumps from one position to another (more small jumps than large jumps).

What is a good way to cope with these jumping numbers? I've tried to check for big jumps and ignore those, but the jumps are still too big. A broader check will result in almost no movement, even when a phone is moving. Or is there a better way to convert the lat and long variables for use in a 3d engine?

If there is someone who has had the same problem as me, some mathematical wonder who can give a good conversion/formula to start with or someone who knows what I'm possibly doing wrong then please, help a fellow programmer out.


Solution

  • Moving Average

    You could use this: (Taken here: https://stackoverflow.com/a/1305/5089204)

    Attention: Please read the comments to this class as this implementation has some flaws... It's just for quick test and show...

        public class LimitedQueue<T> : Queue<T> {
            private int limit = -1;
    
            public int Limit {
                get { return limit; }
                set { limit = value; }
            }
    
            public LimitedQueue(int limit)
                : base(limit) {
                this.Limit = limit;
            }
    
            public new void Enqueue(T item) {
                if (this.Count >= this.Limit) {
                    this.Dequeue();
                }
                base.Enqueue(item);
            }
        }
    

    Just test it like this:

            var queue = new LimitedQueue<float>(4);
    
            queue.Enqueue(52.501280f);
            var avg1 = queue.Average(); //52.50128
            queue.Enqueue(52.501350f);
            var avg2 = queue.Average(); //52.5013161
            queue.Enqueue(52.501140f);
            var avg3 = queue.Average(); //52.50126
            queue.Enqueue(52.501022f);
            var avg4 = queue.Average(); //52.5011978
            queue.Enqueue(52.501635f);
            var avg5 = queue.Average(); //52.50129
            queue.Enqueue(52.501500f);
            var avg6 = queue.Average(); //52.5013237
            queue.Enqueue(52.501505f);
            var avg7 = queue.Average(); //52.5014153
            queue.Enqueue(52.501230f);
            var avg8 = queue.Average(); //52.50147
    

    The limited queue will not grow... You just define the count of elements you want to use (in this case I specified 4). The 5th element pushes the first out and so on...

    The average will always be a smooth sliding :-)