I have a database P with columns X, Y and Z:
x=0:1:50;
r=3.*rand(1,51);
P=[cos(x')+r',sin(x')+r',sin(x'+r').*cos(x')+r'];
P = sortrows(P,[1,2]);
N = 500;
xv = linspace(min(P(:,1)), max(P(:,1)), N);
yv = linspace(min(P(:,2)), max(P(:,2)), N);
[X,Y] = ndgrid(xv, yv);
Z = griddata(P(:,1), P(:,2), P(:,3), X, Y);
contourf(X, Y, Z, 35)
With the code above, I get the following subplot (right):
This "angularity" arises due to the addition of a vector r of random values to the data. How to smooth out this angularity and make the graph smoother?
I tried to increase N
to 2500. It did not give a significant result (in fact, it stopped changing significantly after N
=1500).
To smooth your 2D data you can use a 2D convolution, with the operator conv2
With your example data:
n = 10 ;
kernel = ones(n)/n.^2 ;
Zs = conv2(Z, kernel,'same') ;
contourf(X, Y, Zs, 35) ;
title(sprintf('Filter size: n=%d',n))
will yield:
You have to adjust the filter size (the parameter n
) until you get the desired result. For example with n=20
you will get:
And for n=50
:
A few things to keep in mind:
Since you have NaN
in your matrix Z
, the filtering will erode the border of you initial domain. The stronger the filtering/smoothing (higher n
), the more erosion you will notice until very little non-NaN
data is left .
For it to be a smoothing operation and not another transform or filtering, the convolution kernel
has to be built so (i) all the elements are of equal value, and (ii) the total sum of the elements should be 1.
A quick demonstration with n=2
:
>> n=2
n =
2
>> kernel = ones(n)/n.^2
kernel =
0.25 0.25
0.25 0.25
>> sum(sum(kernel))
ans =
1