Реализация фильтра Калмана для сглаживания данных из API deviceOrientation

Я пытаюсь сгладить данные, которые я получаю от API deviceOrientation, чтобы сделать приложение Google Cardboard в браузере.

Я передаю данные акселерометра прямо во вращение камеры ThreeJs, но мы получаем много шума по сигналу, который вызывает дрожание вида.

кто-то предложил фильтр Калмана как лучший способ приблизиться к сглаживанию шума обработки сигналов, и я нашел эту простую библиотеку Javascript на на GitHub

https://github.com/itamarwe/kalman

однако его действительно свет на документации.

Я понимаю, что мне нужно создать модель Калмана, предоставив вектор и 3 матрицы в качестве аргументов, а затем обновить модель, снова с вектором и матрицами в качестве аргументов в течение периода времени.

Я также понимаю, что уравнение фильтра Калмана имеет несколько различных частей: текущее оценочное положение, значение коэффициента усиления Калмана, текущее значение из API ориентации и предыдущая оценочная позиция.

Я вижу, что точка в 3D-пространстве может быть описана как вектор, поэтому любое из значений позиции, например оценочное положение, или текущее чтение может быть вектором.

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

2 ответов


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

позвольте мне кратко объяснить, каковы все различные матрицы и векторы и как они должны быть получены:

x - это вектор, который вы пытаетесь оценить. В вашем случае это, вероятно, 3 угловых ускорения.

P - ковариационная матрица оценка, означающая неопределенность оценки. Он также оценивается на каждом шаге фильтра Калмана вместе с x.

F - описывает как X развивается по модели. Как правило, модель x[k] = Fx[k-1]+w[k]. В твоем случае, F может быть матрица идентичности, если вы ожидаете, что угловое ускорение будет относительно гладким, или нулевая матрица, если вы ожидаете, что угловое ускорение будет полностью непредсказуемым. Во всяком случае,w будет представьте, насколько вы ожидаете, что ускорение изменится от шага к шагу.

w - описывает шум процесса, что означает, насколько модель отличается от" идеальной " модели. Он определяется как нулевое среднее многомерное нормальное распределение с ковариационной матрицей Q.

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

z - это то, что вы измеряете. В вашем случае, поскольку вы используете акселерометры, вы измеряете то, что вы также оценки. Это будут угловые ускорения.

H - описывает отношение между вашей моделью и наблюдением. z[k]=H[k]x[k]+v[k]. В вашем случае, это матрица.

v - шум измерения и предполагается, что нулевое среднее гауссово белое шум с ковариацией R[k]. Здесь нужно измерить, насколько шумны акселерометры, и вычислить матрицу ковариации шума.

подводя итог, шаги по использованию фильтра Калмана:

  1. определить x[0] и P[0] - начальное состояние модели и первоначальная оценка того, насколько точно вы знаете x[0].
  2. определить F исходя из вашей модели и как она развивается от шага к шагу.
  3. определить Q основываясь на стохастической природе вашей модели.
  4. определить H на основе отношения между тем, что вы измеряете и что вы хотите оценить (между моделью и измерением).
  5. определить R основанный на измерении шума. Как шумно ваше измерение.

затем, с каждым новым наблюдением, вы можете обновить оценку состояния модели с помощью фильтра Калмана и получить оптимальную оценку состояния модель(x[k]), и о точности этой оценки (P[k]).


var acc = {
 x:0,
 y:0,
 z:0
};

var count = 0;

if (window.DeviceOrientationEvent) {
  window.addEventListener('deviceorientation', getDeviceRotation, false);
}else{
  $(".accelerometer").html("NOT SUPPORTED")
}

var x_0 = $V([acc.x, acc.y, acc.z]); //vector. Initial accelerometer values

//P prior knowledge of state
var P_0 = $M([
              [1,0,0],
              [0,1,0],
              [0,0,1]
            ]); //identity matrix. Initial covariance. Set to 1
var F_k = $M([
              [1,0,0],
              [0,1,0],
              [0,0,1]
            ]); //identity matrix. How change to model is applied. Set to 1
var Q_k = $M([
              [0,0,0],
              [0,0,0],
              [0,0,0]
            ]); //empty matrix. Noise in system is zero

var KM = new KalmanModel(x_0,P_0,F_k,Q_k);

var z_k = $V([acc.x, acc.y, acc.z]); //Updated accelerometer values
var H_k = $M([
              [1,0,0],
              [0,1,0],
              [0,0,1]
            ]); //identity matrix. Describes relationship between model and observation
var R_k = $M([
              [2,0,0],
              [0,2,0],
              [0,0,2]
            ]); //2x Scalar matrix. Describes noise from sensor. Set to 2 to begin
var KO = new KalmanObservation(z_k,H_k,R_k);

//each 1/10th second take new reading from accelerometer to update
var getNewPos = window.setInterval(function(){

    KO.z_k = $V([acc.x, acc.y, acc.z]); //vector to be new reading from x, y, z
    KM.update(KO);

    $(".kalman-result").html(" x:" +KM.x_k.elements[0]+", y:" +KM.x_k.elements[1]+", z:" +KM.x_k.elements[2]);
    $(".difference").html(" x:" +(acc.x-KM.x_k.elements[0])+", y:" +(acc.y-KM.x_k.elements[1])+", z:" +(acc.z-KM.x_k.elements[2]))


}, 100);

 //read event data from device
function getDeviceRotation(evt){

    // gamma is the left-to-right tilt in degrees, where right is positive
    // beta is the front-to-back tilt in degrees, where front is positive
    // alpha is the compass direction the device is facing in degrees
    acc.x = evt.alpha;
    acc.y = evt.beta;
    acc.z = evt.gamma; 
    $(".accelerometer").html(" x:" +acc.x+", y:" +acc.y+", z:" +acc.z);
}

вот демонстрационная страница, показывающая мои результаты

http://cardboard-hand.herokuapp.com/kalman.html

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