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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
|
# PEAKS -- The following procedures are general numerical functions
# dealing with finding peaks in a data array.
#
# FIND_PEAKS Find additional peaks in the data array.
# FIND_LOCAL_MAXIMA Find the local maxima in the data array.
# IS_LOCAL_MAX Test a point to determine if it is a local maximum.
# FIND_CONTRAST Find the peaks satisfying the contrast constraint.
# FIND_ISOLATED Flag peaks which are within separation of a peak
# with a higher peak value.
# FIND_NMAX Select up to the nmax highest ranked peaks.
# COMPARE Compare procedure for sort used in FIND_PEAKS.
# FIND_PEAKS -- Find the peaks in the data array.
#
# The peaks are found using the following algorithm:
#
# 1. Find the local maxima which are not near the edge of existing peaks.
# 2. Reject those below the absolute threshold.
# 3. Reject those below the contrast threshold.
# 4. Determine the ranks of the remaining peaks.
# 5. Flag weaker peaks within separation of a stronger peak.
# 6. Add strongest peaks to the peaks array.
#
# Indefinite data points are ignored.
procedure find_peaks (data, npts, contrast, edge, nmax, separation, threshold,
peaks, npeaks)
real data[npts] # Input data array
int npts # Number of data points
real contrast # Maximum contrast between strongest and weakest
int edge # Minimum distance from the edge
int nmax # Maximum number of peaks to be returned
real separation # Minimum separation between peaks
real threshold # Minimum threshold level for peaks
real peaks[nmax] # Positons of input peaks / output peaks
int npeaks # Number of input peaks / number of output peaks
int i, nx
pointer sp, x, y, rank
int compare()
extern compare()
common /sort/ y
begin
if (npeaks >= nmax)
return
call smark (sp)
call salloc (x, npts, TY_INT)
call salloc (y, npts, TY_REAL)
# Find the positions of the local maxima.
call find_local_maxima (data, npts, peaks, npeaks, edge, separation,
threshold, Memi[x], Memr[y], nx)
# Eliminate points not satisfying the contrast constraint.
call find_contrast (data, Memi[x], Memr[y], nx, contrast)
# Rank the peaks by peak value.
call salloc (rank, nx, TY_INT)
for (i = 1; i <= nx; i = i + 1)
Memi[rank + i - 1] = i
call qsort (Memi[rank], nx, compare)
# Reject weaker peaks within a specified separation of a stronger peak.
call find_isolated (Memi[x], Memi[rank], nx, separation)
# Add the strongest peaks.
call find_nmax (Memi[x], Memi[rank], nx, nmax, peaks, npeaks)
call sfree (sp)
end
# FIND_LOCAL_MAXIMA -- Find the local maxima in the data array.
procedure find_local_maxima (data, npts, peaks, npeaks, edge, separation,
threshold, x, y, nx)
real data[npts] # Input data array
int npts # Number of input points
real peaks[ARB] # Positions of peaks
int npeaks # Number of peaks
int edge # Edge buffer distance
real separation # Minimum separation from peaks
real threshold # Data threshold
int x[npts] # Output positions
real y[npts] # Output data values
int nx # Number of maxima
int i, j
bool is_local_max()
begin
# Find the local maxima above the threshold and not near the edge.
nx = 0
for (i = edge + 1; i <= npts - edge; i = i + 1) {
if ((data[i] >= threshold) && (is_local_max (i, data, npts))) {
nx = nx + 1
x[nx] = i
}
}
# Flag maxima within separation of previous peaks.
for (j = 1; j <= npeaks; j = j + 1) {
for (i = 1; i <= nx; i = i + 1) {
if (IS_INDEFI (x[i]))
next
if (x[i] < peaks[j] - separation)
next
if (x[i] > peaks[j] + separation)
break
x[i] = INDEFI
}
}
# Eliminate flagged maxima and set y values.
j = 0
for (i = 1; i <= nx; i = i + 1) {
if (!IS_INDEFI (x[i])) {
j = j + 1
x[j] = x[i]
y[j] = data[x[j]]
}
}
nx = j
end
# IS_LOCAL_MAX -- Test a point to determine if it is a local maximum.
#
# Indefinite points are ignored.
bool procedure is_local_max (index, data, npts)
# Procedure parameters:
int index # Index to test for local maximum
real data[npts] # Data values
int npts # Number of points in the data vector
int i, j, nright, nleft
begin
# INDEFR points cannot be local maxima.
if (IS_INDEFR (data[index]))
return (false)
# Find the left and right indices where data values change and the
# number of points with the same value. Ignore INDEFR points.
nleft = 0
for (i = index - 1; i >= 1; i = i - 1) {
if (!IS_INDEFR (data[i])) {
if (data[i] != data[index])
break
nleft = nleft + 1
}
}
nright = 0
for (j = index + 1; i <= npts; j = j + 1) {
if (!IS_INDEFR (data[j])) {
if (data[j] != data[index])
break
nright = nright + 1
}
}
# Test for failure to be a local maxima
if ((i == 0) && (j == npts)) {
return (FALSE) # Data is constant
} else if (i == 0) {
if (data[j] > data[index])
return (FALSE) # Data increases to right
} else if (j == npts) {
if (data[i] > data[index]) # Data increase to left
return (FALSE)
} else if ((data[i] > data[index]) || (data[j] > data[index])) {
return (FALSE) # Not a local maximum
} else if (!((nleft - nright == 0) || (nleft - nright == 1))) {
return (FALSE) # Not center of plateau
}
# Point is a local maxima
return (TRUE)
end
# FIND_CONTRAST -- Find the peaks with positions satisfying contrast constraint.
procedure find_contrast (data, x, y, nx, contrast)
real data[ARB] # Input data values
int x[ARB] # Input/Output peak positions
real y[ARB] # Output peak data values
int nx # Number of peaks input
real contrast # Contrast constraint
int i, j
real minval, maxval, threshold
begin
if ((nx == 0.) || (contrast <= 0.))
return
call alimr (y, nx, minval, maxval)
threshold = contrast * maxval
j = 0
do i = 1, nx {
if (y[i] < threshold) {
j = j + 1
x[j] = x[i]
y[j] = y[i]
}
}
nx = j
end
# FIND_ISOLATED -- Flag peaks which are within separation of a peak
# with a higher peak value.
#
# The peak positions, x, and their ranks, rank, are input.
# The rank array contains the indices of the peak positions in order from
# the highest peak value to the lowest peak value. Starting with
# highest rank (rank[1]) all peaks of lower rank within separation
# are marked by setting their positions to INDEFI.
procedure find_isolated (x, rank, nx, separation)
int x[ARB] # Positions of points
int rank[ARB] # Rank of peaks
int nx # Number of peaks
real separation # Minimum allowed separation
int i, j
begin
if ((nx == 0) || (separation <= 0.))
return
# Eliminate close neighbors. The eliminated
# peaks are marked by setting their positions to INDEFI.
for (i = 1; i < nx; i = i + 1) {
if (IS_INDEFI (x[rank[i]]))
next
for (j = i + 1; j <= nx; j = j + 1) {
if (IS_INDEFI (x[rank[j]]))
next
if (abs (x[rank[i]] - x[rank[j]]) < separation)
x[rank[j]] = INDEFI
}
}
end
# FIND_NMAX -- Select up to the nmax highest ranked peaks.
procedure find_nmax (x, rank, nx, nmax, peaks, npeaks)
int x[ARB] # Peak positions
int rank[ARB] # Ranks of peaks
int nx # Number of input / output peaks
int nmax # Max number of peaks to be selected
real peaks[nmax] # Output peak position array
int npeaks # Output number of peaks
int i
begin
for (i = 1; (i <= nx) && (npeaks < nmax); i = i + 1) {
if (IS_INDEFI (x[rank[i]]))
next
npeaks = npeaks + 1
peaks[npeaks] = x[rank[i]]
}
end
# COMPARE -- Compare procedure for sort used in FIND_PEAKS.
# Larger values are indexed first. INDEFR values are indexed last.
int procedure compare (index1, index2)
# Procedure parameters:
int index1 # Comparison index
int index2 # Comparison index
pointer y
common /sort/ y
begin
# INDEFR points are considered to be smallest possible values.
if (IS_INDEFR (Memr[y - 1 + index1]))
return (1)
else if (IS_INDEFR (Memr[y - 1 + index2]))
return (-1)
else if (Memr[y - 1 + index1] < Memr[y - 1 + index2])
return (1)
else if (Memr[y - 1 + index1] > Memr[y - 1 + index2])
return (-1)
else
return (0)
end
|