Невозможно настроить размер входных и выходных массивов при выполнении фильтра Калмана с данными псевдодальностей - PullRequest
0 голосов
/ 30 октября 2019

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

Вот код:

#______________________________________________________________________
def h(Xs,X):
  """vecteurs d'entrée : position des satellites. Les 4 premiers seront utilisés dans un premier temps
      matrice de sortie : matrice[1,4] contenant les équations des pseudo distances """
  H= np.array([np.sqrt((Xs[:,0]-X[0])**2+(Xs[:,1]-X[1])**2+(Xs[:,2]-X[2])**2)+c*X[3]])
  print('calcul H ',H)
  return H
#______________________________________________________
def jh(Xs, X):
  """vecteur en entrée : 
  Xs : positions [x,y,z] des satellites
  X    : Vecteur d'état [x,y,z,Δt] calculé à l'étape précédente
  Matrice de sortie : matrice jacobienne du système d'équations cad jacobienne de dimension nbSat,4
  """
  #there will be some weirdo stuff here. It's because by just writing c at the end, the output would be [array[5],array[5],array[5],scalar(c)] now the output is what I need
  tmp = np.array(c)
  for i in range (1,len(Xs)):
    tmp=np.append(tmp,c)
  return np.array([(Xs[:,0]-X[0])/np.sqrt((Xs[:,0]-X[0])**2+(Xs[:,1]-X[1])**2+(Xs[:,2]-X[2])**2),
                    (Xs[:,1]-X[1])/np.sqrt((Xs[:,0]-X[0])**2+(Xs[:,1]-X[1])**2+(Xs[:,2]-X[2])**2),
                    (Xs[:,2]-X[2])/np.sqrt((Xs[:,0]-X[0])**2+(Xs[:,1]-X[1])**2+(Xs[:,2]-X[2])**2),
                    tmp[:]]).T
#______________________________________________________________________
def q(bruitB):
  """prend en argument les valeurs de la variance des données captées à l'instant
  retourne la matrice de covariance du bruit. Les bruits des différentes mesures ne sont pas corrélés entre eux"""
  return np.eye(len(bruitB))*bruitB
#______________________________________________________________________
def predictionX(F,X):
  """retourne la prédiction du vecteur d'état"""
  return F.dot(X)
#______________________________________________________________________
def predictionP(F,P,Q):
  """retourne la matrice de covariance de l'erreur prédite à partir de la précédente"""
  return F.dot(P).dot(F.T)+Q
#______________________________________________________________________
def gain(P,R,J):
  """retourne de le gain de Kalman"""
  """J0 =[[ 5.99092039e-01  6.89189981e-02  7.97708531e-01  2.99792458e+08]
          [ 2.18072986e-01 -2.54363881e-01  9.42201246e-01  2.99792458e+08]
          [ 6.12139719e-01  7.08011156e-01  3.52143675e-01  2.99792458e+08]
          [-2.54436938e-01 -7.13085558e-02  9.64456808e-01  2.99792458e+08]
          [-9.20738262e-02 -9.24447876e-01  3.70025047e-01  2.99792458e+08]]"""
  #return np.divide(P.dot(J),H.dot(P).dot(H.T)+R)
  return (P.dot(J)/J.dot(P).dot(J.T)+R)#(J.dot(P).dot(J.T)+R)
  #return np.matmul(P,J)/(np.matmul(np.matmul(J,P),J.T)+R)
#______________________________________________________________________
def estimationP(P,K,H):
  """retourne l'estimation' de l'erreur"""
  return P-K.dot(H).dot(P)
#______________________________________________________________________
def estimationX(X,K,H,y):
  """retourne l'estimation du vecteur d'état"""
  return X+K.dot(y-H.dot(X))
#______________________________________________________________________
x_e=np.array([0,0,0,0])
p_e=q(data[0].gps.bruitB)

Обратите внимание, что якобиантранспонируется в конце функции jh

"""matrice de transition"""
F=np.eye(4)
"""first state vector that I chose [x,y,z,Δt] """
X=np.array([0,0,0,0.00000001])#Δt = 10ns
"""model noise"""
Q=np.array([[1,0,0,0],
           [0,1,0,0],
           [0,0,0.01,0],
           [0,0,0,0.000000001]])
"""Covariance de l'erreur P"""
P=np.array([[2*2,0,0,0],
           [0,2*2,0,0],
           [0,0,3*3,0],
           [0,0,0,0.0000001]])
for iterator in data:
  #initialisations
  """pseudo-ranges"""
  y=iterator.gps.PRc
  """white noise of the pseudoranges"""
  R=iterator.gps.bruitB*np.eye(len(iterator.gps.bruitB))

  print(len(P))#4
  x_p=predictionX(F,X)
  p_p=predictionP(F,P,Q)
  print('x = ',p_p)
  H=jh(iterator.gps.Xsat,x_p)
  print('H = ',H)
  print('taille de H ', len(H))
  K=gain(p_p,R,H)

Существует три версии для возвращаемого значения функции усиления (усиление). Первые две версии дают эту ошибку:

ValueError: формы (4,4) и (5,4) не выровнены: 4 (dim 1)! = 5 (dim 0)

Последний делает это:

ValueError: matmul: входной операнд 1 имеет несоответствие в своем основном измерении 0, с сигнатурой gufunc (n?, K), (k,m?) -> (n?, m?) (размер 5 отличается от 4)

Я думаю, с матрицей все в порядке, поэтому возникла бы проблема с кодом при использовании np.array. Действительно, число столбцов Иакова и число строк P одинаковы: 4. Таким образом, умножение должно быть возможным ...

[править]

Я думаю, что проблема в том, что я неправильно понимаю Калмана в этом деле. Я пытаюсь оценить положение x, y, z по псевдодальностям спутников nsat.

Но поскольку мы используем псевдодальности, я не понимаю, как мы связываем псевдодальности и x, y, z, t. Вот шаги, которые я думаю, что я делаю, и где я не понимаю

  • X - это матрица состояний, которая содержит [X, Y, Z, Δt] из предыдущегошаг.

  • F - это матрица перехода, которая представляет собой identity4, поскольку нам не требуется вывод переменных.

  • P - ковариацияМатрица ошибки, вычисленная на предыдущем шаге. Размер также равен 4 * 4, так как это ошибка между вычисленным [x, y, z, Δt] и реальной позицией. Тогда ничего не делать с псевдодальностями.

  • Q - матрица покрытия шума. Но это шум значения псевдодальности, поэтому его размер равен [nsat, nsat], верно? Или это шум реальной оценочной позиции? Но как я могу вычислить это, если у меня есть стандартная ошибка для каждого псевдодальности?

, из которой мы вычисляем:

  • предсказаниеследующие переменные состояния Xp = F, умноженные на X

  • предсказание ошибки Pp = FP Ftransposed + Q, но Q неправильного размера ...

мы вычисляем коэффициент усиления Калмана K

и вычисляем новую позицию:

  • X = Xp + K ... подождите, мы должны использовать данныеот датчика здесь, но они псевдодальности. Как мы можем связать псевдодальности и декартову позицию внутри фильтра Калмана?

  • P = Pp - KH Pp

Ответы [ 2 ]

0 голосов
/ 09 ноября 2019

Хорошо, это работает, основная ошибка была в этой строке

return (P.dot(J)/J.dot(P).dot(J.T)+R)#(J.dot(P).dot(J.T)+R)

Мы не можем просто разделить матрицу, мы должны умножить ее на инвертированную матрицу, чтобы это работало:

return P.dot(J.T).dot(np.linalg.pinv(J.dot(P).dot(J.T)+R)) для расчета усиления

0 голосов
/ 30 октября 2019

Он должен работать с различным числом спутников без проблем.

Немного сложно отладить ваш код без каких-либо данных. Я реализовал оценку псевдодальности в MATLAB, используя простой генератор трассировки (предполагая, что мир в области XYZ просто плоский). Количество спутников изменяется от 4 до 14 в каждой итерации.

Пожалуйста, посмотрите на мой код. Может быть, вы найдете несколько подсказок. Я постараюсь пройтись по вашей реализации и найти некоторые несоответствия.

function [] = main()

    c = 299792458; % speed of light

    [t, PosRef, PosSatArr, clockBias] = generateData(c);

    n = numel(t);

    % state
    X = zeros(4, 1); % X, Y, Z, clockBias

    % transition matrix
    F = eye(4, 4); 

    % covariance matrix
    P = diag([100^2 100^2 100^2 1]);

    % system noise
    Q = diag([60 60 60 1e-12]);

    sigmaR2 = 1e6;

    X_arr = zeros(n, 4);

    for i = 1:n

        % setting the measurement
        y = PosSatArr(i).PosSat;

        [NSat, ~] = size(y);

        R = diag(sigmaR2*ones(1, NSat));

        [X, P] = prediction(X, P, Q, F); %Prediction

        [X, P, ~] = update(X, P, y, R, c, NSat); %Update

        X_arr(i, :) = X';
    end  

    figure;
    subplot(4,1,1);
    plot([t(1) t(end)], [PosRef(1) PosRef(1)], '-');
    hold on;
    plot(t, X_arr(:, 1));
    hold off;
    grid minor;
    title('Position X');
    legend('Ground Truth', 'Estimation');

    subplot(4,1,2);
    plot([t(1) t(end)], [PosRef(2) PosRef(2)], '-');
    hold on;
    plot(t, X_arr(:, 2));
    hold off;
    grid minor;
    title('Position Y');
    legend('Ground Truth', 'Estimation');

    subplot(4,1,3);
    plot([t(1) t(end)], [PosRef(3) PosRef(3)], '-');
    hold on;
    plot(t, X_arr(:, 3));
    hold off;
    grid minor;
    title('Position Z');
    legend('Ground Truth', 'Estimation');    

    subplot(4,1,4);
    plot(t, clockBias, '-');
    hold on;
    plot(t, X_arr(:, 4));
    hold off;
    grid minor;    
    title('Clock Bias');
    legend('Ground Truth', 'Estimation');
end

function h = geth(X, y, c)
    h = vecnorm(y(:, 1:3) - X(1:3)', 2, 2) + c*X(4); 
end

function H = getJacobi(X, y, c, NSat)
    ro = vecnorm(y(:, 1:3) - X(1:3)', 2, 2); %pseudoranges from the current state and the satellite positions
    H = [-(y(:, 1:3) - X(1:3)')./ro c*ones(NSat, 1)];
end

function [t, PosRef, PosSatArr, clockBias] = generateData(c)
    t=1:1000;

    clockBias = 0.00001 + 0.00000001*t;

    PosRef = [randn(2,1); 0]*1e4;

    PosSatArr = struct;

    for i=1:numel(t)
        NSat = 4 + randi(10);
        PosSat = [randn(NSat, 3) zeros(NSat, 1)]*1e4; % X, Y, Z, PseudoRange
        %PosSat(:, 3) = abs(PosSat(:, 3)); % if you want your Z to be positive

        Range = vecnorm(PosSat(:, 1:3) - PosRef', 2, 2); 
        PosSat(:, 4) = Range + c*clockBias(i); 

        PosSatArr(i).PosSat = PosSat;
    end
end

function [X, P] = prediction(X, P, Q, F)
    X = F*X;
    P = F*P*F' + Q;
end

function [X, P, K] = update(X, P, y, R, c, NSat)

    h = geth(X, y, c);
    H = getJacobi(X, y, c, NSat);    

    Inn = y(:, 4) - h;
    S = H*P*H' + R;
    K = P*H'/S;

    X = X + K*Inn;
    P = P - K*H*P;
end

Оценщик работает нормально: GPS pseudo range estimator for positioning in a 3D space

Кстати, я думаю, что тамошибка в вашей матрице ЯкобиПоследний элемент должен быть c.

ОБНОВЛЕНИЕ

Вот некоторые формулы для фильтра Калмана:

Вектор состояния

State vector for the pseudorange estimator

Матрица перехода является единичной матрицей, поскольку мы не меняем вектор состояния на этапе прогнозирования

F matrix

Q isматрица шумов системы. Он имеет размер [n x n], где n - размер вектора состояния. Он показывает, сколько неопределенности добавляется к состоянию на этапе прогнозирования. Чем меньше значения, тем быстрее сходится фильтр (но, возможно, к неправильному состоянию).

Q matrix

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

Satillite information received by the receiver

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

Измерение y (в смысле Калмана) состоит только из псевдодальностей:

Measurement vector with pseudoranges

Функция измерения отображает вектор состояния на измерение. Он говорит вам, что измерение будет выглядеть в соответствии с текущим оценочным состоянием. Это связь между псевдодальностями и расчетным состоянием.

measurement function

Матрица Якоби H необходимо рассчитать для линеаризации нелинейной функции измеренияh:

Jacobi matrix

Шум псевдодальностей сохраняется в матрице R (не в Q):

pseudorange noise

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