0

I got an array of data voltages and I want to get the RMS value from the FFT that has been applied before to that data. I've seen that RMS in time domain should be equal to RMS(fft) / sqrt(nFFT) from Parseval's Theorem, but gives me different results. I'm using these functions: 1)FFT

 public static VectorDPoint FFT(double[] trama, double samplingFreq)
    {
        double fs = samplingFreq;   // Sampling frequency
        double t1 = 1 / fs;          // Sample time
        int l = trama.Length;       // Length of signal

        // Time vector
        //Vector t = Normal(0, l, 1) * t1;

        //// Values vector
        //Vector y = new Vector(trama);

        // We just use half of the data as the other half is simetric. The middle is found in NFFT/2 + 1
        int nFFT = (int)Math.Pow(2, NextPow2(l));

        if (nFFT > 655600)
        { }

        // Create complex array for FFT transformation. Use 0s for imaginary part
        Complex[] samples = new Complex[nFFT];
        for (int i = 0; i < nFFT; i++)
        {
            if (i >= trama.Length)
            {
                samples[i] = new MathNet.Numerics.Complex(0, 0);
            }
            else
            {
                samples[i] = new MathNet.Numerics.Complex(trama[i], 0);
            }
        }

        ComplexFourierTransformation fft = new ComplexFourierTransformation(TransformationConvention.Matlab);
        fft.TransformForward(samples);
        ComplexVector s = new ComplexVector(samples);
        s = s / l;

        Vector f = (fs / 2.0) * Linspace(0, 1, (nFFT / 2) + 1);
        VectorDPoint result = new VectorDPoint();

        for (int i = 0; i < (nFFT / 2) + 1; i++)
        {
            result.Add(new DPoint(f[i], 2 * s[i].Modulus));
        }

        s = null;
        f = null;
        samples = null;

        return result;

2) RMS

 public static double RMSCalculate(double[] channelValues, int samplesNumber, double sampleRate, DateTime currentDate)
    {
        double[] times = new double[channelValues.Length];
        double sampleTime = 0.0;
        double period = 0;


            times[0] = currentDate.Second + currentDate.Millisecond / 1000.0;
            sampleTime = 1 / sampleRate;   //s

        // Limited samples
        for (int i = 1; i < channelValues.Length; i++)
        {
            times[i] = times[i - 1] + sampleTime;
        }

        DPoint RMSValues = new DPoint();
            RMSValues.Y = 0;
            if (channelValues.Length == 1)
            {
                double x = channelValues[0];
                double y = channelValues[0];
                RMSValues = new DPoint(x, Math.Abs(y));
            }
            else
            {

                for (int i = 0; i < times.Length - 1; i++)
                {
                    period = 0;

                    if (i + 1 < times.Length)
                    {
                        RMSValues.Y += channelValues[i + 1] * channelValues[i + 1] * (times[i + 1] - times[i]);
                    }
                }

                period = times[times.Length - 1] - times[0];
                RMSValues.Y = RMSValues.Y / period;
                RMSValues.Y = Math.Sqrt(RMSValues.Y);

            }

        return RMSValues.Y;
    }
dataProcs
  • 55
  • 1
  • 13
  • Why are you multiplying the channelValues squared result by the time period in your RMS calculation? – PaulF Apr 12 '17 at 09:04
  • @PaulF: Because that's how *mean* of a time series works. For a frequency series, it ought to be the frequency sampling interval instead, but in the end the frequency internal, time interval, and number of samples are related. – Ben Voigt Apr 12 '17 at 14:37
  • @BenVoigt: with equispaced samples (as implied by the calculation of the sample period at the top of the method), then time between samples is a constant & the final calculated period will be the sample period x number of samples. So in the final calculation you would get ((sum of squares) * sampleperiod) / ((number of samples) * sampleperiod). The sample period cancels out - leaving (sum of squares) / (number of samples) - so the multiplying by the sample period is not required. – PaulF Apr 12 '17 at 15:26
  • @PaulF: Yes, the sample interval cancels. Doesn't make it wrong to include it. – Ben Voigt Apr 12 '17 at 16:59
  • @BenVoigt: It may not be wrong mathematically to include it, but looking at the issue from two other perspectives I would always avoid it. Firstly, every floating point operation performed introduces an error - in the OPs code there is an unnecessary subtraction followed by a multiplication - if this is repeated over half a million times then significant error could be introduced. Secondly performance - I don't know if OP has any time constraints, but again reducing the number of floating point calculations will be beneficial. – PaulF Apr 13 '17 at 08:56
  • @PaulF: When it comes to optimizing performance, that's only one of a lot of missed opportunities. – Ben Voigt Apr 13 '17 at 11:48
  • @PaulF sorry but I keep trying to solve this issue but I can't get how... maybe is something related to nFFT? – dataProcs Apr 17 '17 at 09:22

0 Answers0