mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-22 11:46:34 +08:00
Formatted with Google Java Formatter
This commit is contained in:
478
Maths/FFT.java
478
Maths/FFT.java
@ -4,278 +4,242 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Class for calculating the Fast Fourier Transform (FFT) of a discrete signal using the Cooley-Tukey algorithm.
|
||||
* Class for calculating the Fast Fourier Transform (FFT) of a discrete signal using the
|
||||
* Cooley-Tukey algorithm.
|
||||
*
|
||||
* @author Ioannis Karavitsis
|
||||
* @version 1.0
|
||||
* */
|
||||
public class FFT
|
||||
{
|
||||
/**
|
||||
* This class represents a complex number and has methods for basic operations.
|
||||
*
|
||||
* More info:
|
||||
* https://introcs.cs.princeton.edu/java/32class/Complex.java.html
|
||||
* */
|
||||
static class Complex
|
||||
{
|
||||
private double real, img;
|
||||
*/
|
||||
public class FFT {
|
||||
/**
|
||||
* This class represents a complex number and has methods for basic operations.
|
||||
*
|
||||
* <p>More info: https://introcs.cs.princeton.edu/java/32class/Complex.java.html
|
||||
*/
|
||||
static class Complex {
|
||||
private double real, img;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
* Creates the complex number 0.
|
||||
* */
|
||||
public Complex()
|
||||
{
|
||||
real = 0;
|
||||
img = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Creates a complex number.
|
||||
*
|
||||
* @param r The real part of the number.
|
||||
* @param i The imaginary part of the number.
|
||||
* */
|
||||
public Complex(double r, double i)
|
||||
{
|
||||
real = r;
|
||||
img = i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the real part of the complex number.
|
||||
*
|
||||
* @return The real part of the complex number.
|
||||
* */
|
||||
public double getReal()
|
||||
{
|
||||
return real;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the imaginary part of the complex number.
|
||||
*
|
||||
* @return The imaginary part of the complex number.
|
||||
* */
|
||||
public double getImaginary()
|
||||
{
|
||||
return img;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this complex number to another.
|
||||
*
|
||||
* @param z The number to be added.
|
||||
* @return The sum.
|
||||
* */
|
||||
public Complex add(Complex z)
|
||||
{
|
||||
Complex temp = new Complex();
|
||||
temp.real = this.real + z.real;
|
||||
temp.img = this.img + z.img;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a number from this complex number.
|
||||
*
|
||||
* @param z The number to be subtracted.
|
||||
* @return The difference.
|
||||
* */
|
||||
public Complex subtract(Complex z)
|
||||
{
|
||||
Complex temp = new Complex();
|
||||
temp.real = this.real - z.real;
|
||||
temp.img = this.img - z.img;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies this complex number by another.
|
||||
*
|
||||
* @param z The number to be multiplied.
|
||||
* @return The product.
|
||||
* */
|
||||
public Complex multiply(Complex z)
|
||||
{
|
||||
Complex temp = new Complex();
|
||||
temp.real = this.real*z.real - this.img*z.img;
|
||||
temp.img = this.real*z.img + this.img*z.real;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies this complex number by a scalar.
|
||||
*
|
||||
* @param n The real number to be multiplied.
|
||||
* @return The product.
|
||||
* */
|
||||
public Complex multiply(double n)
|
||||
{
|
||||
Complex temp = new Complex();
|
||||
temp.real = this.real * n;
|
||||
temp.img = this.img * n;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the conjugate of this complex number.
|
||||
*
|
||||
* @return The conjugate.
|
||||
* */
|
||||
public Complex conjugate()
|
||||
{
|
||||
Complex temp = new Complex();
|
||||
temp.real = this.real;
|
||||
temp.img = -this.img;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the magnitude of the complex number.
|
||||
*
|
||||
* @return The magnitude.
|
||||
* */
|
||||
public double abs()
|
||||
{
|
||||
return Math.hypot(this.real, this.img);
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides this complex number by another.
|
||||
*
|
||||
* @param z The divisor.
|
||||
* @return The quotient.
|
||||
* */
|
||||
public Complex divide(Complex z)
|
||||
{
|
||||
Complex temp = new Complex();
|
||||
temp.real = (this.real*z.real + this.img*z.img) / (z.abs()*z.abs());
|
||||
temp.img = (this.img*z.real - this.real*z.img) / (z.abs()*z.abs());
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides this complex number by a scalar.
|
||||
*
|
||||
* @param n The divisor which is a real number.
|
||||
* @return The quotient.
|
||||
* */
|
||||
public Complex divide(double n)
|
||||
{
|
||||
Complex temp = new Complex();
|
||||
temp.real = this.real / n;
|
||||
temp.img = this.img / n;
|
||||
return temp;
|
||||
}
|
||||
/** Default Constructor. Creates the complex number 0. */
|
||||
public Complex() {
|
||||
real = 0;
|
||||
img = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterative In-Place Radix-2 Cooley-Tukey Fast Fourier Transform Algorithm with Bit-Reversal.
|
||||
* The size of the input signal must be a power of 2. If it isn't then it is padded with zeros and the output FFT will be bigger than the input signal.
|
||||
* Constructor. Creates a complex number.
|
||||
*
|
||||
* More info:
|
||||
* https://www.algorithm-archive.org/contents/cooley_tukey/cooley_tukey.html
|
||||
* https://www.geeksforgeeks.org/iterative-fast-fourier-transformation-polynomial-multiplication/
|
||||
* https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm
|
||||
* https://cp-algorithms.com/algebra/fft.html
|
||||
*
|
||||
* @param x The discrete signal which is then converted to the FFT or the IFFT of signal x.
|
||||
* @param inverse True if you want to find the inverse FFT.
|
||||
* */
|
||||
public static void fft(ArrayList<Complex> x, boolean inverse)
|
||||
{
|
||||
/* Pad the signal with zeros if necessary */
|
||||
paddingPowerOfTwo(x);
|
||||
int N = x.size();
|
||||
|
||||
/* Find the log2(N) */
|
||||
int log2N = 0;
|
||||
while((1 << log2N) < N)
|
||||
log2N++;
|
||||
|
||||
/* Swap the values of the signal with bit-reversal method */
|
||||
int reverse;
|
||||
for(int i = 0; i < N; i++)
|
||||
{
|
||||
reverse = reverseBits(i, log2N);
|
||||
if(i < reverse)
|
||||
Collections.swap(x, i, reverse);
|
||||
}
|
||||
|
||||
int direction = inverse ? -1 : 1;
|
||||
|
||||
/* Main loop of the algorithm */
|
||||
for(int len = 2; len <= N; len *= 2)
|
||||
{
|
||||
double angle = -2 * Math.PI / len * direction;
|
||||
Complex wlen = new Complex(Math.cos(angle), Math.sin(angle));
|
||||
for(int i = 0; i < N; i += len)
|
||||
{
|
||||
Complex w = new Complex(1, 0);
|
||||
for(int j = 0; j < len / 2; j++)
|
||||
{
|
||||
Complex u = x.get(i + j);
|
||||
Complex v = w.multiply(x.get(i + j + len/2));
|
||||
x.set(i + j, u.add(v));
|
||||
x.set(i + j + len/2, u.subtract(v));
|
||||
w = w.multiply(wlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Divide by N if we want the inverse FFT */
|
||||
if(inverse)
|
||||
{
|
||||
for (int i = 0; i < x.size(); i++)
|
||||
{
|
||||
Complex z = x.get(i);
|
||||
x.set(i, z.divide(N));
|
||||
}
|
||||
}
|
||||
* @param r The real part of the number.
|
||||
* @param i The imaginary part of the number.
|
||||
*/
|
||||
public Complex(double r, double i) {
|
||||
real = r;
|
||||
img = i;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function reverses the bits of a number.
|
||||
* It is used in Cooley-Tukey FFT algorithm.
|
||||
* Returns the real part of the complex number.
|
||||
*
|
||||
* E.g.
|
||||
* num = 13 = 00001101 in binary
|
||||
* log2N = 8
|
||||
* Then reversed = 176 = 10110000 in binary
|
||||
*
|
||||
* More info:
|
||||
* https://cp-algorithms.com/algebra/fft.html
|
||||
* https://www.geeksforgeeks.org/write-an-efficient-c-program-to-reverse-bits-of-a-number/
|
||||
*
|
||||
* @param num The integer you want to reverse its bits.
|
||||
* @param log2N The number of bits you want to reverse.
|
||||
* @return The reversed number
|
||||
* */
|
||||
private static int reverseBits(int num, int log2N)
|
||||
{
|
||||
int reversed = 0;
|
||||
for(int i = 0; i < log2N; i++)
|
||||
{
|
||||
if((num & (1 << i)) != 0)
|
||||
reversed |= 1 << (log2N - 1 - i);
|
||||
}
|
||||
return reversed;
|
||||
* @return The real part of the complex number.
|
||||
*/
|
||||
public double getReal() {
|
||||
return real;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method pads an ArrayList with zeros in order to have a size equal to the next power of two of the previous size.
|
||||
* Returns the imaginary part of the complex number.
|
||||
*
|
||||
* @param x The ArrayList to be padded.
|
||||
* */
|
||||
private static void paddingPowerOfTwo(ArrayList<Complex> x)
|
||||
{
|
||||
int n = 1;
|
||||
int oldSize = x.size();
|
||||
while(n < oldSize)
|
||||
n *= 2;
|
||||
for(int i = 0; i < n - oldSize; i++)
|
||||
x.add(new Complex());
|
||||
* @return The imaginary part of the complex number.
|
||||
*/
|
||||
public double getImaginary() {
|
||||
return img;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this complex number to another.
|
||||
*
|
||||
* @param z The number to be added.
|
||||
* @return The sum.
|
||||
*/
|
||||
public Complex add(Complex z) {
|
||||
Complex temp = new Complex();
|
||||
temp.real = this.real + z.real;
|
||||
temp.img = this.img + z.img;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a number from this complex number.
|
||||
*
|
||||
* @param z The number to be subtracted.
|
||||
* @return The difference.
|
||||
*/
|
||||
public Complex subtract(Complex z) {
|
||||
Complex temp = new Complex();
|
||||
temp.real = this.real - z.real;
|
||||
temp.img = this.img - z.img;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies this complex number by another.
|
||||
*
|
||||
* @param z The number to be multiplied.
|
||||
* @return The product.
|
||||
*/
|
||||
public Complex multiply(Complex z) {
|
||||
Complex temp = new Complex();
|
||||
temp.real = this.real * z.real - this.img * z.img;
|
||||
temp.img = this.real * z.img + this.img * z.real;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies this complex number by a scalar.
|
||||
*
|
||||
* @param n The real number to be multiplied.
|
||||
* @return The product.
|
||||
*/
|
||||
public Complex multiply(double n) {
|
||||
Complex temp = new Complex();
|
||||
temp.real = this.real * n;
|
||||
temp.img = this.img * n;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the conjugate of this complex number.
|
||||
*
|
||||
* @return The conjugate.
|
||||
*/
|
||||
public Complex conjugate() {
|
||||
Complex temp = new Complex();
|
||||
temp.real = this.real;
|
||||
temp.img = -this.img;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the magnitude of the complex number.
|
||||
*
|
||||
* @return The magnitude.
|
||||
*/
|
||||
public double abs() {
|
||||
return Math.hypot(this.real, this.img);
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides this complex number by another.
|
||||
*
|
||||
* @param z The divisor.
|
||||
* @return The quotient.
|
||||
*/
|
||||
public Complex divide(Complex z) {
|
||||
Complex temp = new Complex();
|
||||
temp.real = (this.real * z.real + this.img * z.img) / (z.abs() * z.abs());
|
||||
temp.img = (this.img * z.real - this.real * z.img) / (z.abs() * z.abs());
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides this complex number by a scalar.
|
||||
*
|
||||
* @param n The divisor which is a real number.
|
||||
* @return The quotient.
|
||||
*/
|
||||
public Complex divide(double n) {
|
||||
Complex temp = new Complex();
|
||||
temp.real = this.real / n;
|
||||
temp.img = this.img / n;
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterative In-Place Radix-2 Cooley-Tukey Fast Fourier Transform Algorithm with Bit-Reversal. The
|
||||
* size of the input signal must be a power of 2. If it isn't then it is padded with zeros and the
|
||||
* output FFT will be bigger than the input signal.
|
||||
*
|
||||
* <p>More info: https://www.algorithm-archive.org/contents/cooley_tukey/cooley_tukey.html
|
||||
* https://www.geeksforgeeks.org/iterative-fast-fourier-transformation-polynomial-multiplication/
|
||||
* https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm
|
||||
* https://cp-algorithms.com/algebra/fft.html
|
||||
*
|
||||
* @param x The discrete signal which is then converted to the FFT or the IFFT of signal x.
|
||||
* @param inverse True if you want to find the inverse FFT.
|
||||
*/
|
||||
public static void fft(ArrayList<Complex> x, boolean inverse) {
|
||||
/* Pad the signal with zeros if necessary */
|
||||
paddingPowerOfTwo(x);
|
||||
int N = x.size();
|
||||
|
||||
/* Find the log2(N) */
|
||||
int log2N = 0;
|
||||
while ((1 << log2N) < N) log2N++;
|
||||
|
||||
/* Swap the values of the signal with bit-reversal method */
|
||||
int reverse;
|
||||
for (int i = 0; i < N; i++) {
|
||||
reverse = reverseBits(i, log2N);
|
||||
if (i < reverse) Collections.swap(x, i, reverse);
|
||||
}
|
||||
|
||||
int direction = inverse ? -1 : 1;
|
||||
|
||||
/* Main loop of the algorithm */
|
||||
for (int len = 2; len <= N; len *= 2) {
|
||||
double angle = -2 * Math.PI / len * direction;
|
||||
Complex wlen = new Complex(Math.cos(angle), Math.sin(angle));
|
||||
for (int i = 0; i < N; i += len) {
|
||||
Complex w = new Complex(1, 0);
|
||||
for (int j = 0; j < len / 2; j++) {
|
||||
Complex u = x.get(i + j);
|
||||
Complex v = w.multiply(x.get(i + j + len / 2));
|
||||
x.set(i + j, u.add(v));
|
||||
x.set(i + j + len / 2, u.subtract(v));
|
||||
w = w.multiply(wlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Divide by N if we want the inverse FFT */
|
||||
if (inverse) {
|
||||
for (int i = 0; i < x.size(); i++) {
|
||||
Complex z = x.get(i);
|
||||
x.set(i, z.divide(N));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function reverses the bits of a number. It is used in Cooley-Tukey FFT algorithm.
|
||||
*
|
||||
* <p>E.g. num = 13 = 00001101 in binary log2N = 8 Then reversed = 176 = 10110000 in binary
|
||||
*
|
||||
* <p>More info: https://cp-algorithms.com/algebra/fft.html
|
||||
* https://www.geeksforgeeks.org/write-an-efficient-c-program-to-reverse-bits-of-a-number/
|
||||
*
|
||||
* @param num The integer you want to reverse its bits.
|
||||
* @param log2N The number of bits you want to reverse.
|
||||
* @return The reversed number
|
||||
*/
|
||||
private static int reverseBits(int num, int log2N) {
|
||||
int reversed = 0;
|
||||
for (int i = 0; i < log2N; i++) {
|
||||
if ((num & (1 << i)) != 0) reversed |= 1 << (log2N - 1 - i);
|
||||
}
|
||||
return reversed;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method pads an ArrayList with zeros in order to have a size equal to the next power of two
|
||||
* of the previous size.
|
||||
*
|
||||
* @param x The ArrayList to be padded.
|
||||
*/
|
||||
private static void paddingPowerOfTwo(ArrayList<Complex> x) {
|
||||
int n = 1;
|
||||
int oldSize = x.size();
|
||||
while (n < oldSize) n *= 2;
|
||||
for (int i = 0; i < n - oldSize; i++) x.add(new Complex());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user