package com.isti.traceview.jnt.FFT;
import org.apache.log4j.Logger;
/**
* Computes the FFT of 2 dimensional complex, single precision data. The data is
* stored in a 1-dimensional array in Row-Major order. The physical layout in
* the array data, of the mathematical data d[i,j] is as follows:
*
* <PRE>
* Re(d[i,j]) = data[i*rowspan + 2*j]
* Im(d[i,j]) = data[i*rowspan + 2*j + 1]
* </PRE>
*
* where <code>rowspan</code> must be at least 2*ncols (it defaults to 2*ncols).
* The transformed data is returned in the original data array in <a
* href="package-summary.html#wraparound">wrap-around</A> order along each
* dimension.
*
* @author Bruce R. Miller bruce.miller@nist.gov
* @author Contribution of the National Institute of Standards and Technology,
* @author not subject to copyright.
*/
public class ComplexFloat2DFFT {
private static final Logger logger = Logger.getLogger(ComplexFloat2DFFT.class);
int nrows;
int ncols;
ComplexFloatFFT rowFFT, colFFT;
/**
* Create an FFT for transforming nrows*ncols points of Complex, double
* precision data.
*/
public ComplexFloat2DFFT(int nrows, int ncols) {
this.nrows = nrows;
this.ncols = ncols;
rowFFT = new ComplexFloatFFT_Mixed(ncols);
colFFT = (nrows == ncols ? rowFFT : new ComplexFloatFFT_Mixed(nrows));
}
protected void checkData(float data[], int rowspan) {
if (rowspan < 2 * ncols)
throw new IllegalArgumentException("The row span " + rowspan
+ "is shorter than the row length " + 2 * ncols);
if (nrows * rowspan > data.length)
throw new IllegalArgumentException(
"The data array is too small for " + nrows + "x" + rowspan
+ " 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*nrows*ncols, consisting
* of alternating real and imaginary parts.
*/
public void transform(float data[]) {
transform(data, 2 * ncols);
}
/**
* Compute the Fast Fourier Transform of data leaving the result in data.
* The array data must be dimensioned (at least) 2*nrows*ncols, consisting
* of alternating real and imaginary parts.
*/
public void transform(float data[], int rowspan) {
try {
checkData(data, rowspan);
for (int i = 0; i < nrows; i++) {
rowFFT.transform(data, i * rowspan, 2);
}
for (int j = 0; j < ncols; j++) {
colFFT.transform(data, 2 * j, rowspan);
}
} catch (IllegalArgumentException e) {
logger.error("IllegalArgumentException:", e);
}
}
/**
* Return data in wraparound order.
*
* @see <a href="package-summary.html#wraparound">wraparound format</A>
*/
public float[] toWraparoundOrder(float data[]) {
return data;
}
/**
* Return data in wraparound order. rowspan is used to traverse data; the
* new array is in packed (rowspan = 2*ncols) format.
*
* @see <a href="package-summary.html#wraparound">wraparound format</A>
*/
public float[] toWraparoundOrder(float data[], int rowspan) {
if (rowspan == 2 * ncols)
return data;
float newdata[] = new float[2 * nrows * ncols];
for (int i = 0; i < nrows; i++)
for (int j = 0; j < ncols; j++) {
newdata[i * 2 * ncols + 2 * j] = data[i * rowspan + 2 * j];
newdata[i * 2 * ncols + 2 * j + 1] = data[i * rowspan + 2 * j
+ 1];
}
return newdata;
}
/** Compute the (unnomalized) inverse FFT of data, leaving it in place. */
public void backtransform(float data[]) {
backtransform(data, 2 * ncols);
}
/** Compute the (unnomalized) inverse FFT of data, leaving it in place. */
public void backtransform(float data[], int rowspan) {
try {
checkData(data, rowspan);
for (int i = 0; i < nrows; i++) {
rowFFT.backtransform(data, i * rowspan, 2);
}
for (int j = 0; j < ncols; j++) {
colFFT.backtransform(data, 2 * j, rowspan);
}
} catch (IllegalArgumentException e) {
logger.error("IllegalArgumentException:", e);
}
}
/**
* Return the normalization factor. Multiply the elements of the
* backtransform'ed data to get the normalized inverse.
*/
public float normalization() {
return 1.0f / ((float) nrows * ncols);
}
/** Compute the (nomalized) inverse FFT of data, leaving it in place. */
public void inverse(float data[]) {
inverse(data, 2 * ncols);
}
/** Compute the (nomalized) inverse FFT of data, leaving it in place. */
public void inverse(float data[], int rowspan) {
backtransform(data, rowspan);
float norm = normalization();
for (int i = 0; i < nrows; i++) {
for (int j = 0; j < ncols; j++) {
data[i * rowspan + 2 * j] *= norm;
data[i * rowspan + 2 * j + 1] *= norm;
}
}
}
}