Пример #1
0
        /// <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();
            }
        }
Пример #2
0
        /// <summary>
        /// 频谱单位转换函数
        /// </summary>
        /// <param name="spectrum">输入频谱,单位转换后返回的序列也保存在里面</param>
        /// <param name="spectrumType">输入频谱类型,功率谱或者幅度谱</param>
        /// <param name="df">频谱间隔</param>
        /// <param name="unitSetting">单位转换设置</param>
        /// <param name="equivalentNoiseBw">计算频谱时,加窗所用窗函数的等效噪声带宽</param>
        /// <returns></returns>
        private static void UnitConversion(double[] spectrum, double df, SpectrumType spectrumType,
                                           UnitConvSetting unitSetting, double equivalentNoiseBw)
        {
            double scale = 1.0;
            int    freq0Idx = 0, N = spectrum.Length;

            //VMLNative.vdSqr(N, spectrum, spectrum);

            if (unitSetting.PeakScaling == PeakScaling.Peak) //峰峰值要乘以2
            {
                switch (spectrumType)
                {
                case SpectrumType.Amplitude:     // Sqrt2
                    scale *= Sqrt2;
                    break;

                case SpectrumType.Power:     // 2
                    scale *= 2;
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(spectrumType), spectrumType, null);
                }
                CBLASNative.cblas_dscal(N, scale, spectrum, 1);
                spectrum[0] /= scale; //零频不用
            }

            //根据设置的转换单位进行转换
            switch (unitSetting.Unit)
            {
            case SpectrumUnits.V:
            {
                if (SpectrumType.Power == spectrumType)
                {
                    VMLNative.vdSqrt(N, spectrum, spectrum);
                }
                break;
            }

            case SpectrumUnits.dBV:
            {
                if (SpectrumType.Power == spectrumType)
                {
                    VMLNative.vdSqrt(N, spectrum, spectrum);
                }
                //lg
                VMLNative.vdLog10(N, spectrum, spectrum);
                scale = 20;
                //20*lg
                CBLASNative.cblas_dscal(N, scale, spectrum, 1);
                break;
            }

            case SpectrumUnits.dBmV:
            {
                if (SpectrumType.Power == spectrumType)
                {
                    VMLNative.vdSqrt(N, spectrum, spectrum);
                }
                CBLASNative.cblas_dscal(N, 1e3, spectrum, 1);        //V To mV
                VMLNative.vdLog10(N, spectrum, spectrum);            //To Lg
                scale = 20;

                CBLASNative.cblas_dscal(N, scale, spectrum, 1);         //To 20*Lg
                break;
            }

            case SpectrumUnits.dBuV:
            {
                if (SpectrumType.Power == spectrumType)
                {
                    VMLNative.vdSqrt(N, spectrum, spectrum);
                }
                CBLASNative.cblas_dscal(N, 1e6, spectrum, 1);    //V To uV
                VMLNative.vdLog10(N, spectrum, spectrum);        //To Lg
                scale = 20;
                CBLASNative.cblas_dscal(N, scale, spectrum, 1);  //To 20*Lg
                break;
            }

            case SpectrumUnits.V2:
            {
                if (SpectrumType.Amplitude == spectrumType)
                {
                    VMLNative.vdSqr(N, spectrum, spectrum);
                }
                break;
            }

            case SpectrumUnits.W:
            case SpectrumUnits.dBW:
            case SpectrumUnits.dBm:
            {
                if (SpectrumType.Amplitude == spectrumType)
                {
                    VMLNative.vdSqr(N, spectrum, spectrum);
                }
                scale = 1.0 / unitSetting.Impedance;                 //1/R
                CBLASNative.cblas_dscal(N, scale, spectrum, 1);      //W = V^2/R

                if (unitSetting.Unit == SpectrumUnits.dBW)           //dBW = 20lgW
                {
                    //lg
                    VMLNative.vdLog10(N, spectrum, spectrum);
                    scale = 20;
                    //20*lg
                    CBLASNative.cblas_dscal(N, scale, spectrum, 1);
                }
                else if (unitSetting.Unit == SpectrumUnits.dBm)         // dBm = 10lg(W/1mW)
                {
                    CBLASNative.cblas_dscal(N, 1e3, spectrum, 1);       // W/1mW
                                                                        //lg
                    VMLNative.vdLog10(N, spectrum, spectrum);
                    scale = 10;
                    //10*lg
                    CBLASNative.cblas_dscal(N, scale, spectrum, 1);
                }
                break;
            }

            default:
            {
                break;
            }
            }
            if (!unitSetting.PSD)
            {
                return;
            }
            //谱密度计算
            scale = 1.0 / (equivalentNoiseBw * df);
            CBLASNative.cblas_dscal(N, scale, spectrum, 1);
        }
Пример #3
0
        /// <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();
        }
Пример #4
0
        public static void GetWindow(WindowType windowType, ref double[] windowdata,
                                     out double CG, out double ENBW)
        {
            if (windowdata == null || windowdata.Length <= 0)
            {
                throw new JYDSPUserBufferException("windowdata length is null!");
            }
            int size = windowdata.Length;

            double[] windowTmp = null;
            for (int i = 0; i < size; i++)
            {
                windowdata[i] = i;
            }
            var pi2DSize = Math.PI * 2 / size;
            var pi4DSize = pi2DSize * 2.0;

            CG   = 1;
            ENBW = 0;
            //根据windowType:窗函数类型产生单位窗函数
            //CG:相干增益 ENBW:等效噪声宽度
            switch (windowType)
            {
            case WindowType.Hanning:    //汉宁窗
                //for (i = 0; i < size; i++)//产生单位窗函数
                //{
                //    windowdata[i] = 0.5 * (1 - cos(2 * M_PI * i / size));
                //}
                //汉宁窗公式:W[i]=1/2*[1-cos(2 * M_PI * i / size)] = 0.5 - 0.5 * cos(2 * M_PI * i / size);
                CBLASNative.cblas_dscal(size, pi2DSize, windowdata, 1);     //2 * M_PI * i / size
                VMLNative.vdCos(size, windowdata, windowdata);              //cos(2 * M_PI * i / size)
                CBLASNative.cblas_dscal(size, -0.5, windowdata, 1);         //-0.5 * cos(2 * M_PI * i / size)
                for (int i = 0; i < size; i++)                              //0.5 - 0.5 * cos(2 * M_PI * i / size);
                {
                    windowdata[i] += 0.5;
                }
                CG   = 0.5;  //汉宁窗的相干增益:0.5
                ENBW = 1.5;  //汉宁窗的等效噪声宽度;1.5
                break;

            case WindowType.Hamming:    //海明窗
                //for (int i = 0; i < size; i++)//产生单位窗函数
                //{
                //    windowdata[i] = 0.54 - 0.46 * cos(2 * M_PI * i / size);//海明窗公式:W[i]=0.54 -0.46cos(2iπ/N);
                //}
                //0.54 - 0.46 * cos(2 * M_PI * i / size)
                CBLASNative.cblas_dscal(size, pi2DSize, windowdata, 1);     //2 * M_PI * i / size
                VMLNative.vdCos(size, windowdata, windowdata);              //cos(2 * M_PI * i / size)
                CBLASNative.cblas_dscal(size, -0.46, windowdata, 1);        //-0.46 * cos(2 * M_PI * i / size)
                for (int i = 0; i < size; i++)                              //0.54 - 0.46 * cos(2 * M_PI * i / size);
                {
                    windowdata[i] += 0.54;
                }

                CG   = 0.54;    //海明窗的相干增益:0.54
                ENBW = 1.36283; //海明窗的等效噪声宽度:1.36283
                break;

            case WindowType.Blackman_Harris:    // Blackman_Harris窗
                //for (i = 0; i < size; i++)//产生单位窗函数
                //{
                //    windowdata[i] = 0.42323 - 0.49755 * cos(2 * M_PI * i / size) + 0.07922 * cos(4 * M_PI * i / size);// Blackman_Harris窗公式:W[i]=0.42323-0.49755cos⁡2iπ/N+0.07922cos4iπ/N;
                //}
                CBLASNative.cblas_dscal(size, pi2DSize, windowdata, 1);     //2 * M_PI * i / size
                VMLNative.vdCos(size, windowdata, windowdata);              //cos(2 * M_PI * i / size)
                CBLASNative.cblas_dscal(size, -0.49755, windowdata, 1);     //-0.49755 * cos(2 * M_PI * i / size)
                windowTmp = new double[size];
                for (int i = 0; i < size; i++)
                {
                    windowdata[i] += 0.42323;
                    windowTmp[i]   = i;
                }

                CBLASNative.cblas_dscal(size, pi4DSize, windowTmp, 1);    //4 * M_PI * i / size
                VMLNative.vdCos(size, windowTmp, windowTmp);              //cos(4 * M_PI * i / size)
                CBLASNative.cblas_dscal(size, 0.07922, windowTmp, 1);     //0.07922 * cos(4 * M_PI * i / size)
                VMLNative.vdAdd(size, windowTmp, windowdata, windowdata); //0.42323 - 0.49755 * Math.Cos(2 * Math.PI * i / size) + 0.07922 * Math.Cos(4 * Math.PI * i / size);

                CG   = 0.42323;                                           // Blackman_Harris窗的相干增益:0.42323
                ENBW = 1.708538;                                          // Blackman_Harris窗的等效噪声宽度:1.708538
                break;

            case WindowType.Exact_Blackman:    //Exact Blackman窗
                //for (i = 0; i < size; i++)//产生单位窗函数
                //{
                //    windowdata[i] = 0.42659 - 0.49656 * cos(2 * M_PI * i / size) + 0.07684 * cos(4 * M_PI * i / size);//Exact Blackman窗公式:W[i]=7938/18608-(9240/18608)*cos⁡2iπ/N+(1430/18608)*cos⁡4iπ/N;
                //}
                CBLASNative.cblas_dscal(size, pi2DSize, windowdata, 1);     //2 * M_PI * i / size
                VMLNative.vdCos(size, windowdata, windowdata);              //cos(2 * M_PI * i / size)
                CBLASNative.cblas_dscal(size, -0.49656, windowdata, 1);     //-0.49656 * cos(2 * M_PI * i / size)
                windowTmp = new double[size];
                for (int i = 0; i < size; i++)                              //0.42659 - 0.49656 * cos(2 * M_PI * i / size);
                {
                    windowdata[i] += 0.42659;
                    windowTmp[i]   = i;
                }

                CBLASNative.cblas_dscal(size, pi4DSize, windowTmp, 1);    //4 * M_PI * i / size
                VMLNative.vdCos(size, windowTmp, windowTmp);              //cos(4 * M_PI * i / size)
                CBLASNative.cblas_dscal(size, 0.07684, windowTmp, 1);     //0.07684 * cos(4 * M_PI * i / size)
                VMLNative.vdAdd(size, windowTmp, windowdata, windowdata); //0.42659 - 0.49656 * Math.Cos(2 * Math.PI * i / size) + 0.07684 * Math.Cos(4 * Math.PI * i / size);

                CG   = 0.42659;                                           //Exact Blackman窗的相干增益:0.42659
                ENBW = 1.69369;                                           //Exact Blackman窗的等效噪声宽度:1.69369
                break;

            case WindowType.Blackman:    //Blackman窗
                //for (i = 0; i < size; i++)//产生单位窗函数
                //{
                //    windowdata[i] = 0.42 - 0.5 * cos(2 * M_PI * i / size) + 0.08 * cos(4 * M_PI * i / size);//Blackman窗公式:W[i]=0.42-0.5cos2iπ/N+0.08cos4iπ/N;
                //}
                CBLASNative.cblas_dscal(size, pi2DSize, windowdata, 1);     //2 * M_PI * i / size
                VMLNative.vdCos(size, windowdata, windowdata);              //cos(2 * M_PI * i / size)
                CBLASNative.cblas_dscal(size, -0.5, windowdata, 1);         //-0.5 * cos(2 * M_PI * i / size)
                windowTmp = new double[size];
                for (int i = 0; i < size; i++)                              //0.42 - 0.5 * cos(2 * M_PI * i / size);
                {
                    windowdata[i] += 0.42;
                    windowTmp[i]   = i;
                }

                CBLASNative.cblas_dscal(size, pi4DSize, windowTmp, 1);    //4 * M_PI * i / size
                VMLNative.vdCos(size, windowTmp, windowTmp);              //cos(4 * M_PI * i / size)
                CBLASNative.cblas_dscal(size, 0.08, windowTmp, 1);        //0.08 * cos(4 * M_PI * i / size)
                VMLNative.vdAdd(size, windowTmp, windowdata, windowdata); //0.42 - 0.5 * Math.Cos(2 * Math.PI * i / size) + 0.08 * Math.Cos(4 * Math.PI * i / size);

                CG   = 0.42;                                              //Blackman窗的相干增益:0.42
                ENBW = 1.72676;                                           //Blackman窗的等效噪声宽度:1.72676
                break;

            case WindowType.Flat_Top:          //平顶窗
                for (int i = 0; i < size; i++) //产生单位窗函数
                {
                    windowdata[i] = 0.21558 - 0.41663 * Math.Cos(2 * Math.PI * i / size)
                                    + 0.27726 * Math.Cos(4 * Math.PI * i / size)
                                    - 0.08358 * Math.Cos(6 * Math.PI * i / size)
                                    + 0.00695 * Math.Cos(8 * Math.PI * i / size);
                    //平顶窗的公式:W(i)=0.21557895-0.41663158cos⁡2iπ/N+0.277263158cos⁡4iπ/N-0.083578947cos⁡6iπ/N+0.006947368cos⁡8iπ/N;
                }

                CG   = 0.22;   //平顶窗的相干增益:0.22
                ENBW = 3.77;   //平顶窗的等效噪声宽度:3.77
                break;

            case WindowType.Four_Term_B_Harris:   //4 Term B-Harris窗

                for (int i = 0; i < size; i++)    //产生单位窗函数
                {
                    windowdata[i] = 0.35875 - 0.48829 * Math.Cos(2 * Math.PI * i / size)
                                    + 0.14128 * Math.Cos(4 * Math.PI * i / size)
                                    - 0.01168 * Math.Cos(6 * Math.PI * i / size);
                    //4 Term B-Harris窗的公式:W(i)=0.35875-0.48829cos⁡2iπ/N+0.14128cos⁡4iπ/N-0.01168cos⁡6iπ/N;
                }
                CG   = 0.35875;  //4 Term B-Harris窗的相干增益:0.35875
                ENBW = 2.00435;  //4 Term B-Harris窗的等效噪声宽度:2.00435
                break;

            //7 Term B-Harris窗
            case WindowType.Seven_Term_B_Harris:
                for (int i = 0; i < size; i++)    //产生单位窗函数
                {
                    windowdata[i] = 0.27105 - 0.43329793923448 * Math.Cos(1 * 2 * Math.PI * i / size)
                                    + 0.21812299954311 * Math.Cos(2 * 2 * Math.PI * i / size)
                                    - 0.06592544638803 * Math.Cos(3 * 2 * Math.PI * i / size)
                                    + 0.01081174209837 * Math.Cos(4 * 2 * Math.PI * i / size)
                                    - 0.00077658482522 * Math.Cos(5 * 2 * Math.PI * i / size)
                                    + 0.00001388721735 * Math.Cos(6 * 2 * Math.PI * i / size);
                }
                CG   = 0.27105;  //7 Term B-Harris窗的相干增益:0.27105140069
                ENBW = 2.63191;  //7 Term B-Harris窗的等效噪声宽度:2.631905
                break;

            //      //Low_sidelobe窗
            //case Low_sidelobe://无
            //	      //break;

            //other 默认矩形窗
            //矩形窗
            case WindowType.None:
                for (int i = 0; i < size; i++)    //产生单位窗函数
                {
                    windowdata[i] = 1.0;
                }

                CG   = 1.0;   //矩形窗的相干增益:1.0
                ENBW = 1.0;   //矩形窗的等效噪声宽度:1.0
                break;

            default:
                throw new JYDSPParamException("Window type is out of range!");
            }
        }