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