annotate saitools/findpeaks.c @ 0:5242703e91d3 tip

Initial checkin for AIM92 aimR8.2 (last updated May 1997).
author tomwalters
date Fri, 20 May 2011 15:19:45 +0100
parents
children
rev   line source
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