Kalman Filter Velocity Estimation Example


% constants

T = 0.01;

% set up desired trajectory

i = 1;

for t = 0:T:0.1
posd(i) = 0;
veld(i) = 0;
accd(i) = 0;
i = i + 1;
end

for t = 0:T:1.0
[p,v,a] = minjerk(t);
posd(i) = p;
veld(i) = v;
accd(i) = a;
i = i + 1;
end

for t = 0:T:0.4
[p,v,a] = minjerk(t);
posd(i) = 1;
veld(i) = 0;
accd(i) = 0;
i = i + 1;
end

% Show how differentiation blows up noise

mpos = posd + 0.001*randn(size(posd));
plot(mpos)                          
title('position with added noise')
xlabel('sample (100Hz)')

plot(diff(mpos)/T)                  
hold
plot(veld,'r')
hold
legend('differentiated position','true velocity')
xlabel('sample (100Hz)')
% Create idealized system to match filter assumptions
% state is (position, velocity)'
% We are assuming Q, R, and P0 to be diagonal

A = [ 1 T
      0 1 ]

B = [ 0
      T ]

C = [ 1 0 ]

% process variance
Q = [ 1e-6 0
      0 1e-5 ]

% sensor noise variance
R = [ 1e-5 ]

% initial state estimate variance
P0 = [ 1e-4 0
       0 1e-4 ]

% Create some data
state = [ sqrt(P0(1,1))*randn(1)
          sqrt(P0(2,2))*randn(1) ];
for i = 1:length(posd)
 postrue(i) = state(1);
 veltrue(i) = state(2);
 % simulate noisy measurement
 measurement(i) = C*state + sqrt(R(1,1))*randn(1);
 torque(i) = accd(i);
 process_noise = [ sqrt(Q(1,1))*randn(1)
                   sqrt(Q(2,2))*randn(1) ];
 state = A*state + B*accd(i) + process_noise;
end

% Design filter
% Note that we can design filter in advance of seeing the data.
Pm = P0;
for i = 1:1000
 % measurement step
 S = C*Pm*C' + R;
 K = Pm*C'*inv(S);
 Pp = Pm - K*C*Pm;
 % prediction step
 Pm = A*Pp*A' + Q;
end

% Run the filter to create example output
sem = [ 0 0 ]'
for i = 1:length(posd)
 % measurement step
 sep = sem + K*(measurement(i)-C*sem);
 pose(i) = sep(1);
 vele(i) = sep(2);	   
 % prediction step
 sem = A*sep + B*torque(i);
end

% Let's plot the Kalman filter output
ii = 1:length(pose);
plot(ii,pose,'b',ii,postrue,'r')
plot(ii,measurement,'b',ii,postrue,'r')
plot(ii,vele,'b',ii,veltrue,'r')
legend('KF velocity','true velocity')
xlabel('sample (100Hz)')
% Let's compare to directly filtering the output.
vel1 = diff( measurement )/T;
% get length right
vel1(length(veltrue)) = 0;
plot(ii,vel1,'b',ii,vele,'r')

% How well can we do with a first order filter?
[B,A]=butter(1,0.1);
vel2 = filter(B,A,vel1);
%plot(ii,vel2,'b',ii,veltrue,'m',ii,vele,'r')
plot(ii,vel2,'b',ii,veltrue,'r')
legend('1st order filtered velocity','true velocity')
xlabel('sample (100Hz)')


% How well can we do with a second order filter?
[B,A]=butter(2,0.1);
vel2 = filter(B,A,vel1);
% plot(ii,vel2,'b',ii,veltrue,'m',ii,vele,'r')
plot(ii,vel2,'b',ii,veltrue,'r')
legend('2nd order filtered velocity','true velocity')
xlabel('sample (100Hz)')


% How well can we do with a third order filter?
[B,A]=butter(3,0.1);
vel2 = filter(B,A,vel1);
% plot(ii,vel2,'b',ii,veltrue,'m',ii,vele,'r')
plot(ii,vel2,'b',ii,veltrue,'r')
legend('3rd order filtered velocity','true velocity')
xlabel('sample (100Hz)')