-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathfitnlorentzian.m
134 lines (89 loc) · 3.9 KB
/
fitnlorentzian.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
function results = fitnlorentzian(data, parameters)
% fit n Lorentzians to xydata with automated guessing of peak locations
% Erik Bauch, May 2017
% github.com/ebauch/matlab
% data is of form [xdata ydata] were xdata and ydata 1 x n arrays
% parameters are of form [par1, par2, ..., parN],
% with par1 = # of peaks to fit
%% unfold data
xdata = data(:,1);
ydata = data(:,2);
npeaks = parameters(1); % number of peaks to fit
%% sort data by x in case it has been randomized
[xdata, xsortindex] = sort(xdata);
ydata = ydata(xsortindex);
%% estimate initial values
% turn dips into peaks
ydatainv = 1 - ydata/max(ydata);
% some smoothing
navg = 1
ydatainv = smooth(ydatainv,navg);
% use findpeaks to get
% change minpeakheight and minpeakwidth to tweak automatic peak
% detection
minpeakheigth = (max(ydatainv)-min(ydatainv))/20;
minpeakwidth = 3;
[peaks locs widths proms] = findpeaks(ydatainv,'SORTSTR', 'descend', 'MINPEAKHEIGHT', minpeakheigth, 'MINPEAKWIDTH', minpeakwidth)
finit = xdata(flip(locs(1:npeaks)))
% found peak frequencies and amplitudes
freq = finit;
freqamp = ydata(locs(1:npeaks));
amp = (max(ydata)-min(ydata));
offset = (max(ydata)+min(ydata))/2;
lw = 0.05; %in GHZ
%% fitting
% build n-peak Lorentzian model function
model = 'A1/(1 + ((x - center1)/(gamma1/2))^2) + offset'; % first Lorentzian
for i = 2 : npeaks
model = [model sprintf(' + A%d/(1 + ((x - center%d)/(gamma%d/2))^2)', i, i, i)];
end
% intial parameters [amplitudes centers linewidths offset]
gammas = lw * ones(npeaks, 1);
startpoints = [freqamp' freq' gammas' offset];
foptions = fitoptions('Method','NonlinearLeastSquares',...
'Algorithm','Trust-Region',... %'Levenberg-Marquardt', 'Gauss-Newton', or 'Trust-Region'. The default is 'Trust-Region' 'MaxIter',1000,...
'Robust','off',... % LAR, Bisquare or off
'Startpoint', startpoints,...
'MaxFunEvals', 5000 ,...
'MaxIter', 5000 ,...
'TolFun', 10^-8);
ftype = fittype(model, 'options', foptions);
% coeffnames(ftype) % gives the order of the parameters
[fitf, gof] = fit(xdata,ydata,ftype);
fitf
%% plotting
% output results with fit function
switch npeaks
case 1
epilog = char(['f1=' num2str(round(fitf.center1,4)) ' GHz R2: ' round(num2str(gof.rsquare)),2]);
results = sort([fitf.center1]);
case 2
epilog = char(['f1=' num2str(round(fitf.center1,4)) ' f2=' num2str(round(fitf.center2,4)) ' GHz R2: ' round(num2str(gof.rsquare)),2]);
results = sort([fitf.center1, fitf.center2]);
case 3
epilog = char(['f1=' num2str(round(fitf.center1,4)) ' f2=' num2str(round(fitf.center2,4)) ' f3= ' num2str(round(fitf.center3,4)) ' GHz R2: ' round(num2str(gof.rsquare)),2]);
results = sort([fitf.center1, fitf.center2, fitf.center3]);
otherwise
epilog ='';
results = [];
end
% create figure
if ~isempty(findobj('name','exp fit'))
fh = findobj('name','exp fit');
set(0, 'currentfigure', fh); % for figures
clf;
else
figure('name','exp fit','Position',[350 200 800 800/(2*1.618)]); %define figure handle
end
% plot data + fit
plot(xdata, ydata, '.-', 'MarkerSize', 7);
text(1.0002*min(xdata), 1.005* min(ydata), epilog);
hold on;
plot(xdata, fitf(xdata),'r-', 'linewidth',1);
xlabel('x (some unit)');
ylabel('amplitude (some unit)');
axis([-inf inf -inf inf]);
legend off;
hold on;
% plot(freq, freqamp, 'k^');
end