Listing 1

/*************************************
 *                                   *
 *    LINEAR & NONLINEAR VARIANCE    *
 *            TEST PROGRAM           *
 *                                   *
 *  M.E. Brandt, Ph.D.               *
 *  02/06/91 Revision                *
 *                                   *
 *************************************/

#include <stdio.h>
#include <math.h>
#include <malloc.h>


#define NMAX                   1024
#define NBINS                    10
#define MAX_DELAY                30
#define MAXRAND             32767.0
#define DBL_LEN      sizeof(double)
#define PI        3.141592653589793
#define TWOPI            (2.0 * PI)



double linvar(double *y, double *x, int nn);
double nonlinvar(double *x, double *y, int n, int nbins);
int    number_bins(int x);
void   estimate_delay(double *x, double *y, int n);



main()
{

   int xx, i, j, nb, n, ch;

   double *x, *y, scale, r2, h2, start,
         noise, gain, a, inc, mean, num;
   char u[3], c;


   srand(1);

  /* SELECT A FUNCTION TO TEST */

  do {

       printf("\n\nSelect a y vs. x function and ");
       printf("compute variances:\n");
       printf("\n1. y = ax + noise (linear)");
       printf("\n2. y = sin(x) + noise");
       printf("\n3. y = sgn(x)*(x*x) + noise");
       printf("\n4. y = pow(3*x, 3) + noise");
       printf("\n5. y = pow(5*x, 5) + noise");
       printf("\n6. Exit");
       printf("\n\nSelect 1-6: ");
       scanf ("%d", &ch);

       if(ch == 6) exit(0);

       do {

          printf("\n\nHow many data points?: ");
          scanf("%d", &n);
       }
       while(n > NMAX);

       do {

          printf("\n\nEnter noise gain: ");
          scanf("%lf", &gain);
          }
          while(gain < 0.0 || gain > 1.0);

          /* allocate space for x and y vectors */

          if((x = (double *)malloc(n * DBL_LEN)) == NULL) {
             fprintf(stderr, "\nMalloc error; x\n");
             exit(1);
          }

          if((y = (double *)malloc(n * DBL_LEN)) == NULL) {
             fprintf(stderr, "\nMalloc error; y\n");
             exit(1);
          }

        /* generate a random uniformly distributed x[n]
           between + or - 0.5
        */

        for(i=0; i<n; i++) x[i] =
                         ((double)rand()/MAXRAND - 0.5);


        /* choose y[n] */

        switch(ch) {

           case 1:  printf("\nEnter a: ");
                   scanf("%lf", &a);

                   for(i=0; i<n; i++) {
                      noise = gain *
                         ((double)rand()/MAXRAND - 0.5);
                      y[i] = a * x[i] + noise;
                   }
                   break;

           case 2:  for(i=0; i<n; i++) {
                      noise = gain *
                         ((double)rand()/MAXRAND - 0.5);
                      y[i] = sin(TWOPI * x[i]) + noise;
                   }
                   break;

           case 3:  for(i=0; i<n; i++) {
                      noise = gain *
                         ((double)rand()/MAXRAND - 0.5);
                      y[i] = (x[i] * x[i]);
                      if(x[i] < 0.0) y[i]*= -1.0;
                      y[i] += noise;
                   }
                   break;

           case 4:  for(i=0; i<n; i++) {
                     noise = gain *
                        ((double)rand()/MAXRAND - 0.5);
                     y[i] = pow(3.0*x[i], 3.0) + noise;
                   }
                   break;

           case 5:  for(i=0; i<n; i++) {
                     noise = gain *
                        ((double)rand()/MAXRAND - 0.5);
                     y[i] = pow(5.0*x[i], 5.0) + noise;
                   }
                   break;

          default:  break;

        }

    printf("\nTest delay estimation <y/n>?: ");
    scanf("%s", u);
    c = toupper(*u);
    if(c == 'Y') {
      estimate_delay(x, y, n);
      continue;
    }



    /* compute linear variance of x vs. y */

    r2 = linvar(x, y, n);

    printf("\nLinear r2(x,y) = %f\n", r2);


    /* choose number of bins */

    nb= number_bins(n);

    /* compute nonlinear variance of x vs. y */

    h2 = nonlinvar(x, y, n, nb);

    printf("\nNonlinear h2(x,y) = %f\n", h2);


    /* y vs. x */

    r2 = linvar(y, x, n);

    printf("\nLinear r2(y,x) = %f\n", r2);


    h2 = nonlinvar(y, x, n, nb);

    printf("\nNonlinear h2(y,x) = %f\n", h2);

    free(x); free(y);

  }
  while(1);


}


/* routine to find variances & delay between 2 lagged
   signals */

double buf[NMAX+MAX_DELAY], r2[MAX_DELAY+10],
      h2[MAX_DELAY+10];

void estimate_delay(double *x, double *y, int n)
{
   int i, j, d, delay, lag, max_lag, np, nb;

   double max;


   do {

     printf("\nEnter delay between x and y in samples: ");
     scanf("%d", &delay);
   }
   while((d = abs(delay)) > MAX_DELAY);


   for(i=0; i<d; i++)
      buf[i] = ((double)rand()/MAXRAND - 0.5);
   max_lag = d + 10;

   if(delay > 0) { /* y lags x */

      /* move y to buf */

      for(j=0, i=d; j<n; i++, j++) buf[i] = y[j];

      for(lag=0; lag<max_lag; lag++) {

          np = n - lag;    /* compute across less points */

          /* get linear variance at lag */

          r2[lag] = linvar(x, &buf[lag], np);

          nb= number_bins(np);

          /* get nonlinear variance at lag */

          h2[lag] = nonlinvar(x, &buf[lag], np, nb);

      }
   }

       else if(delay < 0) { /* x lags y */

              for(j=0, i=d; j<n; i++, j++) buf[i] = x[j];

              for(lag=0; lag<max_tag; lag++) {

                  np= n - lag;

                  r2[lag] = linvar(&buf[lag], y, np);

                  nb= number_bins(np);

                  h2[lag] = nonlinvar(&buf[lag], y, np, nb);

              }
       }


      /* find maximum r2 and corresponding delay */

         max = r2[0];
         for(i=1; i<max_lag; i++)
            if(r2[i] > max) {max = r2[i]; j = i;}

         if(delay < 0) j = -j;

         printf("\nTrue delay = %d; maximum r2 = %f \
    found @ sample %d\n",
                 delay, max, j);


      /* find maximum h2 and corresponding delay */

         max = h2[0];
         for(i=1; i<max_lag; i++)
            if(h2[i] > max) {max = h2[i]; j = i;}

         if(delay < 0) j = -j;

         printf("\nTrue delay = %d; maximum h2 = %f \
    found @ sample %d\n",
                 delay, max, j);


    }

    /* compute number of bins for nonlinear variance calc. */

    int number_bins(int x)
    {
        int y;

        if(x < 129) y = NBINS - 4;
        else
        if(x < 257) y = NBINS - 3;
        else
        if(x < 513) y = NBINS - 2;
        else        y = NBINS;

        return y;

    }

    /* routine to compute linear variance measure */

    double linvar(double *y, double *x, int nn)
    {

       register int j;

       double z, smx, smy, sqx, sqy, sxy, corr;
       double sqrt(), varx, vary, cov, nnn;



    /* initialize values */

    nnn = (double)nn;

    corr = sqy = 0.0;


    smx = 0.0;
    smy = 0.0;
    sqx = 0.0;
    sxy = 0.0;

    for(j=0; j<nn; j++) {

       smx += x[j];
       smy += y[j];
       sqx += (x[j] * x[j]);
       sxy += (x[j] * y[j]);


       sqy += (y[j) * y[j]);


    } /* end for */

    /* Compute covariance and variances */

    cov = (nnn * sxy) - (smx * smy);
    varx = (nnn * sqx) - (smx * smx);



    vary = (nnn * sqy) - (smy * smy);

    z = sqrt(varx * vary);

    if(z != 0.0) corr = cov / z;
    else corr = 0.0;

    return(corr*corr);

    }

    /* routine to compute nonlinear variance measure */

    int bin[NBINS] [2*NMAX/NBINS];
    double q[NBINS], p[NBINS];

    double nonlinvar(double *x, double *y, int n, int nbins)
    {
        int i, J, k, l, index, index2, last;

        double min, max, range, width, hwidth, start, end,
              mean, mean2, totvar, unvar, s, f, h2, uu, offset;


         /* find max and min of x array */

         min = max = x[0]; last = 0;

         for(i=1; i<n; i++) {
            if(x[i] > max) {max = x[i]; last = i;}
            else
            if(x[i] < min) min = x[i];
         }

         range = max - min;

         width = range/(double)nbins;

         hwidth = width/2.0;

         for(i=0; i<nbins; i++) bin[i][0] = 0;

        /* get histogram of indexes */

        for(i=0; i<n; i++) {
           for(j=0; j<nbins; j++) {
              start = (double)j*width + min;
              end = start + width;

              if((x[i] >= start) && (x[i] < end)) {
                 ++bin[j][0];
                 bin[j][bin[j][0]] = i;
                 break;
              }
           }
         }

     /* maximum x value (last one) */

     j = nbins-1;
     ++bin[j][0];
     bin[j][bin[j][0]] = last;

   /* compute x-midpoints and y average amplitudes */

    mean2 = 0.0;
    offset = hwidth + min;

    for(i=0; i<nbins; i++) {

       /* x value midpoints for each bin */

       p[i]= ((double)i * width) + offset;

       /* corresponding y average amplitudes */

       mean = 0.0;

       for(k=1; k<=bin[i][0]; k++) mean += y[bin[i][k]];

       q[i] = mean/double)bin[i][0];
       mean2 += mean;

    }


    mean = mean2/(double)n;     /* overall */


    /* compute h*h coefficient */

    /* first compute total variance of y */

    totvar = 0.0;
    for(i=0; i<n; i++) {
        s = y[i] - mean;
        totvar += (s * s);
    }

    /* compute total unexplained variance of y */

    unvar = 0.0;
    for(i=0; i<n; i++) {

        /* find f(x[i]), the nonlinear value */

        for(j=1; j<nbins-1; j++){
           if(x[i] <= p[j]) {
              index = j-1;
              goto out1;
           }
        }

        index = nbins-2;

  out1:
        index2 = index++;

        f = ((q[index2] - q[index])/
            (p[index2] - p[index])) *
              (x[i] - p[index]) + q[index];

        uu = y[i] - f;
        unvar += (uu * uu);

    }

    /* now compute nonlinear regression coefficient */


    h2 = 1.0 - (unvar/totvar);

    return h2;

}