Exemplo n.º 1
0
        /// <summary>
        /// Runs a complex FFT on the interleaved time domain IQ samples and return the FFT's magnitude in dBFS
        /// </summary>
        /// <param name="timeDataInterleavedIq">Signed 16bit array interleaved with I and Q data.  First sample is I, second sample Q.</param>
        /// <param name="sampleRate_MHz">The sampling frequency, used to scale the analysis data.</param>
        /// <param name="runAnalysis">If true, will return a FftAnalysis structure with information about the FFT</param>
        /// <param name="sampleBitWidth"> Bit width of the converter sample (example: 16bit sample)</param>
        /// <param name="analysisData">FftAnalysis struture that is returned when runAnalysis = true</param>
        /// <returns></returns>
        public static double[] complexfftAndScale(short[] timeDataInterleavedIq, double sampleRate_MHz, byte sampleBitWidth, bool runAnalysis, out FftAnalysis analysisData)
        {
            int numSamples = timeDataInterleavedIq.Length / 2;

            double[] fftReal;
            double[] fftImag;
            double[] fftMagnitude_dB = new double[numSamples];
            analysisData = new FftAnalysis();
            double AdcFullScaleCode = System.Math.Pow(2, (sampleBitWidth - 1)); //2^(16-1) for 16bit converter ...assumming two's complement

            //ScaledWindowType window = ScaledWindowType.Hanning;
            ScaledWindow window = ScaledWindow.CreateHanningWindow();


            ComplexDouble[] complexSignal = new ComplexDouble[numSamples];
            int             j             = 0;

            //determine scaling value to normalize the time domain data.
            ComplexDouble scaleValue = new ComplexDouble(AdcFullScaleCode * (numSamples) * Math.Sqrt(window.EquivalentNoiseBandwidth), 0);

            //deinterleave IQ data array into complex number data type and normalize data.
            for (int i = 0; i < complexSignal.Length; i++)
            {
                complexSignal[i] = new ComplexDouble(timeDataInterleavedIq[j], timeDataInterleavedIq[j + 1]);
                complexSignal[i] = complexSignal[i].Divide(scaleValue);
                j = j + 2;
            }

            //Apply the Window (Default hanning)
            window.Apply(complexSignal);

            ComplexDouble[] fftData = Transforms.Fft(complexSignal, true);
            NationalInstruments.ComplexDouble.DecomposeArray(fftData, out fftReal, out fftImag);

            if (runAnalysis == true)
            {
                analysisData = analyzeFft(fftReal, fftImag, sampleRate_MHz);
            }
            else
            {
                analysisData = new FftAnalysis();
            }

            for (int i = 0; i < numSamples; i++)
            {
                fftMagnitude_dB[i] = 10.0 * System.Math.Log10(fftReal[i] * fftReal[i] + fftImag[i] * fftImag[i]);
            }

            return(fftMagnitude_dB);
        }
Exemplo n.º 2
0
        /// <summary>
        /// This function returns some basic FFT analysis results such as Fundamental Frequency, power, image power, and DC offset
        /// </summary>
        /// <param name="fftReal">The voltage domain (not Log10) real fft data from the complex FFT routine.</param>
        /// <param name="fftImag">The voltage domain (not Log10) imaginary fft data from the complex FFT routine.</param>
        /// <param name="sampleRate_MHz">The sampling frequency of the data converter in MHz</param>
        /// <returns></returns>
        public static FftAnalysis analyzeFft(double[] fftReal, double[] fftImag, double sampleRate_MHz)
        {
            int numBins = fftReal.Length;

            double fundamentalMag   = 0;
            double fundamentalIndex = 0;
            double fftMag           = 0;

            double[]    returnData   = new double[3];
            FftAnalysis analysisData = new FftAnalysis();

            for (int fftBin = 0; fftBin < numBins; fftBin++)
            {
                //Find bin with largest amplitude (fundamental)
                fftMag = fftReal[fftBin] * fftReal[fftBin] + fftImag[fftBin] * fftImag[fftBin];
                if ((fftBin <= (numBins / 2 - 2)) || (fftBin >= (numBins / 2 + 2)))
                {
                    if (fftMag > fundamentalMag)
                    {
                        fundamentalMag   = fftMag;
                        fundamentalIndex = fftBin;
                    }
                }
            }

            double startF = (-1 * sampleRate_MHz / 2);
            double deltaF = (sampleRate_MHz / numBins);

            analysisData.FundamentalPeak_dBFS     = 10 * System.Math.Log10(fundamentalMag);
            analysisData.FundamentalFrequency_MHz = (startF + (fundamentalIndex * deltaF));

            //sum Fundamental power over 5 bins
            int binsToSum = 5;
            int startBin  = (int)(fundamentalIndex - System.Math.Floor((double)(binsToSum / 2)));
            int stopBin   = (int)(fundamentalIndex + System.Math.Floor((double)(binsToSum / 2)));

            if (startBin < 0)
            {
                startBin = 0;
            }
            if (stopBin >= fftReal.Length)
            {
                stopBin = fftReal.Length - 1;
            }

            double sum = 0;

            for (int fftBin = startBin; fftBin <= stopBin; fftBin++)
            {
                fftMag = fftReal[fftBin] * fftReal[fftBin] + fftImag[fftBin] * fftImag[fftBin];
                sum   += fftMag;
            }
            analysisData.FundamentalPower_dBFS = 10 * System.Math.Log10(sum);

            //Calculate image power over 5 bins
            int imageIndex = (int)(((analysisData.FundamentalFrequency_MHz * -1) - startF) / deltaF);

            binsToSum = 5;
            startBin  = (int)(imageIndex - System.Math.Floor((double)(binsToSum / 2)));
            stopBin   = (int)(imageIndex + System.Math.Floor((double)(binsToSum / 2)));
            if (startBin < 0)
            {
                startBin = 0;
            }
            if (stopBin >= fftReal.Length)
            {
                stopBin = fftReal.Length - 1;
            }

            sum = 0;
            for (int fftBin = startBin; fftBin <= stopBin; fftBin++)
            {
                fftMag = fftReal[fftBin] * fftReal[fftBin] + fftImag[fftBin] * fftImag[fftBin];
                sum   += fftMag;
            }
            analysisData.ImagePower_dBFS = 10 * System.Math.Log10(sum);
            analysisData.ImagePower_dBm  = analysisData.FundamentalPower_dBFS - analysisData.ImagePower_dBFS;


            //Calculate DC Offset power over 5 bins
            int DCOffsetIndex = numBins / 2;

            binsToSum = 5;
            startBin  = (int)(DCOffsetIndex - System.Math.Floor((double)(binsToSum / 2)));
            stopBin   = (int)(DCOffsetIndex + System.Math.Floor((double)(binsToSum / 2)));
            if (startBin < 0)
            {
                startBin = 0;
            }
            if (stopBin >= fftReal.Length)
            {
                stopBin = fftReal.Length - 1;
            }

            sum = 0;
            for (int fftBin = startBin; fftBin <= stopBin; fftBin++)
            {
                fftMag = fftReal[fftBin] * fftReal[fftBin] + fftImag[fftBin] * fftImag[fftBin];
                sum   += fftMag;
            }
            analysisData.DcOffset_dBFS = 10 * System.Math.Log10(sum);

            return(analysisData);
        }