C#入门 公式法和FFT法求解DTMF信号的DFT

一、涉及数字信号处理公式

离散傅里叶变换定义式
X [ k ] = ∑ n = 0 N − 1 x [ n ] e − j 2 π k n N X[k] = \sum_{n=0}^{N-1}x[n]e^{-j\frac{2\pi kn}{N}} X[k]=n=0N1x[n]ejN2πkn

W N = e − j 2 π N W_{N} = e^{-j\frac{2\pi }{N} } WN=ejN2π

X [ k ] = ∑ n = 0 N − 1 x [ n ] W N k n X[k] = \sum_{n=0}^{N-1}x[n]W_{N}^{kn} X[k]=n=0N1x[n]WNkn
x1[n]由x[n]的奇数项组成
x2[n]由x[n]的偶数项组成

X [ k ] = ∑ n = 0 N 2 − 1 x 1 [ n ] W N / 2 k n + W N k ∑ n = 0 N 2 − 1 x 2 [ n ] W N / 2 k n X[k] = \sum_{n=0}^{\frac{N}{2} -1}x_{1} [n]W_{N/2}^{kn} +W_{N}^{k} \sum_{n=0}^{\frac{N}{2} -1}x_{2} [n]W_{N/2}^{kn} X[k]=n=02N1x1[n]WN/2kn+WNkn=02N1x2[n]WN/2kn

X [ k ] = X 1 [ k ] + W N k X 2 [ k ] X[k] = X_{1} [k] +W_{N}^{k} X_{2} [k] X[k]=X1[k]+WNkX2[k]

二、 程序源码

using MathNet.Numerics;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace dft
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            //使用Math.net类库


            //生成测试信号
            //DTMF信号1
            //697Hz+1209Hz
            //采样率使用5K
            List<Complex32> signal1 = new List<Complex32>();
            for (int i = 0; i < 5000; i++)
            {
                double data = Math.Sin(2 * Math.PI * 697 * i / 5000) + Math.Sin(2 * Math.PI * 1209 * i / 5000);
                Complex32 complexData = new Complex32((float)data,0);
                signal1.Add(complexData);
            }

            //绘制信号
            for (int i = 0; i < 100; i++)
            {
                chart1.Series[0].Points.AddXY(((double)i/5000)+"s", Complex32.Abs(signal1[i]));
            }

            //扩展信号长度到2的整数次幂
            List<Complex32> signal1_expand = expand(signal1);


            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();

            TimeSpan span = stopWatch.Elapsed;
            double endTime0 = span.TotalMilliseconds;

            //DFT变换(使用公式)未扩展信号
            List<Complex32> dftResult1 = dft(signal1);

            //stopWatch.Stop();
            span = stopWatch.Elapsed;
            //Console.WriteLine(span.TotalMilliseconds);
            double endTime1 = span.TotalMilliseconds;

            //DFT变换(使用公式)扩展长度信号
            List<Complex32> dftResult2 = dft(signal1_expand);
            span = stopWatch.Elapsed;
            //Console.WriteLine(span.TotalMilliseconds);
            double endTime2 = span.TotalMilliseconds;

            //FFT
            List <Complex32> fftResult = fft(signal1_expand);
            span = stopWatch.Elapsed;
            //Console.WriteLine(span.TotalMilliseconds);
            double endTime3 = span.TotalMilliseconds;

            Console.WriteLine(endTime1-endTime0);
            Console.WriteLine(endTime2-endTime1);
            Console.WriteLine(endTime3-endTime2);

            //绘制dft
            for (int i = 0; i < dftResult1.Count/2; i++)
            {
                chart2.Series[0].Points.AddXY(i * 5000 / dftResult1.Count , Complex32.Abs(dftResult1[i]));
            }
            for (int i = 0; i < dftResult2.Count / 2; i++)
            {
                chart2.Series[1].Points.AddXY(i * 5000 / dftResult2.Count, Complex32.Abs(dftResult2[i]));
            }

            //绘制fft
            for (int i = 0; i < fftResult.Count / 2; i++)
            {
                chart3.Series[0].Points.AddXY(i * 5000 / fftResult.Count, Complex32.Abs(fftResult[i]));
            }
        }


        长度扩充到2的整数次幂
        public List<Complex32> expand(List<Complex32> signal)
        {
            int targetLength = 2;
            while (targetLength < signal.Count)
            {
                targetLength = targetLength * 2;
            }

            //补0
            while (targetLength != signal.Count)
            {
                signal.Add(new Complex32(0, 0));
            }

            return signal;
        }

        //使用公式
        public List<Complex32> dft(List<Complex32> signal)
        {
            List<Complex32> dftResult = new List<Complex32>();


            int N = signal.Count;

            for (int k=0; k<signal.Count;k++)
            {
                Complex32 dftItem = new Complex32(0,0);
                for (int n=0; n<signal.Count;n++)
                {
                    Complex32 temp = new Complex32(0,(float)(-2 * Math.PI * k * n / N));
                    temp = Complex32.Multiply(signal[n], Complex32.Exp(temp));

                    dftItem = Complex32.Add(dftItem, temp);
                }
                dftResult.Add(dftItem);
            }

            return dftResult;
        }


        //fft
        //递归方式实现
        //signal的长度为2的整数次幂
        public List<Complex32> fft(List<Complex32> signal)
        {
            List<Complex32> fftResult = new List<Complex32>();
            List<Complex32> tempList = new List<Complex32>();

            List<Complex32> list1 = new List<Complex32>();
            List<Complex32> list2 = new List<Complex32>();


            if (signal.Count == 2)
            {
                return dft(signal);
            }

            //奇偶分解
            for (int i=0; i<signal.Count;i++)
            {
                if (i % 2 == 0)
                {
                    list1.Add(signal[i]);
                }
                else
                {
                    list2.Add(signal[i]);
                }
            }

            List<Complex32> fftResult1 = fft(list1);
            List<Complex32> fftResult2 = fft(list2);

            int N = signal.Count;
            for(int k=0; k<fftResult1.Count; k++)
            {
                Complex32 temp = new Complex32(0, (float)(-2 * Math.PI * k / N));
                Complex32 wnkfftResult2 = Complex32.Multiply(fftResult2[k], Complex32.Exp(temp));

                //Complex32 tempData = fftResult1[k] + wnkfftResult2;

                fftResult.Add(Complex32.Add(fftResult1[k],wnkfftResult2));
                tempList.Add(Complex32.Add(fftResult1[k],Complex32.Negate(wnkfftResult2)));
            }

            fftResult.AddRange(tempList);
            return fftResult;
        }




    }
}

三、 波形截图

在这里插入图片描述

四、 耗时分析

6285.2976
DFT 耗时6274.406
FFT 耗时13.1182000000008
FFT效率远高于公式法直接计算
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值