Приклад трикутника для iBeacons


75

Я розглядаю можливість використання декількох iBeacons для `` грубого '' розташування в приміщенні. Додаток є своєрідною «музейною» обстановкою, і було б простіше мати змогу сформувати сітку з місцями для різних об’єктів, аніж окремими маяками (хоча це теж може бути неможливим).

Чи є приклади, досвід використання декількох маяків для тріангуляції в якесь місце розташування чи якась логіка, яка допоможе мені на шляху написання цього?


5
Перегляньте мою демонстраційну версію: youtube.com/watch?v=dMWEl6GBGqk . У коментарях ви знайдете відповідь Якуба Крзича, компанія якого виготовила маяки, якими я користуюся.
Конрад Дзвінель

Дякую, що дуже корисно. Якщо Estimote збирається випустити API, я міг би почекати і подивитися, як це працює, замість того, щоб вивчати математику сам і спробувати знайти спосіб динамічного калібрування та виправлення маяків, як пропонується в коментарях.
Луук Д. Янсен

@ LuukD.Jansen Я теж дивлюсь на це ... будь-які новини?
Леонардо

Я не міг розібратися в цьому далі. Я думаю, що триангуляція не зможе бути достатньо точною в масштабі (площі приміщення), який мені потрібен. Мати маяк у всіх важливих місцях буде простіше / дешевше
Луук Д. Янсен,

Відповіді:


74

Я проводив кілька експериментів, щоб отримати точну позицію за допомогою трьох маяків.

Результати трилатерації

На жаль, результати були дуже невтішними з точки зору якості. Було в основному два питання:

  1. У неконтрольованих середовищах, де можна знайти метали та інші об'єкти, що впливають на сигнал, сила прийнятого сигналу маяків змінюється настільки часто, що здається неможливим отримати діапазон помилок нижче 5 метрів.
  2. Залежно від того, як користувач обробляє приймач, показання можуть також сильно змінитися. Якщо користувач покладе руку на антену Bluetooth, тоді алгоритм буде мати низькі сигнали як вхід, і, таким чином, маяки повинні бути дуже далеко від пристрою. Дивіться це зображення, щоб побачити точне розташування антени Bluetooth.

Можливі рішення

Після розмови з інженером Apple, який активно відчаював мене йти цим шляхом, варіант, який я відчуваю більш схильним використовувати зараз, - це груба сила. Спробуйте встановити маяк кожні X метри (X - це максимальна допустима похибка в системі), щоб ми могли відстежувати на цій сітці маяків положення даного пристрою, обчислюючи, який маяк у сітці є найближчим до пристрою, і припускаючи, що пристрій знаходиться в тому ж положенні.

Алгоритм трилатерації

Однак задля повноти я поділяю нижче основну функцію алгоритму трилатерації. Він базується на параграфі 3 ("Три відомі відстані") цієї статті .

- (CGPoint)getCoordinateWithBeaconA:(CGPoint)a beaconB:(CGPoint)b beaconC:(CGPoint)c distanceA:(CGFloat)dA distanceB:(CGFloat)dB distanceC:(CGFloat)dC {
    CGFloat W, Z, x, y, y2;
    W = dA*dA - dB*dB - a.x*a.x - a.y*a.y + b.x*b.x + b.y*b.y;
    Z = dB*dB - dC*dC - b.x*b.x - b.y*b.y + c.x*c.x + c.y*c.y;

    x = (W*(c.y-b.y) - Z*(b.y-a.y)) / (2 * ((b.x-a.x)*(c.y-b.y) - (c.x-b.x)*(b.y-a.y)));
    y = (W - 2*x*(b.x-a.x)) / (2*(b.y-a.y));
    //y2 is a second measure of y to mitigate errors
    y2 = (Z - 2*x*(c.x-b.x)) / (2*(c.y-b.y));

    y = (y + y2) / 2;
    return CGPointMake(x, y);
}

2
Здається, я завжди отримую або NaN, або Inf + для свого значення y. Ви коли-небудь стикалися з цим, розробляючи свій алгоритм?
Язид

Ні, у мене не було цієї проблеми. Переконайтеся, що всі вхідні параметри масштабовані у вашій системі координат UIView. Наприклад, якщо ви відстежуєте простір 10x10 метрів і втягуєте його в UIView 500x500 пікселів, то вам потрібно помножити реальні положення та відстані маяків, виміряні на 50.
Хав'єр Чаваррі,

8
Я виявляю, що формула для y іноді ламається, особливо коли точки a і b мають однакову координату y. Це / (2*(b.y-a.y))частина, яка виробляє 0, а потім ділення на нульову помилку.
Язид

1
Це мені дуже допомогло. Я перетворив цей метод на Java, і він спрацював чудово. Працюємо з цим, коли ми говоримо.
Денніс Андерсон,

1
Я згоден, що це рівняння не працює. Маяки розміром 1,5мx2,5м, а мій uiview - 300x500. Згідно з вашим мультиплікатором, мій xy виявляється в області 4k пікселів
jdog

22

Ось бібліотека Java з відкритим кодом, яка буде виконувати трилатерацію / багатосторонність: https://github.com/lemmingapex/Trilateration

приклад

Він використовує популярний нелінійний оптимізатор найменших квадратів, алгоритм Левенберга-Марквардта, від Apache Commons Math.

double[][] positions = new double[][] { { 5.0, -6.0 }, { 13.0, -15.0 }, { 21.0, -3.0 }, { 12.42, -21.2 } };
double[] distances = new double[] { 8.06, 13.97, 23.32, 15.31 };

NonLinearLeastSquaresSolver solver = new NonLinearLeastSquaresSolver(new TrilaterationFunction(positions, distances), new LevenbergMarquardtOptimizer());
Optimum optimum = solver.solve();

// the answer
double[] calculatedPosition = optimum.getPoint().toArray();

// error and geometry information
RealVector standardDeviation = optimum.getSigma(0);
RealMatrix covarianceMatrix = optimum.getCovariances(0);

Більшість наукових прикладів, наприклад, у вікіпедії , стосуються саме трьох кіл і припускають абсолютно точну інформацію. Ці обставини дозволяють набагато простіше формулювати проблеми з точними відповідями, і, як правило, не задовільні для практичних ситуацій.

Зазвичай в евклідовому просторі R 2 або R 3 з відстанями, що містять похибку вимірювання, площу (еліпс) або об’єм (еліпсоїд), що цікавить, зазвичай отримують замість точки. Якщо замість області бажана оцінка точки, слід використовувати центроїд площі або центроїд об’єму. Простір R 2 вимагає принаймні 3 невироджених точок та відстаней для отримання унікальної області; і аналогічно космос R 3 вимагає принаймні 4 невироджених точок та відстаней для отримання унікальної області.


15

Я вивчив це. Термін, який ви хочете, - тристоронній. (У тріангуляції ви маєте кути з 3 відомих точок. У трилатерації ви маєте відстань від 3 відомих точок) Якщо ви шукаєте в Google, ви повинні знайти кілька статей, включаючи одну на Вікі. Він передбачає розв’язання набору з 3 одночасних рівнянь. Документи, які я бачив, стосувались тристоронньої тривимірності - 2D простіше, тому що ви можете просто відмовитись від Z-терміну.

Я знайшов абстрактну математику. Я ще не знайшов часу, щоб відобразити загальний алгоритм у конкретний код, але я планую вирішити це питання в якийсь момент.

Зверніть увагу, що результати, які ви отримаєте, будуть ДУЖЕ сирими, особливо в будь-чому, крім порожньої кімнати. Сигнали досить слабкі, щоб людина, статуя або що-небудь, що блокує лінію зору, значно збільшило показники відстані. Можливо, у вас навіть є місця в будівлі, де конструктивне втручання (здебільшого від стін) змушує деякі місця читати набагато ближче, ніж насправді.


Дякую Дункане, я це подивлюсь. Я знаю недоліки, але хотів би все-таки провести з ним тест. Точності в межах декількох метрів було б достатньо, якщо це заощадить, коли потрібно буде наносити маяк на кожну точку. Навіть якщо це такий шлях, я хотів би це перевірити.
Luuk D. Jansen

7

Точне позиціонування в приміщенні за допомогою iBeacon буде складним з таких причин:

  1. Як зазначалося в попередніх коментарях, сигнал iBeacon, як правило, сильно коливається. Причиною є багатопроменевість ефект, перешкоди динамічного об'єкта між телефоном та iBeacon, коли людина рухається, інші перешкоди 2,4 ГГц тощо. Отже, в ідеалі ви не хочете довіряти даним одного пакета, а замість цього виконуйте деяке усереднення для декількох пакетів від одного маяка. Для цього потрібно, щоб відстань між телефоном і маяком не сильно змінювалось між цими декількома пакетами. Для загальних пакетів BLE (як маяки від StickNFind) можна легко встановити швидкість маяка 10 Гц. Однак для iBeacon це буде важко, оскільки
  2. Частота маяків iBeacon, ймовірно, не може бути вище 1 Гц. Буду радий, якщо хтось може вказати на джерело, яке говорить про інше, але вся інформація, яку я бачив до цього часу, підтверджує це твердження. Це насправді має сенс, оскільки більшість iBeacons будуть працювати від батареї, а високочастотні суттєво впливають на час автономної роботи. Враховуючи середню швидкість ходьби людей 5,3 км (~ 1,5 м / с), тому навіть якщо ви просто використовуєте скромні 3 пакети маяків, щоб виконати усереднення, вам буде важко отримати точність ~ 5 м.

З іншого боку, якщо ви можете збільшити частоту iBeacon до більш ніж 10 Гц (що, я сумніваюся, можливо), тоді можна мати точність 5 м або вище, використовуючи відповідний метод обробки. По-перше, тривіальні рішення, засновані на Законі про зворотну квадратику, такі як трилатерація, часто виявляються неефективними, оскільки на практиці співвідношення відстань / RSSI для різних маяків часто віддаляється від Закону про зворотну площу з причини 1 вище. Але поки RSSI є відносно стабільним для певного маяка в якомусь певному місці (як правило, це трапляється), ви можете використовувати підхід, який називається дактилоскопією, для досягнення більш високої точності. Поширеним методом, що використовується для відбитків пальців, є kNN ( k-Найближчий сусід ).

Оновлення 2014-04-24

Деякі iBeacons можуть транслювати більше 1 Гц, наприклад, Estimote використовує 5 Гц за замовчуванням. Однак, згідно з цим посиланням : " Це обмеження Apple. IOS повертає маяки оновлення щосекунди, незалежно від того, як часто пристрій рекламує ". Там є ще один коментар (ймовірно, від постачальника Estimote), який говорить: " Наші маяки можуть транслювати набагато швидше, і це може покращити результати та вимірювання ". Тож чи вища частота iBeacon корисна, не ясно.


1
Не надто розглядаючи це, у мене є набір маяків Estimote, і інтервал за замовчуванням встановлений на 200 мс. Однак його можна встановити на 50 мс (але, природно, це вплине на час автономної роботи)
Луук Д. Янсен,

У такому випадку ви можете побачити> 1 Гц оновлення в діапазоні у вашому додатку iOS?
Penghe Geng

Не знаю, на даний момент у мене немає належного коду для тестування, і чесно кажучи, не було часу, щоб його написати. Я просто побачив опцію деякий час тому і додав коментар, але оновлення відповіді, схоже, свідчить про те, що цього немає.
Луук Д. Янсен

6

Якщо ви щось подібне до мене і не любите математику, можливо, ви захочете швидко здійснити пошук "sdk позиціонування в приміщенні". Є багато компаній, які пропонують позиціонування в приміщенні як послугу.

Безсоромна вилка: я працюю в indoo.rs і можу рекомендувати цю послугу. Він також включає в себе маршрутизацію та подібні до "просто" позиціонування в приміщенні.


6

Для тих, хто потребує @Javier Chávarriфункції трилатерації для Androidпристроїв (для економії часу):

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;
}

Привіт, я пробую твій код, але не розумію результат, який він мені дав? Мої 3 бали: 49.348657, 6.173041, 3.126м - 49.348658, 6.172981, 5.452м - 49.348588, 6.173028, 4.065м Результат, який я маю в своєму розташуванні: Широта завжди -90,0, а довгота змінюється залежно від відстані? Будь-яка ідея?
Lord St John

1
Перевірте, чи ваші три точки розташування створюють трикутник, і вони не утворюють лінії. Я відповідаю з телефону. Одного разу, коли я перебуваю в ПК, перевіряю ваше місцезнаходження
hrskrs,

@LordStJohn Ви пробували з іншими пунктами? Я маю на увазі, чи завжди ви отримуєте такий результат?
hrskrs

Так, я намагаюся з іншими пунктами, завжди в одній будівлі. Завжди отримуючи однакові результати, Latitude завжди становить -90,0, а довгота змінюється з відстанню.
Lord St John

1
@LordStJohn, я щойно спробував із цією статистикою: 49.348657, 6.173041, 3.126m - 49.348658, 6.172981, 5.452m - 49.348588, 6.173028, 4.065, і це не дає -90. Спробуйте Debuggingі переконайтеся, що ви використовуєте ці місця.
hrskrs

5

Мій архітектор / менеджер, який написав такий алгоритм,

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. Обчисліть центр ваги трикутника (3 маяки)
  2. розрахувати найкоротшу відстань / найближчий маяк
  3. Обчисліть відстань між маяком і центром ваги
  4. Перетворити найкоротшу відстань в координатні одиниці, яка є просто константою, він використовував для прогнозування точності. Ви можете перевірити варіюванням константи
  5. обчислити відстань дельти
  6. додайте дельту з найближчим маяком x, y.

Випробувавши його, я виявив точність до 5 метрів.

Будь ласка, прокоментуйте мені своє тестування, якщо ми зможемо його вдосконалити.


Як ви перетворили значення RSSI як відстань? Як ви отримали відстань еталонного маяка?
Махамута М

4

Я реалізував дуже простий алгоритм відбитків пальців для Android 4.4, протестований у відносно "поганому" середовищі:

  • майже 10 Wi-Fi AP поблизу.
  • кілька інших сигналів Bluetooth поблизу.

точність здається на 5-8 метрів і залежить від того, як я розмістив цього 3 мовника Ibeacon. Алгоритм досить простий, і я думаю, ви можете реалізувати його самостійно, кроки:

  1. завантажте внутрішню карту.
  2. вибірка з картою для всієї очікуваної точки позиціонування.
  3. записувати всі дані вибірки, дані повинні включати: координату карти, сигнали положення та їх RSSI.

отже, коли ви починаєте позиціонувати, це просто зворотний крок подальших кроків.


Ваш алгоритм відбитків пальців використовує трилатерацію чи інший прийом?
andrea.spot.

3

Ми також намагаємось знайти найкращий спосіб точно знайти когось у кімнаті за допомогою iBeacons. Річ у тім, що потужність сигналу маяка не є постійною, і на нього впливають інші сигнали 2,4 ГГц, металеві предмети тощо, тому для досягнення максимальної точності необхідно калібрувати кожен маяк окремо, і як тільки він буде встановлений у потрібне положення . (і проведіть певний польовий тест, щоб побачити коливання сигналу, коли присутні інші пристрої Bluetooth). У нас також є кілька iBeacons від Estimote (те саме з відео Конрада Дзвінеля), і вони вже розробили деякі технічні демонстрації того, що можна зробити з iBeacons. У їхній програмі можна побачити радар, на якому відображаються iBeacons. Іноді це досить точно, але іноді ні, (і, здається, рух телефону не враховується для обчислення позицій).http://goo.gl/98hiza

Хоча в теорії 3 iBeacons має бути достатньо для досягнення гарної точності, можливо, в реальних ситуаціях потрібно більше маяків, щоб забезпечити точність, яку ви шукаєте.


3

Мені справді допоміг цей проект на Code.Google.com: https://code.google.com/p/wsnlocalizationscala/ він містить багато коду, кілька алгоритмів трилатерації, всі написані на C #. Це велика бібліотека, але насправді не призначена для використання “нестандартно”.


2

Будь ласка, перевірте посилання https://proximi.io/accurate-indoor-positioning-bluetooth-beacons/

Proximi SDK подбає про триангуляцію. Цей SDK надає бібліотеки для обробки всієї логіки автоматичного розташування маяків, тріангуляції та фільтрації у фоновому режимі. Окрім маяків, ви можете поєднувати IndoorAtlas, Wi-Fi, GPS та позиціонування стільникового зв'язку.


1

Я знайшов рішення Вішну Прахбу дуже корисним. Я переніс його на c #, якщо це комусь потрібно.

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

Альтернативне рівняння

- (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);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.