Make histogram of every column of a matrix but without zero elements - matlab

I'm running a simulation of particles in a box. When a particle leaves the box, its kinetic energy becomes zero (for time > t escape). So I want to make a histogram of how Wkinet (which is a function of nP=number of particles, ntM=time steps) evolves through time, but I do not want to take into account the zero values of every column. Is there a way to code it so it can find the optimum number of bins?
This is what I've tried:
nbins = 1000;
for j = 1:ntM/5
Wkinet(Wkinet==0) = NaN;
y = Wkinet(:,j).*erg2eV;
end
histfit(y,nbins)

Logical indexing is often rather fast and intuitive once you get the hang of the syntax.
myTolerance=1e-7; % in erg units.
nbins=1000;
for j=1:ntM/5
%Wkinet(Wkinet==0)=NaN;
% y=Wkinet(:,j).*erg2eV; % An extra assigment is costly and probably not needed.
H = histfit(Wkinet(abs(Wkinet(:,j))>myTolerance, j) * erg2ev, nbins);
% Select from column j all rows in column j whose absolute values are greater than the tolerance.
% Assumption; erg2ev is just a scalar, otherwise select its entries with erg2ev(abs(Wkinet(:,j))>myTolerance)
H(1).delete; Remove bins, only keep the fit.
set(gca, 'YScale', 'log'); % Make logarithmic Y
set(gca, 'XScale', 'log'); % Make logarithmic X
pause
end
If you need explicit limiting of axis, use
xlim([lowerBound upperBound]); ylim(etc...
... or sometimes it is helpful to make use of the axis command for precise control, e.g.
ax=axis; ax(3)=min( 8ax(3) maxAllowedY]); axis(ax);
The "pause" (for interactive use) may be replaced by a print command to save plots to disk. E.g.
print(sprintf('My_plot_%02d',j),'-dpng');
Or save the figure:
savefig(sprintf('My_fig_%02d',j));
If are sure that number of plots are less than, say 16, you could put a subplot command in the loop. Replace the pause by
subplot(4,4,j);
Final note; if your intent is to plot a normal distribution fitted to your nonzero data you may get better results replacing the histfit function using
myFit = fitdist(Wkinet(Wkinet(:,j)>myTolerance, j) * erg2ev), 'Normal');
maxEv = max(Wkinet(Wkinet(:,j)>myTolerance, j) * erg2ev);
myX = [myTolerance; maxEv/100; maxEv]; % Alter for different plot X-axis
myY = pdf(myFit, myX);
plot(myX, myY);
I checked and there is a difference between the fitdist and histdist, probably caused by the bin discretization.

Related

How do I find exact rest points?

I have a displacement and a time data of a movement of an object.
The object oscillates around zero. That is, first - it gets set into motion by a small amount of force, then it comes to rest. again, a little force is applied and object gets set into motion.
I have found out the velocity and acceleration using
V= [0 ; diff(disp) ./ diff(times)];
A= [0; diff(V) ./ diff(times)];
I was thinking of finding points where velocity is zero. But i guess there are more than required such instances. Find the graph below:
velocity plot
I am interested in only circles time values. Is there a way to get these?
I observe a pattern
velocity increases then decreases by almost same amount.
Then due to friction, it crosses zero by a smaller amount and again becomes negative
finally comes to rest, but a very little velocity is still present.
It is this touch point to zero that I want. Then again force is applied and the same cycle repeats.
Pl note that I do not have a time of when force is applied. Otherwise there was nothing to be done.
Also, I did plot the acceleration. But is seems so useless..
I am using matlab.
Here's one way to find approximate zeros in gridded data:
% some dummy synthetic data
x = linspace(0, 10, 1e3);
y = exp(-0.3*x) .* sin(x) .* cos(pi*x);
% its derivative (presumably your "acceleration")
yp = diff(y) ./ diff(x);
% Plot data to get an overview
plot(x,y), hold on
% Find zero crossings (product of two consecutive data points is negative)
zero_x = y(1:end-1) .* y(2:end) < 0;
% Use derivative for linear interpolation between those points
x_cross = x(zero_x) + y(zero_x)./yp(zero_x);
% Plot those zeros
plot(x_cross, zeros(size(x_cross)), 'ro')
Result:
It is then up to you to select which zeros you need, because I could not understand from the question what made those points in the circles so special...
The resting points you asked have the following property:
dx / dt = v = 0
d^2 x / dt^2 = a = 0 # at the instance that the object becomes v = 0, there is no force on it.
So you may want to check also the second formula to filter the resting points.

How to interpolate data in Matlab when the data is not monotonically increasing (but structured)?

I frequently use discretized curves described by vectors, say x and y, meaning that each point (x(k),y(k)) lies on the curve. Note that x and y are generally not monotonically increasing.
Then I need to represent the data differently, because I need to know the y-values where x equals a set of given values, i.e. I want a vector yr for a given vector xq such that (xq(k),yr(k)) are all good approximations of the original curve. So normally, interpolation would be used, however
yr = interp1(x,y,xq)
results in an error
The grid vectors are not strictly monotonic increasing.
How can I do this (in a nice way)? Note that I want to preserve the shape (connectivity between neighboring nodes) of the curve given by x and y.
Example Problem
Say you have data representing a circle in a 2D (x,y) space. What would you do if you needed the representation of that circle on a different x-grid?
PS: I will provide my current approach as an answer, but welcome other approaches, especially if they are "nicer" or "simpler"? (forgive me these subjective terms)
The current approach that I have works as follows. Basically, I do normal interpolation steps on pieces of the curve described by x and y.
% Determine whether xq is a column or row vector. This is used to make sure
% that xr and yr have the same orientation as xq.
if iscolumn(xq)
dim = 1;
else
dim = 2;
end
% Make sure that xq is unique and ascending
xq = unique(xq);
% Initialize xr and yr as empty arrays
[xr,yr] = deal([]);
% Loop over all [xk,xkp1]-intervals
for k = 1:length(x)-1
% Choose values from xq that are in [xk,xkp1] (or [xkp1,xk] if
% decreasing)
if x(k) <= x(k+1) % x is locally increasing
xradd = xq(x(k)<=xq & xq<=x(k+1));
else % x is locally decreasing
xradd = flip(xq(x(k+1)<=xq & xq<=x(k)));
% 'flip' ensures that xradd is also decreasing (to maintain order
% of x in xr)
end
% Perform local interpolation
yradd = interp1(x(k:k+1),y(k:k+1),xradd);
% Assemble xr and yr from local interpolations
xr = cat(dim,xr,xradd);
yr = cat(dim,yr,yradd);
end
This method works, but there may be other methods.

How to make a vector that follows a certain trend?

I have a set of data with over 4000 points. I want to exclude grooves from them, ideally from the point from which they start. The data look for example like this:
The problem with this is the noise I get at the top of the plateaus. I have an idea, in which I would take an average value of the most common within some boundaries (again, ideally sth like the red line here:
and then I would construct a temporary matrix, which would fill up one by one with Y if they are less than this average. If the Y(i) would rise above average, the matrix would find its minima and compare it with the global minima. If the temporary matrix's minima wouldn't be sth like 80% of the global minima, it would be discarded as noise.
I've tried using mean(Y), interpolating and fitting it in a polynomial (the green line) - none of those method would cut it to the point I would be satisfied.
I need this to be extremely robust and it doesn't need to be quick. The top and bottom values can vary a lot, as well as the shape of the plateaus. The groove width is more or less the same.
Do you have any ideas? Again, the point is to extract the values that would make the groove.
How about a median filter?
Let's define some noisy data similar to yours, and plot it in blue:
x = .2*sin((0:9999)/1000); %// signal
x(1000:1099) = x(1000:1099) + sin((0:99)/50*pi); %// noise: spike
x(5000:5199) = x(5000:5199) - sin((0:199)/100*pi); %// noise: wider spike
x = x + .05*sin((0:9999)/10); %// noise: high-freq ripple
plot(x)
Now apply the median filter (using medfilt2 from the Image Processing Toolbox) and plot in red. The parameter k controls the filter memory. It should chosen to be large compared to noise variations, and small compared to signal variations:
k = 500; %// filter memory. Choose as needed
y = medfilt2(x,[1 k]);
hold on
plot(y, 'r', 'linewidth', 2)
In case you don't have the image processing toolbox and can't use medfilt2 a method that's more manual. Skip the extreme values, and do a curve fit with sin1 as curve type. Note that this will only work if the signal is in fact a sine wave!
x = linspace(0,3*pi,1000);
y1 = sin(x) + rand()*sin(100*x).*(mod(round(10*x),5)<3);
y2 = 20*(mod(round(5*x),5) == 0).*sin(20*x);
y = y1 + y2; %// A messy sine-wave
yy = y; %// Store the messy sine-wave
[~, idx] = sort(y);
y(idx(1:round(0.15*end))) = y(idx(round(0.15*end))); %// Flatten out the smallest values
y(idx(round(0.85*end):end)) = y(idx(round(0.85*end)));%// Flatten out the largest values
[foo goodness output] = fit(x.',y.', 'sin1'); %// Do a curve fit
plot(foo,x,y) %// Plot it
hold on
plot(x,yy,'black')
Might not be perfect, but it's a step in the right direction.

simulating a random walk in matlab

i have variable x that undergoes a random walk according to the following rules:
x(t+1)=x(t)-1; probability p=0.3
x(t+1)=x(t)-2; probability q=0.2
x(t+1)=x(t)+1; probability p=0.5
a) i have to create this variable initialized at zero and write a for loop for 100 steps and that runs 10000 times storing each final value in xfinal
b) i have to plot a probability distribution of xfinal (a histogram) choosing a bin size and normalization!!* i have to report the mean and variance of xfinal
c) i have to recreate the distribution by application of the central limit theorem and plot the probability distribution on the same plot!
help would be appreciated in telling me how to choose the bin size and normalize the histogram and how to attempt part c)
your help is much appreciated!!
p=0.3;
q=0.2;
s=0.5;
numberOfSteps = 100;
maxCount = 10000;
for count=1:maxCount
x=0;
for i = 1:numberOfSteps
random = rand(1, 1);
if random <=p
x=x-1;
elseif random<=(p+q)
x=x-2;
else
x=x+1;
end
end
xfinal(count) = x;
end
[f,x]=hist(xfinal,30);
figure(1)
bar(x,f/sum(f));
xlabel('xfinal')
ylabel('frequency')
mean = mean(xfinal)
variance = var(xfinal)
For the first question, check the help for hist on mathworks homepage
[nelements,centers] = hist(data,nbins);
You do not select the bin size, but the number of bins. nelements gives the elements per bin and center is all the bin centers. So to say, it would be the same to call
hist(data,nbins);
as
[nelements,centers] = hist(data,nbins);
plot(centers,nelements);
except that the representation is different (line or pile). To normalize, simply divide nelements with sum(nelements)
For c, here i.i.d. variables it actually is a difference if the variables are real or complex. However for real variables the central limit theorem in short tells you that for a large number of samples the distribution will limit the normal distribution. So if the samples are real, you simply asssumes a normal distribution, calculates the mean and variance and plots this as a normal distribution. If the variables are complex, then each of the variables will be normally distributed which means that you will have a rayleigh distribution instead.
Mathworks is deprecating hist that is being replaced with histogram.
more details in this link
You are not applying the PDF function as expected, the expression Y doesn't work
For instance Y does not have the right X-axis start stop points. And you are using x as input to Y while x already used as pivot inside the double for loop.
When I ran your code Y generates a single value, it is not a vector but just a scalar.
This
bar(x,f/sum(f));
bringing down all input values with sum(f) division? no need.
On attempting to overlap the ideal probability density function, often one has to do additional scaling, to have both real and ideal visually overlapped.
MATLAB can do the scaling for us, and no need to modify input data /sum(f).
With a dual plot using yyaxis
You also mixed variance and standard deviation.
Instead try something like this
y2=1 / sqrt(2*pi*var1)*exp(-(x2-m1).^2 / (2*var1))
ok, the following solves your question(s)
codehere
clear all;
close all;
clc
p=0.3; % thresholds
q=0.2;
s=0.5;
n_step=100;
max_cnt=10000;
n_bin=30; % histogram amount bins
xf=zeros(1,max_cnt);
for cnt=1:max_cnt % runs loop
x=0;
for i = 1:n_step % steps loop
t_rand1 = rand(1, 1);
if t_rand1 <=p
x=x-1;
elseif t_rand1<=(p+q)
x=x-2;
else
x=x+1;
end
end
xf(cnt) = x;
end
% [f,x]=hist(xf,n_bin);
hf1=figure(1)
ax1=gca
yyaxis left
hp1=histogram(xf,n_bin);
% bar(x,f/sum(f));
grid on
xlabel('xf')
ylabel('frequency')
m1 = mean(xf)
var1 = var(xf)
s1=var1^.5 % sigma
%applying central limit theorem %finding the mean
n_x2=1e3 % just enough points
min_x2=min(hp1.BinEdges)
max_x2=max(hp1.BinEdges)
% quite same as
min_x2=hp1.BinLimits(1)
max_x2=hp1.BinLimits(2)
x2=linspace(min_x2,max_x2,n_x2)
y2=1/sqrt(2*pi*var1)*exp(-(x2-m1).^2/(2*var1));
% hold(ax1,'on')
yyaxis right
plot(ax1,x2,y2,'r','LineWidth',2)
.
.
.
note I have not used these lines
% Xp=-1; Xq=-2; Xs=1; mu=Xp.*p+Xq.*q+Xs.*s;
% muN=n_step.*mu;
%
% sigma=(Xp).^2.*p+(Xq).^2.*q+(Xs).^2.s; % variance
% sigmaN=n_step.(sigma-(mu).^2);
People ususally call sigma to variance^.5
This supplied script is a good start point to now take it to wherever you need it to go.

maybe matrix plot!

for an implicit equation(name it "y") of lambda and beta-bar which is plotted with "ezplot" command, i know it is possible that by a root finding algorithm like "bisection method", i can find solutions of beta-bar for each increment of lambda. but how to build such an algorithm to obtain the lines correctly.
(i think solutions of beta-bar should lie in an n*m matrix)
would you in general show the methods of plotting such problem? thanks.
one of my reasons is discontinuity of "ezplot" command for my equation.
ok here is my pic:
alt text http://www.mojoimage.com/free-image-hosting-view-05.php?id=5039TE-beta-bar-L-n2-.png
or
http://www.mojoimage.com/free-image-hosting-05/5039TE-beta-bar-L-n2-.pngFree Image Hosting
and my code (in short):
h=ezplot('f1',[0.8,1.8,0.7,1.0]);
and in another m.file
function y=f1(lambda,betab)
n1=1.5; n2=1; z0=120*pi;
d1=1; d2=1; a=1;
k0=2*pi/lambda;
u= sqrt(n1^2-betab^2);
wb= sqrt(n2^2-betab^2);
uu=k0*u*d1;
wwb=k0*wb*d2 ;
z1=z0/u; z1_b=z1/z0;
a0_b=tan(wwb)/u+tan(uu)/wb;
b0_b=(1/u^2-1/wb^2)*tan(uu)*tan(wwb);
c0_b=1/(u*wb)*(tan(uu)/u+tan(wwb)/wb);
uu0= k0*u*a; m=0;
y=(a0_b*z1_b^2+c0_b)+(a0_b*z1_b^2-c0_b)*...
cos(2*uu0+m*pi)+b0_b*z1_b*sin(2*uu0+m*pi);
end
fzero cant find roots; it says "Function value must be real and finite".
anyway, is it possible to eliminate discontinuity and only plot real zeros of y?
heretofore,for another function (namely fTE), which is :
function y=fTE(lambda,betab,s)
m=s;
n1=1.5; n2=1;
d1=1; d2=1; a=1;
z0=120*pi;
k0=2*pi/lambda;
u = sqrt(n1^2-betab^2);
w = sqrt(betab^2-n2^2);
U = k0*u*d1;
W = k0*w*d2 ;
z1 = z0/u; z1_b = z1/z0;
a0_b = tanh(W)/u-tan(U)/w;
b0_b = (1/u^2+1/w^2)*tan(U)*tanh(W);
c0_b = -(tan(U)/u+tanh(W)/w)/(u*w);
U0 = k0*u*a;
y = (a0_b*z1_b^2+c0_b)+(a0_b*z1_b^2-c0_b)*cos(2*U0+m*pi)...
+ b0_b*z1_b*sin(2*U0+m*pi);
end
i'd plotted real zeros of "y" by these codes:
s=0; % s=0 for even modes and s=1 for odd modes.
lmin=0.8; lmax=1.8;
bmin=1; bmax=1.5;
lam=linspace(lmin,lmax,1000);
for n=1:length(lam)
increment=0.001; tolerence=1e-14; xstart=bmax-increment;
x=xstart;
dx=increment;
m=0;
while x > bmin
while dx/x >= tolerence
if fTE(lam(n),x,s)*fTE(lam(n),x-dx,s)<0
dx=dx/2;
else
x=x-dx;
end
end
if abs(real(fTE(lam(n),x,s))) < 1e-6 %because of discontinuity some answers are not correct.%
m=m+1;
r(n,m)=x;
end
dx=increment;
x=0.99*x;
end
end
figure
hold on,plot(lam,r(:,1),'k'),plot(lam,r(:,2),'c'),plot(lam,r(:,3),'m'),
xlim([lmin,lmax]);ylim([1,1.5]),
xlabel('\lambda(\mum)'),ylabel('\beta-bar')
you see i use matrix to save data for this plot.
![alt text][2]
because here lines start from left(axis) to rigth. but if the first line(upper) starts someplace from up to rigth(for the first figure and f1 function), then i dont know how to use matrix. lets improve this method.
[2]: http://www.mojoimage.com/free-image-hosting-05/2812untitled.pngFree Image Hosting
Sometimes EZPLOT will display discontinuities because there really are discontinuities or some form of complicated behavior of the function occurring there. You can see this by generating your plot in an alternative way using the CONTOUR function.
You should first modify your f1 function by replacing the arithmetic operators (*, /, and ^) with their element-wise equivalents (.*, ./, and .^) so that f1 can accept matrix inputs for lambda and betab. Then, run the code below:
lambda = linspace(0.8,1.8,500); %# Create a vector of 500 lambda values
betab = linspace(0.7,1,500); %# Create a vector of 500 betab values
[L,B] = meshgrid(lambda,betab); %# Create 2-D grids of values
y = f1(L,B); %# Evaluate f1 at every point in the grid
[c,h] = contour(L,B,y,[0 0]); %# Plot contour lines for the value 0
set(h,'Color','b'); %# Change the lines to blue
xlabel('\lambda'); %# Add an x label
ylabel('$\overline{\beta}$','Interpreter','latex'); %# Add a y label
title('y = 0'); %# Add a title
And you should see the following plot:
Notice that there are now additional lines in the plot that did not appear when using EZPLOT, and these lines are very jagged. You can zoom in on the crossing at the top left and make a plot using SURF to get an idea of what's going on:
lambda = linspace(0.85,0.95,100); %# Some new lambda values
betab = linspace(0.95,1,100); %# Some new betab values
[L,B] = meshgrid(lambda,betab); %# Create 2-D grids of values
y = f1(L,B); %# Evaluate f1 at every point in the grid
surf(L,B,y); %# Make a 3-D surface plot of y
axis([0.85 0.95 0.95 1 -5000 5000]); %# Change the axes limits
xlabel('\lambda'); %# Add an x label
ylabel('$\overline{\beta}$','Interpreter','latex'); %# Add a y label
zlabel('y'); %# Add a z label
Notice that there is a lot of high-frequency periodic activity going on along those additional lines, which is why they look so jagged in the contour plot. This is also why a very general utility like EZPLOT was displaying a break in the lines there, since it really isn't designed to handle specific cases of complicated and poorly behaved functions.
EDIT: (response to comments)
These additional lines may not be true zero crossings, although it is difficult to tell from the SURF plot. There may be a discontinuity at those lines, where the function shoots off to -Inf on one side of the line and Inf on the other side of the line. When rendering the surface or computing the contour, these points on either side of the line may be mistakenly connected, giving the false appearance of a zero crossing along the line.
If you want to find a zero crossing given a value of lambda, you can try using the function FZERO along with an anonymous function to turn your function of two variables f1 into a function of one variable fcn:
lambda_zero = 1.5; %# The value of lambda at the zero crossing
fcn = #(x) f1(lambda_zero,x); %# A function of one variable (lambda is fixed)
betab_zero = fzero(fcn,0.94); %# Find the value of betab at the zero crossing,
%# using 0.94 as an initial guess