Scaling Objective Function for Widely Varying Parameters: Data Fitting with lsqcurvefit

4 views (last 30 days)
I have am struggling to fit a dataset to a function which has fit parameters may orders of magnitude different from each other. From what I can tell, I need to scale the parameters inside the function so that there are meaningful changes to the output value when the fitting routine tweaks the parameters looking for optimal values. I have tried scaling the p(1) parameter inside the function to fit, "PAnumberSpectra", but have not yet found a method that works. Could someone provide direction?
My code/data are attached below. Sorry it's long, but it should be self-contained, and suffient to run by itself. I am using Matlab R2019B on Windows 10.

Accepted Answer

Thiago Henrique Gomes Lobato
The main problem actually isn't the scaling but rather the optimization algorithm. Your function seems to be extremely non-smooth with plently of local minima, and thus a gradient based approach isn't able to find a good solution. Using a non-gradient based algorithm can somewhat solve this problem. Here is my result when I use fminsearch that optimizes it with the Nelder-Mead algorithm:
The changes that I made in your code were:
lb = NftBnds(1,:); ub = NftBnds(2,:);
%[betaParams,~,residual] = lsqcurvefit(@PAnumberSpectra,guessVec,indVar,binAvgNum,lb,ub,options); % Fit the function (defined at bottom).
[betaParams,residual] = fminsearch(@PAnumberSpectra2,guessVec,options); % Fit the function (defined at bottom).
...
function Nft = PAnumberSpectra2(p,indVar)
% Parameter Labels
% p(1) = A, the amplitude param
% p(2) = sigma, the width param
% p(3) = f0, the center frequency
% p(4) = A0, the constant offset
% p(5) = Gamma, the one-body loss rate
% indVar(1) = Frequency of the PA beam
% indVar(2) = Exposure time
[binAvgFreq,tExp,binAvgNum] = loadData();
indVar = [binAvgFreq,tExp];
beta = p(1)*Gamma_mol/(sqrt(2*pi)*p(2))*exp((-(indVar(:,1)-p(3)).^2./(2*p(2)^2)))+p(4);
numerator = meanN0.*exp(-p(5).*indVar(:,2));
denomFactor = (meann0*beta*xi)./(2^(3/2)*p(5));
denominator = 1 + denomFactor.*(1 - exp(-p(5).*indVar(:,2)));
Nft = numerator./denominator;
Nft = rms(binAvgNum-Nft);
end
And you had a little error by the plotting:
plotNumFit = PAnumberSpectra(betaParams,indVarPlot);
initGuessAtomNum = PAnumberSpectra(guessVec,indVarPlot);%PAnumberSpectra(betaParams,indVarPlot);

More Answers (0)

Products


Release

R2019b

Community Treasure Hunt

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

Start Hunting!