Gnuplot: imposing bounds on fitting parameters - gnuplot

Is there a way to contraint the values that fitting parameters can take with gnuplot?
f(x) = A/(x**2) + B/(x**4)
A = 1
B = 0.01
fit f(x) 'data.dat' u 1:2 via A,B
I know that B < 0 doesn't make any sense. Is there a way to impose B > 0?

Since gnuplot supports non-linear fitting you can use B**2 (or sqrt(B**2)) in your function to constrain your variable to be positive.

You could change your function to something like this:
minB = 0.001
f(x) = A*x**-2 + (B<minB:minB:B)*x**-4
But i'm not sure how the NLLS alogrithm reacts to this. Beware.
Or you might think about something like this:
f(x) = A*x**-2 + 10**B*x**-4
Probably this will react much smoother and be closer to an actual physical model of your data.

Related

Function evaluation of logarithm of normal PDF differs from Python

I plotted the logarithm of the pdf of the normal distribution.
Now i want to plot linear approximations of this function for different x-values (x=3). The problem is, that the returned values are not the expected ones.
set xrange[-4:4]
f(x) = 1/sqrt(2*pi*2**2) * exp(-x**2/(2*2**2))
g(x) = log(f(x))
h(x) = -0.5 * log(2*pi*2**2) - x**2/(2*2**2)
print(f(3))
print(g(3))
print(h(3))
plot h(x) with lines, \
h(3) with lines, \
# expected output
-2.737085713764618 with lines
I expect h(3) = -2.737085713764618, but get h(3) = -2.61208571376462 from gnuplot. I assume i am making a stupid mistake here. It would be great if someone could explain to me what is happening here.
Gnuplot uses integer division if the arguments are integers. To force floating point division you must provide real arguments.
f(x) = 1.0/sqrt(2*pi*2**2) * exp(-x**2/(2.0*2**2))
g(x) = log(f(x))
h(x) = -0.5 * log(2*pi*2**2) - x**2/(2.0*2**2)
print h(3.0)
-2.73708571376462

Limit the intercept for fit with gnuplot

I have a simple linear fitting function as:
f(x) = m*x + b
however, the fitting end up having a negative intercept (b<0) which does not have any meaning in my use case.
I need to restrict the intercept to be only positive numbers. The code that I found
fit [b=0:] f(x) "name_of_the_file" u 1:2 via m, b
only works for x variable restriction, but not for any other parameter.
How can I limit the intercept to positive numbers?
You can try to modify your fitting function and replace b by c**2:
f(x) = m*x + c**2
fit f(x) "name_of_the_file" u 1:2 via m, c
Then you have a nonnegative b = c**2.

Gnuplot: Fitting asymptotic curve to data

I am trying to fit an asymptotic curve to my data using gnuplot. It is a dataset showing reaction time results over a testing period. I have been able to plot the data and fit a straight line through it using the following code.
f(x) = a*x + c;
fit f(x) 'ReactionLearning.txt' using 1:2 via a,c
plot 'ReactionLearning.txt' using 1:2 with points lt 1 pt 3 notitle, \
f(x) with lines notitle
Which gives the following result:
http://imgur.com/PlQmalX.jpg
However, as this is supposed to show a learning effect, an asymptotic curve would make a lot more sense because the increase in performance caused by a learning effect will eventually stop, making the line even out.
From what I understand asymptotic cuves are created with the f(x) = 1/x. So I changed my code to be
f(x) = 1/(a*x)
fit f(x) 'ReactionLearning.txt' using 1:2 via a
plot 'ReactionLearning.txt' using 1:2 with points lt 1 pt 3 notitle, \
f(x) with lines notitle
However, I get this output: http://imgur.com/PimTa1T
Could someone explain what I am doing wrong here?
Thanks
There are many curves that show an asymptotic behavior, and 1/x is probably not the one that comes most often when describing physical or biological processes. Usually, these processes might show some sort of exponential decay. With the data that you show I don't think you can conclude anything about which model you should use, other than "it decays". If you already know what is the functional behavior you expect, that makes things different. That said, the general form of your 1/x curve should be f(x) = a/(x-x0) + c, which will probably give you some meaningful results when you fit to it:
f(x) = a/(x-x0) + c
fit f(x) "data" via a,c,x0
Since fitting might show instabilities for this kind of function if the initial values are bad, you should/might need to provide sensible initial values or reformulate the problem as a linear relation. You can do the latter by a change of variable y = 1/(x - x0) and do the fitting for different values of x0. Record the error in the fit (which is output by gnuplot) for each of them and see how the error gets minimized as a function of x0: it should be quadratic about the optimum value. Something like this:
f(x) = a*x + c
x0 = 1. # give some value for x0
fit f(x) "data" u (1./($1-x0)):2 via a,c # record fit errors for a and c
x0 = 3. # give some other value for x0
fit f(x) "data" u (1./($1-x0)):2 via a,c # record fit errors for a and c

Gnuplot fit of a nested function

What is the proper way in gnuplot to fit a function f(x) having the next form?
f(x) = A*exp(x - B*f(x))
I tried to fit it as any other function using:
fit f(x) "data.txt" via A,B
and the output is just a sentence saying: "stack overflow"
I don't even know how to look for this topic so any help would be much appreciate it.
How are this kind of functions called? Nested? Recursive? Implicit?
Thanks
This doen't only fail for fitting, also for plotting. You'll have to write down the explicit form of f(x), otherwise gnuplot will loop it until it reaches its recursion limit. One way to do it would be to use a different name:
f(x) = sin(x) # for example
g(x) = A*exp(x - B*f(x))
And now use g(x) to fit, rather than f(x). If you have never declared f(x), then gnuplot doesn't have an expression to work with. In any case, if you want to recursively define a function, you'll at least need to set a recursion limit. Maybe something like this:
f0(x) = x
f1(x) = A*exp(x - B*f0(x))
f2(x) = A*exp(x - B*f1(x))
f3(x) = A*exp(x - B*f2(x))
...
This can be automatically looped:
limit=10
f0(x) = x
do for [i=1:limit] {
j=i-1
eval "f".i."(x) = A*exp(x - B*f".j."(x))"
}
Using the expression above you set the recursion limit with the limit variable. In any case it shall remain a finite number.
That is a recursive function. You need a condition for the recursion to stop, like a maximum number of iterations:
maxiter = 10
f(x, n) = (n > maxiter ? 0 : A*exp(x - B*f(x, n+1)))
fit f(x, 0) "data.txt" via A,B
Of course you must check, which value should be returned when the recursion is stopped (here I used 0)
Thanks for your replies
Discussing with a friend about this problem I found a way around.
First, this kind of functions are call "transcendental functions", that means that the function f(x) is not explicitly solvable, but the variable x could be solved as a function of f(x) and it will have the next form
x = B*f(x) + log(f(x)/A)
Therefore it is possible to define a new function (that is not transcendental)
g(x) = B*x + log(x/A)
From here you can fit the function g(x) to the plot x vs y. Using gnuplot it is possible to do the fitting as
fit g(x) "data.txt" using ($2):($1) via A,B
Hope this will help someone else

how to fit 3D data within zrange in gnuplot

I know to fit 2D data has z value between [-1:4] in gnuplot is
f(x)=a*x+b
fit [][-1:4] f(x) "data"
but for 3D data , if I only want to fit data when f(x) has value between [-1:4]
f(x)=a*x+b*y+c
fit [][-1:4] f(x) "data"
fit [][][-1:4] f(x) "data"
are both wrong. why ?
I am not sure, if the range behaviour you describe with the 2D fit is actually intended, because it does not work with the gnuplot development version. And according to the documentation, the range specifications for the fit command apply only to the dummy variables (i.e. x and y). So it might be, that your first fit command works only because of a bug, which is a feature for you.
To limit the z-range, you can set all values outside the desired range to 1/0, which results in an undefined data point which is then ignored:
f(x, y) = a*x + b*y + c
zmin = -1
zmax = 4
fit f(x, y) "data" using 1:2:($3 < zmin || $3 > zmax ? 1/0 : $3):(1) via a,b,c
Note, that your function must be defined for two dummy variables x and y, and you must have the via statement, which is missing in all of your examples.
To fit a function with two independent variables, z=f(x,y), the required
format is using with four items, x:y:z:s. The complete format must be
given---no default columns are assumed for a missing token. Weights for
each data point are evaluated from 's' as above. If error estimates are
not available, a constant value can be specified as a constant expression
(see plot datafile using), e.g., using 1:2:3:(1).
This plots a plane in 3D, not a line. I was confused until I zoomed out and realized. Try the below dataset of 4 points. 'Set autoscale' to make sure you see the whole image. Or just read the fit.log file and realize the errors are high indicating a poor fit.
377.4202 -345.5518 2.1142
377.4201 -345.5505 2.5078
377.4206 -345.556 2.8359
377.4288 -345.5555 3.2109

Resources