Replace a variable in a fuction handle by a function
4 views (last 30 days)
Show older comments
I am fitting a nonlinear model with nlinfit. First I create the function and then invoke the solver:
%
% initial solution
b1 = [6.808e-3, 229.8e3/8.314];
%
% model
originalM = @(c,x)(exp(-c(1)*x(:,1).*exp(-c(2)*(1.0./x(:,2)-1.0/Tref))));
%
% data structure
x1 = double([t,temp]);
y1 = double(yf);
xnew1 = x1;
ynew1 = y1;
%
% fit the model
[cDD,res,jac,CovB] = nlinfit(x1,y1,originalM,b1);
This works fine. My question is how to replace the parameters c(1), c(2) in the originalM model by functions dependent on another set of parameters? Imagine that c(1) in model above is equal to a function wich depends on a new set of parameters c(3) and c(4)
c(1) = 0.5+exp(-c(3)+c(4);
How can we program this?
0 Comments
Answers (4)
Dyuman Joshi
on 19 Oct 2023
You can directly substitute the expression into the function handle -
originalM = @(c,x)(exp(-(0.5+exp(-c(3)+c(4)))*x(:,1).*exp(-c(2)*(1.0./x(:,2)-1.0/Tref))));
Note that since there is a parenthesis missing from the expression, I have assumed the expression to be -
c(1) = 0.5+exp(-c(3)+c(4));
4 Comments
James Tursa
on 19 Oct 2023
Edited: James Tursa
on 19 Oct 2023
@Belmiro Duarte Keep in mind that function handles contain snapshots of all the inputs as they existed at the time the function handle created. Subsequently changing variables that the function handle depends on will have no effect on the function handle. Unfortunatly, it sounds like that is what you want to do. E.g.,
f = @(t) t^2
g = @(t) 3 + f(t)
g(2)
All well and good. Now suppose you want to use a different function f:
f = @(t) t^3
Then re-evaluate g which depends on f:
g(2)
Oops! Nothing changed for g, even though it uses f. Why? Because g contains a snapshot of what f was at the time g was created. Subsequently changing f had no effect on g. The solution to all of this is that you must re-create the function handle if you want it to use the new inputs. E.g., re-create it now and then call the re-created g:
g = @(t) 3 + f(t)
g(2)
The newly created g now has a snapshot of the new f.
Bottom line is once you create a function handle it uses fixed copies of the inputs embedded in the function handle itself.
One way around this is to have the function handle f be one of the inputs to g instead of embedded in g. E.g.,
f = @(t) t^2
g = @(t,f) 3 + f(t)
g(2,f)
f = @(t)t^3
g(2,f)
Now things work as maybe you want it to, where you create g once and can change f on the fly to get updated g behavior.
Dyuman Joshi
on 19 Oct 2023
fun = @(c) 0.5+exp(-c(3)+c(4));
originalM = @(c,x)(exp(-fun(c)*x(:,1).*exp(-c(2)*(1.0./x(:,2)-1.0/Tref))));
Torsten
on 19 Oct 2023
Edited: Torsten
on 19 Oct 2023
Define "modelfun" for "nlinfit" not as a function handle, but as a normal function. Within this function, you can do everything you like with the predefined f:
[cDD,res,jac,CovB] = nlinfit(x1,y1,@(c,x)modelfun(c,x,f),b1);
...
function y = modelfun(c,x,f)
y = exp(-f(c)*x(:,1).*exp(-c(2)*(1.0./x(:,2)-1.0/Tref)));
end
0 Comments
Belmiro Duarte
on 20 Oct 2023
Moved: Torsten
on 20 Oct 2023
Thanks for the suggestion. I followed it, but I am still strugling with a problem.
I am sending a ficticious file which simulates what I want and the problem which appears only in the last line.
Basically, I obtain a vector of symbolic functions from previous calculations. All the elements of this vector are in turn functions of the parameterer to obtaining by nlinfit. I debugged the code and seems this functions
test1()
function test1
%
% find the transformation
%
clear all;
%
% read ficticious data
dat = load('Data1.txt');
[ntime, nvar] = size(dat);
t = dat(:,1);
temp = dat(:,2);
yf = dat(:,3);
np = 3;
%
% data structure
x1 = double([t,temp]);
y1 = double(yf);
xnew1 = x1;
xnew1(:,2) = 1.0./xnew1(:,2);
ynew1 = y1;
%
% simulated matrix and initial parameters
th1 = 6.808e-3;
th2 = 229.8e-3/8.314;
th3 = 1.0/615.0;
tz0 = [th1;th2;th3];
Q = [1, 0.5, -0.8; 0.2, 0.6, -0.4; 0.25, 0.05, 0.2];
%
% generation of symbolic variables that will be substituted by the
% parameters to obtain by fitting
c = transpose(sym("c%d", [1 np]));
%
% solution of a symbolic algebraic system
tz = vpa(simplify(Q*c+tz0));
%
% creation of symbolic variables c(i) to replace those initially created
% c_i
p1 = str2sym('c(1)');
p2 = str2sym('c(2)');
p3 = str2sym('c(3)');
%
% replacement of c_i by c(i) in the expressions. tn is a vector of 3
% symbolic functions on c(i)
tn = subs(tz,{'c1','c2','c3'},{p1,p2,p3});
%
% find the reference point
t_in = vpa(subs(tn,{p1,p2,p3},{th1, th2, th3}));
t_in = transpose(t_in);
%
% fit the model. The model is in modelfunc function and the vector of functions tn is to be passed
% and used. Here, the vector tn contains 3 elements and each one is a function
% of c(i) which are to be fitted.
%
% This part is not working. However, tn is passing correctly to modelfunc
[cDD,res,jac,CovB] = nlinfit(xnew1,ynew1, @(c,xnew1) modelfunc(c,xnew1,tn),t_in);
end
%%
function [F] = modelfunc(c,x,tn)
F = exp(-tn(1).*x(:,1).*exp(-tn(2).*(x(:,2)-tn(3))));
end
2 Comments
Dyuman Joshi
on 20 Oct 2023
Do you get an error? If so, copy and paste the whole error message i.e. all of the red text.
If otherwise, please specify.
Belmiro Duarte
on 21 Oct 2023
@Torsten Yes. you are right I had two variables that were symbolic. One of them is t_in (the initial set of parameters), and I already fixed it. Another is the vector of symbolic functions tn . That I do not know how to handle because it contain the functions to generate the model to fit. That is, I want my model dependent on c pararameters which appear in modelfunc because the functions tn depend on them. Any ideas how to overcome it?
@Dyuman Joshi. This is the message I got after having
t_in = transpose(t_in);
by
t_in = double(transpose(t_in));
...
Warning: Solution does not exist because the system is inconsistent.
> In symengine
In sym/privBinaryOp (line 1218)
In \ (line 562)
In nlinfit>LMfit (line 587)
In nlinfit (line 284)
In test41 (line 55)
Conversion to logical from sym is not possible.
Error in nlinfit>LMfit (line 600)
if sse < sseold
Error in nlinfit (line 284)
[beta,J,~,cause,fullr] = LMfit(X,yw, modelw,beta,options,verbose,maxiter);
Error in test41 (line 55)
[cDD,res,jac,CovB] = nlinfit(xnew1,ynew1, @(c,x) modelfunc(c,x,tn),t_in);
It seems the problem is related with the fact that tn is symbolic mentioned by @Torsten. Probably I am missing something here.
4 Comments
Torsten
on 21 Oct 2023
Edited: Torsten
on 21 Oct 2023
Don't overcomplicate things.
Pass the function handles to your model function and evaluate them when needed:
[cDD,res,jac,CovB] = nlinfit(xnew1,ynew1, @(c,x) modelfunc(c,x,@(z)tr1(z(1),z(2),z(3)),...
@(z)tr2(z(1),z(2),z(3)),@(z)tr3(z(1),z(2),z(3))),t_in);
and use them inside your function when required:
exp(-tr1(c).*x(:,1).*exp(-tr2(c).*(x(:,2)-tr3(c))))
See Also
Categories
Find more on Linear Least Squares in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!