multi-sensors fusion using Kalman filter - kalman-filter

I need to use the Kalman filter to fuse multi-sensors positions for gaussian measurement (for example 4 positions as the input of the filter and 1 position as output). It is possible to help me with some examples or tutorials because all the examples I found are related to the estimation of the positions?

OPTION 1
Weighted Avarage
In this case you don't need to implement a real Kalman Filter. You just can use the signal variances to calculate the weights and then calculate the weighted avarage of the inputs. The weights can be found as an inverse of the variances.
So if you have two signals S1 and S2 with variances V1 and V2, then the fused result would be
A fusion example can be seen on the next plot.
I simulated two signals. The variance of the second signal changes over the time. As long as it's smaller than the variance of the first signal the fused result is close to the second signal. It is not the case when the variance of the second signal is too high.
OPTION 2
Kalman Filter with Multiple Update Steps
The classical Kalman Filter uses prediction and update steps in a loop:
prediction
update
prediction
update
...
In your case you have 4 independent measurements, so you can use those readings after each other in separate update steps:
prediction
update 1
update 2
update 3
update 4
prediction
update 1
...
A very nice point is that the order of those updates does not matter! You can use updates 1,2,3,4 or 3,2,4,1. In both cases you should get the same fused output.
Compared to the first option you have following pros:
You have a variance propogation
You have the system noise matrix Q,
so you can control the smoothness of the fused output
Here is my matlab code:
function [] = main()
% time step
dt = 0.01;
t=(0:dt:2)';
n = numel(t);
%ground truth
signal = sin(t)+t;
% state matrix
X = zeros(2,1);
% covariance matrix
P = zeros(2,2);
% kalman filter output through the whole time
X_arr = zeros(n, 2);
% system noise
Q = [0.04 0;
0 1];
% transition matrix
F = [1 dt;
0 1];
% observation matrix
H = [1 0];
% variance of signal 1
s1_var = 0.08*ones(size(t));
s1 = generate_signal(signal, s1_var);
% variance of signal 2
s2_var = 0.01*(cos(8*t)+10*t);
s2 = generate_signal(signal, s2_var);
% variance of signal 3
s3_var = 0.02*(sin(2*t)+2);
s3 = generate_signal(signal, s3_var);
% variance of signal 4
s4_var = 0.06*ones(size(t));
s4 = generate_signal(signal, s4_var);
% fusion
for i = 1:n
if (i == 1)
[X, P] = init_kalman(X, s1(i, 1)); % initialize the state using the 1st sensor
else
[X, P] = prediction(X, P, Q, F);
[X, P] = update(X, P, s1(i, 1), s1(i, 2), H);
[X, P] = update(X, P, s2(i, 1), s2(i, 2), H);
[X, P] = update(X, P, s3(i, 1), s3(i, 2), H);
[X, P] = update(X, P, s4(i, 1), s4(i, 2), H);
end
X_arr(i, :) = X;
end
plot(t, signal, 'LineWidth', 4);
hold on;
plot(t, s1(:, 1), '--', 'LineWidth', 1);
plot(t, s2(:, 1), '--', 'LineWidth', 1);
plot(t, s3(:, 1), '--', 'LineWidth', 1);
plot(t, s4(:, 1), '--', 'LineWidth', 1);
plot(t, X_arr(:, 1), 'LineWidth', 4);
hold off;
grid on;
legend('Ground Truth', 'Sensor Input 1', 'Sensor Input 2', 'Sensor Input 3', 'Sensor Input 4', 'Fused Output');
end
function [s] = generate_signal(signal, var)
noise = randn(size(signal)).*sqrt(var);
s(:, 1) = signal + noise;
s(:, 2) = var;
end
function [X, P] = init_kalman(X, y)
X(1,1) = y;
X(2,1) = 0;
P = [100 0;
0 300];
end
function [X, P] = prediction(X, P, Q, F)
X = F*X;
P = F*P*F' + Q;
end
function [X, P] = update(X, P, y, R, H)
Inn = y - H*X;
S = H*P*H' + R;
K = P*H'/S;
X = X + K*Inn;
P = P - K*H*P;
end
And here is the result:

Related

I tried 'interp2' to measure the intensity of a line in octave but I have a method error, any suggestions

imshow(matrix(:,:,1))
%identify axes
[x y] = ginput(2);
% preallocate matrices
cog = zeros(size(matrix,3),1);
%cog
% loop start
for i = 1:size(maytrix,3)
I = matrix(:,:,i);
%n = ceil(norm([diff(x), diff(y)])); % A rough estimation of number of points
test = interp2(I, 2, linspace(x(1), x(2),n), linspace(y(1), y(2),n));
%test = round(test);
cog(i) = sum((1:length(test)).*test')/sum(test);
% loop end
end
scog = (cog - min(cog)) / (max(cog) - min(cog));
Here's a toy example to get you started.
% Create a 100x100x100 3D matrix with a certain pattern
% Smooth pattern:
matrix = [1 : 100] .' * [1 : 100];
matrix = matrix(:) * [1 : 100];
matrix = reshape( matrix, 100, 100, 100 );
% Alternatively, try a random matrix:
%matrix = randn(100,100,100);
Endpoints = randi( [1, 100], [3, 2] ); % Randomly get 2 3D points within matrix
Numpoints = max( abs( diff( Endpoints, 1, 2 ) ) ); % Choose width of widest dimension
% Create a line in 3D space (containing N points) going from one Endpoint to the other.
Linepoints = [ linspace( Endpoints(1, 1), Endpoints(1, 2), Numpoints );
linspace( Endpoints(2, 1), Endpoints(2, 2), Numpoints );
linspace( Endpoints(3, 1), Endpoints(3, 2), Numpoints ); ];
InterpolatedIntensities = interp3( 1:100, 1:100, 1:100, matrix, Linepoints(1, :), Linepoints(2, :), Linepoints(3, :) );
plot( InterpolatedIntensities );

Normalization of histogram in Octave by hist(y,x,norm)?

I was trying to normalize the histogram of uniformly distributed random numbers in the interval [0,10]. In octave documentation I came across the function as hist(y, x, norm) which I applied and got the histogram normalized in the interval. The code that I used is
m=input('Number of random numbers required = ')
v=10*rand(1,m)
hist(v,10,1,"facecolor", "b", "edgecolor", "w",'linewidth',1.5);
title(['Normalized histogram for ' num2str(m) ' uniformly distributed random numbers'])
set(gca,'fontsize',30)
but as I changed the bin number to 50 then for getting the normalized histogram I had to change the third argument of hist() to 5.
Here is the code
m=input('Number of random numbers required = ')
v=10*rand(1,m)
hist(v,50,5,"facecolor", "b", "edgecolor", "w",'linewidth',1.5);
title(['Normalized histogram for ' num2str(m) ' uniformly distributed random numbers'])
set(gca,'fontsize',30)
then only it produced a normalized histogram as the previous one. What's actually happening here? Why I need to change the norm argument to 5 when I changed the bin number to 50?
When I tried to normalize the gaussian distribution using same method I got it wrong ?( I had to do it write all the algorithm to get the correct answer) so I would like to know how the norm argument works ?
here is the code that i tried for gaussian distribution which yielded the wrong result
m=input('Number of random numbers required = ');
v=randn(1,m)
[f,x]=hist(v,50);
hold on;
g = 1 / sqrt(2 * pi) * exp(-0.5 * x .^ 2);
plot(x, g, 'r','linewidth',1.5);
hist(v,50,5,"facecolor", "b", "edgecolor", "w",'linewidth',1.5);
title(['Normalized histogram for ' num2str(m) ' gaussian distributed random numbers'])
set(gca,'fontsize',30)
The reason is because you are trying to compare a frequency histogram with a frequency DENSITY function. Which means you have not taken the effect of the bin width into account.
In other words, if we consider each value in v, which represents histogram height, to be the product of the bin width w and a 'density' value h such that v = h * w at each element, then your normalisation says that sum(v) = 1, and therefore sum(h * w) = w * sum(h) = 1.
Therefore in order to obtain a valid 'density' function from your current values, you need to divide your current values in v by the (constant) bin width w, to obtain the density value h.
Compare with this code:
m = 5000;
v = randn( m, 1 );
g = 1 / sqrt(2 * pi) * exp( -0.5 * x .^ 2 );
[nn,xx] = hist( v, 50, 1, 'facecolor', 'b', 'edgecolor', 'w', 'linewidth', 1.5);
nn = nn / diff(xx)(1);
bar( xx, nn, 0.5, 'facecolor', [0, 0.5, 1], 'edgecolor', [0, 0.25, 0.5] );
hold on;
plot(x, g, 'r','linewidth', 3);
title({ ['Normalized histogram for ', num2str(m)], ' gaussian distributed random numbers'})
set(gca,'fontsize',20)
hold off

Interpolation in n dimensions

I'm trying to use interpn function and probing even a simple 2D example I cannot reproduce the interpolation value FUN(xi,yi) compared to the matrix grid value i.e. FUN(1,11) != 4.
A = [13,-1,12;5,4,3;1,6,2];
x = [0,1,2];
y = [10,11,12];
xi = linspace (min (x), max (x), 30);
yi = linspace (min (y), max (y), 60);
FUN = interpn (x, y, A, xi, yi, "spline");
disp("value(1,11) = "), FUN(1, 11)

Silhouette function gives me an error: element number 2 undefined in return list

I am trying to check the performance of k-means with the silhouette function but I am getting an error.
I am calling the function like this [out1,out2] = silhouette(normalized, idx); or [out1,out2] = silhouette(normalized, idx, 'cosine');
The definition of the function is function [si, h] = silhouette(X, clust, metric)
I expect to take a number between -1,+1 but instead of that I am getting error: element number 2 undefined in return list.
My code for the silhouette function:
function [si, h] = silhouette(X, clust, metric)
% Nan Zhou
% Code Matlab 'silhouette' into Octave function
% Sichuan University, Macquarie University
% zhnanx#gmail.com
% input parameters
% X, n-by-p data matrix
% - Rows of X correspond to points, columns correspond to coordinates.
% clust, clusters defined for X; n-by-1 vector
% metric, e.g. Euclidean, sqEuclidean, cosine
% return values
% si, silhouettte values, n-by-1 vector
% h, figure handle, waiting to be solved in the future
% algorithm reference
% - Peter J. Rousseeuw (1987)
% - Silhouettes: a Graphical Aid to the Interpretation and Validation of Cluster Analysis
% - doi:10.1016/0377-0427(87)90125-7
% check size
if (size(X, 1) != size(clust, 1))
error("First dimension of X <%d> doesn't match that of clust <%d>",...
size(X, 1), size(clust, 1));
endif
% check metric
if (! exist('metric', 'var'))
metric = 'sqEuclidean';
endif
%%%% function set
function [dist] = EuclideanDist(x, y)
dist = sqrt((x - y) * (x - y)');
endfunction
function [dist] = sqEuclideanDist(x, y)
dist = (x - y) * (x - y)';
endfunction
function [dist] = cosineDist(x, y)
cosineValue = dot(x,y)/(norm(x,2)*norm(y,2));
dist = 1 - cosineValue;
endfunction
%%% end function set
% calculating
si = zeros(size(X, 1), 1);
%h
%calculate values of si one by one
for iii = 1:length(si)
%%% distance of iii to all others
iii2all = zeros(size(X, 1), 1);
for jjj = 1:size(X, 1)
switch (metric)
case 'Euclidean'
iii2all(jjj) = EuclideanDist(X(iii, :), X(jjj, :));
case 'sqEuclidean'
iii2all(jjj) = sqEuclideanDist(X(iii, :), X(jjj, :));
case 'cosine'
iii2all(jjj) = cosineDist(X(iii, :), X(jjj, :));
otherwise
error('Invalid metric.');
endswitch
endfor
%%% end distance to all
%%% allocate values to clusters
clusterIDs = unique(clust); % eg [1; 2; 3; 4]
groupedValues = {};
for jjj = 1:length(clusterIDs)
groupedValues{clusterIDs(jjj)} = [iii2all(clust == clusterIDs(jjj))];
endfor
%%% end allocation
%%% calculate a(i)
% dist of object iii to all other objects in the same cluster
a_iii = groupedValues{clust(iii)};
% average distance of iii to all other objects in the same cluster
a_i = sum(a_iii) / (size(a_iii, 1) - 1);
%disp(a_i);pause;
%%% end a(i)
%%% calculate b(i)
clusterIDs_new = clusterIDs;
% remove the cluster iii in
clusterIDs_new(find(clusterIDs_new == clust(iii))) = [];
% average distance of iii to all objects of another cluster
a_iii_2others = zeros(length(clusterIDs_new), 1);
for jjj = 1:length(clusterIDs_new)
values_another = groupedValues{clusterIDs_new(jjj)};
a_iii_2others(jjj) = mean(values_another);
endfor
b_i = min(a_iii_2others);
%disp(b_i);disp('---');pause;
%%% end b(i)
%%% calculate s(i)
si(iii) = (b_i - a_i) / max([a_i; b_i]);
%%% end s(i)
endfor
end

create a vector with size x and value f(x) in octave

I have to generate a dataset of N data points, which are defined as t_n=f(x_n)+e, where e is drawn from normal distribution and f(x) is a nonlinear function.
For example, i have a function f(x)=x²+2x+10, how can i fill a vector v, such:
x = 1:1:100;
v = create(f(x)+normrnd(0,1),x);
Thank you
There are many methods to do this. Here I show you how to do it with anonymous functions http://www.gnu.org/software/octave/doc/v4.0.1/Anonymous-Functions.html#Anonymous-Functions
f = #(x) polyval ([1 2 10], x)
x = 1:100;
v = f(x) + normrnd (0, 1, size (x));
Or without a function:
x = 1:100;
v = x.^2 + 2.*x + 10 + normrnd (0, 1, size (x));
I've adjusted x here so that the noise is visible:
x = linspace (-3, 3);
v = f(x) + normrnd (0, 1, size (x));
plot (x, v)
grid on