Проверка ответа фильтра Калмана - PullRequest
0 голосов
/ 12 июня 2018

Итак, я применил фильтр Калмана для этого набора данных .Ниже приведен мой код (обратите внимание, что я добавляю весь код для одного для воспроизведения результатов на его / ее компьютере).

# Multi dimensional Kalman filter
import os
from math import *

class matrix:

    # implements basic operations of a matrix class

    def __init__(self, value):
        if isinstance(value, basestring):
            print "lol"
        self.value = value

        self.dimx = len(value)
        self.dimy = len(value[0])
        if value == [[]]:
            self.dimx = 0

    def zero(self, dimx, dimy):
        # check if valid dimensions
        if dimx < 1 or dimy < 1:
            raise ValueError, "Invalid size of matrix"
        else:
            self.dimx = dimx
            self.dimy = dimy
            self.value = [[0 for row in range(dimy)] for col in range(dimx)]

    def identity(self, dim):
        # check if valid dimension
        if dim < 1:
            raise ValueError, "Invalid size of matrix"
        else:
            self.dimx = dim
            self.dimy = dim
            self.value = [[0 for row in range(dim)] for col in range(dim)]
            for i in range(dim):
                self.value[i][i] = 1

    def show(self):
        for i in range(self.dimx):
            print self.value[i]
        print ' '

    def __add__(self, other):
        # check if correct dimensions
        if self.dimx != other.dimx or self.dimy != other.dimy:
            raise ValueError, "Matrices must be of equal dimensions to add"
        else:
            # add if correct dimensions
            res = matrix([[]])
            res.zero(self.dimx, self.dimy)
            for i in range(self.dimx):
                for j in range(self.dimy):
                    res.value[i][j] = self.value[i][j] + other.value[i][j]
            return res

    def __sub__(self, other):
        # check if correct dimensions
        if self.dimx != other.dimx or self.dimy != other.dimy:
            raise ValueError, "Matrices must be of equal dimensions to subtract"
        else:
            # subtract if correct dimensions
            res = matrix([[]])
            res.zero(self.dimx, self.dimy)
            for i in range(self.dimx):
                for j in range(self.dimy):
                    res.value[i][j] = self.value[i][j] - other.value[i][j]
            return res

    def __mul__(self, other):
        # check if correct dimensions

        if self.dimy != other.dimx:
            raise ValueError, "Matrices must be m*n and n*p to multiply"
        else:
            # subtract if correct dimensions
            res = matrix([[]])
            res.zero(self.dimx, other.dimy)
            for i in range(self.dimx):
                for j in range(other.dimy):
                    for k in range(self.dimy):
                        res.value[i][j] += self.value[i][k] * other.value[k][j]
            return res

    def transpose(self):
        # compute transpose
        res = matrix([[]])
        res.zero(self.dimy, self.dimx)
        for i in range(self.dimx):
            for j in range(self.dimy):
                res.value[j][i] = self.value[i][j]
        return res

    # Thanks to Ernesto P. Adorio for use of Cholesky and CholeskyInverse functions

    def Cholesky(self, ztol=1.0e-5):
        # Computes the upper triangular Cholesky factorization of
        # a positive definite matrix.
        res = matrix([[]])
        res.zero(self.dimx, self.dimx)

        for i in range(self.dimx):
            S = sum([(res.value[k][i])**2 for k in range(i)])
            d = self.value[i][i] - S
            if abs(d) < ztol:
                res.value[i][i] = 0.0
            else:
                if d < 0.0:
                    raise ValueError, "Matrix not positive-definite"
                res.value[i][i] = sqrt(d)
            for j in range(i+1, self.dimx):
                S = sum([res.value[k][i] * res.value[k][j] for k in range(self.dimx)])
                if abs(S) < ztol:
                    S = 0.0
                res.value[i][j] = (self.value[i][j] - S)/res.value[i][i]
        return res

    def CholeskyInverse(self):
        # Computes inverse of matrix given its Cholesky upper Triangular
        # decomposition of matrix.
        res = matrix([[]])
        res.zero(self.dimx, self.dimx)

        # Backward step for inverse.
        for j in reversed(range(self.dimx)):
            tjj = self.value[j][j]
            S = sum([self.value[j][k]*res.value[j][k] for k in range(j+1, self.dimx)])
            res.value[j][j] = 1.0/tjj**2 - S/tjj
            for i in reversed(range(j)):
                res.value[j][i] = res.value[i][j] = -sum([self.value[i][k]*res.value[k][j] for k in range(i+1, self.dimx)])/self.value[i][i]
        return res

    def inverse(self):
        aux = self.Cholesky()
        res = aux.CholeskyInverse()
        return res

    def __repr__(self):
        return repr(self.value)


########################################

# filter function

def kalman_filter(x, P):

        # measurement update

        y = measurements - H * x

        s = H * P * H.transpose() + R
        K = P * H.transpose() * s.inverse()
        x = x + K * y
        P = (I - K * H) * P

        # prediction
        x = F * x  
        P = F * P * F.transpose()
        return x,P

files = []
x = matrix([[0.], [0.], [0.]]) # initial state (location and velocity)

P = matrix([[1000., 0.,0.], [0., 1000.,0.] , [0.,0.,1000.]]) # initial uncertainty
u = matrix([[0.], [0.]]) # external motion
F = matrix([[1., 0., 0.], [0., 1.,0.], [0.,0.,1.] ]) # next state function
H = matrix([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]) # measurement function
R = matrix([[1., 0., 0.], [0.,1.,0.], [0., 0., 1.]]) # measurement uncertainty
I = matrix([[1., 0.,0.], [0., 1.,0.], [0.,0.,1.]]) # identity matrix
for i in os.listdir("/home/fatima/Downloads/thesis/HMP_Dataset/Climb_stairs"):
    if i.endswith('.txt'):
        files.append(i)






for j in range(len(files)-1):
    print "iterationh number"
    print j
    with open("/home/fatima/Downloads/thesis/HMP_Dataset/Climb_stairs/"+files[j]) as f:

        content = f.readlines()
        for e in range(len(content)-1):
            content1 = [z.strip() for z in content]
            content2 = content1[e].split(" ")
            content2[0] =-14.709 + (float(content2[0])/63)*(2*14.709);
            content2[2] =-14.709 + (float(content2[2])/63)*(2*14.709);
            content2[1] =-14.709 + (float(content2[1])/63)*(2*14.709);
            measurements =matrix([ [float(content2[0]) ], [float(content2[1])] , [float(content2[2])] ] )
            print measurements



            x,p=  kalman_filter(x, P)
            print x

Фильтр Калмана находится в конце кода.Я не добавил шума в предсказании матрицы состояний, так как не уверен, как это сделать. О наборе данных: Это набор данных акселерометра для ношения на запястье ADL.Всего существует 14 действий, и ускорение записывается в направлении x, y и z.Значения ускорения варьируются от 0 до 63. Для расчета оно нормируется от -14,7 до +14,7. Вопрос: Мой вопрос заключается в том, направляюсь ли я в правильном направлении или нет.Вывод кажется правильным?Есть улучшения?

1 Ответ

0 голосов
/ 13 июня 2018

Код выглядит хорошо, и вы определенно движетесь в правильном направлении!

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

  • рассмотрите простые случаи, для которых вы знаетерешение, например H = I, P = sigma² * I и R = sigma'² * R. x должно стремиться к x предыдущего шага сигма предыдущего времени, стремящегося к нулю, и x должно стремиться к измерениям, если sigma стремится кв ноль.Или, если sigma = sigma ', тогда анализ фильтра Калмана должен быть средним по предыдущему состоянию, а измерения и P должны быть уменьшены вдвое.Возможно, вы захотите написать модульный тест для этих случаев.
  • убедитесь, что матрица P всегда остается симметричной и определена положительно (все собственные значения положительны)
  • Выполните альтернативный шаг обновления фильтра Калмана, см.Уравнение (28) на странице 39 документа http://modb.oce.ulg.ac.be/mediawiki/upload/Alex/AssimLecture/assim_lecture.pdf. По существу вы можете вычислить усиление Калмана также как:

K = inv (inv (P) + H '* inv (R)) H) H 'inv (R)

, где inv (P) - инверсия матрицы P. Оба должны быть равны с точностью до числовой точности.

Для шума модели выМожно просто добавить небольшую ковариационную матрицу в уравнение P = F * P * F '+ Q. Часто это матрица, пропорциональная единичной матрице.Если Q мало, измерение не повлияет на анализ после некоторых итераций.Если Q слишком велико, состояние модели x будет довольно шумным.

Некоторые замечания по кодированию:

  • Если measurements, H и R также являются параметрамифункция Kalman_filter, тогда ваша функция будет более легко переносимой в другой случай.
  • Вам известно о numpy для матричных операций?Он имеет обширную поддержку операций с матрицами и массивами и использует высоко оптимизированные библиотеки для вычислений.

Дайте мне знать, если это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...