tomwalters@0
|
1 /*
|
tomwalters@0
|
2 Copyright (c) Applied Psychology Unit, Medical Research Council. 1993
|
tomwalters@0
|
3 ===========================================================================
|
tomwalters@0
|
4
|
tomwalters@0
|
5 Permission to use, copy, modify, and distribute this software without fee
|
tomwalters@0
|
6 is hereby granted for research purposes, provided that this copyright
|
tomwalters@0
|
7 notice appears in all copies and in all supporting documentation, and that
|
tomwalters@0
|
8 the software is not redistributed for any fee (except for a nominal
|
tomwalters@0
|
9 shipping charge). Anyone wanting to incorporate all or part of this
|
tomwalters@0
|
10 software in a commercial product must obtain a license from the Medical
|
tomwalters@0
|
11 Research Council.
|
tomwalters@0
|
12
|
tomwalters@0
|
13 The MRC makes no representations about the suitability of this
|
tomwalters@0
|
14 software for any purpose. It is provided "as is" without express or
|
tomwalters@0
|
15 implied warranty.
|
tomwalters@0
|
16
|
tomwalters@0
|
17 THE MRC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
tomwalters@0
|
18 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
tomwalters@0
|
19 THE A.P.U. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
|
tomwalters@0
|
20 OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
tomwalters@0
|
21 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
tomwalters@0
|
22 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
tomwalters@0
|
23 SOFTWARE.
|
tomwalters@0
|
24 */
|
tomwalters@0
|
25
|
tomwalters@0
|
26 /*--------------------------------------------------------------------------*/
|
tomwalters@0
|
27
|
tomwalters@0
|
28 /* findpeaks.c
|
tomwalters@0
|
29 * -------------
|
tomwalters@0
|
30 *
|
tomwalters@0
|
31 * Part of the temporal regularity programs
|
tomwalters@0
|
32 *
|
tomwalters@0
|
33 * M.Akeroyd. Summer 1993. Revised Winter 1994.
|
tomwalters@0
|
34 */
|
tomwalters@0
|
35
|
tomwalters@0
|
36
|
tomwalters@0
|
37 #include <stdio.h>
|
tomwalters@0
|
38 #include <string.h>
|
tomwalters@0
|
39 #include <stdlib.h>
|
tomwalters@0
|
40
|
tomwalters@0
|
41 #include "tip.h"
|
tomwalters@0
|
42
|
tomwalters@0
|
43
|
tomwalters@0
|
44
|
tomwalters@0
|
45
|
tomwalters@0
|
46 /*--------------------------------------------------------------------------*/
|
tomwalters@0
|
47
|
tomwalters@0
|
48
|
tomwalters@0
|
49 int findpeaksreverse()
|
tomwalters@0
|
50 {
|
tomwalters@0
|
51 /* What this code does:
|
tomwalters@0
|
52 * Its primary job is to find out where the tops of local maxima ("peaks")
|
tomwalters@0
|
53 * are. Its secondary job is to define the edges of those peaks.
|
tomwalters@0
|
54 * The locations and heights of the peaks are held in the peak[n] structure,
|
tomwalters@0
|
55 * where n is the number of the peak. The edges are held in the
|
tomwalters@0
|
56 * nextevent[n] structure.
|
tomwalters@0
|
57 *
|
tomwalters@0
|
58 * Its called 'findpeaksreverse' because it traverses the array from 'right'
|
tomwalters@0
|
59 * (ie, +ve Image Time) to 'left' (-ve Image Time): peaks get numbered
|
tomwalters@0
|
60 * accordingly. eg, if nwidth = 0, then the TriggerPeak is peak 1.
|
tomwalters@0
|
61 *
|
tomwalters@0
|
62 * Edge defintions:
|
tomwalters@0
|
63 * for a peak n
|
tomwalters@0
|
64 * nextevent[n] is the LEFT edge (because we are going right-to-left
|
tomwalters@0
|
65 * on samples);
|
tomwalters@0
|
66 * nextevent[n-1] the RIGHT edge.
|
tomwalters@0
|
67 *
|
tomwalters@0
|
68 * Peak definitions:
|
tomwalters@0
|
69 * simple peak: f(sample - 1 ) < f(sample) > f(sample + 1)
|
tomwalters@0
|
70 * complex peak is a plateau: hopefully the code finds the middle, or
|
tomwalters@0
|
71 * the leftedge of the middle (if the middle is an
|
tomwalters@0
|
72 * even number of samples)
|
tomwalters@0
|
73 *
|
tomwalters@0
|
74 * Nextevents definitions:
|
tomwalters@0
|
75 * minima: f(sample - 1 ) > f(sample) < f(sample + 1)
|
tomwalters@0
|
76 * rightzero: the first f(sample) = 0 to the Right of a peak
|
tomwalters@0
|
77 * leftzero: ... ... ... Left ...
|
tomwalters@0
|
78 * (so, because we're going backwards, the RIGHTZERO of a
|
tomwalters@0
|
79 * peak is actually held in nextevent[n-1], the LEFTZERO
|
tomwalters@0
|
80 * in nextevent[n]).
|
tomwalters@0
|
81 *
|
tomwalters@0
|
82 *
|
tomwalters@0
|
83 * The first and last samples of a channel are dealt with differently,
|
tomwalters@0
|
84 * if only because the inequalities will crash if the (sample-1) or
|
tomwalters@0
|
85 * (sample+1) (respectively) don't exist. But I'm not sure if they work
|
tomwalters@0
|
86 * properly. I'm pretty certain they don't: so, they are just ignored.
|
tomwalters@0
|
87 *
|
tomwalters@0
|
88 * Finally, the number of peaks found is RETURNed.
|
tomwalters@0
|
89 *
|
tomwalters@0
|
90 *
|
tomwalters@0
|
91 * Version of 21 May 1993. Revised slighlty Winter 1994.
|
tomwalters@0
|
92 */
|
tomwalters@0
|
93
|
tomwalters@0
|
94
|
tomwalters@0
|
95 /*---------------------------*/
|
tomwalters@0
|
96
|
tomwalters@0
|
97 extern short inputdata[MAX_DATA];
|
tomwalters@0
|
98 extern struct Peak peak[MAX_PEAKS];
|
tomwalters@0
|
99 extern struct NextEvent nextevent[MAX_NEXTEVENTS];
|
tomwalters@0
|
100 extern char progname[MAX_STRING_LENGTH];
|
tomwalters@0
|
101 extern int framewidth_samples; /* pwidth + nwidth * samplerate */
|
tomwalters@0
|
102
|
tomwalters@0
|
103 int sample; /* left to right */
|
tomwalters@0
|
104 int n = 0; /* peak counter: right to left */
|
tomwalters@0
|
105 int zeroflag = OFF; /* used within nextevents */
|
tomwalters@0
|
106 int localsample, flat_top, truesample; /* All 3 used in finding the
|
tomwalters@0
|
107 centre of a plateau */
|
tomwalters@0
|
108
|
tomwalters@0
|
109 /* WARNING: goes from right to left ... */
|
tomwalters@0
|
110
|
tomwalters@0
|
111 /*---------------------------*/
|
tomwalters@0
|
112
|
tomwalters@0
|
113 /* do peak check for first sample: its framewidth - 1, because the channel
|
tomwalters@0
|
114 * starts at 0 */
|
tomwalters@0
|
115 /* NB: removed 18th June 1993*/
|
tomwalters@0
|
116
|
tomwalters@0
|
117 /* if (inputdata[framewidth_samples - 1] > inputdata[framewidth_samples -2]){
|
tomwalters@0
|
118 * peak[++n].sample = framewidth_samples - 1;
|
tomwalters@0
|
119 * peak[n].mag = inputdata[framewidth_samples-1];}
|
tomwalters@0
|
120 */
|
tomwalters@0
|
121
|
tomwalters@0
|
122 /*---------------------------*/
|
tomwalters@0
|
123
|
tomwalters@0
|
124 /* for the rest of the samples */
|
tomwalters@0
|
125 for (sample=framewidth_samples - 2; sample >= 1; sample--) {
|
tomwalters@0
|
126
|
tomwalters@0
|
127 /* simple peak ? */
|
tomwalters@0
|
128 if ((inputdata[sample] > inputdata[sample - 1]) &&
|
tomwalters@0
|
129 (inputdata[sample] > inputdata[sample + 1])){
|
tomwalters@0
|
130 peak[++n].sample = sample;
|
tomwalters@0
|
131 peak[n].mag = inputdata[sample];
|
tomwalters@0
|
132 continue;}
|
tomwalters@0
|
133
|
tomwalters@0
|
134 /* complicated peak? ie, a plateau to it */
|
tomwalters@0
|
135 /* but plateaus on the sides of big peaks don't count ... */
|
tomwalters@0
|
136 if ((inputdata[sample] >= inputdata[sample - 1]) &&
|
tomwalters@0
|
137 (inputdata[sample] > inputdata[sample + 1])){
|
tomwalters@0
|
138 localsample = sample; /* counter to leftedge of the plateau */
|
tomwalters@0
|
139 flat_top = 1; /* width, in samples, of the top */
|
tomwalters@0
|
140 truesample = sample;
|
tomwalters@0
|
141 while (inputdata[--localsample] == inputdata[sample])
|
tomwalters@0
|
142 flat_top ++; /* find out the width of the plateau */
|
tomwalters@0
|
143
|
tomwalters@0
|
144 /* is this plateau a mere bump on the edge of a real peak?
|
tomwalters@0
|
145 * If so, its not a peak.
|
tomwalters@0
|
146 * localsample is just off the leftedge of the plateau */
|
tomwalters@0
|
147 if (inputdata[localsample] > inputdata[localsample+1])
|
tomwalters@0
|
148 continue;
|
tomwalters@0
|
149
|
tomwalters@0
|
150 truesample = sample - (int) (flat_top / 2);
|
tomwalters@0
|
151 /* I think this ensures it is a leftward as possible */
|
tomwalters@0
|
152 peak[++n].sample = truesample;
|
tomwalters@0
|
153 peak[n].mag = inputdata[truesample];
|
tomwalters@0
|
154 continue;}
|
tomwalters@0
|
155
|
tomwalters@0
|
156 /*---------------------------*/
|
tomwalters@0
|
157
|
tomwalters@0
|
158 /* nextevents ... */
|
tomwalters@0
|
159
|
tomwalters@0
|
160 /* This is an errorcheck ...
|
tomwalters@0
|
161 * If we've reached a LEFTZERO, but the current nextevent is a
|
tomwalters@0
|
162 * RIGHTZERO, then something has gone very wrong ...
|
tomwalters@0
|
163 * we should have hit a peak on the way, so incrementing the counter */
|
tomwalters@0
|
164 if ((inputdata[sample] == 0) && nextevent[n].type == RIGHTEDGE) {
|
tomwalters@0
|
165 fprintf(stderr, " %s : something's gone wrong: didn't find a peak between two zeros.\n", progname);
|
tomwalters@0
|
166 exit(-1); }
|
tomwalters@0
|
167
|
tomwalters@0
|
168 if ((inputdata[sample] == 0) && (zeroflag == OFF)) {
|
tomwalters@0
|
169 nextevent[n].type = LEFTZERO;
|
tomwalters@0
|
170 nextevent[n].sample = sample;
|
tomwalters@0
|
171 nextevent[n].mag = inputdata[sample];
|
tomwalters@0
|
172 zeroflag = ON;
|
tomwalters@0
|
173 continue;}
|
tomwalters@0
|
174
|
tomwalters@0
|
175 if ((inputdata[sample] != 0) && (zeroflag == ON)) {
|
tomwalters@0
|
176 nextevent[n].type = RIGHTZERO;
|
tomwalters@0
|
177 nextevent[n].sample = sample+1; /* +1 because you can only notice
|
tomwalters@0
|
178 * such an event when you are off it,
|
tomwalters@0
|
179 * and because we are moving
|
tomwalters@0
|
180 * in reverse */
|
tomwalters@0
|
181 nextevent[n].mag = inputdata[sample+1];
|
tomwalters@0
|
182 zeroflag = OFF;
|
tomwalters@0
|
183 continue;}
|
tomwalters@0
|
184
|
tomwalters@0
|
185 /* This next bit removed at some stage */
|
tomwalters@0
|
186 /*
|
tomwalters@0
|
187 * if ((inputdata[sample] <= inputdata[sample +1]) &&
|
tomwalters@0
|
188 * (inputdata[sample] < inputdata[sample -1]) &&
|
tomwalters@0
|
189 * (nextevent[n].type == NULL)) {
|
tomwalters@0
|
190 */
|
tomwalters@0
|
191
|
tomwalters@0
|
192 if ((inputdata[sample] <= inputdata[sample +1]) &&
|
tomwalters@0
|
193 (inputdata[sample] < inputdata[sample -1])) {
|
tomwalters@0
|
194 nextevent[n].type = MINIMUM;
|
tomwalters@0
|
195 nextevent[n].sample = sample;
|
tomwalters@0
|
196 nextevent[n].mag = inputdata[sample];
|
tomwalters@0
|
197 continue;}
|
tomwalters@0
|
198
|
tomwalters@0
|
199 } /* sample */
|
tomwalters@0
|
200
|
tomwalters@0
|
201 /*-----------------------------*/
|
tomwalters@0
|
202
|
tomwalters@0
|
203 /* repeat for last sample*/
|
tomwalters@0
|
204
|
tomwalters@0
|
205 /* peak ? */
|
tomwalters@0
|
206 /*NB: Removed 18th June 1993 */
|
tomwalters@0
|
207
|
tomwalters@0
|
208 /* if (inputdata[0] > inputdata[1] ){
|
tomwalters@0
|
209 * peak[++n].sample = 0;
|
tomwalters@0
|
210 * peak[n].mag = inputdata[0];}
|
tomwalters@0
|
211 */
|
tomwalters@0
|
212
|
tomwalters@0
|
213
|
tomwalters@0
|
214 /* nextevents ... */
|
tomwalters@0
|
215
|
tomwalters@0
|
216 if (inputdata[0] == 0 && zeroflag == OFF) {
|
tomwalters@0
|
217 nextevent[n].type = LEFTZERO;
|
tomwalters@0
|
218 nextevent[n].sample = 0;
|
tomwalters@0
|
219 nextevent[n].mag = inputdata[0];
|
tomwalters@0
|
220 zeroflag = ON;}
|
tomwalters@0
|
221
|
tomwalters@0
|
222
|
tomwalters@0
|
223 if (inputdata[0] != 0 && zeroflag == ON) {
|
tomwalters@0
|
224 nextevent[n].type = RIGHTZERO;
|
tomwalters@0
|
225 nextevent[n].sample = 0; /* -1 because you only notice such an event
|
tomwalters@0
|
226 * when you've gone past*/
|
tomwalters@0
|
227 nextevent[n].mag = inputdata[0];
|
tomwalters@0
|
228 zeroflag = OFF;}
|
tomwalters@0
|
229
|
tomwalters@0
|
230 if (inputdata[0] < inputdata[1]){
|
tomwalters@0
|
231 nextevent[n].type = MINIMUM;
|
tomwalters@0
|
232 nextevent[n].sample = 0;
|
tomwalters@0
|
233 nextevent[n].mag = inputdata[0]; }
|
tomwalters@0
|
234
|
tomwalters@0
|
235 if (nextevent[n].type == UNSET) {
|
tomwalters@0
|
236 nextevent[n].type = END_OF_WIDTH;
|
tomwalters@0
|
237 nextevent[n].sample = 0;
|
tomwalters@0
|
238 nextevent[n].mag = inputdata[0]; }
|
tomwalters@0
|
239
|
tomwalters@0
|
240 return n; /* total number of peaks found, starting at 1 */
|
tomwalters@0
|
241 }
|
tomwalters@0
|
242
|
tomwalters@0
|
243
|
tomwalters@0
|
244
|
tomwalters@0
|
245
|
tomwalters@0
|
246 /* The End */
|
tomwalters@0
|
247 /*--------------------------------------------------------------------------*/
|
tomwalters@0
|
248
|
tomwalters@0
|
249
|
tomwalters@0
|
250
|
tomwalters@0
|
251
|
tomwalters@0
|
252
|
tomwalters@0
|
253
|
tomwalters@0
|
254
|
tomwalters@0
|
255
|
tomwalters@0
|
256
|