Formatted with Google Java Formatter

This commit is contained in:
github-actions 2021-02-26 19:22:37 +00:00
parent 4264e0f045
commit ca2e20707f
5 changed files with 384 additions and 436 deletions

View File

@ -7,52 +7,49 @@ import java.util.ArrayList;
* *
* @author Ioannis Karavitsis * @author Ioannis Karavitsis
* @version 1.0 * @version 1.0
* */ */
public class CircularConvolutionFFT public class CircularConvolutionFFT {
{ /**
/** * This method pads the signal with zeros until it reaches the new size.
* This method pads the signal with zeros until it reaches the new size. *
* * @param x The signal to be padded.
* @param x The signal to be padded. * @param newSize The new size of the signal.
* @param newSize The new size of the signal. */
* */ private static void padding(ArrayList<FFT.Complex> x, int newSize) {
private static void padding(ArrayList<FFT.Complex> x, int newSize) if (x.size() < newSize) {
{ int diff = newSize - x.size();
if(x.size() < newSize) for (int i = 0; i < diff; i++) x.add(new FFT.Complex());
{
int diff = newSize - x.size();
for(int i = 0; i < diff; i++)
x.add(new FFT.Complex());
}
} }
}
/** /**
* Discrete circular convolution function. It uses the convolution theorem for discrete signals: convolved = IDFT(DFT(a)*DFT(b)). * Discrete circular convolution function. It uses the convolution theorem for discrete signals:
* Then we use the FFT algorithm for faster calculations of the two DFTs and the final IDFT. * convolved = IDFT(DFT(a)*DFT(b)). Then we use the FFT algorithm for faster calculations of the
* * two DFTs and the final IDFT.
* More info: *
* https://en.wikipedia.org/wiki/Convolution_theorem * <p>More info: https://en.wikipedia.org/wiki/Convolution_theorem
* *
* @param a The first signal. * @param a The first signal.
* @param b The other signal. * @param b The other signal.
* @return The convolved signal. * @return The convolved signal.
* */ */
public static ArrayList<FFT.Complex> fftCircularConvolution(ArrayList<FFT.Complex> a, ArrayList<FFT.Complex> b) public static ArrayList<FFT.Complex> fftCircularConvolution(
{ ArrayList<FFT.Complex> a, ArrayList<FFT.Complex> b) {
int convolvedSize = Math.max(a.size(), b.size()); //The two signals must have the same size equal to the bigger one int convolvedSize =
padding(a, convolvedSize); //Zero padding the smaller signal Math.max(
padding(b, convolvedSize); a.size(), b.size()); // The two signals must have the same size equal to the bigger one
padding(a, convolvedSize); // Zero padding the smaller signal
padding(b, convolvedSize);
/* Find the FFTs of both signal. Here we use the Bluestein algorithm because we want the FFT to have the same length with the signal and not bigger */ /* Find the FFTs of both signal. Here we use the Bluestein algorithm because we want the FFT to have the same length with the signal and not bigger */
FFTBluestein.fftBluestein(a, false); FFTBluestein.fftBluestein(a, false);
FFTBluestein.fftBluestein(b, false); FFTBluestein.fftBluestein(b, false);
ArrayList<FFT.Complex> convolved = new ArrayList<>(); ArrayList<FFT.Complex> convolved = new ArrayList<>();
for(int i = 0; i < a.size(); i++) for (int i = 0; i < a.size(); i++) convolved.add(a.get(i).multiply(b.get(i))); // FFT(a)*FFT(b)
convolved.add(a.get(i).multiply(b.get(i))); //FFT(a)*FFT(b)
FFTBluestein.fftBluestein(convolved, true); //IFFT FFTBluestein.fftBluestein(convolved, true); // IFFT
return convolved; return convolved;
} }
} }

View File

@ -5,43 +5,39 @@ package com.maths;
* *
* @author Ioannis Karavitsis * @author Ioannis Karavitsis
* @version 1.0 * @version 1.0
* */ */
public class Convolution public class Convolution {
{ /**
/** * Discrete linear convolution function. Both input signals and the output signal must start from
* Discrete linear convolution function. Both input signals and the output signal must start from 0. * 0. If you have a signal that has values before 0 then shift it to start from 0.
* If you have a signal that has values before 0 then shift it to start from 0. *
* * @param A The first discrete signal
* @param A The first discrete signal * @param B The second discrete signal
* @param B The second discrete signal * @return The convolved signal
* @return The convolved signal */
* */ public static double[] convolution(double[] A, double[] B) {
public static double[] convolution(double[] A, double[] B) double[] convolved = new double[A.length + B.length - 1];
{
double[] convolved = new double[A.length + B.length - 1];
/* /*
The discrete convolution of two signals A and B is defined as: The discrete convolution of two signals A and B is defined as:
A.length A.length
C[i] = Σ (A[k]*B[i-k]) C[i] = Σ (A[k]*B[i-k])
k=0 k=0
It's obvious that: 0 <= k <= A.length , 0 <= i <= A.length + B.length - 2 and 0 <= i-k <= B.length - 1 It's obvious that: 0 <= k <= A.length , 0 <= i <= A.length + B.length - 2 and 0 <= i-k <= B.length - 1
From the last inequality we get that: i - B.length + 1 <= k <= i and thus we get the conditions below. From the last inequality we get that: i - B.length + 1 <= k <= i and thus we get the conditions below.
*/ */
for(int i = 0; i < convolved.length; i++) for (int i = 0; i < convolved.length; i++) {
{ convolved[i] = 0;
convolved[i] = 0; int k = Math.max(i - B.length + 1, 0);
int k = Math.max(i - B.length + 1, 0);
while(k < i + 1 && k < A.length) while (k < i + 1 && k < A.length) {
{ convolved[i] += A[k] * B[i - k];
convolved[i] += A[k] * B[i - k]; k++;
k++; }
}
}
return convolved;
} }
}
return convolved;
}
}

View File

@ -7,55 +7,54 @@ import java.util.ArrayList;
* *
* @author Ioannis Karavitsis * @author Ioannis Karavitsis
* @version 1.0 * @version 1.0
* */ */
public class ConvolutionFFT public class ConvolutionFFT {
{ /**
/** * This method pads the signal with zeros until it reaches the new size.
* This method pads the signal with zeros until it reaches the new size. *
* * @param x The signal to be padded.
* @param x The signal to be padded. * @param newSize The new size of the signal.
* @param newSize The new size of the signal. */
* */ private static void padding(ArrayList<FFT.Complex> x, int newSize) {
private static void padding(ArrayList<FFT.Complex> x, int newSize) if (x.size() < newSize) {
{ int diff = newSize - x.size();
if(x.size() < newSize) for (int i = 0; i < diff; i++) x.add(new FFT.Complex());
{
int diff = newSize - x.size();
for(int i = 0; i < diff; i++)
x.add(new FFT.Complex());
}
} }
}
/** /**
* Discrete linear convolution function. It uses the convolution theorem for discrete signals convolved: = IDFT(DFT(a)*DFT(b)). * Discrete linear convolution function. It uses the convolution theorem for discrete signals
* This is true for circular convolution. In order to get the linear convolution of the two signals we first pad the two signals to have the same size equal to the convolved signal (a.size() + b.size() - 1). * convolved: = IDFT(DFT(a)*DFT(b)). This is true for circular convolution. In order to get the
* Then we use the FFT algorithm for faster calculations of the two DFTs and the final IDFT. * linear convolution of the two signals we first pad the two signals to have the same size equal
* * to the convolved signal (a.size() + b.size() - 1). Then we use the FFT algorithm for faster
* More info: * calculations of the two DFTs and the final IDFT.
* https://en.wikipedia.org/wiki/Convolution_theorem *
* https://ccrma.stanford.edu/~jos/ReviewFourier/FFT_Convolution.html * <p>More info: https://en.wikipedia.org/wiki/Convolution_theorem
* * https://ccrma.stanford.edu/~jos/ReviewFourier/FFT_Convolution.html
* @param a The first signal. *
* @param b The other signal. * @param a The first signal.
* @return The convolved signal. * @param b The other signal.
* */ * @return The convolved signal.
public static ArrayList<FFT.Complex> convolutionFFT(ArrayList<FFT.Complex> a, ArrayList<FFT.Complex> b) */
{ public static ArrayList<FFT.Complex> convolutionFFT(
int convolvedSize = a.size() + b.size() - 1; //The size of the convolved signal ArrayList<FFT.Complex> a, ArrayList<FFT.Complex> b) {
padding(a, convolvedSize); //Zero padding both signals int convolvedSize = a.size() + b.size() - 1; // The size of the convolved signal
padding(b, convolvedSize); padding(a, convolvedSize); // Zero padding both signals
padding(b, convolvedSize);
/* Find the FFTs of both signals (Note that the size of the FFTs will be bigger than the convolvedSize because of the extra zero padding in FFT algorithm) */ /* Find the FFTs of both signals (Note that the size of the FFTs will be bigger than the convolvedSize because of the extra zero padding in FFT algorithm) */
FFT.fft(a, false); FFT.fft(a, false);
FFT.fft(b, false); FFT.fft(b, false);
ArrayList<FFT.Complex> convolved = new ArrayList<>(); ArrayList<FFT.Complex> convolved = new ArrayList<>();
for(int i = 0; i < a.size(); i++) for (int i = 0; i < a.size(); i++) convolved.add(a.get(i).multiply(b.get(i))); // FFT(a)*FFT(b)
convolved.add(a.get(i).multiply(b.get(i))); //FFT(a)*FFT(b)
FFT.fft(convolved, true); //IFFT FFT.fft(convolved, true); // IFFT
convolved.subList(convolvedSize, convolved.size()).clear(); //Remove the remaining zeros after the convolvedSize. These extra zeros came from paddingPowerOfTwo() method inside the fft() method. convolved
.subList(convolvedSize, convolved.size())
.clear(); // Remove the remaining zeros after the convolvedSize. These extra zeros came from
// paddingPowerOfTwo() method inside the fft() method.
return convolved; return convolved;
} }
} }

View File

@ -4,278 +4,242 @@ import java.util.ArrayList;
import java.util.Collections; 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 * @author Ioannis Karavitsis
* @version 1.0 * @version 1.0
* */ */
public class FFT public class FFT {
{ /**
/** * This class represents a complex number and has methods for basic operations.
* 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
* More info: */
* https://introcs.cs.princeton.edu/java/32class/Complex.java.html static class Complex {
* */ private double real, img;
static class Complex
{
private double real, img;
/** /** Default Constructor. Creates the complex number 0. */
* Default Constructor. public Complex() {
* Creates the complex number 0. real = 0;
* */ img = 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;
}
} }
/** /**
* Iterative In-Place Radix-2 Cooley-Tukey Fast Fourier Transform Algorithm with Bit-Reversal. * Constructor. Creates a complex number.
* 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.
* *
* More info: * @param r The real part of the number.
* https://www.algorithm-archive.org/contents/cooley_tukey/cooley_tukey.html * @param i The imaginary part of the number.
* https://www.geeksforgeeks.org/iterative-fast-fourier-transformation-polynomial-multiplication/ */
* https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm public Complex(double r, double i) {
* https://cp-algorithms.com/algebra/fft.html real = r;
* img = i;
* @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. * Returns the real part of the complex number.
* It is used in Cooley-Tukey FFT algorithm.
* *
* E.g. * @return The real part of the complex number.
* num = 13 = 00001101 in binary */
* log2N = 8 public double getReal() {
* Then reversed = 176 = 10110000 in binary return real;
*
* 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. * Returns the imaginary part of the complex number.
* *
* @param x The ArrayList to be padded. * @return The imaginary part of the complex number.
* */ */
private static void paddingPowerOfTwo(ArrayList<Complex> x) public double getImaginary() {
{ return img;
int n = 1;
int oldSize = x.size();
while(n < oldSize)
n *= 2;
for(int i = 0; i < n - oldSize; i++)
x.add(new Complex());
} }
/**
* 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());
}
} }

View File

@ -3,67 +3,59 @@ package com.maths;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
* Class for calculating the Fast Fourier Transform (FFT) of a discrete signal using the Bluestein's algorithm. * Class for calculating the Fast Fourier Transform (FFT) of a discrete signal using the Bluestein's
* algorithm.
* *
* @author Ioannis Karavitsis * @author Ioannis Karavitsis
* @version 1.0 * @version 1.0
* */ */
public class FFTBluestein public class FFTBluestein {
{ /**
/** * Bluestein's FFT Algorithm.
* Bluestein's FFT Algorithm. *
* * <p>More info: https://en.wikipedia.org/wiki/Chirp_Z-transform#Bluestein.27s_algorithm
* More info: * http://tka4.org/materials/lib/Articles-Books/Numerical%20Algorithms/Hartley_Trasform/Bluestein%27s%20FFT%20algorithm%20-%20Wikipedia,%20the%20free%20encyclopedia.htm
* https://en.wikipedia.org/wiki/Chirp_Z-transform#Bluestein.27s_algorithm *
* http://tka4.org/materials/lib/Articles-Books/Numerical%20Algorithms/Hartley_Trasform/Bluestein%27s%20FFT%20algorithm%20-%20Wikipedia,%20the%20free%20encyclopedia.htm * @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.
* @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 fftBluestein(ArrayList<FFT.Complex> x, boolean inverse) {
* */ int N = x.size();
public static void fftBluestein(ArrayList<FFT.Complex> x, boolean inverse) int bnSize = 2 * N - 1;
{ int direction = inverse ? -1 : 1;
int N = x.size(); ArrayList<FFT.Complex> an = new ArrayList<>();
int bnSize = 2*N - 1; ArrayList<FFT.Complex> bn = new ArrayList<>();
int direction = inverse ? -1 : 1;
ArrayList<FFT.Complex> an = new ArrayList<>();
ArrayList<FFT.Complex> bn = new ArrayList<>();
/* Initialization of the b(n) sequence (see Wikipedia's article above for the symbols used)*/ /* Initialization of the b(n) sequence (see Wikipedia's article above for the symbols used)*/
for(int i = 0; i < bnSize; i++) for (int i = 0; i < bnSize; i++) bn.add(new FFT.Complex());
bn.add(new FFT.Complex());
for(int i = 0; i < N; i++) for (int i = 0; i < N; i++) {
{ double angle = (i - N + 1) * (i - N + 1) * Math.PI / N * direction;
double angle = (i - N + 1) * (i - N + 1) * Math.PI / N * direction; bn.set(i, new FFT.Complex(Math.cos(angle), Math.sin(angle)));
bn.set(i, new FFT.Complex(Math.cos(angle), Math.sin(angle))); bn.set(bnSize - i - 1, new FFT.Complex(Math.cos(angle), Math.sin(angle)));
bn.set(bnSize - i - 1, new FFT.Complex(Math.cos(angle), Math.sin(angle)));
}
/* Initialization of the a(n) sequence */
for(int i = 0; i < N; i++)
{
double angle = -i * i * Math.PI / N * direction;
an.add(x.get(i).multiply(new FFT.Complex(Math.cos(angle), Math.sin(angle))));
}
ArrayList<FFT.Complex> convolution = ConvolutionFFT.convolutionFFT(an, bn);
/* The final multiplication of the convolution with the b*(k) factor */
for(int i = 0; i < N; i++)
{
double angle = -1 * i * i * Math.PI / N * direction;
FFT.Complex bk = new FFT.Complex(Math.cos(angle), Math.sin(angle));
x.set(i, bk.multiply(convolution.get(i + N - 1)));
}
/* Divide by N if we want the inverse FFT */
if(inverse)
{
for (int i = 0; i < N; i++)
{
FFT.Complex z = x.get(i);
x.set(i, z.divide(N));
}
}
} }
/* Initialization of the a(n) sequence */
for (int i = 0; i < N; i++) {
double angle = -i * i * Math.PI / N * direction;
an.add(x.get(i).multiply(new FFT.Complex(Math.cos(angle), Math.sin(angle))));
}
ArrayList<FFT.Complex> convolution = ConvolutionFFT.convolutionFFT(an, bn);
/* The final multiplication of the convolution with the b*(k) factor */
for (int i = 0; i < N; i++) {
double angle = -1 * i * i * Math.PI / N * direction;
FFT.Complex bk = new FFT.Complex(Math.cos(angle), Math.sin(angle));
x.set(i, bk.multiply(convolution.get(i + N - 1)));
}
/* Divide by N if we want the inverse FFT */
if (inverse) {
for (int i = 0; i < N; i++) {
FFT.Complex z = x.get(i);
x.set(i, z.divide(N));
}
}
}
} }