Click here to Skip to main content
13,146,742 members (79,966 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

18.2K views
589 downloads
16 bookmarked
Posted 14 May 2016

Comparison of FFT implementations for .NET

, 13 Jun 2016
Rate this:
Please Sign up or sign in to vote.
Comparison and benchmark of Fast Fourier Transform implementations for the .NET platform

Introduction

In this short article, we will compare a couple of Fast Fourier Transform (FFT) implementations for the .NET platform. The contestants are:

 Accord.NETAForge.NETExocortex.DSPMath.NET NumericsNAudioLomontFFTW
Version:3.0.2-1.23.11.01.7.31.13.3.4
License:LGPLLGPLBSDMITMs-PL-GPL
Assemblies:4-111-1+1
Size:728 kb--1252 kb460 kb-2.3 MB
Nuget:yesyesnoyesyesnono

Remarks

  • Accord.NET is an extension to AForge.NET and the original AForge code is part of the Accord assembly, so the AForge assemblies weren't tested separately.
  • The Exocortex project was created in the early .NET 1.0 days. The copy provided with this article was updated to target .NET 4.5 and to use the Complex type of the System.Numerics namespace.
  • NAudio uses a custom Complex type implementation with single precision real and imaginary part.
  • FFTW is a popular, native FFT implementation. It is probably the fastest open source implementation one can find on the internet, so comparison with the managed code is a bit unfair. Still, I thought it might be interesting to see how the code competes.

The FFTW binaries are not distributed with this article. If you want FFTW to be included in the benchmark, go to http://www.fftw.org/install/windows.html and copy libfftw3-3.dll and libfftw3f-3.dll to the application directory.

Benchmark

I was particularly interested in 1D FFTs for real valued input (audio processing). The following interface is used for all tests. If you have your own FFT implementation, it should be easy to incorporate it into the benchmark by implementing this interface and instantiate the test in the Util.LoadTests() method.

interface ITest
{
    bool Enabled {get; set; }

    /// <summary>
    /// Prepare the real valued data for FFT processing.
    /// </summary>
    /// <param name="data">The samples array.</param>
    void Initialize(double[] data);

    /// <summary>
    /// Apply FFT to data.
    /// </summary>
    /// <param name="forward">If false, apply inverse FFT.</param>
    void FFT(bool forward);

    // Ignore for benchmark (used only for 'FFT Explorer', see next section)
    double[] Spectrum(double[] input, bool scale);
}

Take a look at the different tests in the FFTBench.Benchmark namespace to see how to implement the interface properly.

Exocortex, Lomont and FFTW have specialised implementations for real valued data and the code can be expected to be about twice as fast as the standard complex implementation.

Accord.NET, Math.NET and FFTW support input arrays of any size (i.e. the size doesn't have to be a power of 2). Since AForge, Exocortex, NAudio and Lomont support radix 2 only, the benchmark uses arrays with sizes that are a power of 2.

The following table shows the total execution time in milliseconds for FFTs of increasing size:

FFT size1024204840968192
Accord.NET    2524    5615  13309  26700
AForge.NET200040001001627050
Math.NET446075991492629098
NAudio10022004500911510
Exocortex15003000700022008
Lomont10002000450220500
Exocortex (real)500100025016000
Lomont (real)500100025006000
FFTW-50010025501
FFTW (real)--5001504
FFTWF (real)---1000

Each FFT is actually called 25000 times (the repeat value can be chosen from the user interface), so a single call to Accord's FFT routine for size 8192 would - for example - approximatly be 1ms (the absolute runtime will certainly be different on different machines; the above benchmark was run on an AMD Phenom II X2 550 processor (3.1 GHz)).

The next chart shows the benchmark result for the different FFTs of size 4096:

Interpreting FFT Results

The benchmark application contains a util called FFT Explorer. You can open it by clicking on the leftmost icon of the benchmark window.

The FFT Explorer lets you select the FFT implementation, an input signal and the FFT size. Three graphs will display the input signal, the spectrum computed by the selected FFT and the signal computed by the inverse FFT.

Let's have a look at an example signal of the SignalGenerator class. The generated signal is a simple sine wave with frequency 1.0 Hz and amplitude 20.0:

public static double[] Sine(int n)
{
    const int FS = 64; // sampling rate

    return MathNet.Numerics.Generate.Sinusoidal(n, FS, 1.0, 20.0);
}

Let the FFT frame size be n = 256. With a sampling rate of 64 Hz our periodic signal will be repeated exactly four times over the selected window. Be aware that all values are chosen to have an exact match between signal period, sampling rate and FFT size. This way, we won't have to deal with spectral leakage.

Each bin of the FFT output is spaced by the frequency resolution (sampling rate) / (FFT size), which in our case is 64 / 256 = 0.25. So we expect a peek corresponding to our 1.0 Hz signal to be in bin number 4 (since 1.0 = 4 * 0.25).

Due to the nature of the DFT, the spectrum of the signal will get scaled by n = 256, so if no further scaling is done, we expect the value to be 20.0 * 256 / 2 = 2560. We divide by 2, since the amplitude is distributed across two bins. The second bin is located at index 256 - 4 = 252 and will have the same magnitude, because, for real valued input signals, the FFT output is (conjugate) symmetric (across n/2, the bin corresponding to the Nyquist frequency).

The actual values of the peek won't be consistent between FFT implementations, since there's no common scaling convention. If the FFT size is n, then some implementations scale the FFT by 1/n, some scale the inverse FFT by 1/n and some scale both by 1/sqrt(n). Some don't scale at all (like FFTW).

The following table shows the amplitudes computed by the different FFTs for the above example:

 Accord.NETAForge.NETExocortex.DSPMath.NET NumericsNAudioLomontFFTW
Value:2560102560160101602560

You can see that AForge.NET and NAudio scale by 1/n and that Math.NET and Lomont scale by 1/sqrt(n) (both Math.NET and Lomont allow the user to change scaling conventions; the values computed above and used in the benchmark represent the default settings).

Conclusion

Obviously and not completely unexpected, FFTW is the clear winner. So, if using a native DLL is an option for you, go for it. Looking at the managed code, both Exocortex and Lomont seem to be a good choice. For complex valued data, Lomont is slightly faster. For real valued signals, both perform the same. NAudio also performs pretty well, but uses a custom Complex type and does not support real valued input.

History

  • 15 May 2016 - Initial version
  • 14 June 2016 - Add information requested in the comments

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Studied math and computer science at the university of Dortmund.

MCTS .NET Framework 4, Windows Applications

You may also be interested in...

Comments and Discussions

 
QuestionIt would be helpful to expand FFT abbreviation at least once at the beginning of the article. Pin
Roman Ivantsov13-Jun-16 18:46
memberRoman Ivantsov13-Jun-16 18:46 
QuestionNumber of repeats Pin
Gwannoes6-Jun-16 4:44
memberGwannoes6-Jun-16 4:44 
AnswerRe: Number of repeats Pin
Christian Woltering6-Jun-16 7:05
memberChristian Woltering6-Jun-16 7:05 
GeneralRe: Number of repeats Pin
Gwannoes6-Jun-16 20:50
memberGwannoes6-Jun-16 20:50 
QuestionMix Radix Pin
Mark C. Malburg16-May-16 5:15
memberMark C. Malburg16-May-16 5:15 
AnswerRe: Mix Radix Pin
Christian Woltering16-May-16 8:45
memberChristian Woltering16-May-16 8:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.170915.1 | Last Updated 14 Jun 2016
Article Copyright 2016 by Christian Woltering
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid