/// <summary>
        /// 计算时域信号的复数频谱,包含幅度谱和相位谱信息
        /// </summary>
        /// <param name="waveform">时域波形数据</param>
        /// <param name="windowType">窗类型</param>
        /// <param name="spectrum">计算后的复数频谱数据</param>
        public static void AdvanceComplexFFT(double[] waveform, WindowType windowType, ref Complex[] spectrum)
        {
            if (waveform == null || spectrum == null || spectrum.Length < (waveform.Length / 2 + 1))
            {
                throw new JYDSPUserBufferException();
            }

            int    n = waveform.Length, windowsize = waveform.Length; //做FFT的次数
            int    fftsize = windowsize;                              //做FFT点数
            double cg = 0, enbw = 0;

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

            xInTmp = new double[fftsize];

            GCHandle gchXIn  = GCHandle.Alloc(waveform, GCHandleType.Pinned);
            var      xInPtr  = gchXIn.AddrOfPinnedObject();
            GCHandle gchXout = GCHandle.Alloc(spectrum, GCHandleType.Pinned);
            var      xOutPtr = gchXout.AddrOfPinnedObject();

            try
            {
                //生成窗函数的数据
                windowData = new double[windowsize];
                Window.GetWindow(windowType, ref windowData, out cg, out enbw);
                CBLASNative.cblas_dscal(windowsize, 1 / cg, windowData, 1); //窗系数归一化
                CBLASNative.cblas_dscal(spectrum.Length, 0, xOutPtr, 1);    //将xOut清零
                /*TIME_DOMAIN_WINDOWS(windowType, x_in, &CG, &ENBW, windowsize);*//*(double*)(xIn + i * windowsize)*/
                VMLNative.vdMul(windowsize, windowData, xInPtr, xInTmp);
                BasicFFT.RealFFT(xInTmp, ref spectrum);
            }
            finally
            {
                gchXIn.Free();
                gchXout.Free();
            }
        }
        /// <summary>
        /// 计算时域信号的复数频谱,包含幅度谱和相位谱信息
        /// </summary>
        /// <param name="waveform">时域波形数据</param>
        /// <param name="spectralLines">频谱线的条数</param>
        /// <param name="windowType">窗类型</param>
        /// <param name="spectrum">计算后的复数频谱数据</param>
        /// <param name="spectralInfo">返回的频谱数据的参数信息</param>
        public static void AdvanceComplexFFT(double[] waveform, int spectralLines, WindowType windowType,
                                             double[] spectrum, ref SpectralInfo spectralInfo)
        {
            int    n = waveform.Length, windowsize = 0, fftcnt = 0; //做FFT的次数
            int    fftsize = 0;                                     //做FFT点数
            double cg = 0, enbw = 0, scale = 0.0;

            double[]  xInTmp     = null;
            double[]  windowData = null;
            Complex[] 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 (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);
            CBLASNative.cblas_dscal(windowsize, 1 / cg, windowData, 1); //窗系数归一化
            CBLASNative.cblas_dscal(spectrum.Length, 0, spectrum, 1);   //将xOut清零
            GCHandle gch    = GCHandle.Alloc(waveform, 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)*/
                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);

                //每次计算结果累加起来
                VMLNative.vdAdd(spectralLines, xInTmp, spectrum, spectrum);
            }

            scale = 2 * (1.0 / fftcnt) / Sqrt2; //双边到单边有一个二倍关系,输出为Vrms要除以根号2

            //fftcnt次的频谱做平均
            CBLASNative.cblas_dscal(spectralLines, scale, spectrum, 1);

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

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