Состояние ошибки Kalman Filter из MATLAB в Python - PullRequest
6 голосов
/ 05 июня 2019

Я пытаюсь воспроизвести алгоритм, объясненный здесь в Python, но я сталкиваюсь с некоторыми проблемами со странным ростом некоторых параметров. Следующее - моя попытка. Обратите внимание, что get_ang() и get_acc() возвращают угловую скорость и ускорение по оси [x, y, z] в градусах / с (но я преобразовываю эти данные в радиан / с ) и м / с ^ 2 соответственно):

import numpy as np
import quaternion
from utils import get_ang, get_acc

#utils
Z=np.zeros([3,3])
I=np.eye(3)
EARTH_GRAVITY_MS2 = -9.80665

#sample parameters
N=1        #DecimationFactor
fs=10      #SampleRate

#noise parameters
beta=3.0462e-13      #GyroscopeDriftNoise
eta=9.1385e-5       #GyroscopeNoise
kappa=N/fs  #DecimationFactor/SampleRate
lamb=0.00019247      #AccelerometerNoise
nu=0.5        #LinearAccelerationDecayFactor
csi=0.0096236       #LinearAccelerationNoise

#other parameters initialization
lin_acc_prior=np.zeros(3)
gyro_offset=np.zeros([1,3])
Q=np.diag([0.000006092348396, 0.000006092348396, 0.000006092348396, 0.000076154354947,0.000076154354947, 0.000076154354947,0.009623610000000, 0.009623610000000, 0.009623610000000])
R=(lamb+csi+(kappa**2)*(beta+eta))*I
P=Q
q=quaternion.quaternion(1,0,0,0)                     


while(1):

    """----------------------------------------------------------Model----------------------------------------------------------"""

    """Predict orientation (q-)"""
    gyro_readings=np.array(np.radians([get_ang()])) #rad/s

    for i in range(N-1):
        gyro_readings=np.append(gyro_readings,np.radians([get_ang()]),axis=0)

    delta_phi=(gyro_readings-gyro_offset)/fs    #rad/s  
    delta_q=quaternion.from_rotation_vector(delta_phi)
    q=q*np.prod(delta_q)

    """Estimate gravity from orientation (g)"""
    r_prior=quat2rotm(q) 
    g=r_prior[:,2:3].transpose()*(-EARTH_GRAVITY_MS2)   #m/s^2

    """Estimate gravity from acceleration (g_acc)"""
    accel_readings=get_acc() #m/s^2
    g_acc=accel_readings-lin_acc_prior #m/s^2


    """----------------------------------------------------------Error Model----------------------------------------------------------"""

    "Error Model (z)"
    z=g-g_acc #m/s^2

    """----------------------------------------------------------Kalman Equations----------------------------------------------------------"""

    """Observation model (H)"""
    gx=g[0,0]
    gy=g[0,1]
    gz=g[0,2]
    g_cross=np.array([[0, gz, -gy],[-gz, 0, gx],[gy, -gx, 0]])
    H=np.block([g_cross, -kappa*g_cross, I])

    """Innovation covariance (S)""" 
    S=R+np.dot(H,np.dot(P,H.transpose()))

    """Kalman gain (K)"""
    K=np.dot(P,np.dot(H.transpose(),np.linalg.inv(S)))

    """Update error estimate covariance (P+)"""
    P=P-np.dot(K,np.dot(H,P))

    """Predict error estimate covariance (P-)"""
    D1=np.diag(np.diag(P[0:3,0:3]))   #first diagonal block P
    D2=np.diag(np.diag(P[3:6,3:6]))   #second diagonal block P
    D3=np.diag(np.diag(P[6:9,6:9]))   #third diagonal block P

    Q11=D1+kappa**2*D2+(beta+eta)*I
    Q12=(D2+beta*I)
    Q12[0,0]*=-kappa
    Q22=D2+beta*I
    Q33=nu**2*D3+csi*I

    Q=np.block([[Q11,Q12,Z],[Q12,Q22,Z],[Z,Z,Q33]])
    P=Q

    """Update posterior error (x)"""
    x=np.dot(K,z.transpose())

    """----------------------------------------------------------Correct----------------------------------------------------------"""

    """Estimate orientation (q+)"""
    theta=x[:3].transpose() #rad
    q=q*quaternion.from_rotation_vector(-theta)[0]




    """Estimate linear acceleration (lin_acc_prior)"""
    b=x[3:6].transpose() #rad/s
    lin_acc_prior = lin_acc_prior*nu-b

    """Estimate gyro offset (gyro_offset)"""
    a=x[6:].transpose()
    gyro_offset=gyro_offset-a

    """----------------------------------------------------------Compute Angular Velocity----------------------------------------------------------"""

    """Angular velocity (angular_velocity)"""
    angular_velocity=np.sum(gyro_readings,axis=0)/N-gyro_offset

Когда мой IMU остается неподвижным (get_ang возвращает значения около [0,0,0] и get_acc возвращает значения около [0,0,-9.8]), я наблюдаю аномальный рост gyro_offset (возможно, из-за немалого значения a), что приводит к в неправильном вычислении delta_phi, delta_q, q и т.д. в неправильной оценке g и z.

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

Не могли бы вы помочь мне найти то, что мне не хватает?

P.S. Можно воспроизвести мою настройку установки на каждом шаге:

gyro_readings=np.random.normal(0,1,[1,3])/50 
accel_readings=np.array([0,0,-9.8])+np.random.normal(0,1,[3])/50

Ответы [ 2 ]

2 голосов
/ 12 июня 2019

В ссылке, которую вы указали в уравнениях Калмана, транспонирование S инвертируется для вычисления коэффициента усиления Калмана.
Похоже, вы не брали транспонирование S перед инвертированием.в строке:

K=np.dot(P,np.dot(H.transpose(),np.linalg.inv(S)))

должно быть

K=np.dot(P,np.dot(H.transpose(),np.linalg.inv(S.transpose())))
1 голос
/ 17 июня 2019

Я вижу следующие проблемы в вашем коде:

  • при расчете g из матрицы ориентации, которую вы умножили на гравитацию Земли.В результате ваша ошибка наблюдения и, следовательно, инновация измеряются в m/s2.Согласно документации для фильтра нужна ошибка в units g.Поэтому я бы лучше разделил g_acc на гравитацию Земли.

  • при доступе к вектору состояний x вы использовали элементы 4: 6 для оценки линейного ускорения, но эти элементыпринадлежат гироскопу смещения.То же самое относится и к элементам 7: 9, которые следует использовать для ускорения, а не для гироскопического смещения.

  • при генерации тестовых сигналов вы использовали некоторые параметры для нормального распределения длясимулировать шум.Я бы использовал те же параметры шума, которые вы использовали в реализации фильтра, иначе эти два уровня шума не будут соответствовать друг другу, и фильтр не сможет работать оптимально.

  • формула для Q, указанное на странице matlab, не соответствует исходной формуле в документации.Сравните уравнения 10.1.23 и 10.1.24.Они включают элементы P [0,2:3,5] и [3,5:3,5] соответственно.В вашем случае это означает, что подматрица Q12 неверна.

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

Не могли бы вы попробовать и опубликовать некоторые графики?

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