lsqcurvefit not adjusting some parameters as expected
    21 views (last 30 days)
  
       Show older comments
    
I am trying to fit some data to a 3 parameter curve expressed as  .
.
 .
.What I am finding when using lsqcurvefit is that it converges on what appears to be good values for  and
 and  but not for c. In fact, c remains unchanged from the guessed value, regardless of its initial value.
 but not for c. In fact, c remains unchanged from the guessed value, regardless of its initial value.
 and
 and  but not for c. In fact, c remains unchanged from the guessed value, regardless of its initial value.
 but not for c. In fact, c remains unchanged from the guessed value, regardless of its initial value.First I try with c = p(3) = 1000
x = 0:2047;
y = load('y.mat'); % see attachment
fun = @(p,x)abs(p(1)*(x-p(3))+p(2)*(x-p(3)).^3);
options = optimoptions(@lsqcurvefit,'StepTolerance',1e-10, 'Display', 'iter-detailed', 'FunctionTolerance', 1E-12);
pGuess = [2.5E-5 2.6E-12 1000];
[p,fminres] = lsqcurvefit(fun,pGuess,x,y, [], [], options)
                                         Norm of      First-order 
 Iteration  Func-count     f(x)          step          optimality
     0          4      0.00635297                      1.03e+08
     1          8      0.00632173    3.02663e-13           99.9      
     2         12      0.00623569    9.85058e-05       1.13e+04      
     3         16      0.00623569    3.31307e-17         0.0114      
Optimization stopped because the relative sum of squares (r) is changing
by less than options.FunctionTolerance = 1.000000e-12.
p =
      2.58614068198555e-05      1.75916049599052e-12          1000.00009850203
fminres =
       0.00623568562340633
Now I try with c = p(3) = 1400:
pGuess = [2.5E-5 2.6E-12 1400];
[p,fminres] = lsqcurvefit(fun,pGuess,x,y, [], [], options)
                                         Norm of      First-order 
 Iteration  Func-count     f(x)          step          optimality
     0          4        0.168905                      9.79e+09
     1          8         0.10571    6.45539e-12       1.16e+06      
     2         12        0.105681    9.10932e-06       1.43e+08      
     3         16        0.105681    0.000231759       1.43e+08      
     4         20        0.105681    5.79397e-05       1.43e+08      
     5         24        0.105681    1.44849e-05       1.43e+08      
     6         28        0.105681    3.62123e-06       1.43e+08      
     7         32        0.105681    9.05308e-07       1.43e+08      
     8         36        0.105681    2.26327e-07       1.43e+08      
     9         40        0.105681    5.65817e-08       1.43e+08      
    10         44        0.105681    1.41454e-08       1.43e+08      
    11         48        0.105681    3.53636e-09       1.43e+08      
    12         52        0.105681     8.8409e-10       1.43e+08      
    13         56        0.105681    2.21022e-10       1.43e+08      
    14         60        0.105681    5.52556e-11       1.43e+08      
Optimization stopped because the norm of the current step, 5.525560e-11,
is less than options.StepTolerance = 1.000000e-10.
p =
       2.4936115641411e-05      -3.9025705054523e-12           1399.9999908909
fminres =
         0.105680830464589
From the data set it is clear that the min occurs at x = 1066.
>> [m,k] = min(y)
m =
      0.000292016392169768
k =
        1067
>> x(k)
ans =
        1066
3 Comments
  Walter Roberson
      
      
 on 27 Jul 2019
				Your function would benefit from a constraint.
fun = @(p,x)abs(p(1)*(x-p(3))+p(2)*(x-p(3)).^3);
if you feed in -p(1) and -p(2) then you the result will have the same abs() as original p(1) and p(2) . Therefore you can constrain one of the values, such as p(1) to be >= 0, which will reduce searching.
Accepted Answer
  Matt J
      
      
 on 27 Jul 2019
        It helps to pre-normalize your x,y data and to use polyfit to generate a smart initial guess,
%data pre-normalization
y=y.'/max(y);
[~,imin]=min(y);
x=(x-x(imin))/max(x);
%generate initial guess
p0=polyfit(x(imin:end),y(imin:end),3);
pGuess = [p0(1),p0(3), 0];
fun = @(p,x)abs(p(1)*(x-p(3))+p(2)*(x-p(3)).^3);
options = optimoptions(@lsqcurvefit,'StepTolerance',1e-10, 'Display', 'iter-detailed', 'FunctionTolerance', 1E-12);
[p,fminres,~,ef] = lsqcurvefit(fun,pGuess,x,y, [], [], options)
plot(x,y,'o-',x(1:20:end),fun(p,x(1:20:end)),'x--y'); shg

3 Comments
  Matt J
      
      
 on 27 Jul 2019
				You're welcome, but please Accept-click the answer if you are satisfied that the fitting code is now working.
More Answers (1)
  Alex Sha
      
 on 22 Feb 2020
        The best solution seems to be:
Root of Mean Square Error (RMSE): 8.58712889537096E-5
Sum of Squared Residual: 1.50943288116718E-5
Correlation Coef. (R): 0.999947601349384
R-Square: 0.999895205444387
Adjusted R-Square: 0.999895102905683
Determination Coef. (DC): 0.99989229572485
Chi-Square: 0.00435400203642259
F-Statistic: 9515701.1004098
Parameter	Best Estimate
----------	-------------
p1	-2.54821313582336E-5
p2	-2.52958254532916E-12
p3	1062.58024839597
0 Comments
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!


