-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathget_peaks_spline.m
145 lines (119 loc) · 3.67 KB
/
get_peaks_spline.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
134
135
136
137
138
139
140
141
142
143
144
145
function get_peaks_spline(data, prominence, verbose)
% Fit Gaussian curves to chromatogram signal.
%
% Gaussian function : f(x) = a * exp( -(x-b)^2 / (2*c^2) ) where,
% a is the max height of the peak,
% b is the position of the center of the peak (mean), and
% c controls the width of the peak (standard deviation)
%
% INPUTS
% ======
% data : (n x 2) array
% Array with two columns containing time vs signal data.
%
% prominence : float
% Threshold value of peak height to be considered a peak. If too many
% peaks are found, increase the value. If no peaks are found, try to
% decrease the value. Default is 200.
%
% verbose : logical
% Wether or not to show all fitting process data. Default is false.
%
% EXAMPLE
% =======
% get_peaks(original_data)
% get_peaks(original_data, 300, true)
% Argument handling (requires MATLAB 2022+)
arguments
data (:,2) double;
prominence (1,1) double = 200
verbose (1,1) logical = false
end
fprintf('Processing signal... \n\n')
x = data(:,1); % time
y = data(:,2); % absorbance
% Baseline fix (minimum to zero)
ymin = min(y);
y = y - ymin;
% Plot chromatogram
figure(1)
plot(x, y, '-', 'DisplayName','Signal')
xlabel('{\itt} (min)')
ylabel('{\itA} (mAU)')
% Find peaks
[pks, locs, w, p] = findpeaks(y, x, 'MinPeakProminence', prominence);
n_peaks = length(pks); % number of peaks
text(locs+0.2, pks, num2str((1:numel(pks))')) % label peaks in the figure
% Terminate is no peaks are found
if n_peaks < 1
fprintf('NO PEAKS FOUND! Try changing the prominence value.\n\n')
return;
end
% Create different sets of data (one for each peak)
if n_peaks == 1
split_data{1} = data;
else
% Find peak borders (using inverted the signal)
[border, border_locs] = findpeaks(-y, x, 'MinPeakProminence', prominence);
if verbose
figure(1)
hold on;
plot([border_locs border_locs], [0 max(y)], '-.', 'Color','#808080', 'DisplayName','Split')
end
% Split data points acording to respective peaks using border_locs
n = 0;
for i = 1:length(border_locs)
for j = 1:length(x)
if x(n+j) < border_locs(i)
split_data{i}(j,1) = x(n+j);
split_data{i}(j,2) = y(n+j);
else
n = n+j-1;
break
end
end
end
split_data{i+1}(:,1) = x(n+1:end);
split_data{i+1}(:,2) = y(n+1:end);
end
% Fit Gaussian peaks to data
for i = 1:n_peaks
x = split_data{i}(:,1);
y = split_data{i}(:,2);
% Fit spline
[curve, goodness, output] = fit(x, y, 'smoothingspline');
exitflag = output.exitflag;
% Calculate are under curve (integral)
xspan = linspace(x(1), y(end), 1000)';
int = integrate(curve, xspan, x(1));
area = int(end);
% Plot fitted spline
figure(1)
hold on;
peak_name = sprintf('Peak %i', i);
% plot(x_calc, y_calc, '--', 'DisplayName',peak_name)
plot(curve, x, y);
legend;
% Calculate quality of fit statistics
R2 = goodness.rsquare;
R2adj = goodness.adjrsquare;
% Output results
fprintf('PEAK %i \n', i)
fprintf('exitflag = %i \n', exitflag)
fprintf('Area under fitted peak (A) = %.4f \n', area)
% fprintf('AARD = %.4f \n', AARD)
fprintf('Correlation coefficient (R^2) = %.4f \n', R2)
fprintf('Adjusted correlation coefficient (R^2adj) = %.4f \n\n', R2adj)
if i ~= n_peaks
fprintf('----- \n\n')
end
end
function f = fobj(parameters, data)
% Objective function for parameter optimization (Least-Squares)
x_exp = data(:,1);
y_exp = data(:,2);
a = parameters(1);
b = parameters(2);
c = parameters(3);
y_calc = a .* exp( -(x_exp-b).^2 ./ (2*c.^2) );
f = sum( (y_exp - y_calc).^2 );