快速傅里叶算法(FFT)示例
作者:追风剑情 发布于:2018-2-23 18:25 分类:Algorithms
连续非周期信号的傅里叶变换公式
现在假设在x(t)的某一段连续区间上以周期T进行采样,得到N个采样点,则每个采样点的离散傅里叶变换公式就是:
上式可用线性方程组表示为:
for (int n=0; n<N; n++) for (int k=0; k<N; k++) int p = n * k;//旋转因子指数
逆变换公式
原始信号与两个分组信号之间的关系:
每次分解,都将原始信号x(n)按照时间顺序(也就是n的序号)分成奇、偶两个组x1(r)和x2(r),其中r与n的关系是:
当n为偶数时,令n=2r;
当n为奇数时,令n=2r+1;
也就是说,原始信号与两个分组的信号存在以下关系:
x(2r)=x1(r), x(2r+1)=x2(r) 其中r=0,1,...,N/2-1
将一个N点DFT分解为两个N/2点DFT:
由以上关系可知:
一个N点DFT变换的前N/2个周期数据的转换关系是:
一个N点DFT变换的后N/2个周期数据的转换关系是:
欧拉公式
从上面的公式可知,FFT是递归求解过程。不断对数据进行奇偶分组,如下图:
蝶形算法流程图(借用网上一张截图)
旋转因子WNP规律
P = i*(1<<L); (i为第几次蝶形运算, L为当前级数(从0开始算))
FFT算法的复量运算量为
图像处理:先进行行变换,再对变换结果进行列变换,或者先进行列变换,再对结果进行行变换。
示例
using System; using System.Collections.Generic; namespace ConsoleApp34 { class Program { static void Main(string[] args) { TestFFT(); TestFFT2(); Console.Read(); } private static void TestFFT() { const int N = 8; //初始化时域数据 Complex[] TD2FD = new Complex[N]; for (int i = 0; i < N; i++) { Complex cpx = new Complex(); cpx.re = i; cpx.im = 0; TD2FD[i] = cpx; } Console.WriteLine("------ 一维原始信号 -----"); Print(TD2FD); Console.WriteLine("----- FFT -----"); FFT(TD2FD); Print(TD2FD); Console.WriteLine("----- IFFT -----"); IFFT(TD2FD); Print(TD2FD); } private static void TestFFT2() { const int W = 8, H = 8; Complex2D complex2D = new Complex2D(W, H); for (int i=0; i<H; i++) { for (int j=0; j<W; j++) { Complex cpx = new Complex(); cpx.re = i * W + j; cpx.im = 0; complex2D.SetComplex(i, j, cpx); } } Console.WriteLine("------ 二维原始信号 -----"); complex2D.Print(); Console.WriteLine("----- FFT2 -----"); FFT2(complex2D); complex2D.Print(); Console.WriteLine("----- IFFT2 -----"); IFFT2(complex2D); complex2D.Print(); } //快速傅里叶变换 public static void FFT(Complex[] TD2FD) { FFT_Core(TD2FD, WT_LUT(TD2FD.Length, 1)); } //快速傅里叶变换 (二维) public static void FFT2(Complex2D TD2FD) { //对每一行做FFT for (int i=0; i<TD2FD.Height; i++) { Complex[] row = TD2FD.GetRow(i); FFT(row); } //对每一列做FFT for (int i = 0; i < TD2FD.Width; i++) { Complex[] column = TD2FD.GetColumn(i); FFT(column); } } //快速傅里叶逆变换 public static void IFFT(Complex[] FD2TD) { //做FFT变换 Complex[] WT = WT_LUT(FD2TD.Length, -1); FFT_Core(FD2TD, WT); //除以N for (int i = 0; i < FD2TD.Length; i++) { FD2TD[i].re /= FD2TD.Length; FD2TD[i].im /= FD2TD.Length; } } //快速傅里叶逆变换 (二维) public static void IFFT2(Complex2D FD2TD) { //对每一行做IFFT for (int i = 0; i < FD2TD.Height; i++) { Complex[] row = FD2TD.GetRow(i); IFFT(row); } //对每一列做IFFT for (int i = 0; i < FD2TD.Width; i++) { Complex[] column = FD2TD.GetColumn(i); IFFT(column); } } // 返回旋转因子查询表(twiddle factor lookup table) private static Complex[] WT_LUT(int N, int flag = 1) { Complex[] WT = new Complex[N]; for (int i = 0; i < N; i++) { Complex cpx_wt = new Complex(); float angle = (float)(-i * Math.PI * 2 / N); cpx_wt.re = (float)Math.Cos(angle); //IFFT flag=-1, FFT flag=1 cpx_wt.im = flag * (float)Math.Sin(angle); WT[i] = cpx_wt; } return WT; } private static void FFT_Core(Complex[] TD2FD, Complex[] WT) { int power = (int)Math.Log(TD2FD.Length, 2); int butterfly; int p, s; Complex x1, x2, wt; //倒位排序 BitReverse(TD2FD); //蝶形运算 for (int k = 0; k < power; k++) //级数 { for (int j = 0; j < 1 << (power - k - 1); j++) //组数 { //每组有几个元素 butterfly = 1 << k + 1; //计算参与蝶形运算的两个元素的索引 p = j * butterfly; s = p + butterfly / 2; for (int i = 0; i < butterfly / 2; i++) //蝶形运算次数 { x1 = TD2FD[i + p]; x2 = TD2FD[i + s]; wt = WT[i * TD2FD.Length / butterfly]; TD2FD[i + p] = x1 + x2 * wt; TD2FD[i + s] = x1 - x2 * wt; } } } } private static int BitReverse(int x) { //倒位排序 //0 1 2 3 4 5 6 7 十进制 //000 001 010 011 100 101 110 111 十进制对应的二进制 //000 100 010 110 001 101 011 111 码位反转 //0 4 2 6 1 5 3 7 码位反转后对应的十进制 int[] table = new int[8] { 0, 4, 2, 6, 1, 5, 3, 7 }; return table[x]; } // 倒位排序——雷德算法 private static void BitReverse(Complex[] array) { int i, j, k; int N = array.Length; Complex temp; j = 0; for (i = 0; i < N - 1; i++) { if (i < j) { temp = array[i]; array[i] = array[j]; array[j] = temp; } // 求j的下一个倒序位 // N/2的二进制最高位为1,其他位都为0 // 判断最高位是否为1,可与N/2进行比较 // 判断次高位是否为1,可与N/4进行比较 k = N >> 1; //如果k<=j,表示j的最高位为1 while (k <= j) { //当k<=j时,需要将最高位变为0 j = j - k; //判断次高位是否为1,依次类推,逐个比较,直到j某个位为0 k >>= 1; } j = j + k;//将0变为1 } } // 打印 private static void Print(Complex[] TD2FD) { for (int i = 0; i < TD2FD.Length; i++) { Console.WriteLine("(re={0}, im={1})", TD2FD[i].re, TD2FD[i].im); } Console.WriteLine(); } } //定义复数 public class Complex { public float re;//实数部 public float im;//虚数部 // 幅值 public double Amplitude { get { return Math.Sqrt(re*re + im*im); } } // 相位 public double Phase { get { return Math.Atan2(im, re); } } public static Complex operator +(Complex lhs, Complex rhs) { Complex result = new Complex(); result.re = lhs.re + rhs.re; result.im = lhs.im + rhs.im; return result; } public static Complex operator -(Complex lhs, Complex rhs) { Complex result = new Complex(); result.re = lhs.re - rhs.re; result.im = lhs.im - rhs.im; return result; } public static Complex operator *(Complex lhs, Complex rhs) { Complex result = new Complex(); result.re = lhs.re * rhs.re - lhs.im * rhs.im; result.im = lhs.re * rhs.im + lhs.im * rhs.re; return result; } public static Complex operator *(float lhs, Complex rhs) { Complex result = new Complex(); result.re = lhs * rhs.re; result.im = lhs * rhs.im; return result; } public static Complex operator *(Complex lhs, float rhs) { Complex result = new Complex(); result.re = lhs.re * rhs; result.im = lhs.im * rhs; return result; } } public class Complex2D { private List<Complex[]> rows = new List<Complex[]>(); private List<Complex[]> columns = new List<Complex[]>(); private int m_width; private int m_height; public Complex2D(int width, int height) { m_width = width; m_height = height; for (int i = 0; i < height; i++) rows.Add(new Complex[width]); for (int i = 0; i < width; i++) columns.Add(new Complex[height]); } public int Width { get { return m_width; } } public int Height { get { return m_height; } } public Complex[] GetRow(int i) { return rows[i]; } public Complex[] GetColumn(int i) { return columns[i]; } public void SetRow(int i, Complex[] src) { rows[i] = src; } public void SetColumn(int i, Complex[] src) { columns[i] = src; } public void SetComplex(int i, int j, Complex src) { rows[i][j] = src; columns[j][i] = src; } public void SetComplexs(Complex[][] src) { for (int i=0; i<src.Length; i++) { Complex[] row = src[i]; for (int j = 0; j < row.Length; j++) SetComplex(i, j, row[j]); } } public void Print() { for (int i=0; i<rows.Count; i++) { Complex[] row = rows[i]; for (int j = 0; j < row.Length; j++) Console.Write("{0:G} ", row[j].re.ToString().PadRight(5)); Console.WriteLine(); } Console.WriteLine(); } } }
//频谱分析窗函数类型 public enum FFTWindow { // // 矩形窗 (使用最多的窗) // W[n] = 1.0. Rectangular = 0, // // 三角窗 // W[n] = TRI(2n/N). Triangle = 1, // // 汉宁窗(余弦窗) // W[n] = 0.54 - (0.46 * COS(n/N) ). Hamming = 2, // // 海明窗(升余弦窗) // W[n] = 0.5 * (1.0 - COS(n/N) ). Hanning = 3, // // 布拉克曼 // W[n] = 0.42 - (0.5 * COS(nN) ) + (0.08 * COS(2.0 * nN) ). Blackman = 4, // // 哈布斯窗 // W[n] = 0.35875 - (0.48829 * COS(1.0 * nN)) + (0.14128 * COS(2.0 * nN)) - (0.01168 * COS(3.0 * n/N)). BlackmanHarris = 5 }
更多示例: Matlib——二维傅里叶变换
标签: Algorithms
日历
最新文章
随机文章
热门文章
分类
存档
- 2024年11月(3)
- 2024年10月(5)
- 2024年9月(3)
- 2024年8月(3)
- 2024年7月(11)
- 2024年6月(3)
- 2024年5月(9)
- 2024年4月(10)
- 2024年3月(11)
- 2024年2月(24)
- 2024年1月(12)
- 2023年12月(3)
- 2023年11月(9)
- 2023年10月(7)
- 2023年9月(2)
- 2023年8月(7)
- 2023年7月(9)
- 2023年6月(6)
- 2023年5月(7)
- 2023年4月(11)
- 2023年3月(6)
- 2023年2月(11)
- 2023年1月(8)
- 2022年12月(2)
- 2022年11月(4)
- 2022年10月(10)
- 2022年9月(2)
- 2022年8月(13)
- 2022年7月(7)
- 2022年6月(11)
- 2022年5月(18)
- 2022年4月(29)
- 2022年3月(5)
- 2022年2月(6)
- 2022年1月(8)
- 2021年12月(5)
- 2021年11月(3)
- 2021年10月(4)
- 2021年9月(9)
- 2021年8月(14)
- 2021年7月(8)
- 2021年6月(5)
- 2021年5月(2)
- 2021年4月(3)
- 2021年3月(7)
- 2021年2月(2)
- 2021年1月(8)
- 2020年12月(7)
- 2020年11月(2)
- 2020年10月(6)
- 2020年9月(9)
- 2020年8月(10)
- 2020年7月(9)
- 2020年6月(18)
- 2020年5月(4)
- 2020年4月(25)
- 2020年3月(38)
- 2020年1月(21)
- 2019年12月(13)
- 2019年11月(29)
- 2019年10月(44)
- 2019年9月(17)
- 2019年8月(18)
- 2019年7月(25)
- 2019年6月(25)
- 2019年5月(17)
- 2019年4月(10)
- 2019年3月(36)
- 2019年2月(35)
- 2019年1月(28)
- 2018年12月(30)
- 2018年11月(22)
- 2018年10月(4)
- 2018年9月(7)
- 2018年8月(13)
- 2018年7月(13)
- 2018年6月(6)
- 2018年5月(5)
- 2018年4月(13)
- 2018年3月(5)
- 2018年2月(3)
- 2018年1月(8)
- 2017年12月(35)
- 2017年11月(17)
- 2017年10月(16)
- 2017年9月(17)
- 2017年8月(20)
- 2017年7月(34)
- 2017年6月(17)
- 2017年5月(15)
- 2017年4月(32)
- 2017年3月(8)
- 2017年2月(2)
- 2017年1月(5)
- 2016年12月(14)
- 2016年11月(26)
- 2016年10月(12)
- 2016年9月(25)
- 2016年8月(32)
- 2016年7月(14)
- 2016年6月(21)
- 2016年5月(17)
- 2016年4月(13)
- 2016年3月(8)
- 2016年2月(8)
- 2016年1月(18)
- 2015年12月(13)
- 2015年11月(15)
- 2015年10月(12)
- 2015年9月(18)
- 2015年8月(21)
- 2015年7月(35)
- 2015年6月(13)
- 2015年5月(9)
- 2015年4月(4)
- 2015年3月(5)
- 2015年2月(4)
- 2015年1月(13)
- 2014年12月(7)
- 2014年11月(5)
- 2014年10月(4)
- 2014年9月(8)
- 2014年8月(16)
- 2014年7月(26)
- 2014年6月(22)
- 2014年5月(28)
- 2014年4月(15)
友情链接
- Unity官网
- Unity圣典
- Unity在线手册
- Unity中文手册(圣典)
- Unity官方中文论坛
- Unity游戏蛮牛用户文档
- Unity下载存档
- Unity引擎源码下载
- Unity服务
- Unity Ads
- wiki.unity3d
- Visual Studio Code官网
- SenseAR开发文档
- MSDN
- C# 参考
- C# 编程指南
- .NET Framework类库
- .NET 文档
- .NET 开发
- WPF官方文档
- uLua
- xLua
- SharpZipLib
- Protobuf-net
- Protobuf.js
- OpenSSL
- OPEN CASCADE
- JSON
- MessagePack
- C在线工具
- 游戏蛮牛
- GreenVPN
- 聚合数据
- 热云
- 融云
- 腾讯云
- 腾讯开放平台
- 腾讯游戏服务
- 腾讯游戏开发者平台
- 腾讯课堂
- 微信开放平台
- 腾讯实时音视频
- 腾讯即时通信IM
- 微信公众平台技术文档
- 白鹭引擎官网
- 白鹭引擎开放平台
- 白鹭引擎开发文档
- FairyGUI编辑器
- PureMVC-TypeScript
- 讯飞开放平台
- 亲加通讯云
- Cygwin
- Mono开发者联盟
- Scut游戏服务器引擎
- KBEngine游戏服务器引擎
- Photon游戏服务器引擎
- 码云
- SharpSvn
- 腾讯bugly
- 4399原创平台
- 开源中国
- Firebase
- Firebase-Admob-Unity
- google-services-unity
- Firebase SDK for Unity
- Google-Firebase-SDK
- AppsFlyer SDK
- android-repository
- CQASO
- Facebook开发者平台
- gradle下载
- GradleBuildTool下载
- Android Developers
- Google中国开发者
- AndroidDevTools
- Android社区
- Android开发工具
- Google Play Games Services
- Google商店
- Google APIs for Android
- 金钱豹VPN
- TouchSense SDK
- MakeHuman
- Online RSA Key Converter
- Windows UWP应用
- Visual Studio For Unity
- Open CASCADE Technology
- 慕课网
- 阿里云服务器ECS
- 在线免费文字转语音系统
- AI Studio
- 网云穿
- 百度网盘开放平台
- 迅捷画图
- 菜鸟工具
- [CSDN] 程序员研修院
- 华为人脸识别
- 百度AR导航导览SDK
- 海康威视官网
- 海康开放平台
- 海康SDK下载
- git download
交流QQ群
-
Flash游戏设计: 86184192
Unity游戏设计: 171855449
游戏设计订阅号