                                  SIGNAL PROCESSING 
          
          
             The  file  SIGNALP.H  contains  function  prototypes  for  the 
          routines  in this group.          

          MEDIAN.C
          
            This  file  contains three (3) routines which act as  a  median 
          filter for time series.   A median filter is useful for  removing 
          large amplitude spikes from a time series.  A running mean filter 
          would smooth such spikes without removing them.   A median filter 
          is non-linear,  and as such cannot be described by a  convolution 
          integral or a spectrum.   Its behavior depends on the time series 
          being  filtered.   Moreover,  a  median filter of even length  is 
          ambiguous,  since the median value will not necessarily equal one 
          of the time series values.  The resulting 1/2 time interval shift 
          of  the  filter causes a phase shift of the data  that  increases 
          with frequency.  For this reason, I have implemented only filters 
          of  odd length for which the median value is unambiguous in  time 
          and value.
             Median filters mimick hand/eye filtering of time series.  They 
          ought  to  be  useful for  cleaning  up  telemetry,   coded  time 
          signals,  and  pulse  code modulated signals corrupted  by  burst 
          noise.   If  the  pulses one wishes to preserve are N  points  in 
          length,  and  the maximum burst length is B samples,  the  median 
          filter must be 2*B+1 in length and cannot exceed 2*N-3.
             This  routine requires about 4*length operations per new  data 
          point and is fairly efficient.   A FORTRAN median sort routine is 
          available from the USGS in Open file report 81-1091.  It works by 
          shuffling  input values in a stack,  and may be  slightly  faster 
          than this code, but is of the same order of speed.
       
          Prototype:  int median_filter(float *a,int num,int length);
          
             *a  points to the time series to be filtered.   This series is 
          of length num.   The integer (length) is the length of the median 
          filter and must be an odd number.  The routine establishes 4 work 
          arrays  of linked lists and pointers to do a median sort  on  the 
          fly.
          
          
          
          Return Values:  -2 if no memory for allocating work arrays (needs 

          4*length integer locations).
                          -1 if length is even.
                           0 if no error.
          
          Prototype:  float insert_sort(float *a,int length,int median);
          
             This  routine sorts the first length values of the array  (*a) 
          into  descending order in a work array,  sets up a doubly  linked 
          list of ascending and descending order,  a singly linked list  of 
          the  series  by age,  and pointers back to the  array  (*a).   It 
          returns  the  median of these first length values.   The  integer 
          median  is equal to length/2,  the distance to the median  value.  
          It  could be recomputed by the routine each time,  but  that's  a 
          waste of computation.  There is enough to do already. 
          
          Prototype: float insert(float *a,int current,int median);  
          
             This  routine uses the linked structures set up in insert_sort 
          to   maintain   a   median  sorted  list   on   the   fly.    The 
          integer (current) is the index value of the element of (*a) begin 
          added  to the list.   The oldest value currently in the  list  is 
          dumped  and  replaced by this one.   After the insertion is  made 
          the routine returns the new median value.
          
           
          FFT.C
          
          There  are two fast Fourier transform routines on this  diskette.  
          fft.c  contains  a  routine named fft that is  the  shortest  and 
          simplest of the two,  although it is not necessarily the fastest.  
          fft  works only on one-dimensional data,  and only on time series 
          that are a power of 2 in length at that.   The function prototype 
          is:
          
          void  fft(float *real,float *imag,int length,int sign);
          
             Upon  entering the routine *real points to a time series to be 
          transformed.   It is of length (length) which must be a power  of 
          two.   sign  is -1 for a forward transform and +1 for an  inverse 
          transform.   Upon  return  the  array  *real  contains  the  real 
          elements of the transform and *imag the imaginary components. fft 
          automatically  does  the appropriate normalizing of  the  inverse 
          transformation  by dividing by the number of data points (length) 
          if sign is 1.
          
          
          FOURT.C
          
             FOURT.C  and all related routines are contained in a directory 
          included  in  the periodogram in units of average  Nyquist  rate.  
          The  routines  required to  implement  FOURT  are:  
          FOURT.C,   APOWER2.C,   NPOWER2.C,  AFACTOR2.C,  NFACTOR2.C,  and 
          CONJUGAT.C.   This  is  a  fast Fourier  transform  that  accepts 
          arbitrary  lengths  of  time  series  -- odd,  even,  prime,  not 
          restricted to a power of 2 length.  It will work in any number of 
          dimensions,  although  I have trouble coming up with applications 
          for  anything  above the third dimension (a transform  of  a  3-D 
          crystal  for  example  is a reciprocal  lattice).   The  original 
          FORTRAN  routine written by Norman Brenner was also named  FOURT.  
          I tested it quite thoroughly over about 10 years of use.   I have 
          made a substantial alteration to the 'C' version of FOURT to make 
          it  easier  to read and understand,  and I added  input  options.  
          Because  of these changes the user is warned to test the  routine 
          before  relying on it explicitly.   I have tested it in 1 and  2-
          dimensions  for odd and even data lengths,  but I haven't  tested 
          every conceivable combination of dimension and length.
         
          An interesting reference pertaining to this routine is:
          
          C.M. Rader. June 1968. IEEE Proc. V.56 No.6 P1107-1108.
          
          Prototype:  
          int  fourt(float *series,int *values,int dim,int sign,int form);
          
             The original time series is referenced by *series.   This  may 
          be  a complex series,  so the even numbered elements of  (series) 
          are  composed of the real values of the time series,  and the odd 
          numbered  elements  make  up the imaginary  part.   That  is  the 
          complex data structure follows FORTRAN convention.   If the input 
          series is purely real one may provide (series) as an array  twice 
          the  data  length and have all the time series id the  first  1/2 
          adjacent storage locations.
            *values  is  an array of length (dim) that gives the number  of 
          data  elements in each dimension.  For example,  values[0] is the 
          number  of data points in the first dimension.  Integer (dim)  is 
          the number of dimensions.  Sign is -1 for a forward transform, +1 
          for an inverse.  Form may take one of 3 values.  Form=1 indicates 
          that  the  time series is complex,  normal FORTRAN  complex  data 
          structure is expected.   Form=0 indicates that the time series is 
          real  and expects that the odd numbered elements of (series)  are 
          all set to 0.0.   Form=-1 indicates that the time series is real, 
          that  adjacent  elements  of (series) are loaded  with  the  time 
          series, and that the upper 1/2 of (series) is 0.0.
          Error returns:   -1 indicates dimensions<1.
                           -2 at least one element of *values is <1.
                           -3 fourt was handed an improper case to handle.
           
          LOMB.C
          
             The  Nyquist frequency (or rate) is an upper bound to a search 
          for periodicity in a uniformly spaced time series.   However,  if 
          the  time series is not uniformly spaced -- if some  samples  are 
          very close together-- an analyst can use a different algorithm to 
          look  for  periodicity well beyond the Nyquist rate.   The  Lomb-
          Scargle  algorithm is such a beast.   It is essentially a  least-
          squares periodicity analyzer.
    
          Prototype: 
          
          float lomb_scargle(float *t,float *v,int n,float *f,float *p,
                       int m,int sample,int *largest)
          
          
             This routine accepts an array of n times (t) at which n values 
          (v) are observed.   The user supplies arrays f and p which return 
          frequency and the lomb-scargle normalized periodogram value at  a 
          series   of   m   locations.    m  is  equal   to   the   product  
          n*sample/2.   m  is calculated by the user and supplied to the   
          routine. The user should have allocated storage for f and p before
          calling lomb. Sample is an oversampling factor. An fFt analysis 
          produces  a spectrum (periodogram) at equal  increments  of 
          frequency equal to 1.0/T, where T is the time span of the series.  
          The oversampling factor is a measure of how much more finely  the 
          time series is tested to extend the effective nyquist rate.
          An oversampling rate of 2,  for example, produces a periodogram
          with a maximum frequency twice that of the nyquist rate.
          The average Nyquist rate is 1.0/(2*delta_t), where delta_t=T/n.
             The return value from the routine is the probability that  the 
          maximum  value  of the periodogram,  pointed to by the  value  of 
          largest (returned), is the result of random noise.  A small value 
          for this probability indicates a highly significant component.
          
          
          WALSH.C
          
             There  are five (5) routines in the file WALSH.C which involve 
          the orthogonal set of functions known as Walsh functions.   Walsh 
          functions are binary.  They take on only the values 1 and -1, but 
          by  using  a  linear  combination  of  such  functions  one   may 
          approximate  any  time series.  One distinct advantage  of  Walsh 
          functions is that very abrupt transitions in a time series can be 
          represented  without  resorting  to basis functions that  have  a 
          large  number of zero-crossings per unit time.  Users wishing  to 
          learn more about Walsh functions are referred to:
          
          Walsh  functions  and  their  applications.    K.  C.  Beauchamp.  
          Academic Press, New York. 1975.
          
          Protoype:  float walsh(float x,int order);
          
             This routine accepts a floating point number (x) between  zero 
          and 1.0 (the orthogonal interval for the functions), and an order 
          for  the  desired Walsh function,  and returns the value  of  the 
          appropriate  Walsh function at x.   Those having need to evaluate 
          the functions outside the [0.0,1.0] interval will have to rescale 
          their  time  series so that the period is 1.0  (i.e.  divide  all 
          times  by  the  period length).   The  routine  calculates  Walsh 
          functions  from  a  subtractive recursion and is  slow  for  high 
          orders.
          
          
          Prototype: float hadamard(float x,int order);
          
             Hadamard and Walsh functions are the same except for the order 
          in which the functions appear.  This difference in order, though, 
          makes Hadamard function faster to calculate,  since one may use a 
          recursion  based on division.   The function hadamard  accepts  a 
          floating  point  number  in the range [0.0,1.0]  and  an  integer 
          order, and returns the value of the Hadamard function.
         
          Prototype:  void fast_walsh(float *x,float *y,int length);
          
            fast_walsh  is a fast Walsh transform routine analogous to  the 
          fast  Fourier routine.   *x points to an input array of  floating 
          point values defining the time series.   This series is of length 
          (length)  which must be a power of 2  (i.e.  2,4,8,16,32,64,...).  
          On  return  the array y will contain the Walsh transform in  Gray 
          code order.   To sort this Gray code into a useable form call the 
          routine sort_wals.
          
          Prototype:  int sort_wals(float *out,float *in,int length);
          
            Given  the Walsh transform in Gray code sequence pointed to  by 
          *in,  this routine will sort the transform into one of increasing 
          Wals   (*out)   beginning   with  Walsh(0),   and  ending   with 
          Walsh(length-1).   The Walsh functions of even order are  cosine-
          like  (even functions) and those of odd order are sine-like  (odd 
          functions).  Thus the Walsh transform is sorted by sort_wals into 
          something like a Fourier transform with the odd numbered elements 
          playing the part of the imaginery part of the transform.  
         
          Return Values: -1 if no memory for work array (size length/2).
          
          Prototype:  int  gray_sort(float *out,float *in,int num);
          
             This  is  an  inverse function to  sort_wals.   It  takes  the 
          sequence of walsh coefficients sorted in order of increasing wals 
          and  returns  the  order to the reversed bit gray  code  sequence 
          required by fast_walsh.
            Calling  fast_walsh  twice -- using the output array  from  the 
          first  call as input to the second --  will return  the  original 
          time series multiplied by length.   The fast_walsh routine is its 
          own inverse as long as the input to the inverse is in reverse bit 
          gray code sequence.
          
                 fast_walsh(x,y,32);  y=Walsh transform of x.
                 sort_wals(x,y,32);   x contains transform sorted.
                 fast_walsh(y,x,32);  x contains 32*original time series.
          
            If any filtering is to be performed, its is more easily done on 
          a sequence of coefficients sorted by increasing wal.  In order to 
          reconstruct  the filtered time series the wal sorted coefficients 
          have  to  be returned to the gray code order.   The  sequence  of 
          calls is:
          
                   fast_walsh .... does the forward walsh transform.
                   sort_wals  .... sorts into increasing wal order.
                   user filter ... alters coefficients according to design.
                   gray_sort  .... returns the gray sequence of coefs.
                   fast_walsh .... reconstructs the time series.
          
          
          K.T. Kilty
          Cheyenne, Wyoming
          December 1, 1988
                                        -oOo-
