Шаг обновления EKF-SLAM, Kalman Gain становится единичным

16

Я использую EKF для SLAM и у меня возникли проблемы с шагом обновления. Я получаю предупреждение, что K единственное число, rcondоценивает как near eps or NaN. Я думаю, что проследил проблему до инверсии Z. Есть ли способ рассчитать усиление Калмана, не инвертируя последний член?

Я не уверен на 100%, что это является причиной проблемы, поэтому я также поместил весь свой код здесь . Основной точкой входа является slam2d.

function [ x, P ] = expectation( x, P, lmk_idx, observation)
    % expectation
    r_idx = [1;2;3];
    rl = [r_idx; lmk_idx];

    [e, E_r, E_l] = project(x(r), x(lmk_idx)); 
    E_rl = [E_r E_l];
    E = E_rl * P(rl,rl) * E_rl';

    % innovation
    z = observation - e;
    Z = E;

    % Kalman gain
    K = P(:, rl) * E_rl' * Z^-1;

    % update
    x = x + K * z;
    P = P - K * Z * K';
end


function [y, Y_r, Y_p] = project(r, p)     
    [p_r, PR_r, PR_p] = toFrame2D(r, p);
    [y, Y_pr]   = scan(p_r);
    Y_r = Y_pr * PR_r;
    Y_p = Y_pr * PR_p;    
end


function [p_r, PR_r, PR_p] = toFrame2D(r , p)
    t = r(1:2);
    a = r(3);
    R = [cos(a) -sin(a) ; sin(a) cos(a)];
    p_r = R' * (p - t);
    px = p(1);
    py = p(2);
    x = t(1);
    y = t(2);
    PR_r = [...
        [ -cos(a), -sin(a),   cos(a)*(py - y) - sin(a)*(px - x)]
        [  sin(a), -cos(a), - cos(a)*(px - x) - sin(a)*(py - y)]];
    PR_p = R';    
end


function [y, Y_x] = scan(x)
    px = x(1);
    py = x(2);
    d = sqrt(px^2 + py^2);
    a = atan2(py, px);
    y = [d;a];
    Y_x =[...
    [     px/(px^2 + py^2)^(1/2), py/(px^2 + py^2)^(1/2)]
    [ -py/(px^2*(py^2/px^2 + 1)), 1/(px*(py^2/px^2 + 1))]];
end

Изменения: project(x(r), x(lmk))должно было project(x(r), x(lmk_idx))и теперь исправлено выше.

K выходит в единственном числе через некоторое время, но не сразу. Я думаю, что это около 20 секунд или около того. Я попробую изменения, предложенные @josh, когда вернусь домой сегодня вечером и опубликую результаты.

Обновление 1:

7 Икс 2(P(rl,rl) * E_rl') * inv( Z )5 Икс 2

K становится единичным через 4,82 секунды при измерениях при 50 Гц (241 шаг). Следуя приведенному здесь совету , я попробовал, K = (P(:, rl) * E_rl')/Zчто приводит к 250 шагам, прежде чем выдается предупреждение о единственном числе K

Это говорит мне, что проблема не в матричной инверсии, а в другом месте, которое вызывает проблему.

Обновление 2

Мой основной цикл (с объектом робота для хранения указателей x, P и наземных ориентиров):

for t = 0:sample_time:max_time
    P = robot.P;
    x = robot.x;
    lmks = robot.lmks;
    mapspace = robot.mapspace;

    u = robot.control(t);
    m = robot.measure(t);

    % Added to show eigenvalues at each step
    [val, vec] = eig(P);
    disp('***')
    disp(val)

    %%% Motion/Prediction
    [x, P] = predict(x, P, u, dt);

    %%% Correction
    lids = intersect(m(1,:), lmks(1,:));  % find all observed landmarks
    lids_new = setdiff(m(1,:), lmks(1,:));
    for lid = lids
        % expectation
        idx = find (lmks(1,:) == lid, 1);
        lmk = lmks(2:3, idx);
        mid = m(1,:) == lid;
        yi = m(2:3, mid);

        [x, P] = expectation(x, P, lmk, yi);
    end  %end correction

    %%% New Landmarks

    for id = 1:length(lids_new)
    % if id ~= 0
        lid = lids_new(id);
        lmk = find(lmks(1,:)==false, 1);
        s = find(mapspace, 2);
        if ~isempty(s)
            mapspace(s) = 0;
            lmks(:,lmk) = [lid; s'];
            yi = m(2:3,m(1,:) == lid);

            [x(s), L_r, L_y] = backProject(x(r), yi);

            P(s,:) = L_r * P(r,:);
            P(:,s) = [P(s,:)'; eye(2)];
            P(s,s) = L_r * P(r,r) * L_r';
        end
    end  % end new landmarks

    %%% Save State
    robot.save_state(x, P, mapspace, lmks)
    end  
end

В конце этого цикла я сохраняю x и P обратно в робота, поэтому я считаю, что я распространяю ковариацию через каждую итерацию.

10-2

бурундук
источник
1
Вы пропагандируете неопределенность? Собственные значения вашей ковариации становятся сколь угодно малыми или большими?
Джош Вандер Хук
1
То, что вы кладете в pastebin, это собственные векторы, а не собственные значения. сделайте это: [v, d] = eig (P). дисп (Diag (г)). или просто disp (eig (P)). Затем вы можете проверить следующие необходимые условия: все собственные значения> 0 на каждом шаге (они должны быть на практике). Увеличиваются ли они после распространения и уменьшаются после измерений / исправлений? По моему опыту, это обычно проблема.
Джош Вандер Хук
2
Что-то не так, если ваши собственные значения отрицательны. Когда вы инициализируете ориентир, какова неопределенность, связанная с его первой оценочной позицией?
Джош Вандер Хук
Наблюдение за парой. Когда первый ориентир инициализируется, он имеет ковариацию [5.8938, 3.0941; 3.0941, 2.9562]. Во-вторых, это ковариация [22.6630 -14.3822; -14.3822, 10.5484] Полная матрица здесь
Мунк

Ответы:

5

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

Вы пишете ковариационную матрицу инноваций следующим образом

E = jacobian measure * P * jacobian measure

Это может быть хорошо в теории, но что происходит, если ваш алгоритм эффективен, особенно если вы работаете над моделированием: неопределенности уменьшатся, особенно в направлениях вашего измерения. Так Eбудет стремиться [[0,0][0,0]].

Чтобы избежать этой проблемы, вы можете добавить измерительный шум, соответствующий неопределенности измерения, и ваша инновационная ковариация станет

E= Jac*P*Jac'+R

где R- ковариация шума измерения (диагональная матрица, где члены по диагонали - это квадраты стандартного отклонения шума). Если вы на самом деле не хотите учитывать шум, вы можете сделать его настолько маленьким, насколько захотите.

Я также добавляю, что ваше обновление ковариации мне кажется странным, классическая формула:

P=P - K * jacobian measure * P

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

Jaeger0
источник
Ах, старый трюк с солью ковариации.
Джош Вандер Крюк
1

KP(Nр+NL)×(Nр+NL)NрNL

K = P(:, rl) * E_rl' * Z^-1

который, я думаю, должен быть

(P(rl,rl) * E_rl') * inv(Z),

(см .: матричное деление ). Проверьте размер K.

Также: Пожалуйста, предоставьте немного больше информации: Идет ли Kединственное число сразу или только через некоторое время?

Это меня беспокоит: project(x(r), x(lmk));так lmkкак не определено.

Джош Вандер Хук
источник