Beispiel #1
0
        /// <summary>
        /// <para>Computes the power spectrum of input time-domain signal.</para>
        /// <para>Chinese Simplified: 计算输入信号的功率频谱。</para>
        /// </summary>
        /// <param name="x">
        /// <para>input time-domain signal.</para>
        /// <para>Chinese Simplified: 输入的时域波形。</para>
        /// </param>
        /// <param name="samplingRate">
        /// <para>sampling rate of the input time-domain signal, in samples per second.</para>
        /// <para>Chinese Simplified: 输入信号的采样率,以S/s为单位。</para>
        /// </param>
        /// <param name="spectrum">
        /// <para>output sequence containing the power spectrum.</para>
        /// <para>Chinese Simplified: 输出功率谱。</para>
        /// </param>
        /// <param name="df">
        /// <para>the frequency resolution of the spectrum,  in hertz.</para>
        /// <para>Chinese Simplified: 功率谱的频谱间隔,以Hz为单位。</para>
        /// </param>
        /// <param name="unitSettings">
        /// <para>unit settings of the output power spectrum</para>
        /// <para>Chinese Simplified: 设置功率谱的单位。</para>
        /// </param>
        /// <param name="windowType">
        /// <para>the time-domain window to apply to the time signal.</para>
        /// <para>Chinese Simplified: 窗类型。</para>
        /// </param>
        /// <param name="windowPara">
        /// <para>parameter for a Kaiser/Gaussian/Dolph-Chebyshev window, If window is any other window, this parameter is ignored</para>
        /// <para>Chinese Simplified: 窗调整系数,仅用于Kaiser/Gaussian/Dolph-Chebyshev窗。</para>
        /// </param>
        public static void PowerSpectrum(double[] x, double samplingRate, ref double[] spectrum, out double df,
                                         UnitConvSetting unitSettings, WindowType windowType, double windowPara)
        {
            int          spectralLines = spectrum.Length; //谱线数是输出数组的大小
            SpectralInfo spectralInfo  = new SpectralInfo();

            AdvanceRealFFT(x, spectralLines, windowType, spectrum, ref spectralInfo);

            double scale = 1.0 / spectralInfo.FFTSize;

            //CBLASNative.cblas_dscal(spectralLines, scale, spectrum, 1);
            for (int i = 0; i < spectrum.Length; i++)
            {
                spectrum[i] = spectrum[i] * scale;
            }

            df = 0.5 * samplingRate / spectralInfo.spectralLines; //计算频率间隔

            //Unit Conversion
            UnitConversion(spectrum, df, SpectrumType.Amplitude, unitSettings, Window.WindowENBWFactor[(int)windowType]);
        }
Beispiel #2
0
        /// <summary>
        /// <para>Computes the power spectrum of input time-domain signal.</para>
        /// <para>Chinese Simplified: 计算输入信号的功率频谱。</para>
        /// </summary>
        /// <param name="x">
        /// <para>input time-domain signal.</para>
        /// <para>Chinese Simplified: 输入的时域波形。</para>
        /// </param>
        /// <param name="samplingRate">
        /// <para>sampling rate of the input time-domain signal, in samples per second.</para>
        /// <para>Chinese Simplified: 输入信号的采样率,以S/s为单位。</para>
        /// </param>
        /// <param name="spectrum">
        /// <para>output sequence containing the power spectrum.</para>
        /// <para>Chinese Simplified: 输出功率谱。</para>
        /// </param>
        /// <param name="df">
        /// <para>the frequency resolution of the spectrum,  in hertz.</para>
        /// <para>Chinese Simplified: 功率谱的频谱间隔,以Hz为单位。</para>
        /// </param>
        /// <param name="unit">
        /// <para>unit of the output power spectrum</para>
        /// <para>Chinese Simplified: 设置功率谱的单位。</para>
        /// </param>
        /// <param name="windowType">
        /// <para>the time-domain window to apply to the time signal.</para>
        /// <para>Chinese Simplified: 窗类型。</para>
        /// </param>
        /// <param name="windowPara">
        /// <para>parameter for a Kaiser/Gaussian/Dolph-Chebyshev window, If window is any other window, this parameter is ignored</para>
        /// <para>Chinese Simplified: 窗调整系数,仅用于Kaiser/Gaussian/Dolph-Chebyshev窗。</para>
        /// </param>
        /// <param name="PSD">
        /// <para>specifies whether the output power spectrum is converted to power spectral density.</para>
        /// <para>Chinese Simplified: 输出的频谱是否为功率谱密度。</para>
        /// </param>
        public static void PowerSpectrum(double[] x, double samplingRate, ref double[] spectrum, out double df,
                                         SpectrumUnits unit = SpectrumUnits.V2, WindowType windowType = WindowType.Hann,
                                         double windowPara  = double.NaN, bool PSD = false)
        {
            int          spectralLines = spectrum.Length; //谱线数是输出数组的大小
            SpectralInfo spectralInfo  = new SpectralInfo();

            AdvanceRealFFT(x, spectralLines, windowType, spectrum, ref spectralInfo);
            double scale = 1.0 / spectralInfo.FFTSize;

            //CBLASNative.cblas_dscal(spectralLines, scale, spectrum, 1);

            for (int i = 0; i < spectrum.Length; i++)
            {
                spectrum[i] *= scale;
            }
            df = 0.5 * samplingRate / spectralInfo.spectralLines; //计算频率间隔

            //Unit Conversion
            UnitConvSetting unitSettings = new UnitConvSetting(unit, PeakScaling.Rms, 50.00, PSD);

            UnitConversion(spectrum, df, SpectrumType.Amplitude, unitSettings, Window.WindowENBWFactor[(int)windowType]);
        }
Beispiel #3
0
        /// <summary>
        /// Advance Real FFT
        /// </summary>
        /// <param name="xIn">time domain data</param>
        /// <param name="spectralLines">spectralLines</param>
        /// <param name="windowType">window type</param>
        /// <param name="xOut">spectral out data</param>
        /// <param name="spectralInfo">spectral info</param>
        public static void AdvanceRealFFT(double[] xIn, int spectralLines, WindowType windowType,
                                          double[] xOut, ref SpectralInfo spectralInfo)
        {
            int    n = xIn.Length, windowsize = 0, fftcnt = 0; //做FFT的次数
            int    fftsize = 0;                                //做FFT点数
            double cg = 0, enbw = 0, scale = 0.0;

            double[] xInTmp     = null;
            double[] windowData = null;
            double[] xOutCTmp   = null;

            //输入的线数超过最大支持的线数则使用最大支持线数
            if (spectralLines > MaxSpectralLine)
            {
                spectralLines = MaxSpectralLine;
            }

            //输入的点数小于线数,则窗长度为N,先加窗再补零到2*spectralLines再做FFT
            if (n <= 2 * spectralLines)
            {
                windowsize = n;
                fftcnt     = 1;
            }
            else
            {
                windowsize = 2 * spectralLines;
                fftcnt     = n / (2 * spectralLines);
            }

            fftsize = 2 * spectralLines; //不管N与2*spectralLines的关系是怎么样,FFT的点数都应该为 2*spectralLines

            xInTmp = new double[fftsize];
            //xOutCTmp = new Complex[fftsize / 2 + 1];
            if (xInTmp.Length % 2 == 0)
            {
                xOutCTmp = new double[xInTmp.Length + 2];
            }
            else
            {
                xOutCTmp = new double[xInTmp.Length + 1];
            }

            if (n < (2 * spectralLines))
            {
                //memset(x_in + N, 0, (fftsize - N) * sizeof(double)); //补零至spectralLines
                for (int i = n; i < fftsize; i++)
                {
                    xInTmp[i] = 0;
                }
            }
            //memset(xOut, 0, spectralLines * sizeof(double));
            //生成窗函数的数据
            windowData = new double[windowsize];
            Window.GetWindow(windowType, ref windowData, out cg, out enbw);

            for (int i = 0; i < xOut.Length; i++)
            {
                xOut[i] = 0;
            }
            //CBLASNative.cblas_dscal(windowsize, 1 / cg, windowData, 1); //窗系数归一化
            //CBLASNative.cblas_dscal(xOut.Length, 0, xOut, 1); //将xOut清零
            GCHandle gch    = GCHandle.Alloc(xIn, GCHandleType.Pinned);
            var      xInPtr = gch.AddrOfPinnedObject();

            for (int i = 0; i < fftcnt; i++)
            {
                //拷贝数据到临时内存中
                //memcpy(x_in, x + i * windowsize, fftsize * sizeof(double));
                /*TIME_DOMAIN_WINDOWS(windowType, x_in, &CG, &ENBW, windowsize);*//*(double*)(xIn + i * windowsize)*/
                for (int k = 0; k < windowsize; k++)
                {
                    xInTmp[k] = windowData[k] * xIn[i * fftsize + k];
                }
                Buffer.BlockCopy(xInTmp, 0, xOutCTmp, 0, xInTmp.Length * sizeof(double));
                Fourier.ForwardReal(xOutCTmp, xInTmp.Length, FourierOptions.NoScaling);

                //VMLNative.vdMul(windowsize, windowData, xInPtr + i * fftsize * sizeof(double), xInTmp);
                //BasicFFT.RealFFT(xInTmp, ref xOutCTmp);

                ////计算FFT结果复数的模,复用x_in做中间存储
                //VMLNative.vzAbs(fftsize / 2 + 1, xOutCTmp, xInTmp);
                //xOut[0] += xOutCTmp[0];
                for (int j = 0; j < spectralLines; j++)
                {
                    xOut[j] += Math.Sqrt(xOutCTmp[2 * j + 1] * xOutCTmp[2 * j + 1] + xOutCTmp[2 * j] * xOutCTmp[2 * j]);
                }
                ////每次计算结果累加起来
                //VMLNative.vdAdd(spectralLines, xInTmp, xOut, xOut);
            }

            scale = 2 * (1.0 / fftcnt) / Sqrt2; //双边到单边有一个二倍关系,输出为Vrms要除以根号2
            for (int j = 0; j < spectralLines; j++)
            {
                xOut[j] *= scale;
            }
            ////fftcnt次的频谱做平均
            //CBLASNative.cblas_dscal(spectralLines, scale, xOut, 1);

            xOut[0] = xOut[0] / Sqrt2; //上一步零频上多除了根号2,这里乘回来(Rms在零频上不用除根号2,单双边到单边还是要乘2 ?)

            spectralInfo.spectralLines = spectralLines;
            spectralInfo.FFTSize       = fftsize;
            spectralInfo.windowSize    = windowsize;
            spectralInfo.windowType    = windowType;
            gch.Free();
        }