Function works with lsqcurvefit but not nlinfit - matlab

I'm attempting to get a nonlinear least squares fit for the following function:
Nloc = 250;
d = 1 / Nloc;
m = 0.5; %Initial guess
ncmfun = #(m, p) arrayfun(#(p) betainc(d, Nloc*m .* p, Nloc*m .* (1 - p), 'upper'), p);
Where m is the parameter being fit, Nloc and d are constants, and p and freq are vectors of positive real numbers and of the same length (I triple checked). When I use lsqcurvefit everything works fine:
[mfit,resnorm,] = lsqcurvefit(ncmfun, m, p, freq, 0, 1)
Also, if I use any m to evaluate the function, everything works fine as well. However when I use nlinfit:
[mfit,R,Jac,CovB,MSE,ErrorModelInfo] = nlinfit(p, freq, ncmfun, m)
I get the following error(s):
Error using betainc
Z must be real and non-negative.
Error in #(p)betainc(d,Nloc*m.*p,Nloc*m.*(1-p),'upper')
Error in
#(m,p)arrayfun(#(p)betainc(d,Nloc*m.*p,Nloc*m.*(1-p),'upper'),p)
Error in nlinfit>#(b,x)w.*model(b,x) (line 206)
modelw = #(b,x) w.*model(b,x);
Error in nlinfit>LMfit (line 486)
yfit = model(beta,X);
Error in nlinfit (line 207)
[beta,J,~,cause,fullr] = LMfit(X,yw,
modelw,beta,options,verbose,maxiter);
Error in Sloan_NCM_Parameterize_Nm (line 37)
[mfit,R,Jac,CovB,MSE,ErrorModelInfo] = nlinfit(p, freq,
ncmfun, m);
What's especially frustrating was this same script was working a couple weeks ago. I then tried to use it again and it no longer works. I tried to go through and see if I accidentally changed something and didn't remember, but I can't find any errors. Furthermore, I'm confused as to why lsqcurvefit works but not nlinfit. I'd like to use nlinfit because it provides me with more statistical information about the error.
Thanks in advance for any help you can provide!

They both use the same algorithm to identify a solution, however, you are explicitly stating an upper and lower bound for your solution in lsqcurvefit which ensures your incomplete beta function behaves. You don't have this option in nlinfit. I'm not sure what you did before (you can always look at the command history)
You have a few options from this point:
1 - programatically intercept every value that goes to ncmfun, by either expending your anonymous functions in what my nightmares are made of, or creating your own m-file for it. If the value is outside of [0,1] return progressively higher error value (with the boundaries being >>> then any possible value within the set)
2 - Try to force a quicker convergence by playing with some of the parameters (perhaps by using a robust fitting option (cf documentation))

Related

Gradient of implicit symbolic expression in Matlab

The situation I have is as follows:
I have a symbolic expression like:
syms X Y Z K
Ra=51.7;
P=[0 0 200];
Sa=sym('Ra^2==(Z-P(3))^2+(Y-P(2))^2')
Where Y and Z are defined as symbolic. Ra and P are vectors.
I need to get the gradient of Sa but I get an error:
G=gradient(Sa,[Y Z]);
Error using symengine (line 59)
The first argument must be of type 'Type::Arithmetical'.
Error in sym/gradient (line 39)
res = mupadmex('symobj::gradient',fsym.s,x.s);
But if I write the same expression as:
Sa(Y,Z)=((Z-P(3))^2+(Y-P(2))^2-Ra^2);
I get the expected result
G=gradient(Sa,[Y Z])
G(X, Y, Z) =
2*Y
2*Z - 400
Does anyone knows why this is so and if there's any way of using the implicit expression as this is a particular case but in general I have different implicit expressions and my code should be able to deal with them.
I've read the documentation on gradient and some sites, but if I found the answer I didn't notice.
I believe I could use the second form but still, I am curious about this subject.
Thanks for your time.
In the first one Sa is the entire equation, including the ==, while in the second one its a symbolic function depending on 2 variables.
Ultimately the way MATLAB seems to be handle this is that the first one is not derivable (also its dependent in another 2 sym variables, that doesn't know if they are related or not to the derived ones), while the second one gets identified as a function (symbolic) and can get derived.

MATLAB: atan2 breaking ode15s

I have a program that runs ode15s a few thousand times in order to find a particular solution. However, I'm getting many integration tolerance errors such as the following:
"Warning: Failure at t=5.144337e+02. Unable to meet integration tolerances without reducing the step size below the smallest value allowed (1.818989e-12) at time t."
Such warnings cause the program to slow down drastically, and sometimes even grind to a complete halt. The following is some test code that re-produces the error:
%Simulation constants
G = 6.672e-11; %Gravitational constant
M = 6.39e23; %Mass of Mars (kg)
g = 9.81; %Gravitational acceleration on Earth (m/s^2);
T1 = 845000/3; %Total engine thrust, 1 engine (N)
Isp = 282; %Engine specific impulse (s)
mdot1 = T1/(g*Isp); %Engine mass flow rate (kg/s)
xinit_on2 = [72368.8347685214;
3384891.40103322;
-598.36623436025;
-1440.49702235844;
16330.430678033]
tspan_on2 = [436.600093957202, 520.311296453027];
[t3,x3] = ode15s(#(t,x) engine_on_2(t, x, G, g, M, Isp, T1), tspan_on2, xinit_on2)
where the function engine_on_2 contains the system of ODEs that model the descent of a rocket, and is given by,
function xdot = engine_on_2(t, x, G, g, M, Isp, T1)
gamma = atan2(x(4),x(3)); %flight-path angle
xdot = [x(3); %xdot1: x-velocity
x(4); %xdot2: y-velocity
-(G*M*x(1))/((x(1)^2+x(2)^2)^(3/2))-(T1/x(5))*cos(gamma); %xdot3: x-acceleration
-(G*M*x(2))/((x(1)^2+x(2)^2)^(3/2))-(T1/x(5))*sin(gamma); %xdot4: y-acceleration
-T1/(g*Isp)]; %xdot5: engine mass flow rate
end
Having done some testing, it seems that I am getting the integration tolerance warnings because of the use of the atan2 function in gamma = atan2(x(4),x(3)) which is used to calculate the flight-path angle of the rocket. If I change atan2 to another function (for example cos or sin) I don't get any integration tolerance warnings anymore (although, due to such a change, my solutions are obviously incorrect). As such, I was wondering if I am using atan2 incorrectly, or if there is a way to implement it differently so that I do not get the integration tolerance errors anymore. Furthermore, could it be that I am incorrect and that it is something other than atan2 that is causing the errors?
Use the odeset function to create an options structure that you then pass to the solver. RelTol and AbsTol can be adjusted in the ODE solver to eliminate your error. I was able to run your code using this addition without any errors:
options = odeset('RelTol',1e-13,'AbsTol',1e-20)
[t3,x3] = ode15s(#(t,x) engine_on_2(t, x, G, g, M, Isp, T1), tspan_on2, xinit_on2, options)
See the options are passed to the ODE solver as a 4th input parameter. Note the RelTol maxes out just above 1e-13 but hopefully that's fine for your application. Also you can try any of the other ODE solvers which can get rid of your error but from my playing around ode15s seems quite fast.

Numerically solve a gamma parameter estimation

I am trying to numerically solve an equation using fzero in Matlab. It is part of a bigger exercise. I haven't posted much here so not sure how much background information you need about this exercise so will try to keep it short.
This is my code:
fun = #(a)log(a/xBar) + (1/n) * log(dataProd) + diff(gamma(a))/gamma(a);
x0 = 0.8014;
x = fzero(fun,x0)
These are the values:
n = 209
xBar is 0.6078
dataProd = 3.1554e-77
I get the following error message in Matlab:
Operands to the || and && operators must be convertible to logical
scalar values.
Error in fzero (line 306)
elseif ~isfinite(fx) || ~isreal(fx)
Any idea why I get this error message?
I would guess that, during the search for a solution, fzero tries to evaluate your function at a=0, leading to an infinity. To check if this is the case, either look and see if you can set the optimization parameter 'display' to 'iter', or something similar in your version of Matlab. Otherwise, you can simply move your function to a separate m-file and call disp(a) on the first line. That way you will be able to see what fzero is doing and which value of a is causing the problem.

MATLAB: Using FZERO on a function which has a vector output

I am working on my thesis and running in some programming problems in Matlab. I am trying to implement the ''golden Bisection Method'' to speed up my code. To this end, I've consulted the build in function FZERO.
So I am determining the difference between two vectors which are both (1x20).
Difference = Clmax_dist-cl_vec;
Clmax_dist comes from a semi-empirical method and cl_vec comes from the excecution of an external AVL.exe file.
Essentially, this difference depends only on one single variable AOA because the Clmax_dist vector is a constant. Hence, I am constantly feeding a new AOA value to the AVL.exe to obtain a new cl_vec and compare this again to the constant Clmax_dist.
I am iterating this until one of the element in the vector becomes either zero or negative. My loop stops and reveals the final AOA. This is a time consuming method and I wanted to use FZERO to speed this up.
However, the FZERO documentation reveals that it only works on function which has a scalar as input. Hence, my question is: How can I use FZERO with a function which has a vector as an output. Or do i need to do something totally different?
I've tried the following:
[Difference] = obj.DATCOMSPANLOADING(AOA);
fun=#obj.DATCOMSPANLOADING;
AOA_init = [1 20];
AOA_root = fzero(fun,AOA_init,'iter');
this gave me the following error:
Operands to the || and && operators must be convertible to logical scalar values.
Error in fzero (line 423)
while fb ~= 0 && a ~= b
Error in CleanCLmax/run (line 11)
AOA_root = fzero(fun,AOA_init,'iter');
Error in InitiatorController/moduleRunner (line 11)
ModuleHandle.run;
Error in InitiatorController/runModule (line 95)
obj.moduleRunner(ModuleHandle);
Error in RunSteps (line 7)
C.runModule('CleanCLmax');
The DATCOMSPANDLOADING function contains the following:
function [Difference] = DATCOMSPANLOADING(obj,AOA)
[Input]= obj.CLmaxInput; % Creates Input structure and airfoil list
obj.writeAirfoils(Input); % Creates airfoil coordinate files in AVL directory
[Clmax_dist,YClmax,Cla_mainsections] = obj.Clmax_spanwise(Input); % Creates spanwise section CLmax with ESDU method
[CLa] = obj.WingLiftCurveSlope(Input,Cla_mainsections); % Wing lift curve slope
[Yle_wing,cl_vec] = obj.AVLspanloading(Input,CLa,AOA); % Creates spanloading with AVL
Difference = Clmax_dist-cl_vec;
end
If I need to elaborate further, feel free to ask. And of course, Thank you very much.
fzero indeed only works on scalars. However, you can turn your criterion into a scalar: You are interested in AOA where any of the elements in the vector becomes zero, in which case you rewrite your objective function to return two output arguments: minDifference, which is min(Difference), and Difference. The first output, minDifference is the minimum of the difference, i.e. what fzero should try to optimize (from your question, I'm assuming all values start positive). The second output you'd use to inspect your difference vector in the end.

Solving a system of equations using a specific initial guess in Matlab

I have a question about solving a system of equations and initial guesses of the solution. I want to solve a system of equations where "x", a Tx1 vector, are my unknowns, "a" a Tx1 vector and "B" a TxT matrix. "f" is the function I want to solve for. I want to solve for "x" such that "f==0":
x = sym('x', [T,1]);
f = -x+1-(1+erf((a - B*x)./sqrt(2)))/2; % -x+1-normcdf(a-B*x)
Spp = solve(f==0, x);
I use Matlab's solve (or vpasolve) functions to obtain values. If the entries of "B" are above a certain value I should observe a jump for changing values of "a" (which I do). However, depending on the initial guess of the solution, i.e. for example either the initial guess is 1 or 0, the position of the jump occurs at different values for "a", a hysteresis cycle occurs.
I solved the equation using fzero for T=1. I specified the initial guess and indeed was able to observe the hysteresis cycle. For T>1, fzero does not work anymore and I tried solve as well as vpasolve. solve does not allow initial guesses and for vpasolve I even get with examples from Matlab's help site an error whenever I include more than the system of equations and the unknown variables, i.e. vpasolve(eqn,var) works fine but for vpasolve(eqn,var,init_guess) I get the following error:
Error using getEqnsVars (line 50) Expecting two arguments: a vector of
equations and a vector of variables.
Error in sym/vpasolve (line 91) [eqns,vars] =
getEqnsVars(varargin{1:end-1});
What am I doing wrong? Is there another function I could try?
Edit: I didn't use 'fsolve' but 'fzero' to find the roots.
You can use slightly different definition of function f and try fsolve. Here you don't have to explicitly define x as symbolic variables.
f = #(x) -x+1-(1+erf((a - B*x)./sqrt(2)))/2; % -x+1-normcdf(a-B*x)
initial_guess = zeros(T,1);
Spp = fsolve(f,initial_guess);