73 votes

Une implémentation de la transformée de Fourier rapide (FFT) en C#

Où puis-je trouver une implémentation gratuite, très rapide et fiable de la FFT en C# ?

Qui peuvent être utilisés dans un produit ? Ou y a-t-il des restrictions ?

54voto

Le gars qui a fait AForge a fait un assez bon travail mais ce n'est pas de la qualité commerciale. C'est un bon outil d'apprentissage, mais on peut voir qu'il apprenait lui aussi et qu'il a commis de graves erreurs, comme supposer la taille d'une image au lieu d'utiliser le nombre correct de bits par pixel.

Je ne le critique pas, je lui voue un grand respect pour avoir appris tout cela et nous avoir montré comment le faire. Je pense qu'il a un doctorat maintenant ou du moins qu'il est sur le point de l'obtenir, donc il est vraiment intelligent, mais ce n'est pas une bibliothèque utilisable commercialement.

La bibliothèque Math.Net a ses propres bizarreries lorsqu'elle travaille avec des transformées de Fourier et des images/nombres complexes. Par exemple, si je ne me trompe pas, elle produit la transformée de Fourier dans un format visible par l'homme, ce qui est bien pour les humains si vous voulez regarder une image de la transformée, mais ce n'est pas si bien quand vous attendez que les données soient dans un certain format (le format normal). Je peux me tromper, mais je me souviens juste qu'il y avait une certaine bizarrerie, alors j'ai utilisé le code original qu'ils ont utilisé pour la transformation de Fourier et cela a bien mieux fonctionné. (ExocortexDSP v1.2 http://www.exocortex.org/dsp/ )

Math.net avait également d'autres particularités que je n'aimais pas lorsqu'il s'agissait de traiter les données de la FFT. Je ne me souviens plus de ce que c'était, mais je sais qu'il était beaucoup plus facile d'obtenir ce que je voulais avec la bibliothèque DSP ExoCortex. Je ne suis ni mathématicien ni ingénieur ; pour ces personnes, cela peut être parfaitement logique.

J'utilise donc le code FFT extrait d'ExoCortex, sur lequel Math.Net est basé, sans rien d'autre et cela fonctionne très bien.

Enfin, je sais que ce n'est pas du C#, mais j'ai commencé à envisager d'utiliser FFTW ( http://www.fftw.org/ ). Et ce type a déjà créé un wrapper C#, alors j'allais y jeter un coup d'œil, mais je ne l'ai pas encore utilisé. ( http://www.sdss.jhu.edu/~tamas/bytes/fftwcsharp.html )

OH ! Je ne sais pas si vous faites cela pour l'école ou pour le travail, mais dans tous les cas, il existe une excellente série de conférences gratuites données par un professeur de Stanford sur iTunes University.

https://podcasts.apple.com/us/podcast/the-fourier-transforms-and-its-applications/id384232849

2 votes

J'aimerais avoir plus de détails sur la bizarrerie de l'implémentation fft de Math.NET Iridium - afin que nous puissions y remédier !) Est-ce lié à la façon dont les nombres complexes sont traités ? Je n'ai aucune idée de ce que vous voulez dire par "format visible par l'homme". Échantillons : mathnet.opensourcedotnet.info/doc/IridiumFFT.ashx

6 votes

Fftw a une sorte de licence problématique ; regardez ça : "Des licences non libres pour la FFTW sont également disponibles et permettent des conditions d'utilisation différentes de celles de la GPL."

0 votes

C'est une question à Mike Bethany. J'essaie d'apprendre comment convertir des données du domaine temporel au domaine fréquentiel. Votre lien exocortex est-il le bon moyen de le faire ?

34voto

torial Points 9883

AForge.net est une bibliothèque gratuite (open-source) qui supporte la Transformée de Fourier Rapide. (Voir Sources/Imaging/ ComplexImage.cs pour l'usage, Sources/Math/ FourierTransform.cs pour la mise en œuvre)

17voto

Jonas Hallgren Points 318

Juste un commentaire sur @Jacob et @pookleblinky : Le fft d'Iridium est construit sur exocortex mais il est entouré d'un certain nombre de modifications qui, en fait, le rendent plus lent. Donc, si vous avez besoin d'un calcul de fft pur, je m'en tiendrais au paquet fft d'exocortex.

13voto

Jacob Points 9117

Math.NET Bibliothèque Iridium fournit une collection rapide et régulièrement mise à jour de fonctions mathématiques, dont la FFT. Il est sous licence LGPL et vous êtes donc libre de l'utiliser dans des produits commerciaux.

2 votes

+1. Math.NET Iridium est idéal pour traduire du code Java (qui utilise Apache commons-math) en .NET grâce à la correspondance étroite entre les classes et les méthodes de chacun. Dans 95 % des cas, il suffit de changer les noms des classes et des méthodes pour que tout fonctionne.

8voto

Je vois que c'est un vieux fil de discussion, mais pour ce que ça vaut, voici une implémentation FFT 1-D puissance-de-2-longueur-seule en C#, gratuite (licence MIT), que j'ai écrite en 2010.

Je n'ai pas comparé ses performances à d'autres implémentations C# FFT. Je l'ai écrit principalement pour comparer les performances de Flash/ActionScript et de Silverlight/C#. Ce dernier est beaucoup plus rapide, au moins pour le calcul des chiffres.

/**
 * Performs an in-place complex FFT.
 *
 * Released under the MIT License
 *
 * Copyright (c) 2010 Gerald T. Beauregard
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */
public class FFT2
{
    // Element for linked list in which we store the
    // input/output data. We use a linked list because
    // for sequential access it's faster than array index.
    class FFTElement
    {
        public double re = 0.0;     // Real component
        public double im = 0.0;     // Imaginary component
        public FFTElement next;     // Next element in linked list
        public uint revTgt;         // Target position post bit-reversal
    }

    private uint m_logN = 0;        // log2 of FFT size
    private uint m_N = 0;           // FFT size
    private FFTElement[] m_X;       // Vector of linked list elements

    /**
     *
     */
    public FFT2()
    {
    }

    /**
     * Initialize class to perform FFT of specified size.
     *
     * @param   logN    Log2 of FFT length. e.g. for 512 pt FFT, logN = 9.
     */
    public void init(
        uint logN )
    {
        m_logN = logN;
        m_N = (uint)(1 << (int)m_logN);

        // Allocate elements for linked list of complex numbers.
        m_X = new FFTElement[m_N];
        for (uint k = 0; k < m_N; k++)
            m_X[k] = new FFTElement();

        // Set up "next" pointers.
        for (uint k = 0; k < m_N-1; k++)
            m_X[k].next = m_X[k+1];

        // Specify target for bit reversal re-ordering.
        for (uint k = 0; k < m_N; k++ )
            m_X[k].revTgt = BitReverse(k,logN);
    }

    /**
     * Performs in-place complex FFT.
     *
     * @param   xRe     Real part of input/output
     * @param   xIm     Imaginary part of input/output
     * @param   inverse If true, do an inverse FFT
     */
    public void run(
        double[] xRe,
        double[] xIm,
        bool inverse = false )
    {
        uint numFlies = m_N >> 1;   // Number of butterflies per sub-FFT
        uint span = m_N >> 1;       // Width of the butterfly
        uint spacing = m_N;         // Distance between start of sub-FFTs
        uint wIndexStep = 1;        // Increment for twiddle table index

        // Copy data into linked complex number objects
        // If it's an IFFT, we divide by N while we're at it
        FFTElement x = m_X[0];
        uint k = 0;
        double scale = inverse ? 1.0/m_N : 1.0;
        while (x != null)
        {
            x.re = scale*xRe[k];
            x.im = scale*xIm[k];
            x = x.next;
            k++;
        }

        // For each stage of the FFT
        for (uint stage = 0; stage < m_logN; stage++)
        {
            // Compute a multiplier factor for the "twiddle factors".
            // The twiddle factors are complex unit vectors spaced at
            // regular angular intervals. The angle by which the twiddle
            // factor advances depends on the FFT stage. In many FFT
            // implementations the twiddle factors are cached, but because
            // array lookup is relatively slow in C#, it's just
            // as fast to compute them on the fly.
            double wAngleInc = wIndexStep * 2.0*Math.PI/m_N;
            if (inverse == false)
                wAngleInc *= -1;
            double wMulRe = Math.Cos(wAngleInc);
            double wMulIm = Math.Sin(wAngleInc);

            for (uint start = 0; start < m_N; start += spacing)
            {
                FFTElement xTop = m_X[start];
                FFTElement xBot = m_X[start+span];

                double wRe = 1.0;
                double wIm = 0.0;

                // For each butterfly in this stage
                for (uint flyCount = 0; flyCount < numFlies; ++flyCount)
                {
                    // Get the top & bottom values
                    double xTopRe = xTop.re;
                    double xTopIm = xTop.im;
                    double xBotRe = xBot.re;
                    double xBotIm = xBot.im;

                    // Top branch of butterfly has addition
                    xTop.re = xTopRe + xBotRe;
                    xTop.im = xTopIm + xBotIm;

                    // Bottom branch of butterly has subtraction,
                    // followed by multiplication by twiddle factor
                    xBotRe = xTopRe - xBotRe;
                    xBotIm = xTopIm - xBotIm;
                    xBot.re = xBotRe*wRe - xBotIm*wIm;
                    xBot.im = xBotRe*wIm + xBotIm*wRe;

                    // Advance butterfly to next top & bottom positions
                    xTop = xTop.next;
                    xBot = xBot.next;

                    // Update the twiddle factor, via complex multiply
                    // by unit vector with the appropriate angle
                    // (wRe + j wIm) = (wRe + j wIm) x (wMulRe + j wMulIm)
                    double tRe = wRe;
                    wRe = wRe*wMulRe - wIm*wMulIm;
                    wIm = tRe*wMulIm + wIm*wMulRe;
                }
            }

            numFlies >>= 1;     // Divide by 2 by right shift
            span >>= 1;
            spacing >>= 1;
            wIndexStep <<= 1;   // Multiply by 2 by left shift
        }

        // The algorithm leaves the result in a scrambled order.
        // Unscramble while copying values from the complex
        // linked list elements back to the input/output vectors.
        x = m_X[0];
        while (x != null)
        {
            uint target = x.revTgt;
            xRe[target] = x.re;
            xIm[target] = x.im;
            x = x.next;
        }
    }

    /**
     * Do bit reversal of specified number of places of an int
     * For example, 1101 bit-reversed is 1011
     *
     * @param   x       Number to be bit-reverse.
     * @param   numBits Number of bits in the number.
     */
    private uint BitReverse(
        uint x,
        uint numBits)
    {
        uint y = 0;
        for (uint i = 0; i < numBits; i++)
        {
            y <<= 1;
            y |= x & 0x0001;
            x >>= 1;
        }
        return y;
    }

}

0 votes

Cette réponse est maintenant complètement inutile car le lien ne mène nulle part...

0 votes

Je suis désolé. J'ai supprimé mon blog il y a quelques années car il attirait trop de spam. Malheureusement, le code est un peu trop gros pour être inséré dans un commentaire ici. Envoyez-moi un message à g.<mysurname>@ieee.org, et je serai heureux de vous envoyer le code.

0 votes

Vous pouvez mettre à jour votre réponse, ajouter le code et supprimer votre lien mort. Partager votre code via des canaux privés serait contraire à l'esprit de Stack Overflow.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X