C# 实现 FFT 正反变换 和 频域滤波

C# 实现 FFT 正反变换 和 频域滤波

要进行FFT运算首先要构造复数类,参考

http://blog.csdn.net/iamoyjj/archive/2009/05/15/4190089.aspx

 

下面的程序在依赖上述复数类的基础上实现了FFT正反变换算法和频域滤波算法,另外由于一般如果是对实数进行FFT的话,要将FFT得到的复数数组转为实数数组,下面类中的Cmp2Mdl方法的作用就是这个。这个FFT算法是基-2FFT算法,因此,如入的序列必须是2n次方个点长。

频域滤波的基本原理是:

1、  对输入序列进行FFT

2、  得到的频谱乘以一个权函数(滤波器,系统的传递函数)

3、  得到的结果进行IFFT

4、  如果是实数运算的话用Cmp2Mdl方法转为实数

代码如下:

    /// <summary>

    /// 频率分析器

    /// </summary>

    public static class FreqAnalyzer

    {

 

        /// <summary>

        /// 求复数complex数组的模modul数组

        /// </summary>

        /// <param name=”input”>复数数组</param>

        /// <returns>模数组</returns>

        public static double[] Cmp2Mdl(Complex[] input)

        {

            ///有输入数组的长度确定输出数组的长度

            double[] output = new double[input.Length];

 

            ///对所有输入复数求模

            for (int i = 0; i < input.Length; i++)

            {

                if (input[i].Real > 0)

                {

                    output[i] = -input[i].ToModul();

                }

                else

                {

                    output[i] = input[i].ToModul();

                }

            }

 

            ///返回模数组

            return output;

        }

 

        /// <summary>

        /// 傅立叶变换或反变换,递归实现多级蝶形运算

        /// 作为反变换输出需要再除以序列的长度

        /// !注意:输入此类的序列长度必须是2^n

        /// </summary>

        /// <param name=”input”>输入实序列</param>

        /// <param name=”invert”>false=正变换,true=反变换</param>

        /// <returns>傅立叶变换或反变换后的序列</returns>

        public static Complex[] FFT(double[] input, bool invert)

        {

            ///由输入序列确定输出序列的长度

            Complex[] output = new Complex[input.Length];

 

            ///将输入的实数转为复数

            for (int i = 0; i < input.Length; i++)

            {

                output[i] = new Complex(input[i]);

            }

 

            ///返回FFTIFFT后的序列

            return output = FFT(output, invert);

        }

 

        /// <summary>

        /// 傅立叶变换或反变换,递归实现多级蝶形运算

        /// 作为反变换输出需要再除以序列的长度

        /// !注意:输入此类的序列长度必须是2^n

        /// </summary>

        /// <param name=”input”>复数输入序列</param>

        /// <param name=”invert”>false=正变换,true=反变换</param>

        /// <returns>傅立叶变换或反变换后的序列</returns>

        private static Complex[] FFT(Complex[] input, bool invert)

        {

            ///输入序列只有一个元素,输出这个元素并返回

            if (input.Length == 1)

            {

                return new Complex[] { input[0] };

            }

 

            ///输入序列的长度

            int length = input.Length;

 

            ///输入序列的长度的一半

            int half = length / 2;

 

            ///有输入序列的长度确定输出序列的长度

            Complex[] output = new Complex[length];

 

            ///正变换旋转因子的基数

            double fac = -2.0 * Math.PI / length;

 

            ///反变换旋转因子的基数是正变换的相反数

            if (invert)

            {

                fac = -fac;

            }

 

            ///序列中下标为偶数的点

            Complex[] evens = new Complex[half];

 

            for (int i = 0; i < half; i++)

            {

                evens[i] = input[2 * i];

            }

 

            ///求偶数点FFTIFFT的结果,递归实现多级蝶形运算

            Complex[] evenResult = FFT(evens, invert);

 

            ///序列中下标为奇数的点

            Complex[] odds = new Complex[half];

 

            for (int i = 0; i < half; i++)

            {

                odds[i] = input[2 * i + 1];

            }

 

            ///求偶数点FFTIFFT的结果,递归实现多级蝶形运算

            Complex[] oddResult = FFT(odds, invert);

 

            for (int k = 0; k < half; k++)

            {

                ///旋转因子

                double fack = fac * k;

 

                ///进行蝶形运算

                Complex oddPart = oddResult[k] * new Complex(Math.Cos(fack), Math.Sin(fack));

                output[k] = evenResult[k] + oddPart;

                output[k + half] = evenResult[k] – oddPart;

            }

 

            ///返回FFTIFFT的结果

            return output;

        }

 

        /// <summary>

        /// 频域滤波器

        /// </summary>

        /// <param name=”data”>待滤波的数据</param>

        /// <param name=”Nc”>滤波器截止波数</param>

        /// <param name=”Hd”>滤波器的权函数</param>

        /// <returns>滤波后的数据</returns>

        private static double[] FreqFilter(double[] data, int Nc, Complex[] Hd)

        {

            ///最高波数==数据长度

            int N = data.Length;

 

            ///输入数据进行FFT

            Complex[] fData = FreqAnalyzer.FFT(data, false);

 

            ///频域滤波

            for (int i = 0; i < N; i++)

            {

                fData[i] = Hd[i] * fData[i];

            }

 

            ///滤波后数据计算IFFT

            ///!未除以数据长度

            fData = FreqAnalyzer.FFT(fData, true);

 

            ///复数转成模

            data = FreqAnalyzer.Cmp2Mdl(fData);

 

            ///除以数据长度

            for (int i = 0; i < N; i++)

            {

                data[i] = -data[i] / N;

            }

 

            ///返回滤波后的数据

            return data;

        }

    }

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/110913.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 正则提取字符串中的数字_正则表达式忽略空格python

    正则提取字符串中的数字_正则表达式忽略空格pythonpython从字符串中提取数字使用正则表达式,用法如下:##总结##^匹配字符串的开始。##$匹配字符串的结尾。##\b匹配一个单词的边界。##\d匹配任意数字。##\D匹配任意非数字字符。##x?匹配一个可选的x字符(换言之,它匹配1次或者0次x字符)。##x*匹配0次或者多次x字符。##x+匹配1次或者多次x字符。…

    2022年10月3日
    4
  • 数据结构–链表的排序详解

    数据结构–链表的排序详解1、前言前面两篇博客,我已经把线性表的两种基本的表示形式,做了一个基本的介绍和一些对比。但是,我突然发现在链表这里我缺少一个很重要的内容,那就是对我们的链表进行排序,其实,在连接两个链表的时候,就要求我们的那两个链表是有序的。2、链表排序—最简单、直接的方式(直接采用冒泡或者选择排序,而且不是交换结点,只交换数据域)//线性表的排序,采用冒泡排序,直接遍历链表voidListsort(Nod

    2022年10月11日
    3
  • tortoisegit使用教程_git小乌龟拉取代码

    tortoisegit使用教程_git小乌龟拉取代码一、下载之前需要下载三个安装包,分别是git、小乌龟客户端、小乌龟中文语言包:二、下载与配置:1.下载Git并且暗转,下载地址:https://git-for-windows.github.io/2.下载TortoiseGit客户端以及中文语言包地址:https://tortoisegit.org/download/此处省略一万个next3.配置TortoiseGit小乌龟首先选择自己需要进行管理的文件夹作为本地Git的仓库,我设置的是D:\A_Projects\OMS1.0然后在文

    2025年12月3日
    9
  • HashMap工作原理和扩容机制

    HashMap工作原理和扩容机制HashMap工作原理HashMap扩容1HashMap的扩容时机2HashMap的扩容过程补充1容量必须是2的幂2rehashReferences1.HashMap工作原理HashMap作为优秀的Java集合框架中的一个重要的成员,在很多编程场景下为我们所用。HashMap作为数据结构散列表的一种实现,就其工作原理来讲单独列出一篇博客来讲都是不过分的。由于本文主要是简单总

    2022年6月18日
    31
  • pycharm中如何导入库_库乐队如何导入相册的视频

    pycharm中如何导入库_库乐队如何导入相册的视频大家都知道,Python是一个极其方便的由库构建的编程语言。比如机器学习的库sklearn,文件读取pandas,文件读写xlwt,xlrt,矩阵运算numpy等等等等等等等等等等,多到你无法想象!那到底如何导入Python库呢?我们今天就来学习一下~点击File->NewProject,创建一个PyCharm项目,然后点击File->Settings->P…

    2022年8月27日
    8
  • 整除的尾数_整除数

    整除的尾数_整除数整除的尾数时间限制:1000 ms | 内存限制:65535 KB难度:0描述一个整数,只知道前几位,不知道末二位,被另一个整数除尽了,那么该数的末二位该是什么呢?输入输入数据有若干组,每组数据包含二个整数a,b(0输出对应每组数据,将满足条件的所有尾数在一行内输出,格式见样本输出。同组数据的输出,其每个尾数之间空一格,行末没有空格。样例输入

    2025年5月24日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号