package com.isti.traceview.jnt.FFT;
/**
* Abstract Class representing FFT's of complex, double precision data. Concrete
* classes are typically named ComplexDoubleFFT_<i>method</i>, implement the FFT
* using some particular method.
* <P>
* Complex data is represented by 2 double values in sequence: the real and
* imaginary parts. Thus, in the default case (i0=0, stride=2), N data points is
* represented by a double array dimensioned to 2*N. To support 2D (and higher)
* transforms, an offset, i0 (where the first element starts) and stride (the
* distance from the real part of one value, to the next: at least 2 for complex
* values) can be supplied. The physical layout in the array data, of the
* mathematical data d[i] is as follows:
*
* <PRE>
* Re(d[i]) = data[i0 + stride*i]
* Im(d[i]) = data[i0 + stride*i+1]
* </PRE>
*
* The transformed data is returned in the original data array in <a
* href="package-summary.html#wraparound">wrap-around</A> order.
*
* @author Bruce R. Miller bruce.miller@nist.gov
* @author Contribution of the National Institute of Standards and Technology,
* @author not subject to copyright.
*/
public abstract class ComplexDoubleFFT {
int n;
/**
* Create an FFT for transforming n points of complex, double precision
* data.
*/
public ComplexDoubleFFT(int n) {
if (n <= 0)
throw new IllegalArgumentException(
"The transform length must be >=0 : " + n);
this.n = n;
}
/**
* Creates an instance of a subclass of ComplexDoubleFFT appropriate for
* data of n elements.
*/
public ComplexDoubleFFT getInstance(int n) {
return new ComplexDoubleFFT_Mixed(n);
}
protected void checkData(double data[], int i0, int stride) {
if (i0 < 0)
throw new IllegalArgumentException("The offset must be >=0 : " + i0);
if (stride < 2)
throw new IllegalArgumentException("The stride must be >=2 : "
+ stride);
if (i0 + stride * (n - 1) + 2 > data.length)
throw new IllegalArgumentException(
"The data array is too small for " + n + ":" + "i0=" + i0
+ " stride=" + stride + " data.length="
+ data.length);
}
/**
* Compute the Fast Fourier Transform of data leaving the result in data.
* The array data must be dimensioned (at least) 2*n, consisting of
* alternating real and imaginary parts.
*/
public void transform(double data[]) {
transform(data, 0, 2);
}
/**
* Compute the Fast Fourier Transform of data leaving the result in data.
* The array data must contain the data points in the following locations:
*
* <PRE>
* Re(d[i]) = data[i0 + stride*i]
* Im(d[i]) = data[i0 + stride*i+1]
* </PRE>
*/
public abstract void transform(double data[], int i0, int stride);
/**
* Return data in wraparound order.
*
* @see <a href="package-summary.html#wraparound">wraparound format</A>
*/
public double[] toWraparoundOrder(double data[]) {
return data;
}
/**
* Return data in wraparound order. i0 and stride are used to traverse data;
* the new array is in packed (i0=0, stride=2) format.
*
* @see <a href="package-summary.html#wraparound">wraparound format</A>
*/
public double[] toWraparoundOrder(double data[], int i0, int stride) {
if ((i0 == 0) && (stride == 2))
return data;
double newdata[] = new double[2 * n];
for (int i = 0; i < n; i++) {
newdata[2 * i] = data[i0 + stride * i];
newdata[2 * i + 1] = data[i0 + stride * i + 1];
}
return newdata;
}
/** Compute the (unnomalized) inverse FFT of data, leaving it in place. */
public void backtransform(double data[]) {
backtransform(data, 0, 2);
}
/**
* Compute the (unnomalized) inverse FFT of data, leaving it in place. The
* frequency domain data must be in wrap-around order, and be stored in the
* following locations:
*
* <PRE>
* Re(D[i]) = data[i0 + stride*i]
* Im(D[i]) = data[i0 + stride*i+1]
* </PRE>
*/
public abstract void backtransform(double data[], int i0, int stride);
/**
* Return the normalization factor. Multiply the elements of the
* backtransform'ed data to get the normalized inverse.
*/
public double normalization() {
return 1.0 / n;
}
/** Compute the (nomalized) inverse FFT of data, leaving it in place. */
public void inverse(double data[]) {
inverse(data, 0, 2);
}
/**
* Compute the (nomalized) inverse FFT of data, leaving it in place. The
* frequency domain data must be in wrap-around order, and be stored in the
* following locations:
*
* <PRE>
* Re(D[i]) = data[i0 + stride*i]
* Im(D[i]) = data[i0 + stride*i+1]
* </PRE>
*/
public void inverse(double data[], int i0, int stride) {
backtransform(data, i0, stride);
/* normalize inverse fft with 1/n */
double norm = normalization();
for (int i = 0; i < n; i++) {
data[i0 + stride * i] *= norm;
data[i0 + stride * i + 1] *= norm;
}
}
}