FastFourierTransform.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.math4.transform;

  18. import java.util.Arrays;
  19. import java.util.function.DoubleUnaryOperator;

  20. import org.apache.commons.numbers.core.ArithmeticUtils;
  21. import org.apache.commons.numbers.complex.Complex;

  22. /**
  23.  * Implements the Fast Fourier Transform for transformation of one-dimensional
  24.  * real or complex data sets. For reference, see <em>Applied Numerical Linear
  25.  * Algebra</em>, ISBN 0898713897, chapter 6.
  26.  * <p>
  27.  * There are several variants of the discrete Fourier transform, with various
  28.  * normalization conventions, which are specified by the parameter
  29.  * {@link Norm}.
  30.  * <p>
  31.  * The current implementation of the discrete Fourier transform as a fast
  32.  * Fourier transform requires the length of the data set to be a power of 2.
  33.  * This greatly simplifies and speeds up the code. Users can pad the data with
  34.  * zeros to meet this requirement. There are other flavors of FFT, for
  35.  * reference, see S. Winograd,
  36.  * <i>On computing the discrete Fourier transform</i>, Mathematics of
  37.  * Computation, 32 (1978), 175 - 199.
  38.  */
  39. public class FastFourierTransform implements ComplexTransform {
  40.     /** Number of array slots: 1 for "real" parts 1 for "imaginary" parts. */
  41.     private static final int NUM_PARTS = 2;
  42.     /**
  43.      * {@code W_SUB_N_R[i]} is the real part of
  44.      * {@code exp(- 2 * i * pi / n)}:
  45.      * {@code W_SUB_N_R[i] = cos(2 * pi/ n)}, where {@code n = 2^i}.
  46.      */
  47.     private static final double[] W_SUB_N_R = {
  48.         0x1.0p0, -0x1.0p0, 0x1.1a62633145c07p-54, 0x1.6a09e667f3bcdp-1,
  49.         0x1.d906bcf328d46p-1, 0x1.f6297cff75cbp-1, 0x1.fd88da3d12526p-1, 0x1.ff621e3796d7ep-1,
  50.         0x1.ffd886084cd0dp-1, 0x1.fff62169b92dbp-1, 0x1.fffd8858e8a92p-1, 0x1.ffff621621d02p-1,
  51.         0x1.ffffd88586ee6p-1, 0x1.fffff62161a34p-1, 0x1.fffffd8858675p-1, 0x1.ffffff621619cp-1,
  52.         0x1.ffffffd885867p-1, 0x1.fffffff62161ap-1, 0x1.fffffffd88586p-1, 0x1.ffffffff62162p-1,
  53.         0x1.ffffffffd8858p-1, 0x1.fffffffff6216p-1, 0x1.fffffffffd886p-1, 0x1.ffffffffff621p-1,
  54.         0x1.ffffffffffd88p-1, 0x1.fffffffffff62p-1, 0x1.fffffffffffd9p-1, 0x1.ffffffffffff6p-1,
  55.         0x1.ffffffffffffep-1, 0x1.fffffffffffffp-1, 0x1.0p0, 0x1.0p0,
  56.         0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
  57.         0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
  58.         0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
  59.         0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
  60.         0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
  61.         0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
  62.         0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
  63.         0x1.0p0, 0x1.0p0, 0x1.0p0 };

  64.     /**
  65.      * {@code W_SUB_N_I[i]} is the imaginary part of
  66.      * {@code exp(- 2 * i * pi / n)}:
  67.      * {@code W_SUB_N_I[i] = -sin(2 * pi/ n)}, where {@code n = 2^i}.
  68.      */
  69.     private static final double[] W_SUB_N_I = {
  70.         0x1.1a62633145c07p-52, -0x1.1a62633145c07p-53, -0x1.0p0, -0x1.6a09e667f3bccp-1,
  71.         -0x1.87de2a6aea963p-2, -0x1.8f8b83c69a60ap-3, -0x1.917a6bc29b42cp-4, -0x1.91f65f10dd814p-5,
  72.         -0x1.92155f7a3667ep-6, -0x1.921d1fcdec784p-7, -0x1.921f0fe670071p-8, -0x1.921f8becca4bap-9,
  73.         -0x1.921faaee6472dp-10, -0x1.921fb2aecb36p-11, -0x1.921fb49ee4ea6p-12, -0x1.921fb51aeb57bp-13,
  74.         -0x1.921fb539ecf31p-14, -0x1.921fb541ad59ep-15, -0x1.921fb5439d73ap-16, -0x1.921fb544197ap-17,
  75.         -0x1.921fb544387bap-18, -0x1.921fb544403c1p-19, -0x1.921fb544422c2p-20, -0x1.921fb54442a83p-21,
  76.         -0x1.921fb54442c73p-22, -0x1.921fb54442cefp-23, -0x1.921fb54442d0ep-24, -0x1.921fb54442d15p-25,
  77.         -0x1.921fb54442d17p-26, -0x1.921fb54442d18p-27, -0x1.921fb54442d18p-28, -0x1.921fb54442d18p-29,
  78.         -0x1.921fb54442d18p-30, -0x1.921fb54442d18p-31, -0x1.921fb54442d18p-32, -0x1.921fb54442d18p-33,
  79.         -0x1.921fb54442d18p-34, -0x1.921fb54442d18p-35, -0x1.921fb54442d18p-36, -0x1.921fb54442d18p-37,
  80.         -0x1.921fb54442d18p-38, -0x1.921fb54442d18p-39, -0x1.921fb54442d18p-40, -0x1.921fb54442d18p-41,
  81.         -0x1.921fb54442d18p-42, -0x1.921fb54442d18p-43, -0x1.921fb54442d18p-44, -0x1.921fb54442d18p-45,
  82.         -0x1.921fb54442d18p-46, -0x1.921fb54442d18p-47, -0x1.921fb54442d18p-48, -0x1.921fb54442d18p-49,
  83.         -0x1.921fb54442d18p-50, -0x1.921fb54442d18p-51, -0x1.921fb54442d18p-52, -0x1.921fb54442d18p-53,
  84.         -0x1.921fb54442d18p-54, -0x1.921fb54442d18p-55, -0x1.921fb54442d18p-56, -0x1.921fb54442d18p-57,
  85.         -0x1.921fb54442d18p-58, -0x1.921fb54442d18p-59, -0x1.921fb54442d18p-60 };

  86.     /** Type of DFT. */
  87.     private final Norm normalization;
  88.     /** Inverse or forward. */
  89.     private final boolean inverse;

  90.     /**
  91.      * @param normalization Normalization to be applied to the
  92.      * transformed data.
  93.      * @param inverse Whether to perform the inverse transform.
  94.      */
  95.     public FastFourierTransform(final Norm normalization,
  96.                                 final boolean inverse) {
  97.         this.normalization = normalization;
  98.         this.inverse = inverse;
  99.     }

  100.     /**
  101.      * @param normalization Normalization to be applied to the
  102.      * transformed data.
  103.      */
  104.     public FastFourierTransform(final Norm normalization) {
  105.         this(normalization, false);
  106.     }

  107.     /**
  108.      * Computes the standard transform of the data.
  109.      * Computation is done in place.
  110.      * Assumed layout of the input data:
  111.      * <ul>
  112.      *   <li>{@code dataRI[0][i]}: Real part of the {@code i}-th data point,</li>
  113.      *   <li>{@code dataRI[1][i]}: Imaginary part of the {@code i}-th data point.</li>
  114.      * </ul>
  115.      *
  116.      * @param dataRI Two-dimensional array of real and imaginary parts of the data.
  117.      * @throws IllegalArgumentException if the number of data points is not
  118.      * a power of two, if the number of rows of the specified array is not two,
  119.      * or the array is not rectangular.
  120.      */
  121.     public void transformInPlace(final double[][] dataRI) {
  122.         if (dataRI.length != NUM_PARTS) {
  123.             throw new TransformException(TransformException.SIZE_MISMATCH,
  124.                                          dataRI.length, NUM_PARTS);
  125.         }
  126.         final double[] dataR = dataRI[0];
  127.         final double[] dataI = dataRI[1];
  128.         if (dataR.length != dataI.length) {
  129.             throw new TransformException(TransformException.SIZE_MISMATCH,
  130.                                          dataI.length, dataR.length);
  131.         }
  132.         final int n = dataR.length;
  133.         if (!ArithmeticUtils.isPowerOfTwo(n)) {
  134.             throw new TransformException(TransformException.NOT_POWER_OF_TWO,
  135.                                          Integer.valueOf(n));
  136.         }

  137.         if (n == 1) {
  138.             return;
  139.         } else if (n == 2) {
  140.             final double srcR0 = dataR[0];
  141.             final double srcI0 = dataI[0];
  142.             final double srcR1 = dataR[1];
  143.             final double srcI1 = dataI[1];

  144.             // X_0 = x_0 + x_1
  145.             dataR[0] = srcR0 + srcR1;
  146.             dataI[0] = srcI0 + srcI1;
  147.             // X_1 = x_0 - x_1
  148.             dataR[1] = srcR0 - srcR1;
  149.             dataI[1] = srcI0 - srcI1;

  150.             normalizeTransformedData(dataRI);
  151.             return;
  152.         }

  153.         bitReversalShuffle2(dataR, dataI);

  154.         // Do 4-term DFT.
  155.         if (inverse) {
  156.             for (int i0 = 0; i0 < n; i0 += 4) {
  157.                 final int i1 = i0 + 1;
  158.                 final int i2 = i0 + 2;
  159.                 final int i3 = i0 + 3;

  160.                 final double srcR0 = dataR[i0];
  161.                 final double srcI0 = dataI[i0];
  162.                 final double srcR1 = dataR[i2];
  163.                 final double srcI1 = dataI[i2];
  164.                 final double srcR2 = dataR[i1];
  165.                 final double srcI2 = dataI[i1];
  166.                 final double srcR3 = dataR[i3];
  167.                 final double srcI3 = dataI[i3];

  168.                 // 4-term DFT
  169.                 // X_0 = x_0 + x_1 + x_2 + x_3
  170.                 dataR[i0] = srcR0 + srcR1 + srcR2 + srcR3;
  171.                 dataI[i0] = srcI0 + srcI1 + srcI2 + srcI3;
  172.                 // X_1 = x_0 - x_2 + j * (x_3 - x_1)
  173.                 dataR[i1] = srcR0 - srcR2 + (srcI3 - srcI1);
  174.                 dataI[i1] = srcI0 - srcI2 + (srcR1 - srcR3);
  175.                 // X_2 = x_0 - x_1 + x_2 - x_3
  176.                 dataR[i2] = srcR0 - srcR1 + srcR2 - srcR3;
  177.                 dataI[i2] = srcI0 - srcI1 + srcI2 - srcI3;
  178.                 // X_3 = x_0 - x_2 + j * (x_1 - x_3)
  179.                 dataR[i3] = srcR0 - srcR2 + (srcI1 - srcI3);
  180.                 dataI[i3] = srcI0 - srcI2 + (srcR3 - srcR1);
  181.             }
  182.         } else {
  183.             for (int i0 = 0; i0 < n; i0 += 4) {
  184.                 final int i1 = i0 + 1;
  185.                 final int i2 = i0 + 2;
  186.                 final int i3 = i0 + 3;

  187.                 final double srcR0 = dataR[i0];
  188.                 final double srcI0 = dataI[i0];
  189.                 final double srcR1 = dataR[i2];
  190.                 final double srcI1 = dataI[i2];
  191.                 final double srcR2 = dataR[i1];
  192.                 final double srcI2 = dataI[i1];
  193.                 final double srcR3 = dataR[i3];
  194.                 final double srcI3 = dataI[i3];

  195.                 // 4-term DFT
  196.                 // X_0 = x_0 + x_1 + x_2 + x_3
  197.                 dataR[i0] = srcR0 + srcR1 + srcR2 + srcR3;
  198.                 dataI[i0] = srcI0 + srcI1 + srcI2 + srcI3;
  199.                 // X_1 = x_0 - x_2 + j * (x_3 - x_1)
  200.                 dataR[i1] = srcR0 - srcR2 + (srcI1 - srcI3);
  201.                 dataI[i1] = srcI0 - srcI2 + (srcR3 - srcR1);
  202.                 // X_2 = x_0 - x_1 + x_2 - x_3
  203.                 dataR[i2] = srcR0 - srcR1 + srcR2 - srcR3;
  204.                 dataI[i2] = srcI0 - srcI1 + srcI2 - srcI3;
  205.                 // X_3 = x_0 - x_2 + j * (x_1 - x_3)
  206.                 dataR[i3] = srcR0 - srcR2 + (srcI3 - srcI1);
  207.                 dataI[i3] = srcI0 - srcI2 + (srcR1 - srcR3);
  208.             }
  209.         }

  210.         int lastN0 = 4;
  211.         int lastLogN0 = 2;
  212.         while (lastN0 < n) {
  213.             final int n0 = lastN0 << 1;
  214.             final int logN0 = lastLogN0 + 1;
  215.             final double wSubN0R = W_SUB_N_R[logN0];
  216.             double wSubN0I = W_SUB_N_I[logN0];
  217.             if (inverse) {
  218.                 wSubN0I = -wSubN0I;
  219.             }

  220.             // Combine even/odd transforms of size lastN0 into a transform of size N0 (lastN0 * 2).
  221.             for (int destEvenStartIndex = 0; destEvenStartIndex < n; destEvenStartIndex += n0) {
  222.                 final int destOddStartIndex = destEvenStartIndex + lastN0;

  223.                 double wSubN0ToRR = 1;
  224.                 double wSubN0ToRI = 0;

  225.                 for (int r = 0; r < lastN0; r++) {
  226.                     final int destEvenStartIndexPlusR = destEvenStartIndex + r;
  227.                     final int destOddStartIndexPlusR = destOddStartIndex + r;

  228.                     final double grR = dataR[destEvenStartIndexPlusR];
  229.                     final double grI = dataI[destEvenStartIndexPlusR];
  230.                     final double hrR = dataR[destOddStartIndexPlusR];
  231.                     final double hrI = dataI[destOddStartIndexPlusR];

  232.                     final double a = wSubN0ToRR * hrR - wSubN0ToRI * hrI;
  233.                     final double b = wSubN0ToRR * hrI + wSubN0ToRI * hrR;
  234.                     // dest[destEvenStartIndex + r] = Gr + WsubN0ToR * Hr
  235.                     dataR[destEvenStartIndexPlusR] = grR + a;
  236.                     dataI[destEvenStartIndexPlusR] = grI + b;
  237.                     // dest[destOddStartIndex + r] = Gr - WsubN0ToR * Hr
  238.                     dataR[destOddStartIndexPlusR] = grR - a;
  239.                     dataI[destOddStartIndexPlusR] = grI - b;

  240.                     // WsubN0ToR *= WsubN0R
  241.                     final double nextWsubN0ToRR = wSubN0ToRR * wSubN0R - wSubN0ToRI * wSubN0I;
  242.                     final double nextWsubN0ToRI = wSubN0ToRR * wSubN0I + wSubN0ToRI * wSubN0R;
  243.                     wSubN0ToRR = nextWsubN0ToRR;
  244.                     wSubN0ToRI = nextWsubN0ToRI;
  245.                 }
  246.             }

  247.             lastN0 = n0;
  248.             lastLogN0 = logN0;
  249.         }

  250.         normalizeTransformedData(dataRI);
  251.     }

  252.     /**
  253.      * {@inheritDoc}
  254.      *
  255.      * @throws IllegalArgumentException if the length of the data array is not a power of two.
  256.      */
  257.     @Override
  258.     public Complex[] apply(final double[] f) {
  259.         final double[][] dataRI = {
  260.             Arrays.copyOf(f, f.length),
  261.             new double[f.length]
  262.         };
  263.         transformInPlace(dataRI);
  264.         return TransformUtils.createComplex(dataRI);
  265.     }

  266.     /**
  267.      * {@inheritDoc}
  268.      *
  269.      * @throws IllegalArgumentException if the number of sample points
  270.      * {@code n} is not a power of two, if the lower bound is greater than,
  271.      * or equal to the upper bound, if the number of sample points {@code n}
  272.      * is negative
  273.      */
  274.     @Override
  275.     public Complex[] apply(final DoubleUnaryOperator f,
  276.                            final double min,
  277.                            final double max,
  278.                            final int n) {
  279.         return apply(TransformUtils.sample(f, min, max, n));
  280.     }

  281.     /**
  282.      * {@inheritDoc}
  283.      *
  284.      * @throws IllegalArgumentException if the length of the data array is
  285.      * not a power of two.
  286.      */
  287.     @Override
  288.     public Complex[] apply(final Complex[] f) {
  289.         final double[][] dataRI = TransformUtils.createRealImaginary(f);
  290.         transformInPlace(dataRI);
  291.         return TransformUtils.createComplex(dataRI);
  292.     }

  293.     /**
  294.      * Applies normalization to the transformed data.
  295.      *
  296.      * @param dataRI Unscaled transformed data.
  297.      */
  298.     private void normalizeTransformedData(final double[][] dataRI) {
  299.         final double[] dataR = dataRI[0];
  300.         final double[] dataI = dataRI[1];
  301.         final int n = dataR.length;

  302.         switch (normalization) {
  303.         case STD:
  304.             if (inverse) {
  305.                 final double scaleFactor = 1d / n;
  306.                 for (int i = 0; i < n; i++) {
  307.                     dataR[i] *= scaleFactor;
  308.                     dataI[i] *= scaleFactor;
  309.                 }
  310.             }

  311.             break;

  312.         case UNIT:
  313.             final double scaleFactor = 1d / Math.sqrt(n);
  314.             for (int i = 0; i < n; i++) {
  315.                 dataR[i] *= scaleFactor;
  316.                 dataI[i] *= scaleFactor;
  317.             }

  318.             break;

  319.         default:
  320.             throw new IllegalStateException(); // Should never happen.
  321.         }
  322.     }

  323.     /**
  324.      * Performs identical index bit reversal shuffles on two arrays of
  325.      * identical size.
  326.      * Each element in the array is swapped with another element based
  327.      * on the bit-reversal of the index.
  328.      * For example, in an array with length 16, item at binary index 0011
  329.      * (decimal 3) would be swapped with the item at binary index 1100
  330.      * (decimal 12).
  331.      *
  332.      * @param a Array to be shuffled.
  333.      * @param b Array to be shuffled.
  334.      */
  335.     private static void bitReversalShuffle2(double[] a,
  336.                                             double[] b) {
  337.         final int n = a.length;
  338.         final int halfOfN = n >> 1;

  339.         int j = 0;
  340.         for (int i = 0; i < n; i++) {
  341.             if (i < j) {
  342.                 // swap indices i & j
  343.                 double temp = a[i];
  344.                 a[i] = a[j];
  345.                 a[j] = temp;

  346.                 temp = b[i];
  347.                 b[i] = b[j];
  348.                 b[j] = temp;
  349.             }

  350.             int k = halfOfN;
  351.             while (k <= j && k > 0) {
  352.                 j -= k;
  353.                 k >>= 1;
  354.             }
  355.             j += k;
  356.         }
  357.     }

  358.     /**
  359.      * Normalization types.
  360.      */
  361.     public enum Norm {
  362.         /**
  363.          * Should be passed to the constructor of {@link FastFourierTransform}
  364.          * to use the <em>standard</em> normalization convention. This normalization
  365.          * convention is defined as follows
  366.          * <ul>
  367.          * <li>forward transform: \( y_n = \sum_{k = 0}^{N - 1} x_k e^{-2 \pi i n k / N} \),</li>
  368.          * <li>inverse transform: \( x_k = \frac{1}{N} \sum_{n = 0}^{N - 1} y_n e^{2 \pi i n k / N} \),</li>
  369.          * </ul>
  370.          * where \( N \) is the size of the data sample.
  371.          */
  372.         STD,

  373.         /**
  374.          * Should be passed to the constructor of {@link FastFourierTransform}
  375.          * to use the <em>unitary</em> normalization convention. This normalization
  376.          * convention is defined as follows
  377.          * <ul>
  378.          * <li>forward transform: \( y_n = \frac{1}{\sqrt{N}} \sum_{k = 0}^{N - 1} x_k e^{-2 \pi i n k / N} \),</li>
  379.          * <li>inverse transform: \( x_k = \frac{1}{\sqrt{N}} \sum_{n = 0}^{N - 1} y_n e^{2 \pi i n k / N} \),</li>
  380.          * </ul>
  381.          * where \( N \) is the size of the data sample.
  382.          */
  383.         UNIT;
  384.     }
  385. }