'LSQCURVEFIT requires all values returned by functions to be of data type double' error

26 views (last 30 days)
Ok so I think I followed the example https://ch.mathworks.com/help/optim/ug/fit-differential-equation-ode.html and adapted it accurately to my application but now I get the error 'LSQCURVEFIT requires all values returned by functions to be of data type double' which I don't understand since objective_fun returns pos which is similar to the one in the example and all values in pos are doubles
Here's my code. I use an anonymous function objective_fun to pass extra parameters into the real objective function which is paramfun. paramfun itself calls dthetadt to comptute the diiferential equation system.
n=5;
k=[0.1 0.1 0.1 0.1 0.1 0.1];
tspan = [0 5];
theta0 = [deg2rad(linspace(5,-5,n)) zeros(1,n)];
Fm=10;
objective_fun=@(x,tspan)paramfun(x,tspan,n,theta0);
param0=[k, Fm];
xdata=5;
ydata=[0.4239 0.1086 0.0213 -0.1879 -0.3618];
[pbest] = lsqcurvefit(@(x,tspan)objective_fun,param0,xdata,ydata);
function dthetadt = odefcn(t,theta,k,Fm,I,Fg,l,n)
dthetadt = zeros(2*n,1);
clear vars i
dthetadt(1) = theta(n+1);
dthetadt(n+1) = (1/I)*(-k(1)*(theta(1))-k(2)*(theta(1)-theta(2))+Fm*l*sin(theta(1))-Fg*l*cos(theta(1)));
for i=2:n-1
dthetadt(i) = theta(n+i);
dthetadt(n+i) = (1/I)*(-k(i)*(theta(i)-theta(i-1))-k(i+1)*(theta(i)-theta(i+1))+Fm*l*sin(theta(i))-Fg*l*cos(theta(i)));
end
dthetadt(n) = theta(2*n);
dthetadt(2*n) = (1/I)*(-k(n)*(theta(n)-theta(n-1))-k(n+1)*(theta(n))+Fm*l*sin(theta(n))-Fg*l*cos(theta(n)));
end
function pos= paramfun(x,tspan,n,theta0)
k=x(1:n+1);
Fm=x(n+2);
Fg=0.1;
l=30*10^(-3);
I=1;
[~,pos]=ode45(@(t,theta) odefcn(t,theta,k,Fm,I,Fg,l,n),tspan,theta0);
end
It is also worth noting that I would like to fit the response to only some values so xdata and ydata are smaller than tspan and pos.

Accepted Answer

Star Strider
Star Strider on 23 May 2020
It took a bit of effort to figure out what you are doing, and get your code to run correctly, although it still needs for you to make it work as you want it to. I cannot do that. Only you ccan make those decisions.
Specifically, in ‘paramfun’ you need to decide what you want it to return, since it must be a vector the same size as ‘ydata’. As wrritten, the ode45 call returns a (5x10) matrix, and there is no way that is going to fit a (1x5) vector.
The revised code:
n=5;
k=[0.1 0.1 0.1 0.1 0.1 0.1];
ydata=[0.4239 0.1086 0.0213 -0.1879 -0.3618];
tspan = linspace(0, 5, numel(ydata)); % Since ‘tspan’ Is The Independent Variable, It Needs to Be The Same Size
theta0 = [deg2rad(linspace(5,-5,n)) zeros(1,n)];
Fm=10;
objective_fun=@(x,tspan)paramfun(x,tspan,n,theta0);
param0=[k, Fm];
[pbest] = lsqcurvefit(objective_fun,param0,tspan,ydata) % The ‘objective_fun’ Function Already Exists To Work With ‘lsqnonlin’ Correctly, ‘tspan’ Is ‘xdata’
function dthetadt = odefcn(t,theta,k,Fm,I,Fg,l,n)
dthetadt = zeros(2*n,1);
% clear vars i
dthetadt(1) = theta(n+1);
dthetadt(n+1) = (1/I)*(-k(1)*(theta(1))-k(2)*(theta(1)-theta(2))+Fm*l*sin(theta(1))-Fg*l*cos(theta(1)));
for i=2:n-1
dthetadt(i) = theta(n+i);
dthetadt(n+i) = (1/I)*(-k(i)*(theta(i)-theta(i-1))-k(i+1)*(theta(i)-theta(i+1))+Fm*l*sin(theta(i))-Fg*l*cos(theta(i)));
end
dthetadt(n) = theta(2*n);
dthetadt(2*n) = (1/I)*(-k(n)*(theta(n)-theta(n-1))-k(n+1)*(theta(n))+Fm*l*sin(theta(n))-Fg*l*cos(theta(n)));
end
function posout= paramfun(x,tspan,n,theta0)
k=x(1:n+1);
Fm=x(n+2);
Fg=0.1;
l=30*10^(-3);
I=1;
[~,pos]=ode45(@(t,theta) odefcn(t,theta,k,Fm,I,Fg,l,n),tspan,theta0);
posout = pos(:,1).'; % Choose A Column, Then Transpose It So That ‘posout’ & ‘ydata’ Are The Same Size
end
This has the virtue of running without error (although with one warning and a note that it stopped because lsqcurvefit exceeded the funciton evaluation limit, not that it had found a global minimum and a reasonably correct solution.
.

More Answers (0)

Categories

Find more on Systems of Nonlinear Equations 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!