Trying to find the point when two functions differ from each other a 5% with Matlab - matlab

As I've written in the title, I'm trying to find the exact distance (dimensionless distance in this case) when two functions start to differ from each other a 5% of the Y-axis. The two functions intersect at the value of 1 in the X-axis and I need to find the described distance before the intersection, not after (i.e., it must be less than 1). I've written a Matlab code for you to see the shape of the functions and the following calculations which I'm trying to make them work but they don't, I don't know why. "Explicit solution could not be found".
I don't know if I explained it clearly. Please let me know if you need a more detailed explanation.
I hope you can throw some light in this issue.
Thank you so much in advanced.
r=0:0.001:1.2;
ro=0.335;
rt=r./ro;
De=0.3534;
k=2.8552;
B=(2*k/De)^0.5;
Fm=2.*De.*B.*ro.*[1-exp(B.*ro.*(1-rt))].*exp(B.*ro.*(1-rt));
A=5;
b=2.2347;
C=167.4692;
Ftt=(C.*(exp(-b.*rt).*((b.^6.*rt.^5)./120 + (b.^5.*rt.^4)./24 + (b.^4.*rt.^3)./6 + (b.^3.*rt.^2)./2 + b.^2.*rt + b) - b.*exp(-b.*rt).*((b.^6.*rt.^6)./720 + (b.^5.*rt.^5)./120 + (b.^4.*rt.^4)./24 + (b.^3.*rt.^3)./6 + (b.^2.*rt.^2)./2 + b.*rt + 1)))./rt.^6 - (6.*C.*(exp(-b.*rt).*((b.^6.*rt.^6)./720 + (b.^5.*rt.^5)./120 + (b.^4.*rt.^4)./24 + (b.^3.*rt.^3)./6 + (b.^2.*rt.^2)./2 + b.*rt + 1) - 1))./rt.^7 - A.*b.*exp(-b.*rt);
plot(rt,-Fm,'red')
axis([0 2 -1 3])
xlabel('Dimensionless distance')
ylabel('Force, -dU/dr')
hold on
plot(rt,-Ftt,'green')
clear rt
syms rt
%assume(0<rt<1)
r1=solve((Fm-Ftt)/Ftt==0.05,rt)
r2=solve((Ftt-Fm)/Fm==0.05,rt)

Welcome to the crux of floating point data. The reason why is because for the values of r that you are providing, the exact solution of 0.05 may be in between two of the values in your r array and so you won't be able to get an exact solution. Also, FWIW, your equation may never generate a solution of 0.05, which is why you're getting that error too. Either way, doing that explicit solve on floating point data is never recommended, unless you know very well how your data are shaped and what values you expect for the output of the function you're applying the data to.
As such, it's always recommended that you find the nearest value that satisfies your condition. As such, you should do something like this:
[~,ind] = min(abs((Fm-Ftt)./Ftt - 0.05));
r1 = r(ind);
The first line will find the nearest location in your r array that satisfies the 5% criterion. The next line of code will then give you the value that is in your r array that satisfies this. You can do the same with r2 by:
[~,ind2] = min(abs((Ftt-Fm)./Fm - 0.05));
r2 = r(ind2);
What the above code is basically doing is that it is trying to find at what point in your array would the difference between your data and 5% be 0. In other words, which point in your r array would be close enough to make the above relation equal to 0, or essentially when it is as close to 5% as possible.
If you want to improve this, you can always change the step size of r... perhaps make it 0.00001 or something. However, the smaller the step size, the larger your array and you'll eventually run out of memory!

Related

In MATLAB, how can I automatically find a specific portion of a graph using an equation?

I'm new to MATLAB, and I'm plotting a graph which starts off constant, rises, and then oscillates roughly around a constant value. I want to automatically find the x-coordinate for the point where this begins (about 1100 in the figure shown), and I imagine to automate it I need to do something like finding the first point which falls within certain threshold boundaries.
I'm not really sure how to go about that, though; would you be able to help me out?
I can provide the data if it helps, but I think I'm probably asking a pretty basic conceptual question with a straightforward answer I just don't know how to find.
An obvious answer could be to make up some threshold value, and when the y-value of the graph exceeds this threshold, you know there must have been a jump.
The function that retrieves the x value could look like this:
function x = getXofJump(data, threshold)
base_value = data(1)
x = 1
while abs(data(x + 1) - base_value) < threshold && x + 1 < len(data)
x = x + 1
end
end

Calculating vector lengths within my loop

The code is meant to draw a line with each click of the mouse made within the figure. Here is my code;
b=1
while b>0;
axis([-10, 10, -10, 10])
b=b+1
[x(b),y(b)]=ginput(1)
plot(x,y,x,y)
end
However I cant get my head around how I can add the vectors seeing as some are + and some are -, I need to turn the negatives into positives. I need to add code that will give me an overall combined length after all the mouse clicks. Maybe I am just thinking about it completely wrong.
I have tried;
length=(sqrt(x.^2)+(y.^2))
I was hoping this would give me the correct vector length accept unless I click an exact straight line.
So assuming that x and y are vectors of sequential points, if you want to get the total distance then you need to take the sum of the distance between each point i.e.
Σi(sqrt((xi-xi-1)2+(yi-yi-1)2))
in Matlab we can calculate all the x (and y) differences in one step using the diff function so in the end we get
length = sum(sqrt(diff(x).^2 + diff(y).^2))
Your problem is twofold: there's a typo, I think instead of
length=(sqrt(x.^2)+(y.^2))
you mean
length=sqrt((x.^2)+(y.^2))
The second problem is, that this does not actually calculate the length of your path, instead, you probably want something like
clear all
b=1;
radius = 3;
while b>0;
axis([-10, 10, -10, 10])
b=b+1;
[x(b),y(b)]=ginput(1);
plot(x,y,x,y);
length(b)=sqrt((x(b)-x(b-1))^2+(y(b)-y(b-1))^2);
if sqrt(x(b)^2 + y(b)^2) < radius; break; end
end
sum(length)
which calculates the length for each new piece you add and sums them all up.
As soon as you click within "radius" distance of 0 the while loop breaks.
Also, generally it's good practice to preallocate variables, no big deal here, cause your arrays are small, just saying.
Note: Dan's solution gives you a vectorized way of calculating the total length in one step, so in case you don't need the individual path lengths this is the more concise way to go.

What is this code doing? Machine Learning

I'm just learning matlab and I have a snippet of code which I don't understand the syntax of. The x is an n x 1 vector.
Code is below
p = (min(x):(max(x)/300):max(x))';
The p vector is used a few lines later to plot the function
plot(p,pp*model,'r');
It generates an arithmetic progression.
An arithmetic progression is a sequence of numbers where the next number is equal to the previous number plus a constant. In an arithmetic progression, this constant must stay the same value.
In your code,
min(x) is the initial value of the sequence
max(x) / 300 is the increment amount
max(x) is the stopping criteria. When the result of incrementation exceeds this stopping criteria, no more items are generated for the sequence.
I cannot comment on this particular choice of initial value and increment amount, without seeing the surrounding code where it was used.
However, from a naive perspective, MATLAB has a linspace command which does something similar, but not exactly the same.
Certainly looks to me like an odd thing to be doing. Basically, it's creating a vector of values p that range from the smallest to the largest values of x, which is fine, but it's using steps between successive values of max(x)/300.
If min(x)=300 and max(x)=300.5 then this would only give 1 point for p.
On the other hand, if min(x)=-1000 and max(x)=0.3 then p would have thousands of elements.
In fact, it's even worse. If max(x) is negative, then you would get an error as p would start from min(x), some negative number below max(x), and then each element would be smaller than the last.
I think p must be used to create pp or model somehow as well so that the plot works, and without knowing how I can't suggest how to fix this, but I can't think of a good reason why it would be done like this. using linspace(min(x),max(x),300) or setting the step to (max(x)-min(x))/299 would make more sense to me.
This code examines an array named x, and finds its minimum value min(x) and its maximum value max(x). It takes the maximum value and divides it by the constant 300.
It doesn't explicitly name any variable, setting it equal to max(x)/300, but for the sake of explanation, I'm naming it "incr", short for increment.
And, it creates a vector named p. p looks something like this:
p = [min(x), min(x) + incr, min(x) + 2*incr, ..., min(x) + 299*incr, max(x)];

Dot Product: * Command vs. Loop gives different results

I have two vectors in Matlab, z and beta. Vector z is a 1x17:
1 0.430742139435890 0.257372971229541 0.0965909090909091 0.694329541928697 0 0.394960106863064 0 0.100000000000000 1 0.264704325268675 0.387774594078319 0.269207605609567 0.472226643323253 0.750000000000000 0.513121013402805 0.697062571025173
... and beta is a 17x1:
6.55269487769363e+26
0
0
-56.3867588816768
-2.21310778926413
0
57.0726052009847
0
3.47223691057151e+27
-1.00249317882651e+27
3.38202232046686
1.16425987969027
0.229504956512063
-0.314243264212449
-0.257394312588330
0.498644243389556
-0.852510642195370
I'm dealing with some singularity issues, and I noticed that if I want to compute the dot product of z*beta, I potentially get 2 different solutions. If I use the * command, z*beta = 18.5045. If I write a loop to compute the dot product (below), I get a solution of 0.7287.
summation=0;
for i=1:17
addition=z(1,i)*beta(i);
summation=summation+addition;
end
Any idea what's going on here?
Here's a link to the data: https://dl.dropboxusercontent.com/u/16594701/data.zip
The problem here is that addition of floating point numbers is not associative. When summing a sequence of numbers of comparable magnitude, this is not usually a problem. However, in your sequence, most numbers are around 1 or 10, while several entries have magnitude 10^26 or 10^27. Numerical problems are almost unavoidable in this situation.
The wikipedia page http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems shows a worked example where (a + b) + c is not equal to a + (b + c), i.e. demonstrating that the order in which you add up floating point numbers does matter.
I would guess that this is a homework assignment designed to illustrate these exact issues. If not, I'd ask what the data represents to suss out the appropriate approach. It would probably be much more productive to find out why such large numbers are being produced in the first place than trying to make sense of the dot product that includes them.

Calculating the maximum distance between elements of vector in MATLAB

Let's assume that we have a vector like
x = -1:0.05:1;
ids = randperm(length(x));
x = x(ids(1:20));
I would like to calculate the maximum distance between the elements of x in some idiomatic way. It would be easy to just iterate over all possible combinations of x's elements but I feel like there could be a way to do it with MATLAB's built-in functions in some crazy but idiomatic way.
What about
max_dist = max(x) - min(x)
?
Do you mean the difference between the largest and smallest elements in your vector ? If you do, then something like this will work:
max(x) - min(x)
If you don't, then I've misunderstood the question.
This is an interpoint distance computation, although a simple one, since you are working in one dimension. Really that point which falls at a maximum distance in one dimension is always one of two possible points. So all you need do is grab the minimum value and the maximum value from the list, and see which is farther away from the point in question. So assuming that the numbers in x are real numbers, this will work:
xmin = min(x);
xmax = max(x);
maxdistance = max(x - xmin,xmax - x);
As an alternative, some time ago I put a general interpoint distance computation tool up on the file exchange (IPDM). It is smart enough to special case simple problems like the 1-d farthest point problem. This call would do it for you:
D = ipdm(x,'subset','farthest','result','struct');
Of course, it will not be as efficient as the simple code I wrote above, since it is a fully general tool.
Uhh... would love to have a MATLAB at my hands and its still early in the morning, but what about something like:
max_dist = max(x(2:end) - x(1:end-1));
I don't know if this is what You are looking for.