2009-07-15 3 views
114

Я работаю с данными GPS, получая значения каждую секунду и отображая текущую позицию на карте. Проблема в том, что иногда (особенно когда точность низкая) значения сильно меняются, что делает текущую позицию «прыгать» между удаленными точками на карте.Плавные данные GPS

Мне было интересно, какой простой способ избежать этого. В качестве первой идеи я подумал о том, чтобы отбросить значения с точностью до определенного порога, но я думаю, что есть и другие лучшие способы. Как обычно, программы выполняют это?

+0

Я чувствую плохие эффекты «GPS шума» при попытке вычислить связанные (производные) значения, как скорость и наклон, которые очень прерывистые специально для Tracklogs высокой частоты дискретизации (так как время есть целое число [одна секунда]). – heltonbiker

+2

(также, если вы путешествуете по основным дорогам, вы можете использовать алгоритм «привязать к дорогам», если у вас есть хороший [правильный, точный] набор данных дорожной карты. Просто мысль) – heltonbiker

+0

Я столкнулся с этой проблемой и для лучшей точности. – ViruMax

ответ

63

То, что вы ищете, называется Kalman Filter. Он часто используется для smooth navigational data. Это не обязательно тривиально, и вы можете много настраивать, но это очень стандартный подход и работает хорошо. Доступен KFilter library, который является реализацией на C++.

Мой следующий запасной вариант будет least squares fit. Фильтр Калмана сгладит данные, принимая во внимание скорости, тогда как подход с наименьшими квадратами подходит только для использования позиционной информации. Тем не менее, это определенно проще реализовать и понять. Похоже, что в Научной библиотеке GNU может быть implementation of this.

+1

Спасибо Крису. Да, я читал о Калмане, делая некоторые поиски, но это, безусловно, немного выше моих математических знаний. Знаете ли вы, что любой примерный код легко читается (и понимает!), Или еще лучше, какая-то реализация доступна? (C/C++/Java) –

+1

@Al К сожалению, моя единственная экспозиция с фильтрами Kalman - это работа, поэтому у меня есть удивительно элегантный код, который я не могу вам показать. –

+0

Без проблем :-) Я пробовал смотреть, но почему-то кажется, что эта вещь Калмана - черная магия. Много теоретических страниц, но мало кодов. Спасибо, попробуем другие методы. –

3

Один метод, который использует меньше математики/теории, состоит в том, чтобы одновременно выбирать 2, 5, 7 или 10 точек данных и определять те, которые являются выбросами. Менее точная мера выброса, чем фильтр Калмана, состоит в том, чтобы использовать следующее algorithm, чтобы взять все пары с мудрыми расстояниями между точками и выбросить ту, которая наиболее удалена от остальных. Как правило, эти значения заменяются значением ближе всего к отдаленному значению заменяемого

Например

Сглаживания в пять опорных точках A, B, C, D, E

ATOTAL = сумма расстояний АВ AC AD А.Е.

BTOTAL = сумма расстояний АВ БК BD BE

CTOTAL = сумма расстояний переменного тока до н.э. CD-CE

DTOTAL = SUM расстояний DA DB DC DE

ETOTAL = SUM расстояний EA EB EC DE

Если BTOTAL является крупнейшим вы бы заменить точку B с D, если BD = мин {AB, BC, BD, BE }

Это сглаживание определяет выбросы и может быть увеличено с использованием средней точки BD вместо точки D, чтобы сгладить позиционную линию. Ваш пробег может варьироваться, и существуют более математически строгие решения.

+0

Спасибо, я тоже сделаю это. Обратите внимание, что я хочу сгладить текущую позицию, так как она отображается и используется для извлечения некоторых данных. Меня не интересуют прошлые моменты. Моя первоначальная идея заключалась в использовании взвешенных средств, но мне все же нужно посмотреть, что лучше. –

+1

Al, это, по-видимому, форма взвешенных средств. Вам нужно будет использовать «прошлые» точки, если вы хотите сделать сглаживание, потому что система должна иметь больше, чем текущая позиция, чтобы знать, где сгладить. Если ваш GPS принимает данные по времени один раз в секунду, и ваш пользователь смотрит на экран один раз в пять секунд, вы можете использовать 5 точек данных, не заметив его! Скользящее среднее задерживалось бы только на один dp. – Karl

2

Что касается наименьших квадратов, вот несколько других вещей, чтобы экспериментировать с:

  1. Просто потому, что наименьших квадратов не означает, что она должна быть линейной. Вы можете наименьших квадратов - соответствовать квадратичной кривой для данных, тогда это соответствует сценарию, в котором пользователь ускоряется. (Обратите внимание, что по методу наименьших квадратов я имею в виду использование координат в качестве зависимой переменной и времени в качестве независимой переменной.)

  2. Вы также можете попробовать взвешивать точки данных на основе сообщенной точности. Когда точность мала, эти данные ниже.

  3. Еще одна вещь, которую вы, возможно, захотите попробовать, вместо того, чтобы отображать одну точку, если точность низкая, показывает круг или что-то, указывающее диапазон, в котором пользователь может основываться на заявленной точности. (Это то, что делает встроенное приложение Google Maps для iPhone.)

3

Вы также можете использовать сплайн. Подавайте значения, которые у вас есть, и интерполируйте точки между вашими известными точками. Связывание этого с подгонкой наименьших квадратов, скользящим средним или калмановским фильтром (как упоминалось в других ответах) дает вам возможность вычислять точки между вашими «известными» точками.

Возможность интерполировать значения между вашими известными дает приятный плавный переход и/разумное/приближение того, какие данные будут присутствовать, если бы у вас была более высокая точность. http://en.wikipedia.org/wiki/Spline_interpolation

Различные сплайны имеют разные характеристики. Чаще всего я использовал Akima и Cubic сплайны.

Еще один алгоритм, который следует учитывать, - это алгоритм упрощения линии Рамера-Дугласа-Пьюкера, который широко используется в упрощении GPS-данных. (http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm)

3

Возвращаясь к фильтрам Kalman ... Я нашел реализацию C для фильтра Калмана для данных GPS здесь: http://github.com/lacker/ikalman Я еще не пробовал, но кажется многообещающим.

+0

К сожалению, это не работает очень хорошо. –

57

Вот простой фильтр Калмана, который может быть использован именно для этой ситуации. Это было связано с некоторыми работами, которые я делал на устройствах Android.

Общая теория фильтра Калмана касается оценок для векторов с точностью оценок, представленных ковариационными матрицами. Однако для оценки местоположения на устройствах Android общая теория сводится к очень простому случаю. Поставщики местоположения Android предоставляют местоположение в виде широты и долготы вместе с точностью, которая определяется как единое число, измеренное в метрах. Это означает, что вместо ковариационной матрицы точность фильтра Калмана может быть измерена одним числом, хотя местоположение в калмановском фильтре измеряется двумя числами. Также можно игнорировать тот факт, что широта, долгота и метры фактически все разные единицы могут быть проигнорированы, потому что если вы поместите коэффициенты масштабирования в фильтр Калмана, чтобы преобразовать их все в одни и те же единицы, то эти коэффициенты масштабирования в конечном итоге будут отменены при преобразовании результатов обратно в исходные единицы.

Код может быть улучшен, так как он предполагает, что наилучшая оценка текущего местоположения - это последнее известное местоположение, и, если кто-то движется, должно быть возможно использовать датчики Android для получения более точной оценки. Код имеет единственный свободный параметр Q, выраженный в метрах в секунду, который описывает, как быстро точность уменьшается при отсутствии каких-либо новых оценок местоположения. Более высокий параметр Q означает, что точность уменьшается быстрее. Фильтры Kalman в целом работают лучше, когда точность затухает немного быстрее, чем можно было бы ожидать, поэтому для прогулки по телефону с Android я считаю, что Q = 3 метра в секунду отлично работает, хотя я обычно хожу медленнее, чем это. Но если вы путешествуете в быстром автомобиле, очевидно, следует использовать гораздо большее число.

public class KalmanLatLong { 
    private final float MinAccuracy = 1; 

    private float Q_metres_per_second;  
    private long TimeStamp_milliseconds; 
    private double lat; 
    private double lng; 
    private float variance; // P matrix. Negative means object uninitialised. NB: units irrelevant, as long as same units used throughout 

    public KalmanLatLong(float Q_metres_per_second) { this.Q_metres_per_second = Q_metres_per_second; variance = -1; } 

    public long get_TimeStamp() { return TimeStamp_milliseconds; } 
    public double get_lat() { return lat; } 
    public double get_lng() { return lng; } 
    public float get_accuracy() { return (float)Math.sqrt(variance); } 

    public void SetState(double lat, double lng, float accuracy, long TimeStamp_milliseconds) { 
     this.lat=lat; this.lng=lng; variance = accuracy * accuracy; this.TimeStamp_milliseconds=TimeStamp_milliseconds; 
    } 

    /// <summary> 
    /// Kalman filter processing for lattitude and longitude 
    /// </summary> 
    /// <param name="lat_measurement_degrees">new measurement of lattidude</param> 
    /// <param name="lng_measurement">new measurement of longitude</param> 
    /// <param name="accuracy">measurement of 1 standard deviation error in metres</param> 
    /// <param name="TimeStamp_milliseconds">time of measurement</param> 
    /// <returns>new state</returns> 
    public void Process(double lat_measurement, double lng_measurement, float accuracy, long TimeStamp_milliseconds) { 
     if (accuracy < MinAccuracy) accuracy = MinAccuracy; 
     if (variance < 0) { 
      // if variance < 0, object is unitialised, so initialise with current values 
      this.TimeStamp_milliseconds = TimeStamp_milliseconds; 
      lat=lat_measurement; lng = lng_measurement; variance = accuracy*accuracy; 
     } else { 
      // else apply Kalman filter methodology 

      long TimeInc_milliseconds = TimeStamp_milliseconds - this.TimeStamp_milliseconds; 
      if (TimeInc_milliseconds > 0) { 
       // time has moved on, so the uncertainty in the current position increases 
       variance += TimeInc_milliseconds * Q_metres_per_second * Q_metres_per_second/1000; 
       this.TimeStamp_milliseconds = TimeStamp_milliseconds; 
       // TO DO: USE VELOCITY INFORMATION HERE TO GET A BETTER ESTIMATE OF CURRENT POSITION 
      } 

      // Kalman gain matrix K = Covarariance * Inverse(Covariance + MeasurementVariance) 
      // NB: because K is dimensionless, it doesn't matter that variance has different units to lat and lng 
      float K = variance/(variance + accuracy * accuracy); 
      // apply K 
      lat += K * (lat_measurement - lat); 
      lng += K * (lng_measurement - lng); 
      // new Covarariance matrix is (IdentityMatrix - K) * Covarariance 
      variance = (1 - K) * variance; 
     } 
    } 
} 
+0

Не должен вычисляться дисперсия: variance + = TimeInc_milliseconds * TimeInc_milliseconds * Q_metres_per_second * Q_metres_per_second/1000000 – Horacio

+3

@Horacio, я знаю, почему вы так думаете, но нет! Математически неопределенность здесь моделируется винеровским процессом (см. Http://en.wikipedia.org/wiki/Wiener_process), а с винеровским процессом дисперсия растет линейно со временем. Переменная 'Q_metres_per_second' соответствует переменной' sigma' в разделе «Связанные процессы» в этой статье в Википедии. 'Q_metres_per_second' является стандартным отклонением и измеряется в метрах, поэтому его единицы измерения не считаются метрами/секундами. Это соответствует стандартным отклонениям распределения через 1 секунду. – Stochastically

+0

Спасибо за объяснение. Можете ли вы рассказать о том, как оценивать информацию о скорости, чтобы получить более точную оценку? могу ли я просто установить Q_meters_per_second равным скорости пользователя (в метрах на 1 секунду), умноженному на какой-то фактор? скажем, 1,5? – Horacio

9

Вы не должны рассчитывать скорость смены позиции за раз. GPS может иметь неточные позиции, но имеет точную скорость (выше 5 км/ч). Поэтому используйте скорость от отметки местоположения GPS. И дальше вы не должны этого делать, конечно, хотя он работает большую часть времени.

Позиции GPS, поставляемые, уже отфильтрованы Калманом, вероятно, вы не можете улучшить, в постобработке обычно у вас нет той же информации, что и чип GPS.

Вы можете сгладить его, но это также приводит к ошибкам.

Просто убедитесь, что вы удалите позиции, когда устройство стоит на месте, это удаляет позиции прыжка, что некоторые устройства/конфигурации не удаляются.

+4

Не могли бы вы предоставить некоторые рекомендации для этого, пожалуйста? – ivyleavedtoadflax

+1

В этих предложениях много информации и много профессионального опыта. Какое предложение вы хотите получить? для скорости: поиск эффекта доплера и GPS. внутренний Калман? Это базовая информация о GPS, каждая бумага или книга, описывающая, как работает встроенный GPS-чип. smootig-errors: когда-либо сглаживание вводит erros. стоять на месте? попробуйте. – AlexWien

+2

«Перескакивание» при стоянии не является единственным источником ошибок. Есть также отражения сигнала (например, из гор), где положение прыгает вокруг. Мои чипы GPS (например, Garmin Dakota 20, SonyEricsson Neo) не отфильтровали это ... И действительно, шутка - это значение высоты сигналов GPS, когда они не объединены с барометрическим давлением. Эти значения не фильтруются или я не хочу видеть нефильтрованные значения. – hgoebl

2

Обычно я использую акселерометры. Резкое изменение положения за короткий период подразумевает быстрое ускорение. Если это не отражается в телеметрии акселерометра, то это почти наверняка связано с изменением «лучших трех» спутников, используемых для вычисления положения (к которому я отношусь как телепортация GPS).

Когда актив находится в состоянии покоя и прыгает из-за телепортации GPS, если вы постепенно вычисляете центр тяжести, вы фактически пересекаете больший и больший набор снарядов, улучшая точность.

Для этого, когда актив не находится в покое, вы должны оценить его вероятную следующую позицию и ориентацию на основе скорости, заголовка и линейного и вращательного (если у вас есть гироскопа) данные ускорения. Это более или менее то, что делает знаменитый фильтр K. Вы можете получить все это на аппаратных средствах около 150 долларов США на AHRS, где есть все, кроме модуля GPS, и с разъемом для подключения. Он имеет собственный процессор и фильтрацию Kalman на борту; результаты стабильны и неплохи. Инерционное наведение очень устойчиво к дрожанию, но со временем дрейфует. GPS склонен к дрожанию, но не дрейфует со временем, они были практически сделаны, чтобы компенсировать друг друга.

9

Это может прийти немного поздно ...

Я написал эту KalmanLocationManager для Android, который оборачивает два наиболее распространенных провайдер местоположения, сетей и GPS, Кальман фильтрует данные и предоставляет обновления к LocationListener (как два «реальных» провайдера).

Я использую его в основном для «интерполяции» между показаниями - получать обновления (предсказания положения) каждые 100 миллисов (например, вместо максимальной скорости передачи в секунду в секунду), что дает мне лучшую частоту кадров при анимации моей позиции ,

На самом деле он использует три фильтра калмана, для каждого измерения: широту, долготу и высоту. Они все равно независимы.

Это значительно упрощает матричную математику: вместо использования одной матрицы перехода состояния 6x6 я использую 3 разные матрицы 2x2. Фактически в коде я вообще не использую матрицы. Решенные все уравнения и все значения являются примитивами (double).

Исходный код работает, и есть демонстрационная активность. Извините за отсутствие javadoc в некоторых местах, я догоню.

+1

Я попытался использовать ваш код lib, я получил некоторые нежелательные результаты, я не уверен, что я что-то делаю неправильно ... (Ниже приведен URL-адрес изображения, синий путь фильтрованных местоположений, оранжевый - это необработанные местоположения) https: //app.box.com/s/w3uvaz007glp2utvgznmh8vlggvaiifk – umesh

+0

Шипы, которые вы видите «растущие» от среднего (оранжевая линия), выглядят как обновления сетевых провайдеров. Можете ли вы попробовать распечатать как необработанные сетевые, так и gps-обновления? Возможно, вам будет лучше без обновлений сети, в зависимости от того, чего вы пытаетесь достичь. Кстати, откуда вы получаете эти необработанные оранжевые обновления? – villoren

+1

оранжевые точки от поставщика gps, а синий - от Kalman, я построил журналы на карте – umesh

0

Относится к CoffeeScript, если вас интересует. ** edit -> извините, используя магистраль тоже, но вы получите эту идею.

Модифицированный слегка принять маяк с attribs

{широта: item.lat, долгота: item.lng, дата: новый Дата (item.effective_at), точность: пункт.gps_accuracy}

MIN_ACCURACY = 1 

# mapped from http://stackoverflow.com/questions/1134579/smooth-gps-data 

class v.Map.BeaconFilter 

    constructor: -> 
    _.extend(this, Backbone.Events) 

    process: (decay,beacon) -> 

    accuracy  = Math.max beacon.accuracy, MIN_ACCURACY 

    unless @variance? 
     # if variance nil, inititalise some values 
     @variance  = accuracy * accuracy 
     @timestamp_ms = beacon.date.getTime(); 
     @lat   = beacon.latitude 
     @lng   = beacon.longitude 

    else 

     @timestamp_ms = beacon.date.getTime() - @timestamp_ms 

     if @timestamp_ms > 0 
     # time has moved on, so the uncertainty in the current position increases 
     @variance += @timestamp_ms * decay * decay/1000; 
     @timestamp_ms = beacon.date.getTime(); 

     # Kalman gain matrix K = Covarariance * Inverse(Covariance + MeasurementVariance) 
     # NB: because K is dimensionless, it doesn't matter that variance has different units to lat and lng 
     _k = @variance/(@variance + accuracy * accuracy) 
     @lat = _k * (beacon.latitude - @lat) 
     @lng = _k * (beacon.longitude - @lng) 

     @variance = (1 - _k) * @variance 

    [@lat,@lng] 

 Смежные вопросы

  • Нет связанных вопросов^_^