Skip to content
Snippets Groups Projects
Commit 27485144 authored by Erik Frisk's avatar Erik Frisk
Browse files

Updated slides for lecture 3 and added exercise skeletons

parent 92a30064
No related branches found
No related tags found
No related merge requests found
function xhat = EKF(model,init,data)
M = length(data.y);
P = init.P0;
n = numel(init.x0);
xhat = zeros(n,M); xhat(:,1) = init.x0;
for l=1:M-1
% Measurement update
xhat(:,l) = FILL_IN_CODE_HERE;
% Time update
xhat(:,l+1) = FILL_IN_CODE_HERE;
end
end
\ No newline at end of file
%% Cell type:code id: tags:
``` python
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
```
%% Cell type:code id: tags:
``` python
%matplotlib
sns.set(style='white', rc={'lines.linewidth': 0.75})
```
%% Output
Using matplotlib backend: Qt5Agg
%% Cell type:markdown id: tags:
# Simulate robot movement
%% Cell type:markdown id: tags:
Define discrete-time model
%% Cell type:code id: tags:
``` python
Tfinal = 20
Ts = 0.1
V = 3
x0 = [10, 10, 0] # Initial state
model = {}
model['f'] = lambda x, u, w: [x[0] + Ts*V*np.cos(x[2]), x[1] + Ts*V*np.sin(x[2]), x[2] + Ts*u]
model['h'] = lambda x, u: np.array([np.sqrt(x[0]**2 + x[1]**2), np.arctan2(x[1], x[0])])
```
%% Cell type:markdown id: tags:
Simulate robot movement and store results in a dictionary
%% Cell type:code id: tags:
``` python
t = np.arange(0, Tfinal, Ts)
N = len(t)
x = np.zeros((3, N))
x[:, 0] = x0
u = np.zeros((1, N))
u[0][np.logical_and(t >= 5, t < 10)] = -1
u[0][np.logical_and(t >= 10, t < 12)] = 0
u[0][np.logical_and(t >= 12, t < 15)] = 1
u[0][np.logical_and(t >= 15, t < 17)] = -1
for ti in np.arange(0, N-1):
x[:, ti+1] = model['f'](x[:, ti], u[0, ti], 0)
y0 = model['h'](x, u)
y = y0 + (np.diag([0.6, 0.03])@np.random.normal(0, 1, size=(2, N)))
data = {'t': t, 'x': x, 'u': u, 'y0': y0, 'y': y}
```
%% Cell type:markdown id: tags:
Plot nominal path
%% Cell type:code id: tags:
``` python
plt.figure(10, clear=True)
plt.plot(data['x'][0, :], data['x'][1, :])
plt.plot(data['x'][0, 0], data['x'][1, 0], 'bo')
plt.plot(data['x'][0, -1], data['x'][1, -1], 'rx')
plt.axis('square')
plt.xlabel('x')
plt.ylabel('y')
sns.despine()
```
%% Cell type:markdown id: tags:
Plot measurements
%% Cell type:code id: tags:
``` python
plt.figure(20, clear=True)
plt.subplot(2, 1, 1)
plt.plot(data['t'], data['y0'][0], 'b', lw=2)
plt.plot(data['t'], data['y'][0], 'r')
plt.xlabel('t [s]')
plt.ylabel('[m]')
plt.title('Range measurement')
sns.despine()
plt.subplot(2, 1, 2)
plt.plot(data['t'], data['y0'][1]*180/np.pi, 'b', lw=2)
plt.plot(data['t'], data['y'][1]*180/np.pi, 'r')
plt.xlabel('t [s]')
plt.ylabel('[deg]')
plt.title('Angle measurement')
sns.despine()
plt.tight_layout()
```
%% Cell type:markdown id: tags:
# Plot path computed from direct measurement
%% Cell type:markdown id: tags:
Compute position estimate by inverting the measurement equation
%% Cell type:code id: tags:
``` python
dist = data['y'][0]
ang = data['y'][1]
pos_hat_0 = np.row_stack((dist*np.cos(ang), dist*np.sin(ang)))
```
%% Cell type:markdown id: tags:
Plot the estimated path
%% Cell type:code id: tags:
``` python
plt.figure(30, clear=True)
plt.plot(data['x'][0], data['x'][1])
plt.plot(data['x'][0, 0], data['x'][1, 0], 'bo')
plt.plot(data['x'][0, -1], data['x'][1, -1], 'rx')
plt.plot(pos_hat_0[0], pos_hat_0[1], 'k')
plt.axis('square')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Direct computation from measurements')
sns.despine()
```
%% Cell type:markdown id: tags:
Plot position errors
%% Cell type:code id: tags:
``` python
plt.figure(31, clear=True)
plt.subplot(2, 1, 1)
plt.plot(data['t'], data['x'][0] - pos_hat_0[0])
plt.xlabel('t [s]');
plt.ylabel('[m]')
plt.title('x position error in direct computation');
sns.despine()
plt.subplot(2, 1, 2)
plt.plot(data['t'], data['x'][1] - pos_hat_0[1])
plt.xlabel('t [s]');
plt.ylabel('[m]')
plt.title('y position error in direct computation')
sns.despine()
plt.tight_layout()
```
%% Cell type:markdown id: tags:
# Extended Kalman Filter
%% Cell type:markdown id: tags:
Implement your Extended Kalman Filter below
%% Cell type:code id: tags:
``` python
def EKF(model, init, data):
"""Extended Kalman Filter
Input:
model - Dictionary with keys n, f, h, fx, hx, Q, R
init - Dictionary with x0, P0
"""
M = data['y'].shape[1] # Number of data points
P = init['P0'] # Initial covariance P_0|-1
n = model['n'] # Number of states
xhat = np.zeros((n, M)) # Prepare output array
xhat[:, 0] = init['x0'] # Initialize xhat
for l in range(0, M - 1):
pass
# Measurement update
# FILL IN YOUR CODE HERE
# Time update
# FILL IN YOUR CODE HERE
return xhat
```
%% Cell type:markdown id: tags:
Define model dictionary
%% Cell type:code id: tags:
``` python
modelEKF = {}
Q = None # YOUR CODE HERE: 3x3 numpy array matrix, Process noise covariance
R = None # YOUR CODE HERE: 2x2 numpy array matrix, Measurement noise covariance
modelEKF['n'] = 3
modelEKF['m'] = 2
modelEKF['Q'] = lambda x: Q
modelEKF['R'] = lambda x: R
modelEKF['f'] = lambda x, u: model['f'](x, u, 0)
modelEKF['h'] = lambda x, u: model['h'](x,u)
modelEKF['fx'] = lambda x, u: None # YOUR CODE HERE: return df/dx(x, u)
modelEKF['hx'] = lambda x, u: None # YOUR CODE HERE: return dh/dx(x, u)
```
%% Cell type:markdown id: tags:
Define inital conditions and run filter
%% Cell type:code id: tags:
``` python
init = {}
P0 = None # YOUR CODE HERE: 2x2 numpy array matrix, Initial estimate covariance
x0 = None # YOUR CODE HERE: numpy array with initial state (x0, y0, theta0)
init['x0'] = x0
init['P0'] = P0
xhatEKF = EKF(modelEKF, init, data)
```
%% Cell type:markdown id: tags:
Explore, investigate, and plot interesting results.
%% Cell type:code id: tags:
``` python
```
clear
close all
%% Simulate robot movement
Ts = 0.1;
V = 3;
model.f = @(x,u,w) [x(1) + Ts*V*cos(x(3));x(2) + Ts*V*sin(x(3));x(3) + Ts*u];
model.h = @(x,u) [sqrt(x(1,:).^2 + x(2,:).^2);atan(x(2,:)./x(1,:))];
x0 = [10;10;0];
Tfinal = 20;
data.t = (0:Ts:Tfinal);
N = numel(data.t);
data.x = zeros(3,N); data.x(:,1) = x0;
data.u = zeros(1,N);
data.u(data.t>=5 & data.t < 10) = -1;
data.u(data.t>=10 & data.t < 12) = 0;
data.u(data.t>=12 & data.t < 15) = 1;
data.u(data.t>=15 & data.t < 17) = -1;
for t=1:N-1
data.x(:,t+1) = model.f(data.x(:,t),data.u(t),0);
end
data.y0 = model.h(data.x, data.u);
data.y = data.y0 + diag([0.6,0.03])*randn(2,N);
%% Plot mobile robot path
figure(1)
plot( data.x(1,:)', data.x(2,:)' )
hold on
plot( data.x(1,1)', data.x(2,1)', 'bo', ...
data.x(1,end)', data.x(2,end)', 'rx');
hold off
axis([0 max(data.x(1,:))*1.1 0 max(data.x(2,:))*1.1]);
axis square
xlabel('x');
ylabel('y');
%% Plot measurements
figure(2)
subplot( 211 )
plot( data.t', [data.y(1,:)', data.y0(1,:)'])
xlabel('t [s]');
ylabel('[m]')
title('Range measurement');
box off
subplot( 212 )
plot( data.t', 180/pi*[data.y(2,:)', data.y0(2,:)'])
xlabel('t [s]');
ylabel('[deg]');
title('Angle measurement');
box off
%% Plot path from direct measurements
figure(3)
plot( data.x(1,:)', data.x(2,:)' )
hold on
plot( data.x(1,1)', data.x(2,1)', 'bo', ...
data.x(1,end)', data.x(2,end)', 'rx');
plot( (data.y(1,:).*cos(data.y(2,:)))', (data.y(1,:).*sin(data.y(2,:)))', 'k')
hold off
axis([0 max(data.x(1,:))*1.1 0 max(data.x(2,:))*1.1]);
axis square
xlabel('x');
ylabel('y');
title('Direct computation from measurements');
%% EKF estimation
modelEKF.f = @(x,u) FILL_IN_CODE_HERE;
modelEKF.h = @(x,u) FILL_IN_CODE_HERE;
modelEKF.fx = @(x,u) FILL_IN_CODE_HERE;
modelEKF.hx = @(x,u) FILL_IN_CODE_HERE;
modelEKF.Q = @(x) FILL_IN_CODE_HERE;
modelEKF.R = @(x) FILL_IN_CODE_HERE;
init.x0 = [10;5;0]; % Initial state estimate
init.P0 = FILL_IN_CODE_HERE; % Initial covariance
tic; xhatEKF = EKF(modelEKF,init,data); toc
%% Plot estimation results
figure(20)
plot( data.x(1,:)', data.x(2,:)', xhatEKF(1,:)', xhatEKF(2,:)' )
hold on
plot( data.x(1,1)', data.x(2,1)', 'bo', ...
data.x(1,end)', data.x(2,end)', 'rx');
hold off
axis([0 max(data.x(1,:))*1.1 0 max(data.x(2,:))*1.1]);
axis square
xlabel('x');
ylabel('y');
figure(21)
subplot( 211 )
plot( data.t', [xhatEKF(1,:)', data.x(1,:)'])
xlabel('t [s]');
ylabel('[m]')
title('x position estimation');
box off
subplot( 212 )
plot( data.t', xhatEKF(1,:)'-data.x(1,:)')
xlabel('t [s]');
ylabel('[m]')
title('Estimation error');
box off
figure(22)
subplot( 211 )
plot( data.t', [xhatEKF(2,:)', data.x(2,:)'])
xlabel('t [s]');
ylabel('[m]')
title('y position estimation');
box off
subplot( 212 )
plot( data.t', xhatEKF(2,:)'-data.x(2,:)')
xlabel('t [s]');
ylabel('[m]');
title('Estimation error');
box off
figure(23)
subplot( 211 )
plot( data.t', 180/pi*[xhatEKF(3,:)', data.x(3,:)'])
xlabel('t [s]');
ylabel('[deg]')
title('Heading estimation');
box off
subplot( 212 )
plot( data.t', 180/pi*(xhatEKF(3,:)'-data.x(3,:)'))
xlabel('t [s]');
ylabel('[deg]');
title('Estimation error');
box off
No preview for this file type
......@@ -44,7 +44,7 @@ A preliminary course schedule is as follows. Extra discussion seminars can be ad
| Discussion&nbsp;2 | March 26<br> 08:15 - 10:00 | Exercise discussion | [[30](https://doi.org/10.1016/j.automatica.2006.01.026)]||
| Lecture 3 | April 9<br> 08:15 - 10:00 | Lec 3a: Design methods, EKF and UKF, square root algorithms |[[3](https://doi.org/10.1115/1.3153059), [4](https://doi.org/10.1080/00207178708933870)], [[17;p. 55-82](http://urn.kb.se/resolve?urn=urn:nbn:se:liu:diva-11032)], [[22](https://www.fs.isy.liu.se/Edu/Courses/ObserversPhD/CourseMaterial/ArrayAlgorithm_Kailath.pdf), [9](https://doi.org/10.1109/TAC.1978.1101825), [14](https://doi.org/10.1109/JPROC.2003.823141), [23](https://doi.org/10.1109/TSP.2011.2172431)] | [slides](Lectures/slides_3.pdf)|
| Lecture 4 | April 16<br> 08:15 - 10:00| Lec 3b: Design methods, Particle filters |||
| Discussion&nbsp;3 | April 23<br> 08:15 - 10:00 | Exercise discussion|||
| Discussion&nbsp;3 | April 23<br> 08:15 - 10:00 | Exercise discussion| [code skeletons](Exercise/EKF_UKF)||
| Lecture 5 | April 30 <br> 08:15 - 10:00| Lec 4: Linearization, Lyapunov, High gain, Sliding mode, Moving Horizon Estimation |||
| Discussion&nbsp;4 | TBD | Exercise discussion |||
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment