heat transfer for spherical coordinates using matlab - matlab

I want to apply heat transfer ( heat conduction and convection) for a hemisphere. It is a transient homogeneous heat transfer in spherical coordinates. There is no heat generation. Boundary conditions of hemisphere is in the beginning at Tinitial= 20 degree room temperature. External-enviromental temperature is -30 degree. You can imagine that hemisphere is a solid material. Also, it is a non-linear model, because thermal conductivity is changing after material is frozen, and this going to change the temperature profile.
I want to find the temperature profile of this solid during a certain time until center temperature reach to -30degree.
In this case, Temperature depends on 3 parameters : T(r,theta,t). radius, angle, and time.
1/α(∂T(r,θ,t))/∂t =1/r^2*∂/∂r(r^2(∂T(r,θ,t))/∂r)+ 1/(r^2*sinθ )∂/∂θ(sinθ(∂T(r,θ,t))/∂θ)
I applied finite difference method using matlab, however program does not calculate anything for inner nodes of the hemisphere, and just giving me initial temperatures values (Which is Told in here) . You can see some scripts which i used for inner nodes.
% initial conditions
Tair = -30.0; % Temperature of air
Tin = 21;
% setting initial values for grid
for i=1:(nodes)
for j=1:(nodes)
Told(i,j) = Tin;
Tnew(i,j) = Tin;
frozen(i) = 0;
latent(i) = Qs*mass(i)*Water/dt;
k(i) = 0.5;
cp(i) = cw;
W(i) = Water;
l(i) = 0;
S(i) = 1-Water;
end
end
%Simulation conditions
J = 9; % No. of space steps
nodes = J+1; % Number of nodes along radius or theta direction
dt =0.1;
t = 0; % time index on start
tmax = 7000; % Time simmulation is supposed to run
R = d/2;
dr = (d/2)/J; % space steps in r direction
y = pi/2; % (theta) for hemisphere
dy = (pi/2)/J; % space steps in Theta direction
% Top surface condition for hemisphere
i=nodes;
for j=1:1:(nodes-1)
Qcd_ot(i,j) = ((k(i)+ k(i-1))/2)*A(i-1)*(( Told(i,j)-Told(i-1,j))/(dr)); % heat conduction out of nod
Qcv(i,j) = h*(Tair-Told(i,j))*A(i); % heat transfer through convectioin on surface
Tnew(i,j) = ((Qcv(i,j)-Qcd_ot(i,j))/(mass(i)*cp(i))/2)*dt + Told(i,j);
end %end of for loop
% Temperature profile for inner nodes
for i=2:1:(nodes-1)
for j=2:1:(nodes-1)
Qcd_in(i,j)= ((k(i)+ k(i+1))/2)*A(i) *((2/R)*(( Told(i+1,j)-Told(i,j))/(2*dr)) + ((Told(i+1,j)-2*Told(i,j)+Told(i-1,j))/(dr^2)) + ((cot(y)/(R^2))*((Told(i,j+1)-Told(i,j))/(2*dy))) + (1/(R^2))*(Told(i,j+1)-2*Told(i,j)+ Told(i,j-1))/(dy^2));
Qcd_out(i,j)= ((k(i)+ k(i-1))/2)*A(i-1)*((2/R)*(( Told(i,j)-Told(i-1,j))/(2*dr)) +((Told(i+1,j)-2*Told(i,j)+Told(i-1,j))/(dr^2)) + ((cot(y)/(R^2))*((Told(i,j)-Told(i,j-1))/(2*dy))) + (1/(R^2))*(Told(i,j+1)-2*Told(i,j)+ Told(i,j-1))/(dy^2));
Tnew(i,j) = (Qcd_in(i,j)-Qcd_out(i,j))/(mass(i)*cp(i)))*dt + Told(i,j);
end
end
%bottom of the hemisphere solid
Tnew(:,nodes)=-30;
Told=Tnew;
t=t+dt;
EDIT *Thanks, now the scripts are working and calculating. And i can see temperature profile for model system.
However, i want to plot in a 2D or 3D plot for this hemisphere temperature profile. Also if it is possible i would like to run animation for temperature change during certain time. The codes what i am using for simulation and to write a file is
t=0;
tmax=7000;
...................
.....................
ss=0; % index for printouts
%start simulation
while t<tmax
ss=ss+1;
.............
.................
................
if ss==2000
dlmwrite('d:\Results_for_model.txt',Tnew,'-append');
ss=0;
end
end % end of while loop
Do you have any suggestion for it ? Because in text file, for Tnew(i,j) values, after every 10 rows, model calculates for next dt value. Therefore, results data looks like a mess, after every 10 rows, it gives for next time values results.
Is there any way to coordinate to write this results according to specific rows and columns ( because otherwise huge amount of data are needed to be organized again and again) ?
and i want to plot in 3d plot for this temperature profile which is hemisphere in this case, i have Tnew(r,theta,t), but i am confused to how to represent this temperature profile to show in a hemisphere graph. I would like to hear your suggestions about it. Thanks in advance !!

To be precise, the proper syntax as defined by MATLAB for the for loop construct is
for index = values
program statements
...
end
where values has one of the following forms:
initval:endval
initval:step:endval
valArray
your code is parsed to initval:endval = 9:2, which means the loop runs 0 times, resulting in no calculations.

Related

Solution errors using pdepe to solve heat equation in axisymmetric polar coordinates in a multi-layer annulus

I am trying to model heat conduction in a turn of copper wire. I believe the pdepe function is appropriate as the problem is the forced 1D heat equation in cylindrical polar coordinates.
As recommended elsewhere on this forum, I am modelling the entire composite domain (insulation-copper-insulation) as a single domain with variable properties in space.
The equation in pdepe syntax is (1/alpha(r))du/dt = (1/r)(r*du/dr) + q(r)/k(r)
Temperature u(r,t), diffusivity alpha(r), volumetric heat generation rate q(r), conductivity k(r)
It has external boundary conditions du/dr = 0 (insulated) on the inner surface and k(r)du/dr + h(u-u0) =0 (convective) on the outer surface.
Initial conditions are zero everywhere.
I have compared the output as t --> inf to the analytic steady-state solution (attached), which is completely different. The temperature rise should be of the order 120 deg C in steady state.
Steady State solution profile
Outputs from the code (relevant excerpts attached below) however are all O(1). I would be grateful if anyone could shed some light on what I'm doing wrong or if pdepe is just not appropriate here. With many thanks in advance.
function [sol,systInfo]=ThreeLayerHeat
%uses pdepe()
%% geometry
rInner=0.05;
rOuter=0.1;
tIns=50e-6; %insulation thickness
r2=rInner+tIns; %internal boundaries
r3=rOuter-tIns;
tDomain=rOuter-rInner;
tCond=tDomain-tIns; %one conductor layer
m = 1; %CPCs
%% material properties
%copper
k_cond=394;
rho_cond=8960;
cp_cond=390;
%mica
k_ins=0.5;
rho_ins=2800;
cp_ins=880;
alpha_cond=k_cond/(rho_cond*cp_cond);
alpha_ins=k_ins/(rho_ins*cp_ins);
%%Internal generation
Jlimit=4e6; %4A/mm^2
ACfactor=1.2; %CF design of electrical machines
rho_conductor=1.75e-8; %electrical resistivity Table 9.3 293K %at reference level
%%boundary details
Tinf=0; %fluid temp on outer boundary
h2=100; %HTC on outer boundary
%%Characteristic (Fo) times
tau_chic_cond=tCond^2/alpha_cond;
tau_chic_ins=tIns^2/alpha_ins;
tau_chic_limiting=max(tau_chic_cond,tau_chic_ins);
%%discretisation
%spatial
npoints=50;
x=linspace(rInner,rOuter,npoints);
%ensure mesh points exist at internal boundaries r2 and r3
x=unique(sort(horzcat(x,r2,r3)));
%temporal
nt=10;
nPeriods=50; %how many times limiting (longest) tau (>1 to reach equilibrium)
%linspace
t0=0;
tf=t0+tau_chic_limiting*nPeriods;
t=linspace(t0,tf,nt);
if t0~=0
t=horzcat(0,t); %add 0 padding if doesn't start at 0 to allow initialisation
end
%logspace - uncomment this to use log time
% logi=-2; %initial point
% logf=log10(tf);
% t=logspace(logi,logf,nt);
% t=horzcat(0,t);
%%solve the system
sol= pdepe(m,#pdefun,#pdeic,#pdebc,x,t);
% Extract the first solution component as u.
u = sol(:,:,1);
% A surface plot
surf(x./rOuter,t./tau_chic_limiting,u-Tinf)
title(horzcat('Numerical solution computed with ',num2str(npoints), ' mesh points.'))
xlabel('Nondimensional radial distance r/r_O_u_t_e_r')
ylabel('Limiting Fourier number Fo')
zlabel('Temperature rise T')
set(gca, 'YScale','log') %if logspace used
% A limiting solution profile.
figure
plot(x,u(end,:))
hold on
plot([r2 r2],[0 max(u(end,:))],'--')
plot(x,0,'.')
plot([r3 r3],[0 max(u(end,:))],'--')
hold off
title('Final timestep (Fo \rightarrow \infty) solution')
xlabel('Distance r')
ylabel('T_\infty')
% --------------------------------------------------------------
function [c,f,s] = pdefun(x,t,u,DuDx) %computes cfs
%geometry and material info passed through nesting
%material distribution of alpha, k
if (x>=r2 && x<=r3)
alpha1=alpha_cond;
k=k_cond;
else
alpha1=alpha_ins;
k=k_ins;
end
%define for pdepe
c = 1/alpha1;
%definition of flux term
f = DuDx;
%heating distribution (currently constant with t)
rho_cond_max=rho_conductor; %for invariable resistivity
sigma_cond=1/rho_cond_max; %definition of conductivity = 1/resistivity
qvdot=ACfactor*(Jlimit^2)/sigma_cond; %volumetric heating rate (of conductor)
%source terms: heating only in conductor
s_cond=qvdot/k_cond;
s_ins=0/k_ins;
if (x>=r2 && x<=r3)
s=s_cond;
else
s=s_ins;
end
end
% --------------------------------------------------------------
function u0 = pdeic(x) %ICs
u0 = 0.*x; %starts at zero relative temp
end
% --------------------------------------------------------------
function [pl,ql,pr,qr] = pdebc(xl,ul,xr,ur,t) %BCs
%exterior BCs only
%constants passed through nesting
%nb f is set as du/dx
% %insulated LHS (inner)
pl = 0;
ql = -1*k_ins;
%convective RHS (outer)
pr = -1*h2*(ur-Tinf);
qr = -1*k_ins;
end
%end of nesting
end

Fourier transform for fiber alignment

I'm working on an application to determine from an image the degree of alignment of a fiber network. I've read several papers on this issue and they basically do this:
Find the 2D discrete Fourier transform (DFT = F(u,v)) of the image (gray, range 0-255)
Find the Fourier Spectrum (FS = abs(F(u,v))) and the Power Spectrum (PS = FS^2)
Convert spectrum to polar coordinates and divide it into 1º intervals.
Calculate number-averaged line intensities (FI) for each interval (theta), that is, the average of all the intensities (pixels) forming "theta" degrees with respect to the horizontal axis.
Transform FI(theta) to cartesian coordinates
Cxy(theta) = [FI*cos(theta), FI*sin(theta)]
Find eigenvalues (lambda1 and lambda2) of the matrix Cxy'*Cxy
Find alignment index as alpha = 1 - lamda2/lambda1
I've implemented this in MATLAB (code below), but I'm not sure whether it is ok since point 3 and 4 are not really clear for me (I'm getting similar results to those of the papers, but not in all cases). For instance, in point 3, "spectrum" is referring to FS or to PS?. And in point 4, how should this average be done? are all the pixels considered? (even though there are more pixels in the diagonal).
rgb = imread('network.tif');%513x513 pixels
im = rgb2gray(rgb);
im = imrotate(im,-90);%since FFT space is rotated 90º
FT = fft2(im) ;
FS = abs(FT); %Fourier spectrum
PS = FS.^2; % Power spectrum
FS = fftshift(FS);
PS = fftshift(PS);
xoffset = (513-1)/2;
yoffset = (513-1)/2;
% Avoid low frequency points
x1 = 5;
y1 = 0;
% Maximum high frequency pixels
x2 = 255;
y2 = 0;
for theta = 0:pi/180:pi
% Transposed rotation matrix
Rt = [cos(theta) sin(theta);
-sin(theta) cos(theta)];
% Find radial lines necessary for improfile
xy1_rot = Rt * [x1; y1] + [xoffset; yoffset];
xy2_rot = Rt * [x2; y2] + [xoffset; yoffset];
plot([xy1_rot(1) xy2_rot(1)], ...
[xy1_rot(2) xy2_rot(2)], ...
'linestyle','none', ...
'marker','o', ...
'color','k');
prof = improfile(F,[xy1_rot(1) xy2_rot(1)],[xy1_rot(2) xy2_rot(2)]);
i = i + 1;
FI(i) = sum(prof(:))/length(prof);
Cxy(i,:) = [FI(i)*cos(theta), FI(i)*sin(theta)];
end
C = Cxy'*Cxy;
[V,D] = eig(C)
lambda2 = D(1,1);
lambda1 = D(2,2);
alpha = 1 - lambda2/lambda1
Figure: A) original image, B) plot of log(P+1), C) polar plot of FI.
My main concern is that when I choose an artificial image perfectly aligned (attached figure), I get alpha = 0.91, and it should be exactly 1.
Any help will be greatly appreciated.
PD: those black dots in the middle plot are just the points used by improfile.
I believe that there are a couple sources of potential error here that are leading to you not getting a perfect alpha value.
Discrete Fourier Transform
You have discrete imaging data which forces you to take a discrete Fourier transform which inevitably (depending on the resolution of the input data) have some accuracy issues.
Binning vs. Sampling Along a Line
The way that you have done the binning is that you literally drew a line (rotated by a particular angle) and sampled the image along that line using improfile. Using improfile performs interpolation of your data along that line introducing yet another potential source of error. The default is nearest neighbor interpolation which in the example shown below can cause multiple "profiles" to all pick up the same points.
This was with a rotation of 1-degree off-vertical when technically you'd want those peaks to only appear for a perfectly vertical line. It is clear to see how this sort of interpolation of the Fourier spectrum can lead to a spread around the "correct" answer.
Data Undersampling
Similar to Nyquist sampling in the Fourier domain, sampling in the spatial domain has some requirements as well.
Imagine for a second that you wanted to use 45-degree bin widths instead of the 1-degree. Your approach would still sample along a thin line and use that sample to represent 45-degrees worth or data. Clearly, this is a gross under-sampling of the data and you can imagine that the result wouldn't be very accurate.
It becomes more and more of an issue the further you get from the center of the image since the data in this "bin" is really pie wedge shaped and you're approximating it with a line.
A Potential Solution
A different approach to binning would be to determine the polar coordinates (r, theta) for all pixel centers in the image. Then to bin the theta components into 1-degree bins. Then sum all of the values that fall into that bin.
This has several advantages:
It removes the undersampling that we talked about and draws samples from the entire "pie wedge" regardless of the sampling angle.
It ensures that each pixel belongs to one and only one angular bin
I have implemented this alternate approach in the code below with some false horizontal line data and am able to achieve an alpha value of 0.988 which I'd say is pretty good given the discrete nature of the data.
% Draw a bunch of horizontal lines
data = zeros(101);
data([5:5:end],:) = 1;
fourier = fftshift(fft2(data));
FS = abs(fourier);
PS = FS.^2;
center = fliplr(size(FS)) / 2;
[xx,yy] = meshgrid(1:size(FS,2), 1:size(FS, 1));
coords = [xx(:), yy(:)];
% De-mean coordinates to center at the middle of the image
coords = bsxfun(#minus, coords, center);
[theta, R] = cart2pol(coords(:,1), coords(:,2));
% Convert to degrees and round them to the nearest degree
degrees = mod(round(rad2deg(theta)), 360);
degreeRange = 0:359;
% Band pass to ignore high and low frequency components;
lowfreq = 5;
highfreq = size(FS,1)/2;
% Now average everything with the same degrees (sum over PS and average by the number of pixels)
for k = degreeRange
ps_integral(k+1) = mean(PS(degrees == k & R > lowfreq & R < highfreq));
fs_integral(k+1) = mean(FS(degrees == k & R > lowfreq & R < highfreq));
end
thetas = deg2rad(degreeRange);
Cxy = [ps_integral.*cos(thetas);
ps_integral.*sin(thetas)]';
C = Cxy' * Cxy;
[V,D] = eig(C);
lambda2 = D(1,1);
lambda1 = D(2,2);
alpha = 1 - lambda2/lambda1;

How to create random points alongside a complex polyline?

I would like to populate random points on a 2D plot, in such a way that the points fall in proximity of a "C" shaped polyline.
I managed to accomplish this for a rather simple square shaped "C":
This is how I did it:
% Marker color
c = 'k'; % Black
% Red "C" polyline
xl = [8,2,2,8];
yl = [8,8,2,2];
plot(xl,yl,'r','LineWidth',2);
hold on;
% Axis settings
axis equal;
axis([0,10,0,10]);
set(gca,'xtick',[],'ytick',[]);
step = 0.05; % Affects point quantity
coeff = 0.9; % Affects point density
% Top Horizontal segment
x = 2:step:9.5;
y = 8 + coeff*randn(size(x));
scatter(x,y,'filled','MarkerFaceColor',c);
% Vertical segment
y = 1.5:step:8.5;
x = 2 + coeff*randn(size(y));
scatter(x,y,'filled','MarkerFaceColor',c);
% Bottom Horizontal segment
x = 2:step:9.5;
y = 2 + coeff*randn(size(x));
scatter(x,y,'filled','MarkerFaceColor',c);
hold off;
As you can see in the code, for each segment of the polyline I generate the scatter point coordinates artificially using randn.
For the previous example, splitting the polyline into segments and generating the points manually is fine. However, what if I wanted to experiment with a more sophisticated "C" shape like this one:
Note that with my current approach, when the geometric complexity of the polyline increases so does the coding effort.
Before going any further, is there a better approach for this problem?
A simpler approach, which generalizes to any polyline, is to run a loop over the segments. For each segment, r is its length, and m is the number of points to be placed along that segment (it closely corresponds to the prescribed step size, with slight deviation in case the step size does not evenly divide the length). Note that both x and y are subject to random perturbation.
for n = 1:numel(xl)-1
r = norm([xl(n)-xl(n+1), yl(n)-yl(n+1)]);
m = round(r/step) + 1;
x = linspace(xl(n), xl(n+1), m) + coeff*randn(1,m);
y = linspace(yl(n), yl(n+1), m) + coeff*randn(1,m);
scatter(x,y,'filled','MarkerFaceColor',c);
end
Output:
A more complex example, using coeff = 0.4; and xl = [8,4,2,2,6,8];
yl = [8,6,8,2,4,2];
If you think this point cloud is too thin near the endpoints, you can artifically lengthen the first and last segments before running the loop. But I don't see the need: it makes sense that the fuzzied curve is thinning out at the extremities.
With your original approach, two places with the same distance to a line can sampled with a different probability, especially at the corners where two lines meet. I tried to fix this rephrasing the random experiment. The random experiment my code does is: "Pick a random point. Accept it with a probability of normpdf(d)<rand where d is the distance to the next line". This is a rejection sampling strategy.
xl = [8,4,2,2,6,8];
yl = [8,6,8,2,4,2];
resolution=50;
points_to_sample=200;
step=.5;
sigma=.4; %lower value to get points closer to the line.
xmax=(max(xl)+2);
ymax=(max(yl)+2);
dist=zeros(xmax*resolution+1,ymax*resolution+1);
x=[];
y=[];
for n = 1:numel(xl)-1
r = norm([xl(n)-xl(n+1), yl(n)-yl(n+1)]);
m = round(r/step) + 1;
x = [x,round(linspace(xl(n)*resolution+1, xl(n+1)*resolution+1, m*resolution))];
y = [y,round(linspace(yl(n)*resolution+1, yl(n+1)*resolution+1, m*resolution))];
end
%dist contains the lines:
dist(sub2ind(size(dist),x,y))=1;
%dist contains the normalized distance of each rastered pixel to the line.
dist=bwdist(dist)/resolution;
pseudo_pdf=normpdf(dist,0,sigma);
%scale up to have acceptance rate of 1 for most likely pixels.
pseudo_pdf=pseudo_pdf/max(pseudo_pdf(:));
sampled_points=zeros(0,2);
while size(sampled_points,1)<points_to_sample
%sample a random point
sx=rand*xmax;
sy=rand*ymax;
%accept it if criteria based on normal distribution matches.
if pseudo_pdf(round(sx*resolution)+1,round(sy*resolution)+1)>rand
sampled_points(end+1,:)=[sx,sy];
end
end
plot(xl,yl,'r','LineWidth',2);
hold on
scatter(sampled_points(:,1),sampled_points(:,2),'filled');

how to create a 3d spatial density map?

I have a time-dependent system of varying number of particles (~100k particles). In fact, each particle represents an interaction in a 3D space with a particular strength. Thus, each particle has (X,Y,Z;w) which is the coordinate plus a weight factor between 0 and 1, showing the strength of interaction in that coordinate.
Here http://pho.to/9Ztti I have uploaded 10 real-time snapshots of the system, with particles are represented as reddish small dots; the redder the dot, the stronger the interaction is.
The question is: how one can produce a 3D (spatial) density map of these particles, preferably in Matlab or Origin Pro 9 or ImageJ? Is there a way to, say, take the average of these images based on the red-color intensity in ImageJ?
Since I have the numerical data for particles (X,Y,Z;w) I can analyze those data in other software as well. So, you are welcome to suggest any other analytical approach/software
Any ideas/comments are welcome!
Assuming your data is in 3D continuous space and your dataset is just a list of the 3d positions of each particle interaction, it sounds like you want to make a 4D weighted histogram. You'll have to chop the 3d space into bins and sum the weighted points in each bin over time, then plot the results in a single 3d plot where color represents the summed weighted interactions over time.
Heres an example with randomly generated particle interactions:`
%% Create dataSet of random particle interations in 3d space
for i=1:5000
if i == 1
dataSet = [rand()*100 rand()*100 rand()*100 rand() i];
else
dataSet(i,:) = [rand()*100 rand()*100 rand()*100 rand() i];
end
end
% dataSet = [x y z interactionStrength imageNumber]
xLimits = [min(dataSet(:,1)) max(dataSet(:,1))];
yLimits = [min(dataSet(:,2)) max(dataSet(:,2))];
zLimits = [min(dataSet(:,3)) max(dataSet(:,3))];
binSize = 10; % Number of bins to split each spatial dimention into
binXInterval = (xLimits(2)-xLimits(1))/binSize;
binYInterval = (yLimits(2)-yLimits(1))/binSize;
binZInterval = (zLimits(2)-zLimits(1))/binSize;
histo = [];
for i=xLimits(1)+(binSize/2):binXInterval:xLimits(2) + (binSize/2)
for j=yLimits(1)+(binSize/2):binYInterval:yLimits(2) + (binSize/2)
for k=zLimits(1)+(binSize/2):binZInterval:zLimits(2) + (binSize/2)
%% Filter out particle interactions found within the current spatial bin
idx = find((dataSet(:,1) > (i - binSize)) .* (dataSet(:,1) < i));
temp = dataSet(idx,:);
idx = find((temp(:,2) > (j - binSize)) .* (temp(:,2) < j));
temp = temp(idx,:);
idx = find((temp(:,3) > (k - binSize)) .* (temp(:,3) < k));
temp = temp(idx,:);
%% Add up all interaction strengths found within this bin
histo = [histo; i j k sum(temp(:,4))];
end
end
end
%% Remove bins with no particle interactions
idx = find(histo(:,4)>0);
histo = histo(idx,:);
numberOfImages = max(dataSet(:,5));
%% Plot result
PointSizeMultiplier = 100000;
scatter3(histo(:,1).*binXInterval + xLimits(1),histo(:,2).*binYInterval + yLimits(1),histo(:,3).*binZInterval + zLimits(1),(histo(:,4)/numberOfImages)*PointSizeMultiplier,(histo(:,4)/numberOfImages));
colormap hot;
%Size and color represent the average interaction intensity over time
4D histogram made from 10000 randomly generated particle interactions. Each axis divided into 10 bins. Size and color represent summed particle interactions in each bin over time:
If your system can handle the matrix in Matlab it could be as easy as
A = mean(M, 4);
Assuming M holds the 4D compilation of your images then A would be your map.
One way would be to use a 3D scatter (bubble) plot, with variable circle/bubble sizes, proportional to the intensity of your particle.
Here is a simulated example:
N = 1e4; % number of particles
X = randn(N,1); % randomly generated coordinates
Y = 2*randn(N,1);
Z = 0.5*randn(N,1);
S = exp(-sqrt(X.^2 + Y.^2 + Z.^2)); % bubble size vector
scatter3(X,Y,Z,S*200)
end
Here I have randomly generated values for X, Y and Z, while S is reversely proportional to the distance from the center of the cloud.
In your case, if we assume that the (X,Y,Z,w) values are stored in a 2D array called Particles, it would be:
X = Particles(:,1);
Y = Particles(:,2);
Z = Particles(:,3);
S = Particles(:,4);
Hope that helped.

Finding 2D area defined by contour lines in Matlab

I am having difficulty with calculating 2D area of contours produced from a Kernel Density Estimation (KDE) in Matlab. I have three variables:
X and Y = meshgrid which variable 'density' is computed over (256x256)
density = density computed from the KDE (256x256)
I run the code
contour(X,Y,density,10)
This produces the plot that is attached. For each of the 10 contour levels I would like to calculate the area. I have done this in some other platforms such as R but am having trouble figuring out the correct method / syntax in Matlab.
C = contourc(density)
I believe the above line would store all of the values of the contours allowing me to calculate the areas but I do not fully understand how these values are stored nor how to get them properly.
This little script will help you. Its general for contour. Probably working for contour3 and contourf as well, with adjustments of course.
[X,Y,Z] = peaks; %example data
% specify certain levels
clevels = [1 2 3];
C = contour(X,Y,Z,clevels);
xdata = C(1,:); %not really useful, in most cases delimters are not clear
ydata = C(2,:); %therefore further steps to determine the actual curves:
%find curves
n(1) = 1; %n: indices where the certain curves start
d(1) = ydata(1); %d: distance to the next index
ii = 1;
while true
n(ii+1) = n(ii)+d(ii)+1; %calculate index of next startpoint
if n(ii+1) > numel(xdata) %breaking condition
n(end) = []; %delete breaking point
break
end
d(ii+1) = ydata(n(ii+1)); %get next distance
ii = ii+1;
end
%which contourlevel to calculate?
value = 2; %must be member of clevels
sel = find(ismember(xdata(n),value));
idx = n(sel); %indices belonging to choice
L = ydata( n(sel) ); %length of curve array
% calculate area and plot all contours of the same level
for ii = 1:numel(idx)
x{ii} = xdata(idx(ii)+1:idx(ii)+L(ii));
y{ii} = ydata(idx(ii)+1:idx(ii)+L(ii));
figure(ii)
patch(x{ii},y{ii},'red'); %just for displaying purposes
%partial areas of all contours of the same plot
areas(ii) = polyarea(x{ii},y{ii});
end
% calculate total area of all contours of same level
totalarea = sum(areas)
Example: peaks (by Matlab)
Level value=2 are the green contours, the first loop gets all contour lines and the second loop calculates the area of all green polygons. Finally sum it up.
If you want to get all total areas of all levels I'd rather write some little functions, than using another loop. You could also consider, to plot just the level you want for each calculation. This way the contourmatrix would be much easier and you could simplify the process. If you don't have multiple shapes, I'd just specify the level with a scalar and use contour to get C for only this level, delete the first value of xdata and ydata and directly calculate the area with polyarea
Here is a similar question I posted regarding the usage of Matlab contour(...) function.
The main ideas is to properly manipulate the return variable. In your example
c = contour(X,Y,density,10)
the variable c can be returned and used for any calculation over the isolines, including area.