2
$\begingroup$

I am averaging several FFT results together in an attempt to get the average frequency spectrum of a track of audio. I'm attempting to use Parseval's Relation to get the RMS of the audio from the resulting average spectrum, but i've noticed the RMS i get is wrong, usually only by a couple dB. Why does this happen? Does it mean i am averaging the spectra together incorrectly? Is it more complicated than simply adding the corresponding N magnitudes together and dividing by N? When i get the RMS from a single FFT using Parseval's Relation it is correct.

Here is the code i am using to average the FFTs:

    int N = pow(2, resolution);

    //temporary buffers
    vector< array<double,2> > RXT; 
    vector< array<double,2> > IXT;

    //final signals
    REX.assign(N, array<double,2>() );
    IMX.assign(N, array<double,2>() );
    magnitude.assign( N, array<double,2>() ); 
    phase.assign( N, array<double,2>() );

    int start;
    bool lastSeg = false;
    int seg = 0;
    //double radians = 2 * PI / N; //used for windowing functions

    while ( !lastSeg ) {

        start = seg * N;

        if (X.size() >= start + N) {
            RXT.assign(X.begin()+start,X.begin()+start+N);
        } else {
            RXT.assign(X.begin()+start,X.end());
            for ( int n = 0; n < RXT.size(); n++ ) {
                for ( int chan = 0; chan < channels; chan++ ) {

                    RXT.at(n).at(chan) *= (double)N / RXT.size();

                }
            }
            RXT.resize( N, array<double,2>() );
            lastSeg = true;
        }

        IXT.assign( N, array<double,2>() );

        FFT(RXT, IXT);

        for ( int n = 0; n < N; n++ ) {
            for ( int chan = 0; chan < channels; chan++ ) {

                magnitude.at(n).at(chan) += getMag( RXT.at(n).at(chan), IXT.at(n).at(chan) );

            }
        }

        seg++;

    }

    for ( int n = 0; n < N; n++ ) {
        for ( int chan = 0; chan < channels; chan++ ) {

            magnitude.at(n).at(chan) /= seg;

            REX.at(n).at(chan) = getReal(magnitude.at(n).at(chan), phase.at(n).at(chan));
            IMX.at(n).at(chan) = getImag(magnitude.at(n).at(chan), phase.at(n).at(chan));
        }
    }
$\endgroup$
  • $\begingroup$ Do you have a code snippet or equation to describe what you are doing? Try squaring the individual RMS values, averaging them, then taking the root. $\endgroup$ – geometrikal Aug 22 '13 at 23:09
  • $\begingroup$ I guess i am much more concerned that the averaging is correct than the rms. It just seemed to indicate that i was doing something wrong. I'll edit my post to include code of the averaging part. $\endgroup$ – Rob Allsopp Aug 23 '13 at 3:42
  • $\begingroup$ While some methods may be more common than others, there are many ways to compute the spectrum of a signal. For example, will you overlap your segments? Will you apply any windowing to the segments? What is your FFT size? All of these decisions will affect the result. There is also more than one way to take an average, but a power spectrum will usually involve a squaring operation. Also be aware that averaging linear-scaled values is very different than averaging log-scaled (dB) values. $\endgroup$ – nispio Aug 23 '13 at 7:57
  • $\begingroup$ I am using no windowing, no overlapping, and the RMS is off with every FFT length i've tried. I'm just averaging the linear-scaled polar magnitudes. Is there a special way i should be doing this? $\endgroup$ – Rob Allsopp Aug 23 '13 at 15:20
  • $\begingroup$ @RobbyAllsopp: In taking the FFT of multiple segments, you are applying a rectangular window, whether you realize it or not. Consider the spectrum of a rectangular window. It is a sinc function that grows wider as the window length shrinks. So every time you apply a rectangular window, you add frequency content that varies with window length. $\endgroup$ – nispio Aug 23 '13 at 21:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.