All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jm.audio.math.RealFloatFFT_Radix2 Maven / Gradle / Ivy

The newest version!
package jm.audio.math;

/**
 * Computes  FFT's of real, single precision data where n is an integral power of 2.
 * The physical layout of the mathematical data d[i] in the array data is as follows:
 * 
 * d[i] = data[i0 + stride*i]
 * 
* The FFT (D[i]) of real data (d[i]) is complex, but restricted by symmetry: *
 * D[n-i] = conj(D[i])
 * 
* It turns out that there are still n `independent' values, so the transformation * can still be carried out in-place. * For RealFloatFFT_Radix2, the correspondence is as follows: * * * * * * * * * * * * * * * * * * *
LogicalPhysical
Re(D[0])=data[0]
Im(D[0])=0
Re(D[1])=data[1]
Im(D[1])=data[n-1]
......
Re(D[k])=data[k]
Im(D[k])=data[n-k]
......
Re(D[n/2])=data[n/2]
Im(D[n/2])=0
......
Re(D[n-k])= data[k]
Im(D[n-k])=-data[n-k]
......
Re(D[n-1])= data[1]
Im(D[n-1])=-data[n-1]
* * @author Bruce R. Miller [email protected] * @author Contribution of the National Institute of Standards and Technology, * @author not subject to copyright. * @author Derived from GSL (Gnu Scientific Library) * @author GSL's FFT Code by Brian Gough [email protected] * @author Since GSL is released under * @author GPL
, * @author this package must also be. */ public class RealFloatFFT_Radix2 extends RealFloatFFT { private int logn; /** * Create an FFT for transforming n points of real, single precision data. * n must be an integral power of 2. */ public RealFloatFFT_Radix2(int n) { /* make sure that n is a power of 2 */ super(n); logn = Factorize.log2(n); if (logn < 0) throw new IllegalArgumentException(n + " is not a power of 2"); } /** * Compute the Fast Fourier Transform of data leaving the result in data. * See {@link Radix2 Transform Layout} for description of * the resulting data layout. */ public void transform(float data[], int i0, int stride) { checkData(data, i0, stride); int p, p_1, q; if (n == 1) return; /* identity operation */ /* bit reverse the ordering of input data for decimation in time algorithm */ bitreverse(data, i0, stride); /* apply fft recursion */ p = 1; q = n; for (int i = 1; i <= logn; i++) { int a, b; p_1 = p; p = 2 * p; q = q / 2; /* a = 0 */ for (b = 0; b < q; b++) { float t0_real = data[i0 + stride * b * p] + data[i0 + stride * (b * p + p_1)]; float t1_real = data[i0 + stride * b * p] - data[i0 + stride * (b * p + p_1)]; data[i0 + stride * b * p] = t0_real; data[i0 + stride * (b * p + p_1)] = t1_real; } /* a = 1 ... p_{i-1}/2 - 1 */ { float w_real = 1.0f; float w_imag = 0.0f; double theta = -2.0 * Math.PI / p; float s = (float) Math.sin(theta); float t = (float) Math.sin(theta / 2.0); float s2 = 2.0f * t * t; for (a = 1; a < (p_1) / 2; a++) { /* trignometric recurrence for w-> exp(i theta) w */ { float tmp_real = w_real - s * w_imag - s2 * w_real; float tmp_imag = w_imag + s * w_real - s2 * w_imag; w_real = tmp_real; w_imag = tmp_imag; } for (b = 0; b < q; b++) { float z0_real = data[i0 + stride * (b * p + a)]; float z0_imag = data[i0 + stride * (b * p + p_1 - a)]; float z1_real = data[i0 + stride * (b * p + p_1 + a)]; float z1_imag = data[i0 + stride * (b * p + p - a)]; /* t0 = z0 + w * z1 */ data[i0 + stride * (b * p + a)] = z0_real + w_real * z1_real - w_imag * z1_imag; data[i0 + stride * (b * p + p - a)] = z0_imag + w_real * z1_imag + w_imag * z1_real; /* t1 = -(z0 - w * z1) */ data[i0 + stride * (b * p + p_1 - a)] = z0_real - w_real * z1_real + w_imag * z1_imag; data[i0 + stride * (b * p + p_1 + a)] = -(z0_imag - w_real * z1_imag - w_imag * z1_real); } } } if (p_1 > 1) { for (b = 0; b < q; b++) { /* a = p_{i-1}/2 */ data[i0 + stride * (b * p + p - p_1 / 2)] *= -1; } } } } /** * Compute the (unnomalized) inverse FFT of data, leaving it in place. * The data must be in the same arrangement as that produced by * {@link #transform transform}. */ public void backtransform(float data[], int i0, int stride) { checkData(data, i0, stride); int p, p_1, q; if (n == 1) return; /* identity operation */ /* apply fft recursion */ p = n; q = 1; p_1 = n / 2; for (int i = 1; i <= logn; i++) { int a, b; /* a = 0 */ for (b = 0; b < q; b++) { float z0 = data[i0 + stride * b * p]; float z1 = data[i0 + stride * (b * p + p_1)]; data[i0 + stride * b * p] = z0 + z1; data[i0 + stride * (b * p + p_1)] = z0 - z1; } /* a = 1 ... p_{i-1}/2 - 1 */ { float w_real = 1.0f; float w_imag = 0.0f; double theta = 2.0 * Math.PI / p; float s = (float) Math.sin(theta); float t = (float) Math.sin(theta / 2.0); float s2 = 2.0f * t * t; for (a = 1; a < (p_1) / 2; a++) { /* trignometric recurrence for w-> exp(i theta) w */ float tmp_real = w_real - s * w_imag - s2 * w_real; float tmp_imag = w_imag + s * w_real - s2 * w_imag; w_real = tmp_real; w_imag = tmp_imag; for (b = 0; b < q; b++) { float z0_real = data[i0 + stride * (b * p + a)]; float z0_imag = data[i0 + stride * (b * p + p - a)]; float z1_real = data[i0 + stride * (b * p + p_1 - a)]; float z1_imag = -data[i0 + stride * (b * p + p_1 + a)]; /* t0 = z0 + z1 */ data[i0 + stride * (b * p + a)] = z0_real + z1_real; data[i0 + stride * (b * p + p_1 - a)] = z0_imag + z1_imag; /* t1 = (z0 - z1) */ float t1_real = z0_real - z1_real; float t1_imag = z0_imag - z1_imag; data[i0 + stride * (b * p + p_1 + a)] = (w_real * t1_real - w_imag * t1_imag); data[i0 + stride * (b * p + p - a)] = (w_real * t1_imag + w_imag * t1_real); } } } if (p_1 > 1) { for (b = 0; b < q; b++) { data[i0 + stride * (b * p + p_1 / 2)] *= 2; data[i0 + stride * (b * p + p_1 + p_1 / 2)] *= -2; } } p_1 = p_1 / 2; p = p / 2; q = q * 2; } /* bit reverse the ordering of output data for decimation in frequency algorithm */ bitreverse(data, i0, stride); } /** * Return data in wraparound order. * * @see wraparound format */ public float[] toWraparoundOrder(float data[]) { return toWraparoundOrder(data, 0, 1); } /** * Return data in wraparound order. * i0 and stride are used to traverse data; the new array is in * packed (i0=0, stride=1) format. * * @see wraparound format */ public float[] toWraparoundOrder(float data[], int i0, int stride) { checkData(data, i0, stride); float newdata[] = new float[2 * n]; int nh = n / 2; newdata[0] = data[i0]; newdata[1] = 0.0f; newdata[n] = data[i0 + stride * nh]; newdata[n + 1] = 0.0f; for (int i = 1; i < nh; i++) { newdata[2 * i] = data[i0 + stride * i]; newdata[2 * i + 1] = data[i0 + stride * (n - i)]; newdata[2 * (n - i)] = data[i0 + stride * i]; newdata[2 * (n - i) + 1] = -data[i0 + stride * (n - i)]; } return newdata; } protected void bitreverse(float data[], int i0, int stride) { /* This is the Goldrader bit-reversal algorithm */ for (int i = 0, j = 0; i < n - 1; i++) { int k = n / 2; if (i < j) { float tmp = data[i0 + stride * i]; data[i0 + stride * i] = data[i0 + stride * j]; data[i0 + stride * j] = tmp; } while (k <= j) { j = j - k; k = k / 2; } j += k; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy