[sci.math] Correlation and FFT

kimy@ingr.com (Yongsup Kim) (12/27/89)

Hello World!, Signal/Image Proc. Programmers or Simply Hackers!

I ask your favor to solve a well-known problem in the signal/image 
processing fields.  I want to compute the correlation of two signals 
using the Fourier Transform.  The two discrete signals are as follows:
 
	f(n) = {1,1,1,1,2,2,2,2,8,8,8,8,9,9,9,9},    n=0,1,....,15.
	h(n) = {1,2}				     n=0,1.

The result should have the highest correlation coefficients at 1,2 and 
8,9 transitions.  In other words I want to do a pattern matching using FFT.
I was able to get the expected results in the spatial domain, but not in
the frequency domain. I haven't figured out the normalization steps to take
care of the scale changes when I used the FFT.  
Note that the lengths of the two signals are not the same, but we can 
assume that they are a power of two. I've never posted a news before.
You're more than welcome to call me if you have answers, questions and 
problems.

Thanks in advance.

Name:	Youngsup Kim 
Phone:	1-800-633-7207, 1-205-772-1999 USA
mail: 	kimy@ingr.com 			
	b15!ysk!youngsup@ingr.com		

!!HappyNewYear!!HappyNewYear!!HappyNewYear!!HappyNewYear!!HappyNewYear!!Happy
!!HappyNewYear!!HappyNewYear!!HappyNewYear!!HappyNewYear!!HappyNewYear!!Happy

==========
BACKGROUND
==========

The discrete correlation function is defined as

In the spatial domain:
----------------------

		      M-1
	f(x) o h(x) = SUM f(m) h(x+m)		for x=0,1,..,M-1.
		      m=0

The normalization should be carried out to overcome the scaling
problem.  Here is the formular to compute the correlation coefficients. 

		     SUM [f(x) - f'(x)] [h(x-m) - h']
	r(m) = ----------------------------------------------
		sqrt{ SUM [f(x) - f'(x)] SUM [h(x-m) - h'] }

	where m=0,1,...M-1, h' is the average value of the signal, 
f'(x) is the average value of f(x) in the region coincident with h(x),
and the summations are taken over the coordinates common to both f and h.
The coefficient r(m) is scaled to the range from -1 to 1, independent of
scale changes in the amplitude of f(x) and h(x).  This works great.
Once again I want to do the same thing in the frequency domain or using
the Fourier tranform. 

In the freqency domain: 
----------------------
                        -1         *
	f(x) o h(x) = FFT  [ F(n) H(n) ]

       *
where H(n) is the complex conjugate of H(n).  F(n) and H(n) are the 
Fourier Transform of f(n) and h(n), respectively.


For your convenience, I include the forward/inverse FFT routines and
complex.h.  The FFT routines are not optimized but working. 


/* 
 * File: complex.h 
 *
 *	define the complex number structure and operations
 *
 * History:
 * 11/01/89	YSK 	Creation
 * 
 */

#ifndef IM_CMPLX
#define IM_CMPLX

struct IM_sd_cmplx
 {
  float	r;	/* real part 		*/
  float	i;	/* imaginary part	*/
 };

typedef struct IM_sd_cmplx IM_S_CMPLX;
typedef struct IM_sd_cmplx *IM_p_CMPLX;


/* 
	IDEA: 
	** Computing a complex product (A + iB) * (X + iY) can be done 
        ** with only three real multiplications at a price of one additional 
        ** addition and assignment.
        ** (A+B)(X-Y)+AY-BX + i(BX+AY)
	** When you do the massive complex multiplications, you use the idea
	** described above instead of using CMPLX_mul(). 
 */

#define 	CMPLX_cnj(a)		(a.i = -a.i)
#define		CMPLX_add(a,b,c)	(a.r = b.r + c.r, a.i = b.i + c.i)
#define		CMPLX_addto(a,b)	(a.r += b.r, a.i += b.i)
#define 	CMPLX_mul(a,b,c)	((a.r = b.r * c.r - b.i * c.i), \
					 (a.i = b.r * c.i + b.i * c.r))
#define		CMPLX_abs(a,b)		(a = sqrt(b.r * b.r + b.i * b.i))
#endif






/***************************************************************************
*
*  file: fft.c
*
*	FFT()			Forward Fast Fourier Transform
*	FFT_inverse()		Inverse Fast Fourier Transform
*	is_pow_2 ()		Check if an integer is a power of 2.
*
*  Author: Youngsup Kim
*
*  History:
*
*	11/08/89	YSK	Creation 
*
****************************************************************************/

#include <stdio.h>
#include <math.h>
#include "complex.h" 

#define Debug 0

extern double sin(), cos();
	
/*-----------------------------------------------------------------------*\
				FFT
Abstract: 
 	This routine performs 1-dimensional Fast Fourier Transform.
	This implementation of the successive-doubling FFT algorithm
	is adapted from Cooley and Tukey's paper.

			1   M-1  
		F(u) = ---  SUM f(x) exp(-j2 PI(ux/M))
		        N   x=0 

	The size of the input array or the number of point to compute
	should be a power of 2.
	Also it assumes that n = 2**ln (NO checking will be done).
	The output is overwritten on the input.

Bug:	

History:
	11/1/89:	YSK	Initial implementation
\*-----------------------------------------------------------------------*/




int FFT (f, n, ln)
IM_p_CMPLX 	f;		/* input array				*/
int		n;		/* size of input array			*/
int 		ln;		/* n = 2**ln 				*/
 {
  IM_S_CMPLX 	u, w, t;
  register int	i, j;
  int		k, l, nv2, nm1, ip, le, le1;
  float		ay, bx;

  /* for (i=1, n=2; i<ln; n*=2, i++); Since n is already known, just pass it */

  nv2 = n / 2;
  nm1 = n - 1;
  j = 0;

  for (i=0; i<nm1; i++)
   {
    if (i <= j)
     {
      t = f[j];		f[j] = f[i];		f[i] = t;
     }
    k = nv2;
    while (k <= j)
     {
      j -= k;
      k /= 2;
     }
    j += k;
   }

  for (l=0; l<ln; l++)
   {

    le = 2;
    for (i=1; i<=l; le*=2, i++);
    le1 = le / 2;

    u.r = 1.0; 				u.i = 0.0;

    w.r = cos(M_PI/le1); 		w.i = -sin(M_PI/le1); 

    for (j=0; j<le1; j++)
     {
      for (i=j; i<n; i+=le)
       {
	ip = i + le1;
	CMPLX_mul (t, f[ip], u);
        CMPLX_add (f[ip], f[i], -t);
	CMPLX_addto (f[i], t);
       }

       CMPLX_mul (t, u, w); 
       u = t;

      /**
       ** Computing a complex product (A + iB) * (X + iY) can be done 
       ** with only three real multiplications at a price of one additional 
       ** addition and assignment.
       ** (A+B)(X-Y)+AY-BX + i(BX+AY)
       **/
#if 0
      ay = u.r * w.i;
      bx = u.i * w.r;
      u.r = (u.i + u.r) * (w.r - w.i) + ay - bx;
      u.i = ay + bx;
#endif
     } 
   }

  /* Normalize */
 
  for (i=0; i<n; f[i].r /= (float) n, f[i++].i /= (float) n);
 }





/*-----------------------------------------------------------------------*\
				FFT_inverse
Abstract: 
 	This routine performs 1-dimensional Inverse Fast Fourier 
	Transform in place.
	This routine simply calls the one-dimensional forward FFT after
	it conjugates and scales the input array.

	The size of the input array or the number of point to compute
	should be a power of 2.
	The input is scaled down by n.
	Also it assumes that n = 2**ln (NO checking will be done).
	The output is overwritten on the input or this is in-place
	operation.

Bug:	

History:
	11/1/89:	YSK	Initial implementation
\*-----------------------------------------------------------------------*/


int FFT_inverse (me, n, ln)
IM_p_CMPLX 	me;	/* input one-dimensional array			*/
int 		n;	/* size of "me"					*/
int 		ln;	/* n = 2 ** ln					*/ 
{
  int i;
  IM_p_CMPLX ptr;
  ptr=me;
  for (i=0; i<n; i++, ptr++) 
   {
    ptr->r =  ptr->r * n;
    ptr->i = -ptr->i * n;
   }
  return (FFT (me, n, ln));
}


/*
** is_pow_2: checks if the number is a power of 2 and returns the power,
**	or a -1 if the number isn't
*/

int is_pow_2 (k)
unsigned int	k;	/* is this number a power of 2? */
{
int		i, j, l;

for (i=1; i<sizeof(int) * 8; i++)
	{
	if (k == 0) break;

	j = 1 << i;

	if (j == k) break;
	}
if (i == (sizeof (int) * 8)) i = -1;
return (i);
}

!HappyNewYear!!HappyNewYear!!HappyNewYear!!HappyNewYear!!HappyNewYear!

JDurand@cup.portal.com (Gerald Joseph Durand) (12/29/89)

>Hello World!, Signal/Image Proc. Programmers or Simply Hackers!

>I ask your favor to solve a well-known problem in the signal/image 
>processing fields.  I want to compute the correlation of two signals 
using the Fourier Transform.  The two discrete signals are as follows:
> 
>	f(n) = {1,1,1,1,2,2,2,2,8,8,8,8,9,9,9,9},    n=0,1,....,15.
>	h(n) = {1,2}				     n=0,1.
>
>The result should have the highest correlation coefficients at 1,2 and 
>8,9 transitions.  In other words I want to do a pattern matching using FFT.
>I was able to get the expected results in the spatial domain, but not in
>the frequency domain. I haven't figured out the normalization steps to take
>care of the scale changes when I used the FFT.  
>Note that the lengths of the two signals are not the same, but we can 
>assume that they are a power of two. I've never posted a news before.
>You're more than welcome to call me if you have answers, questions and 
>problems.
>
>Thanks in advance.
>
>Name:	Youngsup Kim 
>Phone:	1-800-633-7207, 1-205-772-1999 USA
>mail: 	kimy@ingr.com 			
>	b15!ysk!youngsup@ingr.com		

                       Hi Kim
                       ------

    You may be helped by the following reference book

    "Multidimensional Digital Signal Processing"

    by DAN E. DUDGEON  & RUSSEL M. MERSEREAU

                PRENTICE-HALL 1984



                thank you Jerry Durand.

    	This routine simply calls the one-dimensional forward FFT after
	it conjugates and scales the input array.

	The size of the input array or the number of point to compute
	should be a power of 2.
	The input is scaled down by n.
	Also it assumes that n = 2**ln (NO checking will be done).
	The output is overwritten on the input or this is in-place
	operation.

Bug:	

History:
	11/1/89:	YSK	Initial implementation
\*-----------------------------------------------------------------------*/


int FFT_inverse (me, n, ln)
IM_p_CMPLX 	me;	/* input one-dimensional array			*/