Skip to content

Commit dbdb3f0

Browse files
committed
Add Kalman filter design documents
1 parent 0fb4f03 commit dbdb3f0

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SparkFun OTOS Kalman Filter Design
2+
3+
This folder contains the simulation that was used to design the Kalman filter for the [SparkFun Optical Tracking Odometry Sensor](https://www.sparkfun.com/products/24904). This script can be run in either [MATLAB](https://www.mathworks.com/products/matlab.html) (not tested) or [GNU Octave](https://octave.org/) (free). This is mainly provided for transparency on how the Kalman filter was designed and tuned, although you're welcome to play around with it and try to improve it!
4+
5+
The Kalman filter is what performs the sensor fusion between the acceleration measurements from the IMU (LSM6DSO), and the velocity measurements from the optical tracking sensor (PAA5160). The LSM6DSO acceleration measurements were measured to have a standard deviation of about 0.03 m/s^2, and the PAA5160 velocity measurements were measured to have a standard deviation of about 3 in/s (0.076 m/s).
6+
7+
The process noise covariance matrix Q was manually tuned to give a good balance of fast response times and low noise. The simulation also includes a handful of tests to verify robustness, such as loss of optical tracking data and acceleration offsets.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
################################################################################
2+
# Simulation setup
3+
################################################################################
4+
5+
# The OTOS velocity measurement was calculated to have a standard deviation of
6+
# about 3 inches per second
7+
velStd = 3 * .0254;
8+
9+
# The IMU acceleration measurement was calculated to have a standard deviation
10+
# of about 0.03 meters per second^2
11+
accStd = 0.03;
12+
13+
# The OTOS has 2.4ms loop period. With 1500 time steps, this simulates about 3.5
14+
# seconds
15+
dt = 0.0024;
16+
numSteps = 1500;
17+
t = 0 : dt : dt*(numSteps-1);
18+
19+
# Acceleration offset error
20+
accOffset = 0.5;
21+
22+
# Generate measurement noise
23+
velNoise = randn([numSteps, 1]) * velStd;
24+
accNoise = randn([numSteps, 1]) * accStd + accOffset;
25+
26+
# Pre-allocate arrays for position, velocity, and acceleration
27+
a = zeros([numSteps, 1]);
28+
v = zeros([numSteps, 1]);
29+
p = zeros([numSteps, 1]);
30+
31+
# Simulate acceleration at start and end
32+
a(t < .3) = 5;
33+
a(t > 3) = -5;
34+
35+
# Initialize Kalman filter state vector X:
36+
# [Position]
37+
# [Velocoty]
38+
# [Accleration]
39+
X = zeros([3,1]);
40+
41+
# Initialize Kalman filter state transition model F (X_{k+1} = F * X_k):
42+
# [P_{k+1}] = P_k + V_k * dt = [1 dt 0] [P_k]
43+
# [V_{k+1}] = V_k + A_k * dt = [0 1 dt] * [V_k]
44+
# [A_{k+1}] = A_k = [0 0 1] [A_k]
45+
F = eye(3);
46+
F(1,2) = dt;
47+
F(2,3) = dt;
48+
49+
# Initialize Kalman filter state estimate covariance matrix P:
50+
P = eye(3)*0;
51+
52+
# Initialize Kalman filter observation models H (Z_k = H * X_k):
53+
# Z_{vk} = [0 1 0] * [P_k]
54+
# [V_k]
55+
# [A_k]
56+
# Z_{ak} = [0 0 1] * [P_k]
57+
# [V_k]
58+
# [A_k]
59+
Hv = [0 1 0];
60+
Ha = [0 0 1];
61+
62+
# Initialize Kalman filter observation noise variance elements R:
63+
Rv = velStd^2;
64+
Ra = accStd^2;
65+
66+
# Initialize Kalman filter process noise covariance matrix Q:
67+
Q = eye(3);
68+
Q(1,1) = 1e-8;
69+
Q(2,2) = 1e-6;
70+
Q(3,3) = 1e-4;
71+
72+
################################################################################
73+
# Simulation loop
74+
################################################################################
75+
76+
# Loop through all time steps
77+
for i = 1:numSteps
78+
79+
# Physics time step, calculate next true velocity and position
80+
v(i+1) = v(i) + a(i) * dt;
81+
p(i+1) = p(i) + v(i) * dt;
82+
83+
# Sensor measurement
84+
za = [a(i) + accNoise(i)];
85+
zv = [v(i) + velNoise(i)];
86+
87+
# Simulate temporary loss of optical data
88+
if(i >= 500 && i < 700)
89+
zv = 0;
90+
end
91+
92+
% Kalman filter prediction step
93+
X = F*X;
94+
P = F*P*F' + Q;
95+
96+
# Kalman filter measurement update (accleration)
97+
y = za - Ha*X;
98+
S = Ha*P*Ha' + Ra;
99+
K = P*Ha'*inv(S);
100+
X = X + K*y;
101+
P = (eye(3) - K*Ha)*P;
102+
103+
# Ignore velocity measurement if measurement is very different from estimate
104+
if(abs(zv - X(2)) < .5)
105+
# Kalman filter measurement update (velocity)
106+
y = zv - Hv*X;
107+
S = Hv*P*Hv' + Rv;
108+
K = P*Hv'*inv(S);
109+
X = X + K*y;
110+
P = (eye(3) - K*Hv)*P;
111+
else
112+
# Log velocity for plots to know where measurements are being ignored
113+
v(i) = 0;
114+
end
115+
116+
# Log Kalman filter state and diagonal elements of covariance matrix
117+
ps(i) = X(1);
118+
pvs(i) = P(1,1);
119+
vs(i) = X(2);
120+
vvs(i) = P(2,2);
121+
as(i) = X(3);
122+
avs(i) = P(3,3);
123+
end
124+
125+
# Remove last couple elements of these arrays to get sizes correct for plots
126+
v(end) = [];
127+
p(end) = [];
128+
129+
################################################################################
130+
# Output plots
131+
################################################################################
132+
133+
# Use Figure 1 and clear it
134+
figure 1
135+
clf
136+
137+
# Position subplot
138+
subplot(3,1,1)
139+
hold on
140+
grid on
141+
142+
# True position
143+
plot(t, p, 'g')
144+
145+
# Estimated position and standard deviation
146+
plot(t, ps, 'b')
147+
plot(t, ps - sqrt(pvs), 'r')
148+
plot(t, ps + sqrt(pvs), 'r')
149+
150+
# Velocity subplot
151+
subplot(3,1,2)
152+
hold on
153+
grid on
154+
155+
# True velocity and measured velocity
156+
plot(t, v, 'g')
157+
plot(t, v + velNoise, 'k')
158+
159+
# Estimated velocity and standard deviation
160+
plot(t, vs, 'b')
161+
plot(t, vs - 2*sqrt(vvs), 'r')
162+
plot(t, vs + 2*sqrt(vvs), 'r')
163+
164+
# Acceleration subplot
165+
subplot(3,1,3)
166+
hold on
167+
grid on
168+
169+
# True acceleration and measured velocity
170+
plot(t, a, 'g')
171+
plot(t, a + accNoise, 'k')
172+
173+
# Estimated acceleration and standard deviation
174+
plot(t, as, 'b')
175+
plot(t, as - 2*sqrt(avs), 'r')
176+
plot(t, as + 2*sqrt(avs), 'r')
177+

0 commit comments

Comments
 (0)