tomwalters@0: /* tomwalters@0: SCCS VERSION 1.29 WITH 1.28 STRIPPED OUT. tomwalters@0: tomwalters@0: tomwalters@0: tomwalters@0: Copyright (c) Applied Psychology Unit, Medical Research Council. 1988, 1989 tomwalters@0: =========================================================================== tomwalters@0: tomwalters@0: Permission to use, copy, modify, and distribute this software without fee tomwalters@0: is hereby granted for research purposes, provided that this copyright tomwalters@0: notice appears in all copies and in all supporting documentation, and that tomwalters@0: the software is not redistributed for any fee (except for a nominal shipping tomwalters@0: charge). Anyone wanting to incorporate all or part of this software in a tomwalters@0: commercial product must obtain a license from the Medical Research Council. tomwalters@0: tomwalters@0: The MRC makes no representations about the suitability of this tomwalters@0: software for any purpose. It is provided "as is" without express or implied tomwalters@0: warranty. tomwalters@0: */ tomwalters@0: tomwalters@0: /*************************************************************************** tomwalters@0: * image.c Version with trigger at right end of sai. tomwalters@0: * ======= tomwalters@0: * Input data derived from a cochleagram is used to construct a stabilised tomwalters@0: * auditory image (sai) of size `chans' * `framewidth' points. tomwalters@0: * tomwalters@0: * Organisation of data. tomwalters@0: * Data is 2-dimensional: in time (rows) and frequency (columns). tomwalters@0: * tomwalters@0: * Input data is ordered by columns. The input array consists of blocks (columns) tomwalters@0: * of `chans' points, each column being one time sample of `chans' channels. tomwalters@0: * The zero'th point in each column is the lowest frequency channel. tomwalters@0: * tomwalters@0: * Output (sai) data is ordered by rows. The output array consists of blocks tomwalters@0: * (rows) of `framewidth' points. tomwalters@0: * The zero'th point in each row is the "oldest" time, as the time origin is tomwalters@0: * on the right edge of the sai. tomwalters@0: * tomwalters@0: * Each sai is called a `frame', and its dimensions are `chans' rows by tomwalters@0: * `framewidth' columns. In the code, the `framewidth' is often represented tomwalters@0: * as imagewidth/chans, where imagewidth is the total amount of data in an tomwalters@0: * sai frame, (ie. imagewidth=chans*framewidth). tomwalters@0: tomwalters@0: * This module has been modified to have 5 levels of strobing. tomwalters@0: A Jay Datta 6/03/95 tomwalters@0: ***************************************************************************/ tomwalters@0: tomwalters@0: #include tomwalters@0: #include tomwalters@0: tomwalters@0: #include "options.h" tomwalters@0: #include "stitch.h" tomwalters@0: #include "source.h" tomwalters@0: #include "model.h" tomwalters@0: #include "units.h" tomwalters@0: #include "image.h" tomwalters@0: #include "calc.h" tomwalters@0: tomwalters@0: #define MAX_BUFFER (1l<<15) tomwalters@0: tomwalters@0: #ifdef FLOAT tomwalters@0: #define INPUT_SCALE 0.25 tomwalters@0: #define DECAY_SCALE 0.875 tomwalters@0: #else tomwalters@0: #define INPUT_SHIFT 2 tomwalters@0: #define DECAY_ROUND 7 tomwalters@0: #endif tomwalters@0: #define DECAY_SHIFT 3 tomwalters@0: tomwalters@0: #define MAXCHAN 1000 tomwalters@0: tomwalters@0: #ifndef lint tomwalters@0: static char *sccs_id = "@(#)image.c 1.27 J. Holdsworth, M. Allerhand (MRC-APU) 6/6/91" ; tomwalters@0: #endif tomwalters@0: tomwalters@0: #ifdef DSP32 tomwalters@0: static int segsize = 16 ; tomwalters@0: #else tomwalters@0: static int segsize = 50 ; tomwalters@0: #endif tomwalters@0: tomwalters@0: typedef enum { False, True } Bool ; tomwalters@0: typedef struct Node{int index; short val; struct Node *next;} node; tomwalters@0: tomwalters@0: static void doColumn(); tomwalters@0: static Pointer sai_callback(); tomwalters@0: static Pointer summary_callback(); tomwalters@0: static void save_callback(); tomwalters@0: static void addIn(); tomwalters@0: static void decayImage(); tomwalters@0: tomwalters@0: void output_simple_strobe_info(); tomwalters@0: void doList_strobe_info(); tomwalters@0: void output_thresh_info(); tomwalters@0: void decay_strobe_threshold(); tomwalters@0: void print_trigger_debugging_info(); tomwalters@0: tomwalters@0: void initlist(); tomwalters@0: node *getnode(); tomwalters@0: node *insertl(); tomwalters@0: void inss(); tomwalters@0: tomwalters@0: FILE *trigger_file; tomwalters@0: FILE *infotxt_file; tomwalters@0: FILE *thresho_file; tomwalters@0: tomwalters@0: int locmax_searchtime[MAXCHAN]; tomwalters@0: int locmax_searchstart[MAXCHAN]; tomwalters@0: int val[MAXCHAN]; tomwalters@0: int ltime[MAXCHAN]; tomwalters@0: int initial_strobe_candidate_time[MAXCHAN]; tomwalters@0: int ttime[MAXCHAN]; tomwalters@0: tomwalters@0: static node *start, *endl, *pp, *qq; tomwalters@0: static char *exposwitch; tomwalters@0: tomwalters@0: #ifdef FLOAT tomwalters@0: float *S; tomwalters@0: #else tomwalters@0: short *S; tomwalters@0: #endif tomwalters@0: tomwalters@0: tomwalters@0: /*************************************************************************** tomwalters@0: * struct _sai_state: tomwalters@0: * The source->info->state structure which is initialised by the tomwalters@0: * routine Sai, and is then the state argument for the callback tomwalters@0: * function: sai_callback. tomwalters@0: ***************************************************************************/ tomwalters@0: struct _sai_state { tomwalters@0: struct _pullable_source parent ; tomwalters@0: Source source; tomwalters@0: void (*trigger)(); /* trigger algorithm (originally doColumn) */ tomwalters@0: unsigned chans; /* number of filter channels */ tomwalters@0: unsigned framestep; /* sai display update period */ tomwalters@0: DataType *image; /* sai array (DataType = short) */ tomwalters@0: unsigned imagewidth; /* length of sai array (framewidth*chans) */ tomwalters@0: unsigned imagenwidth; /* portion of sai array for transient info */ tomwalters@0: unsigned decay_time; /* a factor of sai decay time constant */ tomwalters@0: unsigned decay_count; tomwalters@0: ScalarType *framedecay; /* array of factors for cochleagram frame */ tomwalters@0: int *cps; /* array of 1/centre-freq (in samples) */ tomwalters@0: int *isPulse; /* array of bools, to see if data > thres */ tomwalters@0: tomwalters@0: int Stcrit; /* int restriction */ tomwalters@0: int SusThresh; /* Level 2 user settable thresh */ tomwalters@0: ScalarType triggerdecay; /* prop/point decay for strobe threshold */ tomwalters@0: int *trigtime; /* time of last trigger pulse */ tomwalters@0: int *trigheight; /* height of last trigger pulse */ tomwalters@0: int *isStrobe; /* array of booleans, set when pulse peak found */ tomwalters@0: float *thresh; /* array of thresholds, one per channel */ tomwalters@0: float *tlim; /* linear decay value */ tomwalters@0: int time; /* keep track of sai */ tomwalters@0: int *previnput; /* lock till new pulse found */ tomwalters@0: int *def_strobe_candidate_time; tomwalters@0: int *def_strobe_height; tomwalters@0: char *switch_info; tomwalters@0: int tlim1; tomwalters@0: int stlag; /* strobe nwid first attempt to decouple nwids */ tomwalters@0: }; tomwalters@0: tomwalters@0: /*************************************************************************** tomwalters@0: * Sai: tomwalters@0: * Sai is called from SaiEntry (in module model.c). tomwalters@0: * Routines in this module it uses are: tomwalters@0: * doColumn, (which uses: addIn) tomwalters@0: * sai_callback, (which uses: decayImage) tomwalters@0: * tomwalters@0: * SaiEntry (in model.c) is the entry-point function to the stabilised image tomwalters@0: * processing module. Its purpose is to prepare the arguments for Sai by tomwalters@0: * converting parameter-option strings to integers, and then to call Sai. tomwalters@0: * tomwalters@0: * Sai is called with the following arguments (in model.c): tomwalters@0: * Sai( source, Frameheight(), segment, width, tomwalters@0: * (int) Samples( decaystr )/Framestep(), (int) Freq( samplestr ), tomwalters@0: * frequencies, Samples(ttstr)/Framestep(), Samples(cgmstr)/Framestep(), tomwalters@0: * (int) Freq("250Hz"), (int) Freq("20Hz") ) ; tomwalters@0: * tomwalters@0: * The arguments are as follows: tomwalters@0: * (The option name refers to the description given by "help". The values etc tomwalters@0: * can be found in table.c as described in model.docs). tomwalters@0: * tomwalters@0: * Argument Option name Default Comment tomwalters@0: * -------- ----------- ------- ------- tomwalters@0: * chans (see below) Number of filter channels tomwalters@0: * framestep segment_sai 16ms SAI display update period tomwalters@0: * framewidth duration_sai 32ms SAI duration (ms) tomwalters@0: * decay decayrate_sai 32ms SAI decay time constant (SU/ms) 15ms NOW Default tomwalters@0: * samplerate samplerate 20000. Input wave sample rate (Hz) tomwalters@0: * cfs (see below) An array of filter centre frequencies tomwalters@0: * cgmdecay napdecay_sai 16ms NAP (ie cochleagram) decay time constant tomwalters@0: * tomwalters@0: * Both "chans" and "cfs" are setup from the routine "updateFrequencies" in tomwalters@0: * model.c, because both arguments are derived from three basic parameters: tomwalters@0: * tomwalters@0: * minstr mincf_afb 220Hz Minimum center frequency (Hz) tomwalters@0: * maxstr maxcf_afb 4400Hz Maximum center frequency (Hz) tomwalters@0: * denstr dencf_afb 4. Filter density (filters/critical band) tomwalters@0: * tomwalters@0: * The "chans" argument is calculated in the routine "NumberCenterFrequencies", tomwalters@0: * and the result is copied into the "frameheightstr" by a call to the routine tomwalters@0: * "setFrameheight". tomwalters@0: * The "cfs" argument is calculated in the routine "GenerateCenterFrequencies". tomwalters@0: * (Both CenterFrequency routines are in gamma_tone.c). tomwalters@0: * tomwalters@0: ***************************************************************************/ tomwalters@0: tomwalters@0: Source Sai(source, chans, framestep, pwidth, nwidth, decay, samplerate, cfs, ttdecay, cgmdecay, tlim1, tlim2, suslevel, susthresh, switchinfo, expoSwitch,stlag) tomwalters@0: Source source ; tomwalters@0: int chans, framestep, pwidth, nwidth, decay ; tomwalters@0: int samplerate; tomwalters@0: double *cfs ; tomwalters@0: double ttdecay, cgmdecay ; tomwalters@0: int tlim1, tlim2; tomwalters@0: int suslevel; tomwalters@0: char *susthresh; tomwalters@0: char *switchinfo; tomwalters@0: char *expoSwitch; tomwalters@0: int stlag; tomwalters@0: { tomwalters@0: tomwalters@0: DeclareNew( struct _sai_state *, state ) ; tomwalters@0: int i, chan, startup, segment, framewidth ; tomwalters@0: double pts_per_ms, lin_napdec, lin_napfac ; /* roy 11-8-92 roy */ tomwalters@0: char *ThreshoFile, *InfotxtFile, *TriggerFile; tomwalters@0: tomwalters@0: exposwitch=(char *)calloc(5, sizeof(char)); tomwalters@0: exposwitch=expoSwitch; tomwalters@0: tomwalters@0: ThreshoFile = (char *)calloc(256, sizeof(char)); tomwalters@0: InfotxtFile = (char *)calloc(256, sizeof(char)); tomwalters@0: TriggerFile = (char *)calloc(256, sizeof(char)); tomwalters@0: tomwalters@0: state->switch_info = (char *)calloc(256,sizeof(char)); tomwalters@0: state->switch_info = switchinfo; tomwalters@0: tomwalters@0: if (!strcmp(susthresh, "on")) tomwalters@0: state->SusThresh=0; tomwalters@0: else if (!strcmp(susthresh, "off")) tomwalters@0: state->SusThresh=1; tomwalters@0: else tomwalters@0: state->SusThresh=atoi(susthresh); tomwalters@0: tomwalters@0: if (!strcmp(state->switch_info, "off")) tomwalters@0: ; tomwalters@0: else if (!strcmp(state->switch_info, "on")) tomwalters@0: infotxt_file=stdout; tomwalters@0: else{ tomwalters@0: strcpy(InfotxtFile, switchinfo); tomwalters@0: strcat(InfotxtFile, ".info"); tomwalters@0: infotxt_file=fopen(InfotxtFile, "w"); tomwalters@0: tomwalters@0: strcpy(TriggerFile, switchinfo); tomwalters@0: strcat(TriggerFile, ".trigger"); tomwalters@0: trigger_file=fopen(TriggerFile, "w"); tomwalters@0: tomwalters@0: strcpy(ThreshoFile, switchinfo); tomwalters@0: strcat(ThreshoFile, ".thresh"); tomwalters@0: thresho_file=fopen(ThreshoFile, "w"); tomwalters@0: } tomwalters@0: tomwalters@0: initlist(); tomwalters@0: state->tlim1=0; tomwalters@0: tomwalters@0: framewidth = pwidth+nwidth; tomwalters@0: tomwalters@0: pts_per_ms = (double)samplerate/1000 ; tomwalters@0: tomwalters@0: state->stlag=stlag; /* NEW line 95April */ tomwalters@0: /* Initialise members of the sai state structure */ tomwalters@0: state->source = NewRetainingSource( source, sizeof ( DataType ) * framewidth * chans ) ; tomwalters@0: state->chans = chans ; tomwalters@0: state->trigger = doColumn ; tomwalters@0: state->framestep = framestep * chans ; tomwalters@0: state->imagewidth = framewidth * chans ; /* size of sai buffer */ tomwalters@0: state->imagenwidth = nwidth * chans ; /* size of buffer for transient info */ tomwalters@0: state->decay_time = decay * -log( 1. - 1. / ( 1 << DECAY_SHIFT ) ) ; tomwalters@0: state->decay_count = state->decay_time ; tomwalters@0: tomwalters@0: state->Stcrit = suslevel; tomwalters@0: if (stlag==0 && state->Stcrit==5) /* was nwid NEW */ tomwalters@0: state->Stcrit = suslevel-1; tomwalters@0: tomwalters@0: /* state->SusThresh = susthresh; */ tomwalters@0: tomwalters@0: if (!strcmp(exposwitch, "on")) fprintf(stderr, "Exponential trigger decay SWITCH is ON\n"); tomwalters@0: /* if (!strcmp(exposwitch, "off")) printf("SWITCH is OFF\n"); */ tomwalters@0: tomwalters@0: if (!strcmp(exposwitch, "on")) tomwalters@0: state->triggerdecay = (double) 1-((ttdecay / pts_per_ms ) /100.0) ; tomwalters@0: else tomwalters@0: state->triggerdecay = (double) (ttdecay /pts_per_ms) / 100.0 ; tomwalters@0: tomwalters@0: if (!strcmp(switchinfo, "off")) tomwalters@0: ; tomwalters@0: else tomwalters@0: fprintf(infotxt_file, "\ntriggerdecay = %15e\n", state->triggerdecay); tomwalters@0: tomwalters@0: state->isStrobe = NewZeroedArray( int, state->chans, "image.c for Strobe" ) ; tomwalters@0: state->isPulse = NewZeroedArray( int, state->chans, "image.c for trigger pulse" ) ; tomwalters@0: state->trigtime = NewZeroedArray( int, state->chans, "image.c for trigger time" ) ; tomwalters@0: state->trigheight = NewZeroedArray( int, state->chans, "image.c for trigger height" ) ; tomwalters@0: state->thresh = NewZeroedArray( float, state->chans, "image.c for thresh" ) ; tomwalters@0: state->tlim = NewZeroedArray( float, state->chans, "image.c for decay" ) ; tomwalters@0: state->time = 0; /* Time initialized to Zero */ tomwalters@0: state->previnput = NewZeroedArray( int, state->chans, "image.c for pulse lock" ) ; tomwalters@0: tomwalters@0: state->def_strobe_candidate_time = NewZeroedArray( int, state->chans, "image.c for prevtrig time" ); tomwalters@0: state->def_strobe_height = NewZeroedArray( int, state->chans, "image.c for prev trig" ); tomwalters@0: tomwalters@0: for (chan=0; chan < MAXCHAN; chan++) tomwalters@0: locmax_searchtime[chan]=0; tomwalters@0: for (chan=0; chan < MAXCHAN; chan++) tomwalters@0: locmax_searchstart[chan]=0; tomwalters@0: for (chan=0; chan < MAXCHAN; chan++) tomwalters@0: val[chan]=0; tomwalters@0: for (chan=0; chan < MAXCHAN; chan++) tomwalters@0: initial_strobe_candidate_time[chan]=0; tomwalters@0: for (chan=0; chan < MAXCHAN; chan++) tomwalters@0: ltime[chan]=0; tomwalters@0: for (chan=0; chan < MAXCHAN; chan++) tomwalters@0: ttime[chan]=0; tomwalters@0: tomwalters@0: #ifdef FLOAT tomwalters@0: S=(float *)calloc(state->chans, sizeof(float)); tomwalters@0: #else tomwalters@0: S=(short *)calloc(state->chans, sizeof(short)); tomwalters@0: #endif tomwalters@0: tomwalters@0: /* Declare new arrays for members of state structure */ tomwalters@0: tomwalters@0: state->framedecay = NewArray( ScalarType, framewidth, "image.c for decay" ) ; tomwalters@0: state->image = NewZeroedArray( DataType, state->imagewidth, "image.c for image" ) ; tomwalters@0: state->cps = NewZeroedArray( int, state->chans, "image.c for channel centre periods" ) ; tomwalters@0: tomwalters@0: /* Initialise cochleagram frame decay factors */ tomwalters@0: if (cgmdecay > 0) tomwalters@0: { tomwalters@0: /* 11111 roy 11-8-92 These mods change to a linear nap decay. 1111111 roy */ tomwalters@0: /* It requires pts_per_ms, lin_napdec and lin_napfac declared just after DeclareNew above */ tomwalters@0: tomwalters@0: lin_napdec = ((cgmdecay/100)/pts_per_ms)/pts_per_ms ; /* roy 19-8 roy */ tomwalters@0: tomwalters@0: /* cgmdecay is div by pts_per_ms to get back to napdecay in the original units */ tomwalters@0: /* When napdecay is interpreted as the % to decay per ms, and since we are */ tomwalters@0: /* operating in points, we need napdec/pts_per_ms, as the dec for each pt within the ms */ tomwalters@0: /* The decay vector is set to scale the NAP by 1.0 at strobe point. So, in the sai, */ tomwalters@0: /* it falls to the left AND RISES to the right of 0 ms. **** roy **** */ tomwalters@0: tomwalters@0: lin_napfac = 1.0 + nwidth*lin_napdec ; tomwalters@0: tomwalters@0: for (i=0 ; i < framewidth ; i++) tomwalters@0: { tomwalters@0: if ( lin_napfac > 0 ) tomwalters@0: state->framedecay[i] = SCALAR( lin_napfac ); tomwalters@0: else tomwalters@0: state->framedecay[i] = SCALAR( 0 ); tomwalters@0: lin_napfac -= lin_napdec ; tomwalters@0: } tomwalters@0: } tomwalters@0: else /* disable decay factor on zero argument */ tomwalters@0: for (i=0 ; i < framewidth ; i++) tomwalters@0: state->framedecay[i] = SCALAR( 1.0 ) ; tomwalters@0: tomwalters@0: /* Initialise centre-period for each channel */ tomwalters@0: for (i=0 ; i < state->chans ; i++) tomwalters@0: state->cps[i] = samplerate / cfs[i]; tomwalters@0: tomwalters@0: #if defined( PC ) || defined( THINK_C ) tomwalters@0: if( (long) ( MAX_BUFFER - (long) state->imagewidth * sizeof ( DataType ) ) < (long) ( state->chans * sizeof ( DataType ) ) ) tomwalters@0: stitch_error( "Sorry, image larger than maximum buffer size\n" ) ; tomwalters@0: #endif tomwalters@0: tomwalters@0: /* for (i=0; iimagewidth;i++) tomwalters@0: fprintf(stderr, "Image Buffer is %f, count = %d\n", *(state->image+i), (i+1)); */ tomwalters@0: tomwalters@0: tomwalters@0: tomwalters@0: return ( SetPullableSource( state, sai_callback, "image.c stabilised image" ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: /**************************************************************************** tomwalters@0: * sai_callback tomwalters@0: * The callback function at source->info->callback in the source tomwalters@0: * returned by Sai. tomwalters@0: * A "frame" is a window over the cochleagram, of size chans * points. tomwalters@0: * A "segment" is a stretch of the cochleagram which is segsize (ie 50) time tomwalters@0: * samples long, ie segsize columns of the cochleagram. tomwalters@0: * tomwalters@0: * This callback routine is executed once for each sai frame which is plotted. tomwalters@0: * "*bytes" is the number of bytes in the sai, ie: tomwalters@0: * *bytes = state->imagewidth * sizeof(DataType) tomwalters@0: ****************************************************************************/ tomwalters@0: static Pointer sai_callback( state, bytes ) tomwalters@0: struct _sai_state *state ; tomwalters@0: ByteCount *bytes ; tomwalters@0: { tomwalters@0: register long col, point ; tomwalters@0: register long points = state->framestep; /* total num points under frame */ tomwalters@0: #if defined( PC ) tomwalters@0: int segment = ( MAX_BUFFER - state->imagewidth * sizeof ( DataType ) ) / state->chans / sizeof ( DataType ) * state->chans ; tomwalters@0: #else tomwalters@0: int segment = segsize * state->chans ; tomwalters@0: #endif tomwalters@0: register DataType *input ; /* cochleagram (input) data array */ tomwalters@0: static int first=1; tomwalters@0: static int test=0; tomwalters@0: int chan; tomwalters@0: int i; tomwalters@0: /* #if defined( PC ) tomwalters@0: test=1; tomwalters@0: #else tomwalters@0: if (state->SusThresh == 0) tomwalters@0: segment= 30 * state->chans ; tomwalters@0: #endif */ tomwalters@0: tomwalters@0: /* test++; */ tomwalters@0: tomwalters@0: tomwalters@0: /* If size argument is zero, then by convention free space and return null */ tomwalters@0: if( *bytes == 0 ) { tomwalters@0: Pull( state->source, 0 ) ; tomwalters@0: Delete( state->image ) ; tomwalters@0: return ( DeletePullableSource( state ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: /* Initially pull enough data to buffer transient info ahead of the trigger */ tomwalters@0: /* Note, the pull operation is not valid when the size arg is zero. */ tomwalters@0: /* The result would be a segmentation fault on the next pull, below. */ tomwalters@0: tomwalters@0: if (state->Stcrit==0 || state->Stcrit==1 || state->Stcrit==2 || state->Stcrit==3) tomwalters@0: if (first) { tomwalters@0: if (state->imagenwidth > 0) tomwalters@0: input = PullItems(state->source, state->imagenwidth, DataType); tomwalters@0: first = 0; tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: /* Search frame in segment blocks for trigger-points */ tomwalters@0: for( point=0 ; point < points ; point += segment ) { tomwalters@0: if( segment > points - point ) /* Finish at end of frame */ tomwalters@0: segment = points - point ; tomwalters@0: /* Get one segment of the input data */ tomwalters@0: /* Pull 50 columns of data from the source, in buffer *input. */ tomwalters@0: /* Keep one sai of data, from last pull, in buffer behind *input */ tomwalters@0: input = PullItems(state->source, segment, DataType); tomwalters@0: tomwalters@0: for( col=0 ; col < segment ; col += state->chans ) { tomwalters@0: /* Retard the "current" data point by transient buffer width */ tomwalters@0: /* (This retards the trigger by the transient time, about 5ms) */ tomwalters@0: if (state->Stcrit==0 || state->Stcrit==1 || state->Stcrit==2 || state->Stcrit==3) tomwalters@0: state->trigger(input-state->imagenwidth, state) ; tomwalters@0: else{ tomwalters@0: state->trigger( input, state) ; /* -state->imagenwidth, state ) ; */ tomwalters@0: /*fprintf(stderr, " %d ", points) ; */ } tomwalters@0: input += state->chans ; /* next column */ tomwalters@0: /* decay image periodically, once every `decay_time' columns */ tomwalters@0: /* Lines moved down */ tomwalters@0: if( --state->decay_count <= 0 ) { tomwalters@0: decayImage( state ) ; tomwalters@0: state->decay_count = state->decay_time ; tomwalters@0: } tomwalters@0: } /* for each col */ tomwalters@0: } /* for each seg */ tomwalters@0: tomwalters@0: /* whatever the number of bytes requested, the image is always this size */ tomwalters@0: *bytes = state->imagewidth * sizeof ( *state->image ) ; tomwalters@0: tomwalters@0: /* if (state->Stcrit==1 && state->SusThresh==0){ tomwalters@0: if (test%5==0) tomwalters@0: decayImage( state ); tomwalters@0: test++;} tomwalters@0: else if (state->Stcrit==1 && state->SusThresh>0){ changed 2 to 3 tomwalters@0: if (test%10==0) tomwalters@0: decayImage( state ); tomwalters@0: test++;} tomwalters@0: else{ */ tomwalters@0: tomwalters@0: return ( (Pointer) state->image ) ; tomwalters@0: } tomwalters@0: tomwalters@0: /**************************************************************************** tomwalters@0: * decayImage tomwalters@0: * Periodically attenuate image to give computationally efficient image decay. tomwalters@0: * Attenuate all points in the sai by a constant factor. tomwalters@0: ****************************************************************************/ tomwalters@0: static void decayImage( state ) tomwalters@0: struct _sai_state *state ; tomwalters@0: { tomwalters@0: register DataType *image_ptr, *image_end ; tomwalters@0: #ifdef FLOAT tomwalters@0: register FLOAT image_decay = DECAY_SCALE ; tomwalters@0: #endif tomwalters@0: tomwalters@0: image_end = state->image + state->imagewidth ; /* end of sai array */ tomwalters@0: #ifdef FLOAT tomwalters@0: for( image_ptr=state->image ; image_ptr < image_end ; ) tomwalters@0: *image_ptr++ *= image_decay ; tomwalters@0: #else tomwalters@0: for( image_ptr=state->image ; image_ptr < image_end ; image_ptr++ ) tomwalters@0: *image_ptr -= *image_ptr + DECAY_ROUND >> DECAY_SHIFT ; tomwalters@0: #endif tomwalters@0: return ; tomwalters@0: } tomwalters@0: tomwalters@0: /**************************************************************************** tomwalters@0: * doColumn tomwalters@0: * Trigger algorithm for Sai. tomwalters@0: * Installed as source->info->state->trigger. tomwalters@0: * tomwalters@0: ****************************************************************************/ tomwalters@0: static void doColumn( input, state ) tomwalters@0: DataType *input ; tomwalters@0: struct _sai_state *state ; tomwalters@0: { tomwalters@0: tomwalters@0: register int chan ; tomwalters@0: float strobelag; tomwalters@0: int s_lag; tomwalters@0: tomwalters@0: tomwalters@0: short *STI; tomwalters@0: static int check=0; tomwalters@0: int storev; tomwalters@0: char buf[2]; tomwalters@0: short stipts=-2000; tomwalters@0: short zeroval=0; tomwalters@0: tomwalters@0: STI=(short *)calloc(state->chans, sizeof(short)); tomwalters@0: tomwalters@0: strobelag = (double) (state->time)-(state->stlag); tomwalters@0: tomwalters@0: s_lag=(state->time)-(state->stlag); tomwalters@0: tomwalters@0: /* For each channel up column, add a row of data to sai if the */ tomwalters@0: /* current point is non-zero. Add the row from the current point */ tomwalters@0: /* plus state->imagenwidth, to display the transient (nwidth) info. */ tomwalters@0: tomwalters@0: tomwalters@0: /* 000000000000000000000000 stcrit 0000000000000000000000000000000000 */ tomwalters@0: /* Add on every point : Low Pass Filter */ tomwalters@0: tomwalters@0: if (state->Stcrit==0) tomwalters@0: { tomwalters@0: for( chan=0 ; chan < state->chans ; chan++ ) tomwalters@0: { tomwalters@0: addIn(input+(state->imagenwidth), chan, state); tomwalters@0: output_simple_strobe_info(state, stipts); tomwalters@0: } tomwalters@0: } /* if (state->Stcrit==0) */ tomwalters@0: tomwalters@0: tomwalters@0: /* 111111111111111111111111 stcrit 1111111111111111111111111111111111 */ tomwalters@0: /* Add on every point greater than "stthresh_ai" (default 0) */ tomwalters@0: tomwalters@0: if (state->Stcrit==1) tomwalters@0: { tomwalters@0: for( chan=0 ; chan < state->chans ; chan++ ) tomwalters@0: { tomwalters@0: if (input[chan] > state->SusThresh ) tomwalters@0: { tomwalters@0: addIn(input+(state->imagenwidth), chan, state); tomwalters@0: output_simple_strobe_info(state, stipts); tomwalters@0: } tomwalters@0: else if (input[chan] <=state->SusThresh) tomwalters@0: output_simple_strobe_info(state, zeroval); tomwalters@0: } tomwalters@0: } /* if (state->Stcrit==1) */ tomwalters@0: tomwalters@0: tomwalters@0: /* 222222222222222222222222 stcrit 2222222222222222222222222222222222 */ tomwalters@0: /* Add on every Nap pulse peak */ tomwalters@0: tomwalters@0: if (state->Stcrit==2) tomwalters@0: { tomwalters@0: for( chan=0 ; chan < state->chans ; chan++ ) tomwalters@0: { tomwalters@0: if (state->isStrobe[chan]) /* Check to see if it is time to addIn */ tomwalters@0: { tomwalters@0: addIn(input+((state->imagenwidth)-2*(state->chans)), chan, state); tomwalters@0: state->isStrobe[chan]=0; /* Reset strobe flag */ tomwalters@0: doList_strobe_info(state, chan); tomwalters@0: } tomwalters@0: tomwalters@0: /* Find a pulse peak routine */ tomwalters@0: tomwalters@0: if (!state->isPulse[chan]) /* Not in pulse, looking for pulse */ tomwalters@0: { tomwalters@0: state->thresh[chan]=input[chan]; tomwalters@0: if (input[chan] > 0 /*state->thresh[chan] */ ) /* Start of a Nap pulse */ tomwalters@0: state->isPulse[chan] =1; /* set in pulse flag */ tomwalters@0: } tomwalters@0: else /* In pulse, looking for peak */ tomwalters@0: { tomwalters@0: if (input[chan] < state->thresh[chan]) /* peak found */ tomwalters@0: { tomwalters@0: state->isPulse[chan]=0; tomwalters@0: state->isStrobe[chan]=1; /* set strobe pending flag */ tomwalters@0: } tomwalters@0: else tomwalters@0: state->thresh[chan]=input[chan]; tomwalters@0: } tomwalters@0: output_thresh_info(state, chan); tomwalters@0: } tomwalters@0: } /* if (state->stcrit==2) */ tomwalters@0: tomwalters@0: tomwalters@0: tomwalters@0: /* 333333333333333333333333 stcrit 3333333333333333333333333333333333 */ tomwalters@0: /* Add on pulse peaks that exceed strobe threshold (temporal shadow ) */ tomwalters@0: /* Primitive Local Max algorithm */ tomwalters@0: tomwalters@0: if (state->Stcrit==3) tomwalters@0: { tomwalters@0: for( chan=0 ; chan < state->chans ; chan++ ) tomwalters@0: { tomwalters@0: if (state->isStrobe[chan]) /* Check to see if it is time to addIn */ tomwalters@0: { tomwalters@0: addIn(input+((state->imagenwidth)-2*(state->chans)), chan, state); tomwalters@0: state->isStrobe[chan] = 0; /* Reset strobe flag */ tomwalters@0: doList_strobe_info(state, chan); tomwalters@0: } tomwalters@0: tomwalters@0: /* Find a pulse peak routine */ tomwalters@0: tomwalters@0: if (!state->isPulse[chan]) /* Not in Pulse, looking for Pulse */ tomwalters@0: { tomwalters@0: if (input[chan] > state->thresh[chan] && input[chan] > state->previnput[chan]) tomwalters@0: { /* Previnput check ensures threshold decay tomwalters@0: does not cut into pulse */ tomwalters@0: tomwalters@0: state->isPulse[chan] = 1; /* set flag: in pulse */ tomwalters@0: state->thresh[chan] = input[chan]; /* start search for peak */ tomwalters@0: } tomwalters@0: else { tomwalters@0: decay_strobe_threshold(state, chan); tomwalters@0: if (input[chan]==0) /* in the zeroes between nap pulses */ tomwalters@0: state->previnput[chan] = 0; /* Set it to Zero previnput */ tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: if (state->isPulse[chan]) /* Else in ongoing pulse looking for peak */ tomwalters@0: { tomwalters@0: if (input[chan] <= state->thresh[chan] && input[chan] <= state->previnput[chan]) tomwalters@0: /* pulse peak found */ tomwalters@0: { tomwalters@0: state->isPulse[chan] = 0; /* clear flag: not in pulse */ tomwalters@0: state->isStrobe[chan] = 1; /* set Strobe pending flag */ tomwalters@0: if (!strcmp(exposwitch, "off")) tomwalters@0: state->tlim[chan]=state->triggerdecay * state->thresh[chan]; tomwalters@0: state->trigtime[chan]=(state->time)-1; tomwalters@0: /* state->previnput[chan]=input[cha */ tomwalters@0: } tomwalters@0: else /* still in pulse, so continue search for peak */ tomwalters@0: state->thresh[chan] = input[chan]; tomwalters@0: tomwalters@0: } /* if in Pulse */ tomwalters@0: state->previnput[chan]=input[chan]; tomwalters@0: output_thresh_info(state, chan); tomwalters@0: } /* for all chans... */ tomwalters@0: } /* if (state->Stcrit==3) */ tomwalters@0: tomwalters@0: tomwalters@0: tomwalters@0: /* 444444444444444444444444 stcrit 4444444444444444444444444444444444 */ tomwalters@0: /* Add on pulse peaks that exceed strobe threshold and which are not succeeded by tomwalters@0: a larger pulse in nwid ms. (Better Local Max mechanism) */ tomwalters@0: tomwalters@0: if (state->Stcrit==4) tomwalters@0: { tomwalters@0: for( chan=0 ; chan < state->chans ; chan++ ) tomwalters@0: { tomwalters@0: if (state->isStrobe[chan]) /* Check to see if it is time to addIn */ tomwalters@0: { tomwalters@0: if ( strobelag-1 >= state->trigtime[chan]) tomwalters@0: /* initiates strobe after nwid ms */ tomwalters@0: { tomwalters@0: addIn(input-(state->chans), chan, state); tomwalters@0: doList_strobe_info(state, chan); tomwalters@0: state->isStrobe[chan] = 0; /* Reset strobe flag */ tomwalters@0: state->trigheight[chan] = 0; /* Reset local max value */ tomwalters@0: tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: /* Find a pulse peak routine */ tomwalters@0: tomwalters@0: if (!state->isPulse[chan]) /* Not in Pulse, looking for pulse */ tomwalters@0: { tomwalters@0: if (input[chan] > state->thresh[chan] && input[chan] > state->previnput[chan]) tomwalters@0: { /* Previnput check ensures threshold tomwalters@0: decay does not cut into pulse */ tomwalters@0: tomwalters@0: state->isPulse[chan] = 1; /* set flag: in pulse */ tomwalters@0: state->thresh[chan] = input[chan]; /* start search for peak */ tomwalters@0: /* state->previnput[chan]= 1; in pulse till the next zero value */ tomwalters@0: } tomwalters@0: else tomwalters@0: { tomwalters@0: decay_strobe_threshold(state, chan); tomwalters@0: if (input[chan]==0) /* in the zeroes between nap pulses */ tomwalters@0: state->previnput[chan] = 0; /* Free previnput */ tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: if (state->isPulse[chan]) /* Else in ongoing pulse, looking for peak */ tomwalters@0: { tomwalters@0: if (input[chan] <= state->thresh[chan] && input[chan] <= state->previnput[chan]) tomwalters@0: /* pulse peak found */ tomwalters@0: { tomwalters@0: state->isPulse[chan] = 0; /* clear flag: not in pulse */ tomwalters@0: state->isStrobe[chan] = 1; /* set Strobe pending flag */ tomwalters@0: tomwalters@0: if ( state->thresh[chan] > state->trigheight[chan] ) tomwalters@0: /* Check for LOCAL MAX */ tomwalters@0: { tomwalters@0: state->trigheight[chan] = state->thresh[chan]; tomwalters@0: state->trigtime[chan] = (state->time)-1; /* Set strobe time */ tomwalters@0: if (!strcmp(exposwitch, "off")) tomwalters@0: state->tlim[chan]=state->triggerdecay * state->trigheight[chan]; tomwalters@0: } tomwalters@0: } tomwalters@0: else /* still in pulse, so continue search for peak */ tomwalters@0: state->thresh[chan] = input[chan]; tomwalters@0: } /* if in Pulse */ tomwalters@0: state->previnput[chan]=input[chan]; tomwalters@0: output_thresh_info(state, chan); tomwalters@0: } /* for all chans... */ tomwalters@0: } /* if (state->Stcrit==4) */ tomwalters@0: tomwalters@0: tomwalters@0: tomwalters@0: /* 555555555555555555555555 stcrit 5555555555555555555555555555555555 */ tomwalters@0: /* Add on pulse peaks that exceed storbe threshold and which are not succeeded by tomwalters@0: a larger pulse in nwid ms, provided total lag is < 2*nwid ms tomwalters@0: Local Max mechanism with a timeout */ tomwalters@0: tomwalters@0: if (state->Stcrit==5) tomwalters@0: { tomwalters@0: for (chan = 0; chan < state->chans; chan++) tomwalters@0: { tomwalters@0: if(state->isStrobe[chan]) /* Check to see if it is time to addIn */ tomwalters@0: { /* check for waiting till the first local max found */ tomwalters@0: if (strobelag-1 >= state->def_strobe_candidate_time[chan]) tomwalters@0: /* initiate strobe after nwid ms */ tomwalters@0: { tomwalters@0: /* print_trigger_debugging_info(state, chan, s_lag, 1); */ tomwalters@0: addIn(input-state->chans, chan, state); tomwalters@0: doList_strobe_info(state, chan); tomwalters@0: tomwalters@0: state->def_strobe_candidate_time[chan] = 0; /* Reset strobe time */ tomwalters@0: state->def_strobe_height[chan] = 0; /* Reset local max value */ tomwalters@0: state->trigheight[chan]=0; tomwalters@0: state->isStrobe[chan]=0; /* Reset strobe flag */ tomwalters@0: tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: /* Find a pulse peak routine */ tomwalters@0: tomwalters@0: if (!state->isPulse[chan]) /* Not in pulse, looking for pulse */ tomwalters@0: { tomwalters@0: if (input[chan] > state->thresh[chan] && input[chan] > state->previnput[chan]) tomwalters@0: { /* Previnput check ensures threshold tomwalters@0: decay does not cut into pulse */ tomwalters@0: tomwalters@0: state->isPulse[chan] = 1; /* set flag: in pulse */ tomwalters@0: state->thresh[chan] = input[chan]; /* start search for peak */ tomwalters@0: /* state->previnput[chan] = 1; in pulse till the next zero value */ tomwalters@0: } tomwalters@0: else tomwalters@0: { tomwalters@0: decay_strobe_threshold(state, chan); tomwalters@0: if (input[chan]==0) /* in the zeroes between nap pulses */ tomwalters@0: state->previnput[chan]=0; /* Free previnput */ tomwalters@0: } tomwalters@0: tomwalters@0: } tomwalters@0: tomwalters@0: if (state->isPulse[chan]) /* Else in ongoing pulse, looking for peak */ tomwalters@0: { tomwalters@0: if (input[chan] <= state->thresh[chan] && input[chan] <= state->previnput[chan]) tomwalters@0: /* Pulse Peak Found */ tomwalters@0: { tomwalters@0: state->isPulse[chan]=0; /* clear flag: not in pulse */ tomwalters@0: tomwalters@0: if (locmax_searchstart[chan]==0 ) tomwalters@0: /* && state->time>=((ttime[chan]-initial_strobe_candidate_time[chan])+ltime[chan])) AJD 1-2-96 */ tomwalters@0: { /* start local max time (for timeout) tomwalters@0: and shift search window */ tomwalters@0: locmax_searchtime[chan]=1; /* local max time started */ tomwalters@0: locmax_searchstart[chan]=1; /* local max flag set */ tomwalters@0: print_trigger_debugging_info(state, chan, s_lag, 2); tomwalters@0: initial_strobe_candidate_time[chan]=(state->time)-1; /* local max start time noted */ tomwalters@0: tomwalters@0: } tomwalters@0: tomwalters@0: /* if (locmax_searchstart[chan]==1) */ /* 8rd March, 1995 AJayDatta */ tomwalters@0: if (state->thresh[chan] > state->trigheight[chan]) tomwalters@0: /* Check for LOCAL MAX */ tomwalters@0: { tomwalters@0: state->trigheight[chan]=state->thresh[chan]; tomwalters@0: state->trigtime[chan]=(state->time)-1; /* Set strobe time */ tomwalters@0: if (!strcmp(exposwitch, "off")) tomwalters@0: state->tlim[chan]=state->triggerdecay * state->trigheight[chan]; tomwalters@0: if (locmax_searchstart[chan]==1) tomwalters@0: print_trigger_debugging_info(state, chan, s_lag, 3); tomwalters@0: } /* if greater than thresh */ tomwalters@0: tomwalters@0: tomwalters@0: /* Reached end of time-out period (While in the peak finding stage !) tomwalters@0: End of the timeout period can occur at two stages of the algorithm, tomwalters@0: at a Nap pulse peak or at any point of the pulse train. */ tomwalters@0: tomwalters@0: if (locmax_searchtime[chan]==(state->stlag)) /* imagenwidth/state->chans)) */ tomwalters@0: { tomwalters@0: print_trigger_debugging_info(state, chan, s_lag, 4); tomwalters@0: tomwalters@0: state->def_strobe_candidate_time[chan]=state->trigtime[chan]; tomwalters@0: state->def_strobe_height[chan]=state->trigheight[chan]; tomwalters@0: locmax_searchtime[chan]=0; tomwalters@0: locmax_searchstart[chan]=0; tomwalters@0: state->trigheight[chan]=0; tomwalters@0: state->trigtime[chan]=0; tomwalters@0: state->isStrobe[chan]=1; /* set Strobe pending flag */ tomwalters@0: ltime[chan]=state->time; /* End of search time */ tomwalters@0: ttime[chan]=state->def_strobe_candidate_time[chan]; /* Local Max time */ tomwalters@0: } tomwalters@0: /* reset search period to zero */ tomwalters@0: /* as y ms search period ends, update the info for strobe and tomwalters@0: clear current_ values for the next y ms */ tomwalters@0: } /* Pulse Peak Loop */ tomwalters@0: else tomwalters@0: state->thresh[chan]=input[chan]; tomwalters@0: } /* if (state->isPulse..) */ tomwalters@0: tomwalters@0: if (locmax_searchtime[chan] == (state->stlag)) /* imagenwidth/state->chans)) */ tomwalters@0: /* && state->def_strobe_candidate_time[chan]==0) */ tomwalters@0: { /* start local max time (for timeout) */ tomwalters@0: print_trigger_debugging_info(state, chan, s_lag, 5); tomwalters@0: tomwalters@0: state->def_strobe_candidate_time[chan]=state->trigtime[chan]; tomwalters@0: state->def_strobe_height[chan]=state->trigheight[chan]; tomwalters@0: locmax_searchtime[chan]=0; tomwalters@0: locmax_searchstart[chan]=0; tomwalters@0: state->trigheight[chan]=0; tomwalters@0: state->trigtime[chan]=0; tomwalters@0: state->isStrobe[chan]=1; /* set Strobe pending flag */ tomwalters@0: ltime[chan]=state->time; tomwalters@0: ttime[chan]=state->def_strobe_candidate_time[chan]; tomwalters@0: } tomwalters@0: /* reset search period to zero */ tomwalters@0: /* as y ms search period ends, update the info for strobe and tomwalters@0: clear current_ values for the next y ms */ tomwalters@0: tomwalters@0: tomwalters@0: if (locmax_searchstart[chan]==1) tomwalters@0: (locmax_searchtime[chan])++; tomwalters@0: state->previnput[chan]=input[chan]; tomwalters@0: output_thresh_info(state, chan); tomwalters@0: tomwalters@0: } /* for all chans */ tomwalters@0: } /* if (state->Stcrit== 5) */ tomwalters@0: tomwalters@0: tomwalters@0: qq=insertl(state->time); /* insert time to list */ tomwalters@0: (state->time)++; tomwalters@0: return; tomwalters@0: tomwalters@0: } /* doColumn */ tomwalters@0: tomwalters@0: tomwalters@0: /**************************************************************************** tomwalters@0: * addIn tomwalters@0: * add row cochleagram into stabilised image tomwalters@0: ****************************************************************************/ tomwalters@0: static void addIn( input, chan, state ) tomwalters@0: DataType *input ; tomwalters@0: int chan ; tomwalters@0: struct _sai_state *state ; tomwalters@0: { tomwalters@0: register DataType *channel_ptr, *image_ptr, *end; tomwalters@0: #ifdef FLOAT tomwalters@0: register FLOAT input_scale = INPUT_SCALE ; tomwalters@0: #endif tomwalters@0: register ScalarType *decayfactor = state->framedecay; tomwalters@0: tomwalters@0: /* Initialize channel_ptr to the input data to be added in. */ tomwalters@0: /* `input' points to a particular column in the cochleagram, */ tomwalters@0: /* and `chan' indexes a particular channel in this column. */ tomwalters@0: channel_ptr = input + chan ; tomwalters@0: end = channel_ptr - state->imagewidth ; tomwalters@0: tomwalters@0: /* Initialize image_ptr to end of sai row corresponding to `chan'.*/ tomwalters@0: /* `state->image' points to the start of the sai, */ tomwalters@0: /* so increment pointer by chan*framewidth to get to row `chan'. */ tomwalters@0: /* To get to end of row, increment by ((chan+1)*framewidth)-1. */ tomwalters@0: /* But framewidth = state->imagewidth / state->chans, and hence: */ tomwalters@0: /* Added fix; as new spiral.c accepts nwid AJD 17-3-95 */ tomwalters@0: if (state->Stcrit==4 && state->stlag==0) tomwalters@0: image_ptr = (state->image + state->imagewidth / state->chans * (chan+1)); tomwalters@0: /* 13-3-95 removed -1; ajd */ tomwalters@0: else tomwalters@0: image_ptr = (state->image + state->imagewidth / state->chans * (chan+1))-1; tomwalters@0: tomwalters@0: /* Decrement channel_ptr by columns, from the initial column, */ tomwalters@0: /* until one complete sai row has been added into, which is when */ tomwalters@0: /* channel_ptr has decreased by a whole imagewidth. */ tomwalters@0: while( channel_ptr > end ) { tomwalters@0: #ifdef FLOAT tomwalters@0: *image_ptr += ( ( *channel_ptr * input_scale ) * (*decayfactor++) ) ; tomwalters@0: #else tomwalters@0: *image_ptr += DESCALE( ( *channel_ptr >> INPUT_SHIFT ) * (*decayfactor++) ) ; tomwalters@0: #endif tomwalters@0: /* if (state->chans <= 40) */ tomwalters@0: if (*image_ptr > 32767.0) tomwalters@0: *image_ptr = 32767.0; /* 32767 */ tomwalters@0: tomwalters@0: image_ptr--; tomwalters@0: tomwalters@0: channel_ptr -= state->chans ; /* next (ie previous) input time point */ tomwalters@0: } tomwalters@0: tomwalters@0: return ; tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: /*************************************************************************** tomwalters@0: * Summary is not called in this module. tomwalters@0: * (see SummaryEntry in model.c, which is the entry point for gensas). tomwalters@0: * Summary computes a row summary spectrogram and is called during the tomwalters@0: * program "gensas". tomwalters@0: tomwalters@0: * Routines in this module it uses are: tomwalters@0: * summary_callback tomwalters@0: ****************************************************************************/ tomwalters@0: tomwalters@0: struct _summary_state { tomwalters@0: struct _fillable_source parent ; tomwalters@0: Source source; tomwalters@0: int framewidth; /* number of time-points or cols in an sai */ tomwalters@0: int frameheight; /* number of channels or rows in an sai */ tomwalters@0: double scale; tomwalters@0: int *llim; /* integration limits (lower & upper) for sai summary data */ tomwalters@0: int *ulim; tomwalters@0: }; tomwalters@0: tomwalters@0: tomwalters@0: Source Summary( source, frameheight, scale, cfs, samplerate, llimstr, ulimstr) tomwalters@0: Source source ; tomwalters@0: int frameheight ; tomwalters@0: double scale ; tomwalters@0: double *cfs, samplerate ; /* array of channel centre frequencies */ tomwalters@0: char *llimstr, *ulimstr; /* lower and upper limit strings */ tomwalters@0: { tomwalters@0: int i, framewidth, max_ulim=0, min_llim=99999999; tomwalters@0: tomwalters@0: DeclareNew( struct _summary_state *, state ) ; tomwalters@0: tomwalters@0: /* Allocate new arrays for integration limits */ tomwalters@0: state->llim = NewArray(int, frameheight, "image.c for lower limit array" ); tomwalters@0: state->ulim = NewArray(int, frameheight, "image.c for upper limit array" ); tomwalters@0: tomwalters@0: for (i=0 ; illim[i] = Cycles( llimstr, cfs[i], Samplerate() ); tomwalters@0: state->ulim[i] = Cycles( ulimstr, cfs[i], Samplerate() ); tomwalters@0: tomwalters@0: /* Check that llim < ulim, and quit if not so */ tomwalters@0: if (state->llim[i] >= state->ulim[i]) tomwalters@0: stitch_error("Warning: gensas integration limits badly ordered\n"); tomwalters@0: tomwalters@0: /* Find limits on required framewidth */ tomwalters@0: if (state->ulim[i] > max_ulim) tomwalters@0: max_ulim = state->ulim[i]; tomwalters@0: if (state->llim[i] < min_llim) tomwalters@0: min_llim = state->llim[i]; tomwalters@0: } tomwalters@0: tomwalters@0: if (min_llim > 0) min_llim = 0; tomwalters@0: framewidth = max_ulim - min_llim; tomwalters@0: tomwalters@0: /* Adjust the integration limits for an sai with triggering on the */ tomwalters@0: /* right. (The parameters llim <= ulim, but the resulting sai indices */ tomwalters@0: /* state->llim[i] > state->ulim[i]). */ tomwalters@0: /* This is done by subtracting from (framewidth-1), where framewidth is */ tomwalters@0: /* the maximum required number of points, (ie ulim in points). */ tomwalters@0: tomwalters@0: for (i=0 ; illim[i] = framewidth - state->llim[i] ; tomwalters@0: state->ulim[i] = framewidth - state->ulim[i] ; tomwalters@0: } tomwalters@0: tomwalters@0: framewidth++; /* extra point as array starts from zeroth location */ tomwalters@0: tomwalters@0: /* a blockings requests up into requests of the size specifed */ tomwalters@0: state->source = NewBlockingSource( source, sizeof ( DataType ) * framewidth * frameheight ) ; tomwalters@0: state->framewidth = framewidth ; tomwalters@0: state->frameheight = frameheight ; tomwalters@0: state->scale = scale ; tomwalters@0: tomwalters@0: return ( SetFillableSource( state, summary_callback, "image.c summarising sai" ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: /*********************** Routines supporting Summary ***********************/ tomwalters@0: tomwalters@0: static Pointer summary_callback( state, bytes, buffer ) tomwalters@0: struct _summary_state *state ; tomwalters@0: ByteCount *bytes ; tomwalters@0: DataType *buffer ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: register int i, j, ulim, llim, point, points=ToPoints(DataType,*bytes) ; tomwalters@0: register DataType *sairow; tomwalters@0: #ifdef FLOAT tomwalters@0: register DataType sum ; tomwalters@0: #else tomwalters@0: register long sum ; tomwalters@0: #endif tomwalters@0: tomwalters@0: /* Pull an sai frame */ tomwalters@0: tomwalters@0: for( point=0 ; point < points ; ) tomwalters@0: /* For each channel (row) in the sai, sum the row between the given limits */ tomwalters@0: for(i=0 ; iframeheight ; i++) { tomwalters@0: tomwalters@0: sairow = PullItems(state->source,state->framewidth,DataType); tomwalters@0: tomwalters@0: ulim = state->ulim[i]; tomwalters@0: llim = state->llim[i]; tomwalters@0: sum = 0; tomwalters@0: for (j=ulim ; j<=llim ; j++) tomwalters@0: sum += sairow[j]; tomwalters@0: tomwalters@0: /* store the row-sum, scaled and normalized for the range of the sum */ tomwalters@0: buffer[point++] = sum*state->scale / (llim-ulim); tomwalters@0: } tomwalters@0: tomwalters@0: if( !last ) tomwalters@0: return ( (Pointer) buffer ) ; tomwalters@0: else { tomwalters@0: Delete( state->llim ) ; tomwalters@0: Delete( state->ulim ) ; tomwalters@0: tomwalters@0: return ( DeleteFillableSource( state ) ) ; tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: /********************************************************************************/ tomwalters@0: /* */ tomwalters@0: /* initlist initialises the linked list pointer before the other list functions */ tomwalters@0: /* call the list. */ tomwalters@0: /* */ tomwalters@0: /********************************************************************************/ tomwalters@0: void initlist() tomwalters@0: { tomwalters@0: static int status=0; tomwalters@0: if (status==0) tomwalters@0: start = endl = pp = qq = (node *)malloc(sizeof(node)); tomwalters@0: status=1; tomwalters@0: } tomwalters@0: tomwalters@0: /********************************************************************************/ tomwalters@0: /* */ tomwalters@0: /* Function getnode allocates storage for a link list node and returns a */ tomwalters@0: /* pointer to that node */ tomwalters@0: /* */ tomwalters@0: /********************************************************************************/ tomwalters@0: node *getnode() tomwalters@0: { tomwalters@0: node *q; tomwalters@0: q=(node *)malloc(sizeof(node)); tomwalters@0: if (q==NULL) exit(66); tomwalters@0: return q; tomwalters@0: } tomwalters@0: tomwalters@0: /********************************************************************************/ tomwalters@0: /* */ tomwalters@0: /* The function insertl inserts the value x at the end of the linked list and */ tomwalters@0: /* moves the end point by another node */ tomwalters@0: /* */ tomwalters@0: /********************************************************************************/ tomwalters@0: node *insertl(x) tomwalters@0: int x; tomwalters@0: { tomwalters@0: node *q=endl; tomwalters@0: endl=getnode(); tomwalters@0: q->next=endl; tomwalters@0: q->index=x; tomwalters@0: q->val=0; tomwalters@0: /* fprintf(testfile, "insertl: index is %d, val is %d\n", q->index, q->val); */ tomwalters@0: return q; tomwalters@0: } tomwalters@0: tomwalters@0: /********************************************************************************/ tomwalters@0: /* */ tomwalters@0: /* The function inss searches the list from the start, stops 3 nodes before the */ tomwalters@0: /* value x, assigns the value -2000 to the three nodes till the (x+1)th node. */ tomwalters@0: /* */ tomwalters@0: /********************************************************************************/ tomwalters@0: void inss(x) tomwalters@0: int x; tomwalters@0: { tomwalters@0: node *q=start; tomwalters@0: int y=x-3; tomwalters@0: int z=x; tomwalters@0: while (q!=endl) tomwalters@0: { tomwalters@0: if (q->index == y) tomwalters@0: do tomwalters@0: { tomwalters@0: q->val=-2000; tomwalters@0: q=q->next; tomwalters@0: /* fprintf(stderr, "Inss(x) index=%d\n",q->index); */ tomwalters@0: } while (q->index < z); tomwalters@0: q=q->next; tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: /********************************************************************************/ tomwalters@0: /* */ tomwalters@0: /* output_simple_strobe_info routine creates a file pointed by trigger file */ tomwalters@0: /* which writes the points in the Nap pulse which initiates strobing */ tomwalters@0: /* */ tomwalters@0: /********************************************************************************/ tomwalters@0: void output_simple_strobe_info(state, value) tomwalters@0: struct _sai_state *state; tomwalters@0: short value; tomwalters@0: { tomwalters@0: tomwalters@0: if (!(!strcmp(state->switch_info, "off") || !strcmp(state->switch_info, "on"))) tomwalters@0: fwrite(&(value), sizeof(short), 1 , trigger_file); tomwalters@0: } tomwalters@0: tomwalters@0: /********************************************************************************/ tomwalters@0: /* */ tomwalters@0: /* doList_strobe_info creates a file (pointed by "trigger_file") which writes */ tomwalters@0: /* in binary shorts the points in the Nap pulse which initiates a strobe */ tomwalters@0: /* It uses a linked list data structure to keep track of the actual time which */ tomwalters@0: /* causes a strobe, rather than the time when the strobing event occurs. */ tomwalters@0: /* At stcrit 4 or 5, strobing occurs nwid ms after a nap pulse peak has been */ tomwalters@0: /* located. */ tomwalters@0: /* */ tomwalters@0: /********************************************************************************/ tomwalters@0: void doList_strobe_info(state, chan) tomwalters@0: struct _sai_state *state; tomwalters@0: int chan; tomwalters@0: { tomwalters@0: int storev; tomwalters@0: tomwalters@0: if (state->Stcrit==2) tomwalters@0: storev=(state->time)-2; tomwalters@0: else if (state->Stcrit==5) tomwalters@0: storev=state->def_strobe_candidate_time[chan]; tomwalters@0: /* fprintf(stderr, "Storev value of doList is = %d\n", storev);} */ tomwalters@0: else tomwalters@0: storev=state->trigtime[chan]; tomwalters@0: tomwalters@0: inss(storev); tomwalters@0: tomwalters@0: while (pp->index<=storev) /* (pp!=qq) */ tomwalters@0: { tomwalters@0: if (!(!strcmp(state->switch_info, "off") || !strcmp(state->switch_info, "on"))) tomwalters@0: fwrite(&(pp->val), sizeof(short), 1, trigger_file); tomwalters@0: /* fprintf(testfile, "doList: index is %d, val is %d\n", pp->index, pp->val); */ tomwalters@0: pp=pp->next; tomwalters@0: } tomwalters@0: /* pp=qq; */ tomwalters@0: } tomwalters@0: tomwalters@0: /********************************************************************************/ tomwalters@0: /* */ tomwalters@0: /* output_thresh_info writes threshold values (in binary shorts or floats) to */ tomwalters@0: /* the file opened by the file pointer "thresho_file" */ tomwalters@0: /* */ tomwalters@0: /********************************************************************************/ tomwalters@0: void output_thresh_info(state, chan) tomwalters@0: struct _sai_state *state; tomwalters@0: int chan; tomwalters@0: { tomwalters@0: S[chan]=state->thresh[chan]; tomwalters@0: tomwalters@0: if (!(!strcmp(state->switch_info, "off") || !strcmp(state->switch_info, "on"))) tomwalters@0: #ifdef FLOAT tomwalters@0: fwrite((S+chan), sizeof(float), 1, thresho_file); tomwalters@0: #else tomwalters@0: fwrite((S+chan), sizeof(short), 1, thresho_file); tomwalters@0: #endif tomwalters@0: tomwalters@0: } tomwalters@0: tomwalters@0: /********************************************************************************/ tomwalters@0: /* */ tomwalters@0: /* decay_strobe_threshold decays the strobe threshold at every clock */ tomwalters@0: /* tick either linearly or exponentially */ tomwalters@0: /* */ tomwalters@0: /********************************************************************************/ tomwalters@0: void decay_strobe_threshold(state, chan) tomwalters@0: struct _sai_state *state; tomwalters@0: int chan; tomwalters@0: { tomwalters@0: tomwalters@0: if (!strcmp(exposwitch, "on")) tomwalters@0: state->thresh[chan] *= state->triggerdecay; tomwalters@0: else tomwalters@0: { tomwalters@0: state->thresh[chan] -= state->tlim[chan]; tomwalters@0: if (state->thresh[chan] < 0) tomwalters@0: state->thresh[chan]=0; tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: /********************************************************************************/ tomwalters@0: /* */ tomwalters@0: /* This routine prints debugging information of the local max search */ tomwalters@0: /* with timeout (i.e. stcrit_ai=5) */ tomwalters@0: /* */ tomwalters@0: /********************************************************************************/ tomwalters@0: void print_trigger_debugging_info(state, chan, strobe_lag, stage) tomwalters@0: struct _sai_state *state; tomwalters@0: int chan; tomwalters@0: int strobe_lag; tomwalters@0: int stage; tomwalters@0: { tomwalters@0: if (stage==1) tomwalters@0: { tomwalters@0: if (strobe_lag > state->def_strobe_candidate_time[chan]) tomwalters@0: val[chan]=strobe_lag-state->def_strobe_candidate_time[chan]; tomwalters@0: if (strobe_lag == state->def_strobe_candidate_time[chan]) tomwalters@0: val[chan]=0; tomwalters@0: tomwalters@0: if (!strcmp(state->switch_info,"off")); tomwalters@0: else tomwalters@0: fprintf(infotxt_file, "Chan %d: :: Actual time of trigger: s_lag=%d, trigtime=%d\n", chan, strobe_lag, state->def_strobe_candidate_time[chan]); tomwalters@0: } tomwalters@0: tomwalters@0: /* fprintf(infotxt_file, "Chan %d: Actual time of trigger: s_lag=%d, trigtime=%d, shift=%d\n", chan, strobe_lag, state->def_strobe_candidate_time[chan], val[chan]*state->chans); */ tomwalters@0: tomwalters@0: tomwalters@0: if (stage==2) tomwalters@0: { tomwalters@0: if (!strcmp(state->switch_info,"off")); tomwalters@0: else tomwalters@0: fprintf(infotxt_file, "Chan %d: Loc Max Start Time = %d, trigcurrent %d, Threshold=%f, shift=%d\n", chan, state->time, state->trigheight[chan], state->thresh[chan], (ttime[chan]-initial_strobe_candidate_time[chan])); tomwalters@0: } tomwalters@0: tomwalters@0: if (stage==3) tomwalters@0: { tomwalters@0: if (!strcmp(state->switch_info,"off")); tomwalters@0: else tomwalters@0: fprintf(infotxt_file, "Chan %d: Loc Max is %d Time is %d\n", chan, state->trigheight[chan], state->trigtime[chan] ); tomwalters@0: } tomwalters@0: tomwalters@0: if (stage==4) tomwalters@0: { tomwalters@0: if (!strcmp(state->switch_info,"off")); tomwalters@0: else tomwalters@0: fprintf(infotxt_file, "Chan %d: At the End of Search (At peak), trigtime = %d time = %d height = %d\n", chan, state->trigtime[chan], state->time, state->trigheight[chan]); tomwalters@0: } tomwalters@0: if (stage==5) tomwalters@0: { tomwalters@0: if (!strcmp(state->switch_info,"off")); tomwalters@0: else tomwalters@0: fprintf(infotxt_file, "Chan %d: At the End of Search, trigtime = %d time = %d height = %d\n", chan, state->trigtime[chan], state->time, state->trigheight[chan]); tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: } tomwalters@0: