I have this equation that I need to simulate and then plot Y in terms of X. I use the following code to do this but at the end it gives me this straight line as the graph which clearly isn't what I expect to see:
r = .5;
beta = 5;
b = 1;
N = 10;
K = 15;
p = .7:.05:5.7;
l_0 = 0:.01:1;
p*K.*(1-(l_0/r)) == 1./((N*beta*(b^beta)./((beta-1)*l_0))).^(1/(beta-1));
plot(p,l_0,'b*-')
I need to see how l_0 varies as p varies by simulating the equation and using the parameter values above.
This is the graph that I get when I run the code:
I somehow guess that there's something wrong with the way I've set the values for p and l_0 but I'm almost new to MATLAB and don't know how to fix it. I'd appreciate if any one could help me to find out where I'm making mistake(s).
If you view the MATLAB Documents page for the colon operator, you will see that : acts as a unit vector. Basically, it creates a linear space from j to k, by i intervals. So the graph as it is currently displayed is correct. It displays two linear vectors.
However, what you may want to change is the aspect ratio of the graph. Right now, your aspect ratio custom fits your data (which it sounds like you do not want). Look under the axis style section in the MATLAB Documentation for axis limits and aspect ratios to see what style you want your plot in.
Hope this helps you out.
The graph/plot that you are showing here is seems to work only with this:
p = .7:.05:5.7;
l_0 = 0:.01:1;
plot(p,l_0,'b*-')
YES! that is it. All the other things that you have written are playing no role (it seems).
basically you have not evaluated / populated p with l_0 so if you want to see that then
keep p blank
Rearrange your equation with only p at LHS.
Let l_0 handle/fill the values of p.
Now if you only want to see the curve/plot between p = .7:.05:5.7;, then you can check how to do that with the axes property or simply zoom-in/out.
Hope this helps
Related
we have measured data that we managed to determine the distribution type that it follows (Gamma) and its parameters (A,B)
And we generated n samples (10000) from the same distribution with the same parameters and in the same range (between 18.5 and 59) using for loop
for i=1:1:10000
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
W(i,:) =random(tot,1,1);
end
Then we tried to fit the generated data using:
h1=histfit(W);
After this we tried to plot the Gamma curve to compare the two curves on the same figure uing:
hold on
h2=histfit(W,[],'Gamma');
h2(1).Visible='off';
The problem s the two curves are shifted as in the following figure "Figure 1 is the generated data from the previous code and Figure 2 is without truncating the generated data"
enter image description here
Any one knows why??
Thanks in advance
By default histfit fits a normal probability density function (PDF) on the histogram. I'm not sure what you were actually trying to do, but what you did is:
% fit a normal PDF
h1=histfit(W); % this is equal to h1 = histfit(W,[],'normal');
% fit a gamma PDF
h2=histfit(W,[],'Gamma');
Obviously that will result in different fits because a normal PDF != a gamma PDF. The only thing you see is that for the gamma PDF fits the curve better because you sampled the data from that distribution.
If you want to check whether the data follows a certain distribution you can also use a KS-test. In your case
% check if the data follows the distribution speccified in tot
[h p] = kstest(W,'CDF',tot)
If the data follows a gamma dist. then h = 0 and p > 0.05, else h = 1 and p < 0.05.
Now some general comments on your code:
Please look up preallocation of memory, it will speed up loops greatly. E.g.
W = zeros(10000,1);
for i=1:1:10000
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
W(i,:) =random(tot,1,1);
end
Also,
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
is not depending in the loop index and can therefore be moved in front of the loop to speed things up further. It is also good practice to avoid using i as loop variable.
But you can actually skip the whole loop because random() allows to return multiple samples at once:
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
W =random(tot,10000,1);
I am currently running improfile on MATLAB with a line going through the center of the picture below:
After doing so, I'm plotting the resultant using the code below:
xi = [1 size(d_Img,2) size(d_Img,2) 1];
yi = [ceil(size(d_Img,1)/2), ceil(size(d_Img,1)/2), ceil(size(d_Img,1)/2 ),ceil(size(d_Img,1)/2)];
c_d = improfile(d_Img,xi,yi);
c_c = improfile(c_Img,xi,yi);
c_d = c_d';
c_c = c_c';
size_c = size(c_d);
n = 1:size_c(2);
plot(n,c_d);
And here is the plot:
Why are the curves mirroring each other? I am asking to gain a better understanding of what exactly improfile seems to be achieving in MATLAB.
improfile computes something like a "path integral", it gives you the image intensity values around a user specified path. For example, if you use:
improfile(img,[1 1],[1 size(img,2)]);
It gives the same as img(:,1). This is because the path you are using in improfile is from (1,1) to (1,size(img,2)) , meaning the first row. However you could definitely add more complicated paths.
In your case you are going trow a path defined by 4 points. The points are, if I substitute your equation by the resultant numbers:
(1,79)->(134,79)->(134,79)->(1,79). Thus, looking at this, it is obvious that your result should be mirrored, because you are integrating over a line the way there, and back!
Sidenote:
you can do plot(c_d); and forget about that n
I have data values y, which can be calculated by a function y=A x B x exp(C) where A and C are variables and B is a constant. The data values y are given for different B. I want to determine the variables A and C.
My idea was to define a ratio between the given data y and the calculated data y (y_calc). y_calc will be calculated with values of A and C which are near the real variables A and C. So this ratio needs to be minimized for all y_calc at different B.
--> ratio = ((y - y_calc)/(y + y_calc))^2.
Additionally, there are constraints for A and C (e.g. A<10, C>20). I also want to define constraints for the ratio (e.g. ratio<1e-5)
I want to solve this with MATLAB. Unfortunately, I have no idea which of the many available functions i have to use and how these functions will be applied.
Can anyone help me? Is it even possible to solve my problem this way?
Thank you.
I assume you made a typo in your OP like the other user suggested.
Your idea for getting started goes in the right direction, look up 'cost function'.
There's an fminsearch function you can use. I'm not that knowledgeable in this area because I learned all of this pretty recently, most of the time the SVD method (again look it up) is used for stuff like this.
This should work
clear all
close all
clc
B = [1,2,3,4,5]; % test values B
y = [3,5,7,9,15]; % test values y
vParam = [1,1]; % starting test value A and C
fct='fct';
options=optimset('TolX', 1.e-4, 'TolFun', 1.e-4, 'MaxFunEvals', 1500,'MaxIter', 500);
[vParam_optimized] = fminsearch(fct,vParam,options,B,y);
fit = vParam_optimized(1).*B.*exp(vParam_optimized(2));
plot(fit)
hold on
plot(y,'*')
function y=fct(vParam,B,y_meas)
% Parameters, x values, y result values
y=0;
for i=1:length(B)
y=y+(y_meas(i)-(vParam(1)*B(i)*exp(vParam(2)))).^2; % cost function
end
end
I find examples the best way to demonstrate my question. I generate some data, add some random noise, and fit it to get back my chosen "generator" value...
x = linspace(0.01,1,50);
value = 3.82;
y = exp(-value.*x);
y = awgn(y,30);
options = optimset('MaxFunEvals',1000,'MaxIter',1000,'TolFun',1e-10,'Display','off');
model = #(p,x) exp(-p(1).*x);
startingVals = [5];
lb = [1];
ub = [10];
[fittedValue] = lsqcurvefit(model,startingVals,x,y,lb,ub,options)
fittedGraph = exp(-fittedValue.*x);
plot(x,y,'o');
hold on
plot(x,fittedGraph,'r-');
In this new example, I have generated the same data but this time added much more noise to the first 15 points. Because it is random sometimes it works out okay, but after a few runs I get a good example that illustrates my problem. Same code, except for these lines added under value = 3.82
y = exp(-value.*x);
y(1:15) = awgn(y(1:15),5);
y(15:end) = awgn(y(15:end),30);
As you can see, it has clearly not given a good fit to where the data seems reliable, because it is fitting from points 1-50. What I want to do is say, okay MATLAB, I can see we have some noisy data but it seems decent over a range, only fit your exponential from points 15 to the end. I could go back to my code and update it to do this, but I will be batch fitting graphs like this where each one will have different ranges of 'good' data.
So what I am after is a GUI callback mechanisms that allows me to click on two circles from the data and have them change color or something, which indicates the lsqcurvefit will only fit over that range. Internally all it has to change is inside the lsqcurvefit call e.g.
x(16:end),y(16:end)
But the range should update depending on the starting and ending circles I have clicked.
I hope my question is clear. Thanks.
You could use ginput to select the two points for your min and max in the plot.
[x,y]=ginput(2);
%this returns you the x and y coordinates of two points clicked after each other
%the min point is assumed to be clicked first
min=[x(1) y(1)];
max=[x(2) y(2)];
then you could fit your curve with the coordinates for min and max I guess.
You could also switch between a rightclick for the min and a leftclick for the max etc.
Hope this helps you.
I have a Matlab project in which I need to make a GUI that receives two mathematical functions from the user. I then need to find their intersection point, and then plot the two functions.
So, I have several questions:
Do you know of any algorithm I can use to find the intersection point? Of course I prefer one to which I can already find a Matlab code for in the internet. Also, I prefer it wouldn't be the Newton-Raphson method.
I should point out I'm not allowed to use built in Matlab functions.
I'm having trouble plotting the functions. What I basically did is this:
fun_f = get(handles.Function_f,'string');
fun_g = get(handles.Function_g,'string');
cla % To clear axes when plotting new functions
ezplot(fun_f);
hold on
ezplot(fun_g);
axis ([-20 20 -10 10]);
The problem is that sometimes, the axes limits do not allow me to see the other function. This will happen, if, for example, I will have one function as log10(x) and the other as y=1, the y=1 will not be shown.
I have already tried using all the axis commands but to no avail. If I set the limits myself, the functions only exist in certain limits. I have no idea why.
3 . How do I display numbers in a static text? Or better yet, string with numbers?
I want to display something like x0 = [root1]; x1 = [root2]. The only solution I found was turning the roots I found into strings but I prefer not to.
As for the equation solver, this is the code I have so far. I know it is very amateurish but it seemed like the most "intuitive" way. Also keep in mind it is very very not finished (for example, it will show me only two solutions, I'm not so sure how to display multiple roots in one static text as they are strings, hence question #3).
function [Sol] = SolveEquation(handles)
fun_f = get(handles.Function_f,'string');
fun_g = get(handles.Function_g,'string');
f = inline(fun_f);
g = inline(fun_g);
i = 1;
Sol = 0;
for x = -10:0.1:10;
if (g(x) - f(x)) >= 0 && (g(x) - f(x)) < 0.01
Sol(i) = x;
i = i + 1;
end
end
solution1 = num2str(Sol(1));
solution2 = num2str(Sol(2));
set(handles.roots1,'string',solution1);
set(handles.roots2,'string',solution2);
The if condition is because the subtraction will never give me an absolute zero, and this seems to somewhat solve it, though it's really not perfect, sometimes it will give me more than two very similar solutions (e.g 1.9 and 2).
The range of x is arbitrary, chosen by me.
I know this is a long question, so I really appreciate your patience.
Thank you very much in advance!
Question 1
I think this is a more robust method for finding the roots given data at discrete points. Looking for when the difference between the functions changes sign, which corresponds to them crossing over.
S=sign(g(x)-f(x));
h=find(diff(S)~=0)
Sol=x(h);
If you can evaluate the function wherever you want there are more methods you can use, but it depends on the size of the domain and the accuracy you want as to what is best. For example, if you don't need a great deal of accurac, your f and g functions are simple to calculate, and you can't or don't want to use derivatives, you can get a more accurate root using the same idea as the first code snippet, but do it iteratively:
G=inline('sin(x)');
F=inline('1');
g=vectorize(G);
f=vectorize(F);
tol=1e-9;
tic()
x = -2*pi:.001:pi;
S=sign(g(x)-f(x));
h=find(diff(S)~=0); % Find where two lines cross over
Sol=zeros(size(h));
Err=zeros(size(h));
if ~isempty(h) % There are some cross-over points
for i=1:length(h) % For each point, improve the approximation
xN=x(h(i):h(i)+1);
err=1;
while(abs(err)>tol) % Iteratively improve aproximation
S=sign(g(xN)-f(xN));
hF=find(diff(S)~=0);
xN=xN(hF:hF+1);
[~,I]=min(abs(f(xN)-g(xN)));
xG=xN(I);
err=f(xG)-g(xG);
xN=linspace(xN(1),xN(2),15);
end
Sol(i)=xG;
Err(i)=f(xG)-g(xG);
end
else % No crossover points - lines could meet at tangents
[h,I]=findpeaks(-abs(g(x)-f(x)));
Sol=x(I(abs(f(x(I))-g(x(I)))<1e-5));
Err=f(Sol)-g(Sol)
end
% We also have to check each endpoint
if abs(f(x(end))-g(x(end)))<tol && abs(Sol(end)-x(end))>1e-12
Sol=[Sol x(end)];
Err=[Err g(x(end))-f(x(end))];
end
if abs(f(x(1))-g(x(1)))<tol && abs(Sol(1)-x(1))>1e-12
Sol=[x(1) Sol];
Err=[g(x(1))-f(x(1)) Err];
end
toc()
Sol
Err
This will "zoom" in to the region around each suspected root, and iteratively improve the accuracy. You can tweak the parameters to see whether they give better behaviour (the tolerance tol, the 15, number of new points to generate, could be higher probably).
Question 2
You would probably be best off avoiding ezplot, and using plot, which gives you greater control. You can vectorise inline functions so that you can evaluate them like anonymous functions, as I did in the previous code snippet, using
f=inline('x^2')
F=vectorize(f)
F(1:5)
and this should make plotting much easier:
plot(x,f(x),'b',Sol,f(Sol),'ro',x,g(x),'k',Sol,G(Sol),'ro')
Question 3
I'm not sure why you don't want to display your roots as strings, what's wrong with this:
text(xPos,yPos,['x0=' num2str(Sol(1))]);