Mercurial > hg > aim92
comparison model/spiral.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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:5242703e91d3 |
---|---|
1 /* | |
2 Copyright (c) Applied Psychology Unit, Medical Research Council. 1988, 1989 | |
3 =========================================================================== | |
4 | |
5 Permission to use, copy, modify, and distribute this software without fee | |
6 is hereby granted for research purposes, provided that this copyright | |
7 notice appears in all copies and in all supporting documentation, and that | |
8 the software is not redistributed for any fee (except for a nominal shipping | |
9 charge). Anyone wanting to incorporate all or part of this software in a | |
10 commercial product must obtain a license from the Medical Research Council. | |
11 | |
12 The MRC makes no representations about the suitability of this | |
13 software for any purpose. It is provided "as is" without express or implied | |
14 warranty. | |
15 | |
16 THE MRC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
17 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE | |
18 A.P.U. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY | |
19 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
20 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
21 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
22 */ | |
23 | |
24 /* | |
25 spiral.c | |
26 ======== | |
27 | |
28 Tap SAI frames and draw each one as a spiral in the given window. | |
29 */ | |
30 | |
31 /* | |
32 Modifications made to the routines draw_spiral, map_ribbon, map_spiral | |
33 so that the nwidth section of the SAI image is taken into account while | |
34 doing the calculations, (in image.c, doColumn()) and while plotting, | |
35 only the positive section of the time axis is drawn. | |
36 Added a new field "nwid" in the _draw_state object. | |
37 17 March, 1995. A Jay Datta | |
38 */ | |
39 | |
40 #include <math.h> | |
41 #include <stdio.h> | |
42 | |
43 #include "windows.h" | |
44 #include "stitch.h" | |
45 #include "source.h" | |
46 #include "draw.h" | |
47 #include "ops.h" | |
48 #include "spiral.h" | |
49 | |
50 #ifndef lint | |
51 static char *sccs_id = "@(#)spiral.c 1.9 Mike Allerhand (MRC-APU) 6/1/91" ; | |
52 #endif | |
53 | |
54 /**************************************************************************** | |
55 * Misc definitions | |
56 ****************************************************************************/ | |
57 #define TWOPI 6.28318530717 | |
58 #define log2(x) (log((double)x)/log(2.0)) | |
59 | |
60 /**************************************************************************** | |
61 * Model parameters. | |
62 * Defaults: | |
63 * form_spl = 'arch' | |
64 * dotsize_spl = 2 | |
65 * axis_spl = off | |
66 * zero_spl = 4.072 | |
67 * dotthresh_spl = 50 | |
68 ****************************************************************************/ | |
69 int frameheight, framewidth, nwid; /* Dimensions of each sai */ | |
70 | |
71 char form_spl = 'A' ; /* Form of spiral, 'A' or 'L' */ | |
72 int dotsize_spl = 2 ; /* Dotsize in pixels */ | |
73 int axis_spl = 0 ; /* Flag for spiral axis */ | |
74 double zero_spl = 4.072 ; /* For rotation and circuit removal */ | |
75 int dotthresh_spl = 25 ; /* Min peak height */ | |
76 | |
77 /*=================== COORDINATE SYSTEM OF THE DATA =======================*/ | |
78 | |
79 /**************************************************************************** | |
80 * Size and location, (program arguments), of calibrated box, in | |
81 * coord system of the data. | |
82 * range = range or size of both axes, (ie. "magnification" of plot). | |
83 * xorg,yorg = real plot coordinates at centre of screen. | |
84 ****************************************************************************/ | |
85 static float range; | |
86 static float xorg; | |
87 static float yorg; | |
88 | |
89 /**************************************************************************** | |
90 * Limits of calibrated box in coord system of the data. | |
91 ****************************************************************************/ | |
92 static float Xd0, Yd0; /* Bottom-left corner */ | |
93 static float Xd1, Yd1; /* Top-right corner */ | |
94 | |
95 | |
96 /*===================== PIXEL COORDINATE SYSTEM ==========================*/ | |
97 | |
98 /**************************************************************************** | |
99 * Dimensions of window (box plus border) in pixel coord system. | |
100 ****************************************************************************/ | |
101 static int width,height; | |
102 static int border; /* border = min(width,height) / 6; */ | |
103 | |
104 /**************************************************************************** | |
105 * Limits of on-screen calibrated box in pixel coord system. | |
106 ****************************************************************************/ | |
107 static int Xp0, Yp0; /* Bottom-left corner (border, height-border) */ | |
108 static int Xp1, Yp1; /* Top-right corner (width-border, border) */ | |
109 | |
110 /**************************************************************************** | |
111 * Dimensions of calibrated box in pixel coord system | |
112 ****************************************************************************/ | |
113 static int Wb; /* Box width Wb = Xp1-Xp0 */ | |
114 static int Hb; /* Box height Hb = Yp0-Yp1 */ | |
115 | |
116 /**************************************************************************** | |
117 * The parameters for the calibrated box in the pixel coord system are | |
118 * initialized for a given window size (width, height, in pixels), | |
119 * as follows: | |
120 * | |
121 * border = min(width,height) / 6; | |
122 * Xp0 = border; | |
123 * Xp1 = width - border; | |
124 * Yp0 = border; | |
125 * Yp1 = height - border; | |
126 * Wb = Xp1-Xp0; | |
127 * Hb = Yp1-Yp0; | |
128 ****************************************************************************/ | |
129 | |
130 /*================= COORDINATE SYSTEM TRANSFORMATIONS =====================*/ | |
131 | |
132 /**************************************************************************** | |
133 * Transformations from coord system of the data to pixel coord system. | |
134 * For example, if the origin in the data coord system is (0,0), then | |
135 * the origin in the pixel coord system is (px(0),py(0)). | |
136 ****************************************************************************/ | |
137 #define px(x) ((int)(Xp0+Wb/2+(x-xorg)*(Wb/range))) | |
138 #define py(y) ((int)(Yp0+Hb/2+(y-yorg)*(Hb/range))) | |
139 | |
140 /**************************************************************************** | |
141 * Screen Position (in pixel coord system): test position is within box. | |
142 ****************************************************************************/ | |
143 #define Xinbox(x) ((Xp0<=x && x<=Xp1) ? 1 : 0) | |
144 #define Yinbox(y) ((Yp0<=y && y<=Yp1) ? 1 : 0) | |
145 #define inbox(x,y) ((Xinbox(x) && Yinbox(y)) ? 1 : 0) | |
146 | |
147 | |
148 | |
149 | |
150 /**************************************************************************** | |
151 * This routine is called once per SAI frame. The SAI data is in array "frame". | |
152 * The SAI frame is formatted row-wise, starting with the lowest-frequency row. | |
153 * The state structure is: | |
154 * struct _draw_state { | |
155 * Source source; | |
156 * WindowObject window; | |
157 * int min, max; | |
158 * int framewidth, frameheight; dimensions of the SAI | |
159 * int nwid; | |
160 * long frames; | |
161 * long framenumber; | |
162 * void (*interceptor)(); function which stores window for replay | |
163 * void (*drawer)(); drawing function | |
164 * }; | |
165 * | |
166 * This struct is defined in stitch/draw.h | |
167 * It is initialized by routine "SourceDraw" in stitch/draw.c, which is called | |
168 * from gen.c. Note that this takes place after the SaiEntry routine has been | |
169 * called, so the sai dimensions set there will apply. | |
170 * | |
171 ****************************************************************************/ | |
172 void draw_spiral( state, image ) | |
173 struct _draw_state *state ; | |
174 short *image ; | |
175 { | |
176 static int first=1; /* flag for first-call of this routine */ | |
177 | |
178 /* Coordinate arrays for axis and spiral points */ | |
179 static short *Xaxis; | |
180 static short *Yaxis; | |
181 static int naxis = 0; /* number of points plotted along spiral axis */ | |
182 /* (naxis = (100 * nsamples) +1) */ | |
183 static short *Xspiral; | |
184 static short *Yspiral; | |
185 int npoints = 0; /* number of samples in pulse ribbon and spiral */ | |
186 | |
187 static short *Xdot; | |
188 static short *Ydot; | |
189 | |
190 static short *frame ; | |
191 | |
192 frameheight = state->frameheight; | |
193 framewidth= (state->framewidth)+(state->nwid); /* -nwid */ | |
194 /* fprintf(stderr, "THE NWID VALUE is %d\n", state->nwid); */ | |
195 nwid=-state->nwid; | |
196 /* fprintf(stderr, "framewidth=%d, frameheight=%d\n", frameheight, framewidth); */ | |
197 /* Initialize parameters of pixel coord system (see spiral.h) */ | |
198 width = Width( state->window ) ; | |
199 height = Height( state->window ) ; | |
200 | |
201 border = 0; | |
202 | |
203 Xp0 = border; | |
204 Xp1 = width - border; | |
205 Yp0 = border; | |
206 Yp1 = height - border; | |
207 Wb = Xp1-Xp0; | |
208 Hb = Yp1-Yp0; | |
209 | |
210 /* Initialize parameters of data coord system */ | |
211 if (form_spl == 'A') range = 2 * (TWOPI * log2((double)(framewidth+nwid)) - TWOPI * zero_spl); | |
212 if (form_spl == 'L') range = 2 * (framewidth+nwid); | |
213 xorg = 0; | |
214 yorg = 0; | |
215 | |
216 /* Allocate space (first-time call only). */ | |
217 if (first) { | |
218 first = 0; | |
219 frame = NewArray(short, frameheight*(framewidth+nwid), "frame spiral.c" ); | |
220 if (axis_spl) { | |
221 /* Allocate space and compute (X,Y) coords for spiral axis. */ | |
222 /* Resolution of points on axis is 100 times greater, so that */ | |
223 /* inner circuits look smooth. Add 1 as time starts from zero.*/ | |
224 naxis = (100*framewidth+nwid)+1; | |
225 Xaxis = NewArray(short, naxis, "Xaxis, spiral.c" ); | |
226 Yaxis = NewArray(short, naxis, "Yaxis, spiral.c" ); | |
227 naxis = gen_axis(Xaxis,Yaxis,naxis,form_spl,zero_spl); | |
228 } | |
229 if (dotsize_spl) { | |
230 /* Allocate space for coords of spiral points.*/ | |
231 Xspiral = NewArray(short, frameheight * framewidth+nwid, "Xspiral spiral.c" ); | |
232 Yspiral = NewArray(short, frameheight * framewidth+nwid, "Yspiral spiral.c" ); | |
233 Xdot = NewArray(short, frameheight * framewidth+nwid, "Xdot spiral.c" ); | |
234 Ydot = NewArray(short, frameheight * framewidth+nwid, "Ydot spiral.c" ); | |
235 } | |
236 } | |
237 | |
238 CopyArray( image, frame, (framewidth+nwid)*frameheight ) ; | |
239 | |
240 /* Map one SAI frame onto a pulse ribbon, and return the number of 1's */ | |
241 npoints = map_ribbon(frame,dotthresh_spl); | |
242 | |
243 /* Map 1's in a pulse ribbon onto points in spiral coords. */ | |
244 /* Return the number of points in the plot window. */ | |
245 npoints = map_spiral(frame,Xspiral,Yspiral,form_spl,zero_spl); | |
246 | |
247 /* Plot spiral points and axis in window. */ | |
248 if (dotsize_spl) | |
249 plotdots(state->window,Xspiral,Yspiral,Xdot,Ydot,npoints,dotsize_spl-1); | |
250 if (axis_spl) | |
251 Draw(state->window,Xaxis,Yaxis,naxis); | |
252 | |
253 return ; | |
254 } | |
255 | |
256 | |
257 | |
258 /**************************************************************************** | |
259 Map an SAI frame onto a "pulse ribbon". | |
260 | |
261 Convert a "frame" into a binary array where a `1' corresponds to a peak in | |
262 the SAI frame, and everwhere else is `0'. This binary array is called a | |
263 pulse ribbon. | |
264 | |
265 Each SAI is a "frame". A frame is a matrix of "frameheight" rows by | |
266 "framewidth" columns. Each row corresponds to a frequency channel, and | |
267 frameheight corresponds to "chans" in image.c. The columns correspond to | |
268 the number of time samples in the "image_duration", and framewidth | |
269 corresponds to framewidth (or imagewidth/chans) in image.c. | |
270 | |
271 The format of data in the input file, (short *frame), is "unmultiplexed". | |
272 This is an SAI frame in row-wise format, with the row corresponding | |
273 to the lowest-frequency channel comming first. | |
274 | |
275 Every point in the sai frame is a coordinate pair: | |
276 (f,t); f=0,1,...,frameheight-1, t=0,1,...,framewidth-1. | |
277 (The lowest frequency channel has the lowest channel number f). | |
278 (The time-origin is the rightmost point, framewidth-1). | |
279 | |
280 Peaks in the SAI frame are maxima along the time axis. Peaks are independent | |
281 of adjacent frequency channels. | |
282 A peak is defined as the highest point between zeroes, which also exceeds a | |
283 threshold. (A zero-crossing between peaks is guaranteed, since the cochleagram | |
284 signal has been half-wave rectified). | |
285 | |
286 The number of peaks found is returned. | |
287 ****************************************************************************/ | |
288 map_ribbon(frame,threshold) | |
289 short *frame; | |
290 int threshold; | |
291 { | |
292 short p, pmax; | |
293 int i, j, k, jk, npoints=0; | |
294 | |
295 /* for each SAI row (each frequency channel) in turn */ | |
296 for (i=0, k=0 ; i<frameheight ; i++, k+=framewidth+nwid) /* SSS */ | |
297 /* for each time sample, working from right to left */ | |
298 for (j=framewidth ; j>=0 ; j--) { /* SSS */ | |
299 /* while zero, advance to next peak */ | |
300 while (j>=(0-1) && frame[j+k]<=0) { /* SSS */ | |
301 frame[j+k]=0; | |
302 j--; | |
303 } | |
304 /* while greater than zero, search for max peak */ | |
305 for (pmax=0 ; j>=(0-1) && (p=frame[j+k])>0 ; j--) { /* SSS */ | |
306 frame[j+k]=0; | |
307 if (p>pmax) { | |
308 pmax=p; jk=j+k; | |
309 } | |
310 } | |
311 /* record max peak if it exceeds the threshold */ | |
312 if (pmax > threshold) { | |
313 frame[jk]=1; | |
314 npoints++; | |
315 } | |
316 } | |
317 return npoints; | |
318 } | |
319 | |
320 | |
321 /**************************************************************************** | |
322 * Map 1's in pulse ribbon onto (x,y) spiral coords, and store in the | |
323 * given arrays if the points will appear in the plot window. | |
324 * Return the number of mapped points within the plot window. | |
325 ****************************************************************************/ | |
326 map_spiral(frame,Xarray,Yarray,form_spl,zero_spl) | |
327 short *frame; | |
328 short *Xarray, *Yarray; | |
329 char form_spl; | |
330 float zero_spl; | |
331 { | |
332 float t, f, x, y; | |
333 float r0, r, theta; | |
334 int i, j, k, X, Y; | |
335 int points=0; | |
336 | |
337 /* for each SAI row (each frequency channel) in turn */ | |
338 for (i=0, k=0 ; i<frameheight ; i++, k+=framewidth+nwid) /* SSS */ | |
339 /* for each time sample, working from right to left */ | |
340 for (j=framewidth ; j>=0 ; j--) /* SSS */ | |
341 if (frame[j+k] == 1) { /* for each `1' in pulse ribbon */ | |
342 f = i; | |
343 t = (framewidth-1) - j ; /* time origin is on the right */ | |
344 | |
345 /* calculate polar coords of point, (r,theta): */ | |
346 /* radius r at outer edge of spiral cycle, (ie at min f) */ | |
347 /* radius r0, at same theta, at min f on previous cycle */ | |
348 if (t > 1) theta = TWOPI * (log2(t) - zero_spl); | |
349 else theta = 0; /* special case of 1st cycle */ | |
350 if (form_spl == 'A') { /* spiral == ARCHEMEDIAN */ | |
351 r = theta; | |
352 if (r < 0) r = 0; | |
353 if (r > 0) r0 = r - TWOPI; | |
354 else r0 = 0; /* special case of 1st cycle */ | |
355 } | |
356 if (form_spl == 'L') { /* spiral == LOGARITHMIC */ | |
357 r = t; | |
358 if (t > 1) r0 = r/2; | |
359 else r0 = 0; /* special case of 1st cycle */ | |
360 } | |
361 /* scale radius r for current frequency f (>= min f) */ | |
362 /* scale such that spiral axis occupies its own channel */ | |
363 r = r - ((f+1)/(frameheight+1)) * (r-r0); | |
364 /* convert polar to cartesian coords */ | |
365 x = r*cos(theta); | |
366 y = r*sin(theta); | |
367 /* Transform into pixel coord system and store point */ | |
368 X = px(x); | |
369 Y = py(y); | |
370 if (inbox(X,Y)) { | |
371 Xarray[points] = X; | |
372 Yarray[points++] = Y; | |
373 } | |
374 } | |
375 | |
376 return points; | |
377 } | |
378 | |
379 | |
380 /**************************************************************************** | |
381 * Generate points (X,Y coords) for spiral axis and store in given arrays. | |
382 * Return the number of points stored. | |
383 ****************************************************************************/ | |
384 int gen_axis(Xarray,Yarray,naxis,form_spl,zero_spl) | |
385 short *Xarray, *Yarray; | |
386 int naxis; | |
387 char form_spl; | |
388 float zero_spl; | |
389 { | |
390 int t; | |
391 float r, theta; | |
392 int X, Y; | |
393 float x, y; | |
394 int points=0; | |
395 | |
396 /* Calculate axis points in data coord system */ | |
397 for (t=100 ; t < naxis ; t++) { | |
398 theta = TWOPI * (log2((float)t/100) - zero_spl); | |
399 if (theta < 0) theta = 0; | |
400 if (form_spl == 'A') /* spiral == Achemedian */ | |
401 r = theta; | |
402 else /* spiral == Logarithmic */ | |
403 r = (float)t/100; | |
404 x = r*cos(theta); | |
405 y = r*sin(theta); | |
406 /* Transform into pixel coord system and store */ | |
407 X = px(x); | |
408 Y = py(y); | |
409 if (inbox(X,Y)) { | |
410 Xarray[points] = X; | |
411 Yarray[points++] = Y; | |
412 } | |
413 | |
414 } | |
415 return points; | |
416 } | |
417 | |
418 | |
419 | |
420 /**************************************************************************** | |
421 * Plot dots of size d. | |
422 * | |
423 * Plotting in a given window uses the glib routines Draw and Plot. | |
424 * These routines, and associated structures, are declared in windows.h. | |
425 * The WindowObject structure has an "entries" pointer to a WindowEntries | |
426 * structure, and this holds pointers to a set of functions which operate on | |
427 * the window. The window functions, and the routine newDisplayWindow which | |
428 * allocates a new WindowObject, are defined in X.c. | |
429 * | |
430 * void Draw(win,X,Y,points) | |
431 * Takes two arrays of shorts, one with x-coords the other with y-coords. | |
432 * The number of x's = the number of y's = "points". | |
433 * The user must ensure that the data coords are scaled into the pixel | |
434 * coord system. This is as follows: (1,1) is bottom-left corner, and | |
435 * (width,height) is top-right corner. | |
436 * void Plot(win,X,Y,points) | |
437 * Same as Draw, but plots points. | |
438 ****************************************************************************/ | |
439 plotdots(win,Xspiral,Yspiral,X,Y,npoints,d) | |
440 WindowObject win; | |
441 short *Xspiral, *Yspiral; | |
442 short *X, *Y; | |
443 int npoints, d; | |
444 { | |
445 int x, y, i; | |
446 | |
447 if (d==0) /* dotsize = 1 */ | |
448 Plot(win,Xspiral,Yspiral,npoints); | |
449 else { /* dotsize > 1 */ | |
450 for (x=(-d) ; x<=d ; x++) | |
451 for (y=(-d) ; y<=d ; y++) { | |
452 for (i=0 ; i<npoints ; i++) { | |
453 X[i] = Xspiral[i] + x; | |
454 Y[i] = Yspiral[i] + y; | |
455 } | |
456 Plot(win,X,Y,npoints); | |
457 } | |
458 } | |
459 } | |
460 |