Use lsqnonlin to optimize parameters to fit the property of a function

4 views (last 30 days)
Hi everyone,
I would like to use lsqnonline to optimize the parameters of a function with lsqnonlin. I already use it in the past, but now I am trying to adjust only one property of a parametrized function rather than the whole function itself.
For example, I am trying this trivial example: I have a sin function f=sin(x*q) and I want to optimize that q so to have a specific period of the sinus. Here is my script:
x=[0:0.1:1000]
q = 2
f = sind(x*q)
%find peaks and then make the difference between two consecutive peaks to
%find the period of the sinus
[pks, locs] = findpeaks(f,x)
p = (locs(2)-locs(1))
lb = [0];
ub = [1000];
param = q;
options = optimset('MaxFunEvals',30000,'MaxIter',10000,'Display','iter'); % specify options
[param_fitted, resnorm] = lsqnonlin(@fun,param,lb,ub);
q_fit=param_fitted
f_fit = sind(x*q_fit)
[pks, locs] = findpeaks(f_fit,x)
p_fit = (locs(3)-locs(2))
figure
plot(x,f,'b',x,f_fit,'r')
And the function fun wants to calculate the difference between the period with the parameter q and an arbitrary period=10.
function differences=fun(param)
q=param;
x=[0:0.1:1000]
f = sind(x*q)
[pks, locs] = findpeaks(f,x)
p = (locs(2)-locs(1))
differences = p-10;
I should expect to find the q that gives a sinus function with period 10, but the parameter is not optimized at all. What am I doing wrong?

Answers (1)

Torsten
Torsten on 6 Jul 2022
lsqnonlin slightly changes the input to "fun" from the first to the second call, but does not recognize any change of the output "differences". The solver concludes that a decrease in "differences" is not possible and that the initial point already is a local minimum.
format long
x=[0:0.1:1000];
q = 2;
f = sind(x*q);
%find peaks and then make the difference between two consecutive peaks to
%find the period of the sinus
[pks, locs] = findpeaks(f,x);
p = (locs(2)-locs(1));
lb = [0];
ub = [1000];
param = q;
options = optimset('MaxFunEvals',30000,'MaxIter',10000,'Display','iter'); % specify options
[param_fitted, resnorm] = lsqnonlin(@fun,param,lb,ub);
p =
180
differences =
170
p =
180
differences =
170
Initial point is a local minimum. Optimization completed because the size of the gradient at the initial point is less than the value of the optimality tolerance.
fun(param_fitted)
p =
180
differences =
170
ans =
170
q_fit=param_fitted;
f_fit = sind(x*q_fit)
f_fit = 1×10001
0 0.003490651415224 0.006981260297962 0.010471784116246 0.013962180339145 0.017452406437284 0.020942419883357 0.024432178152653 0.027921638723569 0.031410759078128 0.034899496702501 0.038387809087520 0.041875653729200 0.045362988129254 0.048849769795613 0.052335956242944 0.055821504993164 0.059306373575962 0.062790519529313 0.066273900400000 0.069756473744125 0.073238197127632 0.076719028126819 0.080198924328859 0.083677843332315 0.087155742747658 0.090632580197780 0.094108313318514 0.097582899759149 0.101056297182946
[pks, locs] = findpeaks(f_fit,x);
p_fit = (locs(3)-locs(2));
figure
plot(x,f,'b',x,f_fit,'r')
function differences=fun(param)
q=param;
x=[0:0.1:1000];
f = sind(x*q);
[pks, locs] = findpeaks(f,x);
p = (locs(2)-locs(1))
differences = p-10
end
  2 Comments
Torsten
Torsten on 7 Jul 2022
Edited: Torsten on 7 Jul 2022
No, the reason is that the x-array
x=[0:0.1:1000]
is too coarse for findpeaks to find the peaks with sufficient accuracy. Try
x = [0:1e-6:1000]
or something similar and set the options parameter "FinDiffRelStep" to a higher value than the default.
Or just compute the peaks analytically by differentiating sin(x*q) and setting the result to 0.

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by