1
votes

some days ago I posted my FFT-Test tool with some problems, so this here is my "remake" poste with almost the same problems, but different code.

Problem: I´m trying to make a tool to read some sensor values and do the fft of these. I implemented a normal DFT, a FFT(Bluestein) and a FFT(Cooley-Tukey). It all works fine and the inverse transformation shows the input like it should. The only thing is when i plot the Frequenz/Amplitude graph i have a huge peak at the begining (not only at 0 like the DC (0Hz) component should be!).

For Bluestein and DFT I use the complet input and for Cooley-Tukey I calculate with ZeroPadding or just cut the input to a 2^n length.

For example here is my input, just a simple sinuswave. Here the output with DFT and Bluetstein(looks the same) and FFT(ZeroPadding) and one DFT zoomed in at 0Hz. And here is the ouput of the same input with octave, what I expected to get.

Here my Code fore CT-FFT

            public static void TransformRadix2(Complex[] vector, bool inverse)
        {
            // Length variables
            int n = vector.Length;
            int levels = 0;  // compute levels = floor(log2(n))
            for (int temp = n; temp > 1; temp >>= 1)
                levels++;
            if (1 << levels != n)
                throw new ArgumentException("Length is not a power of 2");

            // Trigonometric table
            Complex[] expTable = new Complex[n / 2];
            double coef = 2 * Math.PI / n * (inverse ? 1 : -1);
            for (int i = 0; i < n / 2; i++)
                expTable[i] = Complex.Exp(new Complex(0, i * coef));

            // Bit-reversed addressing permutation
            for (int i = 0; i < n; i++)
            {
                int j = (int)((uint)ReverseBits(i) >> (32 - levels));
                if (j > i)
                {
                    Complex temp = vector[i];
                    vector[i] = vector[j];
                    vector[j] = temp;
                }
            }

            // Cooley-Tukey decimation-in-time radix-2 FFT
            for (int size = 2; size <= n; size *= 2)
            {
                int halfsize = size / 2;
                int tablestep = n / size;
                for (int i = 0; i < n; i += size)
                {
                    for (int j = i, k = 0; j < i + halfsize; j++, k += tablestep)
                    {
                        Complex temp = vector[j + halfsize] * expTable[k];
                        vector[j + halfsize] = vector[j] - temp;
                        vector[j] += temp;
                    }
                }
                if (size == n)  // Prevent overflow in 'size *= 2'
                    break;
            }
        }

And here Bluestein.

            public static void TransformBluestein(Complex[] vector, bool inverse)
        {
            // Find a power-of-2 convolution length m such that m >= n * 2 + 1
            int n = vector.Length;
            if (n >= 0x20000000)
                throw new ArgumentException("Array too large");
            int m = 1;
            while (m < n * 2 + 1)
                m *= 2;

            // Trignometric table
            Complex[] expTable = new Complex[n];
            double coef = Math.PI / n * (inverse ? 1 : -1);
            for (int i = 0; i < n; i++)
            {
                int j = (int)((long)i * i % (n * 2));  // This is more accurate than j = i * i
                expTable[i] = Complex.Exp(new Complex(0, j * coef));
            }

            // Temporary vectors and preprocessing
            Complex[] avector = new Complex[m];
            for (int i = 0; i < n; i++)
                avector[i] = vector[i] * expTable[i];
            Complex[] bvector = new Complex[m];
            bvector[0] = expTable[0];
            for (int i = 1; i < n; i++)
                bvector[i] = bvector[m - i] = Complex.Conjugate(expTable[i]);

            // Convolution
            Complex[] cvector = new Complex[m];
            Convolve(avector, bvector, cvector);

            // Postprocessing
            for (int i = 0; i < n; i++)
                vector[i] = cvector[i] * expTable[i];
        }


        /* 
         * Computes the circular convolution of the given complex vectors. Each vector's length must be the same.
         */
        public static void Convolve(Complex[] xvector, Complex[] yvector, Complex[] outvector)
        {
            int n = xvector.Length;
            if (n != yvector.Length || n != outvector.Length)
                throw new ArgumentException("Mismatched lengths");
            xvector = (Complex[])xvector.Clone();
            yvector = (Complex[])yvector.Clone();
            Transform(xvector, false);
            Transform(yvector, false);
            for (int i = 0; i < n; i++)
                xvector[i] *= yvector[i];
            Transform(xvector, true);
            for (int i = 0; i < n; i++)  // Scaling (because this FFT implementation omits it)
                outvector[i] = xvector[i] / n;
        }

        private static int ReverseBits(int val)
        {
            int result = 0;
            for (int i = 0; i < 32; i++, val >>= 1)
                result = (result << 1) | (val & 1);
            return result;
        }

And this is the input per periode with an interval of 0,00001953125.

0
 0.03141
 0.06279
 0.09411
 0.12533
 0.15643
0.18738
 0.21814
 0.24869
 0.27899
 0.30902
 0.33874
 0.36812
 0.39715
 0.42578
 0.45399
 0.48175
 0.50904
 0.53583
0.56208
 0.58779
 0.61291
 0.63742
 0.66131
 0.68455
0.70711
 0.72897
 0.75011
 0.77051
 0.79016
 0.80902
 0.82708
 0.84433
 0.86074
 0.87631
 0.89101
 0.90483
 0.91775
 0.92978
 0.94088
 0.95106
 0.96029
 0.96858
 0.97592
0.98229
 0.98769
 0.99211
 0.99556
 0.99803
 0.99951
1
 0.99951
   0.99803
   0.99556
   0.99211
   0.98769
   0.98229
   0.97592
   0.96858
   0.96029
   0.95106
   0.94088
   0.92978
  0.91775
   0.90483
   0.89101
   0.87631
   0.86074
   0.84433
  0.82708
  0.80902
  0.79016
   0.77051
   0.75011
   0.72897
   0.70711
   0.68455
   0.66131
   0.63742
   0.61291
   0.58779
   0.56208
   0.53583
   0.50904
   0.48175
   0.45399
   0.42578
   0.39715
  0.36812
   0.33874
   0.30902
   0.27899
   0.24869
   0.21814
  0.18738
   0.15643
   0.12533
   0.09411
   0.06279
   0.03141
   0
   -0.03141
   -0.06279
   -0.09411
   -0.12533
   -0.15643
   -0.18738
  -0.21814
   -0.24869
   -0.27899
   -0.30902
   -0.33874
   -0.36812
-0.39715
   -0.42578
   -0.45399
   -0.48175
   -0.50904
   -0.53583
  -0.56208
   -0.58779
   -0.61291
   -0.63742
   -0.66131
   -0.68455
   -0.70711
   -0.72897
   -0.75011
   -0.77051
   -0.79016
   -0.80902
   -0.82708
  -0.84433
   -0.86074
   -0.87631
   -0.89101
   -0.90483
   -0.91775
  -0.92978
   -0.94088
   -0.95106
   -0.96029
   -0.96858
   -0.97592
   -0.98229
   -0.98769
   -0.99211
   -0.99556
   -0.99803
   -0.99951
   -1
  -0.99951
   -0.99803
   -0.99556
   -0.99211
   -0.98769
   -0.98229
  -0.97592
   -0.96858
   -0.96029
   -0.95106
   -0.94088
   -0.92978
  -0.91775
   -0.90483
   -0.89101
   -0.87631
   -0.86074
   -0.84433
   -0.82708
   -0.80902
   -0.79016
   -0.77051
   -0.75011
   -0.72897
   -0.70711
  -0.68455
   -0.66131
   -0.63742
   -0.61291
   -0.58779
   -0.56208
  -0.53583
   -0.50904
   -0.48175
   -0.45399
   -0.42578
   -0.39715
   -0.36812
   -0.33874
   -0.30902
   -0.27899
   -0.24869
   -0.21814
   -0.18738
   -0.15643
   -0.12533
   -0.09411
   -0.06279
   -0.03141
   0

I have no idear what this peak could be. The only thing i can say is, when my interval is bigger the peak at the beginning is also bigger: Interval 0,00001953125 ; 0,0001953125 ; 0,001953125

Here is how i create the input of the fft. Just my shown input and the intervall....

                    float UsedInterval = float.Parse(Interval.Replace(",", "."), CultureInfo.InvariantCulture);
                float x = 0; //Intervall starting at 0
                foreach (var line in input)
                {
                    if (string.IsNullOrWhiteSpace(line)) continue; //delete empty lines

                    x += UsedInterval;  //add intervall
                    double y = double.Parse(line.Replace(",", "."), CultureInfo.InvariantCulture);

                    arr.Add(new Vector2XY(x, y));
                }

I hope you can help me with my problems and thanks for your attention.

When I do a 256bit ZeroPadding FFT with the upper Data over one periode and the interval 0,00001953125 this is my ouput

1
It's probably just the "smeared" DC component - the smearing is due to spectral leakage because you are presumably not applying a window function. - Paul R
Could you show code for generation input data? - MBo
i added how i generate the input data - Sim91
Emm.. So Complex structure contains x-coordinate (sloped line) as real part and some data as imaginary part?? - MBo
sry, but what do you mean with "sloped line" ? the complex structure contains in x the consecutive interval(newinterval[i] = lastinterval + interval) as real part and in Y as imaginary part the amplitude of the sinus wave in y-Coordinates - Sim91

1 Answers

1
votes

You should fill real part of complex input with Sin(coeff*i) and imaginary part with zero - pure real input, and you'll get right output without large peak near zero - it is due to linear component of current real part.