Triangulate example for iBeacons

后端 未结 13 2255
梦毁少年i
梦毁少年i 2020-11-28 17:14

I am looking into the possibility to use multiple iBeacons to do a \'rough\' indoor position location. The application is a kind of \'museum\' setting, and it would be easie

相关标签:
13条回答
  • 2020-11-28 17:43

    Please check the reference https://proximi.io/accurate-indoor-positioning-bluetooth-beacons/

    Proximi SDK will take care of the triangulation. This SDK provides libraries for handling all the logic for beacon positioning, triangulation and filtering automatically in the background. In addition to beacons, you can combine IndoorAtlas, Wi-Fi, GPS and cellular positioning.

    0 讨论(0)
  • 2020-11-28 17:44

    For those who need @Javier Chávarri trilateration function for Android devices (for saving some time):

    public static Location getLocationWithTrilateration(Location beaconA, Location beaconB, Location beaconC, double distanceA, double distanceB, double distanceC){
    
        double bAlat = beaconA.getLatitude();
        double bAlong = beaconA.getLongitude();
        double bBlat = beaconB.getLatitude();
        double bBlong = beaconB.getLongitude();
        double bClat = beaconC.getLatitude();
        double bClong = beaconC.getLongitude();
    
        double W, Z, foundBeaconLat, foundBeaconLong, foundBeaconLongFilter;
        W = distanceA * distanceA - distanceB * distanceB - bAlat * bAlat - bAlong * bAlong + bBlat * bBlat + bBlong * bBlong;
        Z = distanceB * distanceB - distanceC * distanceC - bBlat * bBlat - bBlong * bBlong + bClat * bClat + bClong * bClong;
    
        foundBeaconLat = (W * (bClong - bBlong) - Z * (bBlong - bAlong)) / (2 * ((bBlat - bAlat) * (bClong - bBlong) - (bClat - bBlat) * (bBlong - bAlong)));
        foundBeaconLong = (W - 2 * foundBeaconLat * (bBlat - bAlat)) / (2 * (bBlong - bAlong));
        //`foundBeaconLongFilter` is a second measure of `foundBeaconLong` to mitigate errors
        foundBeaconLongFilter = (Z - 2 * foundBeaconLat * (bClat - bBlat)) / (2 * (bClong - bBlong));
    
        foundBeaconLong = (foundBeaconLong + foundBeaconLongFilter) / 2;
    
        Location foundLocation = new Location("Location");
            foundLocation.setLatitude(foundBeaconLat);
            foundLocation.setLongitude(foundBeaconLong);
    
        return foundLocation;
    }
    
    0 讨论(0)
  • 2020-11-28 17:46

    My Architect/Manager, who wrote the following algorithm,

    public static Location getLocationWithCenterOfGravity(Location beaconA, Location beaconB, Location beaconC, double distanceA, double distanceB, double distanceC) {
    
        //Every meter there are approx 4.5 points
        double METERS_IN_COORDINATE_UNITS_RATIO = 4.5;
    
        //http://stackoverflow.com/a/524770/663941
        //Find Center of Gravity
        double cogX = (beaconA.getLatitude() + beaconB.getLatitude() + beaconC.getLatitude()) / 3;
        double cogY = (beaconA.getLongitude() + beaconB.getLongitude() + beaconC.getLongitude()) / 3;
        Location cog = new Location("Cog");
        cog.setLatitude(cogX);
        cog.setLongitude(cogY);
    
    
        //Nearest Beacon
        Location nearestBeacon;
        double shortestDistanceInMeters;
        if (distanceA < distanceB && distanceA < distanceC) {
            nearestBeacon = beaconA;
            shortestDistanceInMeters = distanceA;
        } else if (distanceB < distanceC) {
            nearestBeacon = beaconB;
            shortestDistanceInMeters = distanceB;
        } else {
            nearestBeacon = beaconC;
            shortestDistanceInMeters = distanceC;
        }
    
        //http://www.mathplanet.com/education/algebra-2/conic-sections/distance-between-two-points-and-the-midpoint
        //Distance between nearest beacon and COG
        double distanceToCog = Math.sqrt(Math.pow(cog.getLatitude() - nearestBeacon.getLatitude(),2)
                + Math.pow(cog.getLongitude() - nearestBeacon.getLongitude(),2));
    
        //Convert shortest distance in meters into coordinates units.
        double shortestDistanceInCoordinationUnits = shortestDistanceInMeters * METERS_IN_COORDINATE_UNITS_RATIO;
    
        //http://math.stackexchange.com/questions/46527/coordinates-of-point-on-a-line-defined-by-two-other-points-with-a-known-distance?rq=1
        //On the line between Nearest Beacon and COG find shortestDistance point apart from Nearest Beacon
    
        double t = shortestDistanceInCoordinationUnits/distanceToCog;
    
        Location pointsDiff = new Location("PointsDiff");
        pointsDiff.setLatitude(cog.getLatitude() - nearestBeacon.getLatitude());
        pointsDiff.setLongitude(cog.getLongitude() - nearestBeacon.getLongitude());
    
        Location tTimesDiff = new Location("tTimesDiff");
        tTimesDiff.setLatitude( pointsDiff.getLatitude() * t );
        tTimesDiff.setLongitude(pointsDiff.getLongitude() * t);
    
        //Add t times diff with nearestBeacon to find coordinates at a distance from nearest beacon in line to COG.
    
        Location userLocation = new Location("UserLocation");
        userLocation.setLatitude(nearestBeacon.getLatitude() + tTimesDiff.getLatitude());
        userLocation.setLongitude(nearestBeacon.getLongitude() + tTimesDiff.getLongitude());
    
        return userLocation;
    }
    
    1. Calculate the centre of gravity for a triangle (3 beacons)
    2. calculate the shortest distance / nearest beacon
    3. Calculate the distance between the beacon and the centre of gravity
    4. Convert the shortest distance to co-ordinate units which is just a constant, he used to predict accuracy. You can test with varing the constant
    5. calculate the distance delta
    6. add the delta with the nearest beacon x,y.

    After testing it, I found it accurate to 5 meters.

    Please comment me your testing, if we can refine it.

    0 讨论(0)
  • 2020-11-28 17:46

    I found Vishnu Prahbu's solution very useful. I ported it to c#, if anybody need it.

    public static PointF GetLocationWithCenterOfGravity(PointF a, PointF b, PointF c, float dA, float dB, float dC)
        {
            //http://stackoverflow.com/questions/20332856/triangulate-example-for-ibeacons
            var METERS_IN_COORDINATE_UNITS_RATIO = 1.0f;
    
            //http://stackoverflow.com/a/524770/663941
            //Find Center of Gravity
            var cogX = (a.X + b.X + c.X) / 3;
            var cogY = (a.Y + b.Y + c.Y) / 3;
            var cog = new PointF(cogX,cogY);
    
            //Nearest Beacon
            PointF nearestBeacon;
            float shortestDistanceInMeters;
            if (dA < dB && dA < dC)
            {
                nearestBeacon = a;
                shortestDistanceInMeters = dA;
            }
            else if (dB < dC)
            {
                nearestBeacon = b;
                shortestDistanceInMeters = dB;
            }
            else
            {
                nearestBeacon = c;
                shortestDistanceInMeters = dC;
            }
    
            //http://www.mathplanet.com/education/algebra-2/conic-sections/distance-between-two-points-and-the-midpoint
            //Distance between nearest beacon and COG
            var distanceToCog =  (float)(Math.Sqrt(Math.Pow(cog.X - nearestBeacon.X, 2)
                    + Math.Pow(cog.Y - nearestBeacon.Y, 2)));
    
            //Convert shortest distance in meters into coordinates units.
            var shortestDistanceInCoordinationUnits = shortestDistanceInMeters * METERS_IN_COORDINATE_UNITS_RATIO;
    
            //http://math.stackexchange.com/questions/46527/coordinates-of-point-on-a-line-defined-by-two-other-points-with-a-known-distance?rq=1
            //On the line between Nearest Beacon and COG find shortestDistance point apart from Nearest Beacon
            var t = shortestDistanceInCoordinationUnits / distanceToCog;
            var pointsDiff = new PointF(cog.X - nearestBeacon.X, cog.Y - nearestBeacon.Y);
            var tTimesDiff = new PointF(pointsDiff.X * t, pointsDiff.Y * t);
    
            //Add t times diff with nearestBeacon to find coordinates at a distance from nearest beacon in line to COG.
            var userLocation = new PointF(nearestBeacon.X + tTimesDiff.X, nearestBeacon.Y + tTimesDiff.Y);
    
            return userLocation;
        }
    
    0 讨论(0)
  • 2020-11-28 17:58

    Alternative Equation

    - (CGPoint)getCoordinateWithBeaconA:(CGPoint)a beaconB:(CGPoint)b beaconC:(CGPoint)c distanceA:(CGFloat)dA distanceB:(CGFloat)dB distanceC:(CGFloat)dC {
    
    
    CGFloat x, y;
    x = ( ( (pow(dA,2)-pow(dB,2)) + (pow(c.x,2)-pow(a.x,2)) + (pow(b.y,2)-pow(a.y,2)) ) * (2*c.y-2*b.y) - ( (pow(dB,2)-pow(dC,2)) + (pow(c.x,2)-pow(c.x,2)) + (pow(c.y,2)-pow(b.y,2)) ) *(2*b.y-2*a.y) ) / ( (2*b.x-2*c.x)*(2*b.y-2*a.y)-(2*a.x-2*b.x)*(2*c.y-2*b.y) );
    
    y = ( (pow(dA,2)-pow(dB,2)) + (pow(c.x,2)-pow(a.x,2)) + (pow(b.y,2)-pow(a.y,2)) + x*(2*a.x-2*b.x)) / (2*b.y-2*a.y);
    
    
    
    return CGPointMake(x, y);
    }
    
    0 讨论(0)
  • 2020-11-28 17:59

    Accurate indoor positioning with iBeacon will be challenging for the following reasons:

    1. As pointed in earlier comments, iBeacon signal tend to fluctuate a lot. The reason include multipath effect, the dynamic object obstructions between the phone and iBeacon when the person is moving, other 2.4GHz interferences, and more. So ideally you don't want to trust 1 single packet's data and instead do some averaging for several packets from the same beacon. That would require the phone/beacon distance doesn't change too much between those several packets. For general BLE packets (like beacons from StickNFind) can easily be set to 10Hz beaconing rate. However for iBeacon, that'll be hard, because
    2. iBeacon's beaconing frequency probably cannot be higher than 1Hz. I will be glad if anyone can point to source that says otherwise, but all information I've seen so far confirms this assertion. That actually make sense since most iBeacons will be battery powered and high frequency significantly impact the battery life. Considering people's average walking speed is 5.3km (~1.5m/s), so even if you just use a modest 3 beacon packets to do the averaging, you will be hard to get ~5m accuracy.

    On the other hand, if you could increase iBeacon frequency to larger than 10Hz (which I doubt is possible), then it's possible to have 5m or higher accuracy using suitable processing method. Firstly trivial solutions based on the Inverse-Square Law, like trilateration, is often not performing well because in practice the distance/RSSI relationship for different beacons are often way off from the Inverse-Sqare Law for the reason 1 above. But as long as the RSSI is relatively stable for a certain beacon in any certain location (which usually is the case), you can use an approach called fingerprinting to achieve higher accuracy. A common method used for fingerprinting is kNN (k-Nearest Neighbor).

    Update 2014-04-24

    Some iBeacons can broadcast more than 1Hz, like Estimote use 5Hz as default. However, according to this link: "This is Apple restriction. IOS returns beacons update every second, no matter how frequently device is advertising.". There is another comment there (likely from the Estimote vendor) saying "Our beacons can broadcast much faster and it may improve results and measurement". So whether higher iBeacon frequency is beneficial is not clear.

    0 讨论(0)
提交回复
热议问题