Replace a variable in a fuction handle by a function
4 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
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 comentarios
Respuestas (4)
Dyuman Joshi
el 19 de Oct. de 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 comentarios
James Tursa
el 19 de Oct. de 2023
Editada: James Tursa
el 19 de Oct. de 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
el 19 de Oct. de 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
el 19 de Oct. de 2023
Editada: Torsten
el 19 de Oct. de 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 comentarios
Belmiro Duarte
el 20 de Oct. de 2023
Movida: Torsten
el 20 de Oct. de 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 comentarios
Dyuman Joshi
el 20 de Oct. de 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
el 21 de Oct. de 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 comentarios
Torsten
el 21 de Oct. de 2023
Editada: Torsten
el 21 de Oct. de 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))))
Ver también
Categorías
Más información sobre Linear Least Squares en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!