精华内容
下载资源
问答
  • 傅里叶变换

    千次阅读 2018-08-20 16:22:18
    对于图像,2D离散傅里叶变换(DFT)用于找到频域.快速傅里叶变换(FFT)用于计算DFT. 对于正弦信号,x(t)= Asin(2πft),我们可以说f是信号的频率,如果采用其频域,我们可以看到f处的尖峰。 如果对信号进行...

    官网原文

    理论:

    傅立叶变换用于分析各种滤波器的频率特性。对于图像,2D离散傅里叶变换(DFT)用于找到频域.快速傅里叶变换(FFT)用于计算DFT.

    对于正弦信号,x(t)= Asin(2πft),我们可以说f是信号的频率,如果采用其频域,我们可以看到f处的尖峰。
    如果对信号进行采样以形成离散信号,则得到相同的频域,但在[-π,π]或[0,2π]范围内是周期性的(对于N点DFT,则是[0,N]).您可以将图像视为在两个方向上采样的信号。因此,在X和Y方向上进行傅里叶变换可以得到图像的频率表示。

    更直观地说,对于正弦信号,如果幅度在短时间内变化如此之快,则可以说它是高频信号。如果变化缓慢,则为低频信号。您可以将相同的想法扩展到图像.幅度在图像中的哪些地方幅度变化很大?在边缘点,或噪音.们可以说,边缘和噪声是图像中的高频内容。如果幅度没有太大变化,则它是低频分量.

    Numpy中的傅里叶变换

    np.fft.fft2()为我们提供了一个复杂数组的频率变换。它的第一个参数是输入图像,它是灰度图。第二个参数是可选的,它决定了输出数组的大小。如果它大于输入图像的大小,则在计算FFT之前用零填充输入图像。如果小于输入图像,则将裁剪输入图像。如果没有传递参数,则输出数组大小将与输入相同。

    现在,一旦得到结果,零频率分量(DC分量)将位于左上角。

    如果要将其置于中心位置,则需要在两个方向上将结果移动N/2。通过函数np.fft.fftshift()来完成。找到频率变换后,您可以找到幅度谱(the magnitude spectrum)。

    具体例子请参考官网原文.

    你可以在中心位置看到更多的白色区域,显示更多的低频内容。

    所以你找到了频率变换,现在你可以在频域做一些操作,比如高通滤波和重建图像,即找到逆DFT.为此,您只需通过使用尺寸为60x60的矩形窗口来移除低频信号.然后使用np.fft.ifftshift()应用反向移位,以便DC组件再次出现在左上角。然后使用np.ifft2()函数找到逆FFT.结果再次是一个复杂的数字。 你可以采取它的绝对值。

    具体例子请参考官网原文.

    结果显示高通滤波是边缘检测操作。这是我们在Image Gradients章节中看到的.这也表明大多数图像数据存在于光谱的低频区域.无论如何,我们已经看到如何在Numpy找到DFT,IDFT等。现在让我们看看如何在OpenCV中完成它。

    如果你仔细观察结果,特别是JET颜色的最后一个图像,你可以看到一些文物(我用红色箭头标记的一个实例)。 它在那里显示出一些类似波纹的结构,它被称为振铃效应。它是由我们用于腌膜的矩形窗口引起的。 此腌膜转换为sinc形状,这会导致此问题。 因此矩形窗口不用于过滤。 更好的选择是高斯窗口

    OpenCV中的傅里叶变换

    OpenCV为此提供了cv.dft()cv.idft()函数。 它返回与之前相同的结果,但有两个通道。 第一个通道将具有结果的实部,第二个通道将具有结果的虚部。 输入图像应首先转换为np.float32。

    注意: OpenCV函数cv.dft()和cv.idft()比Numpy函数更快。 但是Numpy功能更加用户友好。

    展开全文
  • C语言快速傅里叶变换

    2019-01-14 13:35:43
    将快速傅里叶变换公式用C语言编写出,实现输入序列完成对序列傅里叶变换功能,经过与matlab中的傅里叶变换进行对比证明,代码的精度符合一般要求
  • 快速傅里叶变换

    千次阅读 2018-09-09 09:46:23
    FFT,即为快速傅氏变换,是离散傅氏变换的快速算法,它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的...我们可以这么理解:FFT(Fast Fourier Transformation)就是“快速傅里叶变换”的意思,它...

    FFT,即为快速傅氏变换,是离散傅氏变换的快速算法,它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。它对傅氏变换的理论并没有新的发现,但是对于在计算机系统或者说数字系统中应用离散傅立叶变换,可以说是进了一大步。这是360百科中对于fft的一种概念解释。我们可以这么理解:FFT(Fast Fourier Transformation)就是“快速傅里叶变换”的意思,它是一种用来计算DFT(离散傅里叶变换)和IDFT(离散傅里叶反变换)的一种快速算法。这种算法运用了一种高深的数学方式、把原来复杂度为O(n2)的朴素多项式乘法转化为了O(nlogn)的算法。

    那么这种快速傅里叶变换是如何实现的呢?由于离散信号是由很多点组成的,所以DFT的公式如公式1所示。而连续信号的傅里叶变换是在连续域中进行的运算,其积分运算公式如公式2所示。离散傅里叶变换将这个积分运算变为了累加运算,即使如此,实际运算量也依然非常可观。所以在实际的应用场景中,离散傅里叶变换的实用性较差。因此,FFT作为新的计算方式被广泛接受。其本质是将离散傅里叶变换通过它本身的奇、偶、虚、实的性质,对该公式进行推导改进。公式1中的k和t均为时域中的输入参数,X(k)以及F[f(t)]即为相对与x以及t的傅里叶变换。

                                          X(k) =\sum_{n=0}^{N-1}x_ne^{-j2\pi nk/N }                                                                                    公式1    

                                         F(w)=F[f(t)]=\int_{-\infty }^{\infty }f(t)e^{-jwt}dt                                                                  公式2                                                                                                          

    首先我们对于离散傅里叶变换的公式进行转换推导。离散傅里叶变换实际可以表示为:

                                         X(k)=x_1 e^{-j2 \pi k/N}+x_2 e^{-j2 \pi k 2/N}+x_3 e^{-j2 \pi k 3/N}+\cdots x_n e^{-j2 \pi k 2k/N}             公式3

    我们改变一种表示方式,离散傅里叶变换也可以表示为

                                         F(x)=A_0+A_1 x+A_2 x^2+A_3 x^3+\cdots +A_n x^n                                              公式4

    对于这种公式,我们应该如何来进行求解呢。在这里我们不进行传统计算方式的介绍,直接按照fft的思想来进行解析推导。

    首先,我们对于多项式进行分解,现在我们将该多项式分解为奇数次项和偶数次项的进行分类表示。而且为了表现的更清楚,我们先将该多项式的最高次项定为7,即有8个多项式进行累加,然后重新排列后的多项式为:

                                         F(x)=(A_0+A_2 x^2+A_4 x^4+A_6 x^6)+x(A_1+A_3 x^2+A_5 x^4+A_7 x^7)         公式5

    为了表示的更清晰,我们分别给奇数次项和偶数次项重新起一个名字,即f(x)和g(x),这两个多项式依次表示为:

                                         f(x)=A_0+A_2 x^2+A_4 x^4+A_6 x^6                                                                    公式6

                                         g(x)=A_1+A_3 x^2+A_5 x^4+A_7 x^6                                                                    公式7

    对该公式进行还原,我们又可以还原回原来的总公式。

                                         F(x)=f(x^2 )+xg(x^2)                                                                                      公式8

    之前我们的思维一直停留在实数范畴内,现在我们引入一个复数域内的概念。我们叫它复根用ω 表示。如果w^k=1 ,那么我们称“ω 为1的k次复根”计做 w_{k}^{n} ,单位复根地表示,其中n就是一个序号数,我们把所有的负根按照复数域角度的大小逆时针排序从零开始编号。

    如下图所示,即为一个四次复根的图形表示。

                                                                                             图 1 四次复根

    根据该图我们可以推论,其实k次复根就相当于是将图中的圆周平均分成k个弧,弧与弧之间的端点就是k次复根。另外,从图中可以看出 w_{4}^{2} = -1 = i^2 = (w_{4}^{1})^2w_{4}^{0} 是这个圆与“Real”轴即实数轴正半轴的交点,所以无论k取多少,w_{k}^{0}  始终是1。我们只需要知道 w_{k}^{1},就能求出 w_{k}^{n},所以我们称 w_{k}^{1} 为“单位复根”。

    在正常使用过程中,我们也能够w_{k}表示单位复根,w_{k}^{1} 表示的是“单位复根”的“1次方”也就是它本身,其他的就叫做k次单位复根的n次方。

    关于单位复根,它还有一些特性,

    1. n次单位复根的值随指数变化而循环,w_{k}^{n+k} = w_{k}^{k}w_{k}^{n} = w_{k}^{n} 。
    2. 折半引理: w_{k}^{n} = w_{k/2}^{n/2},这个引理在fft的公式推导优化过程中会使用到,如图1中,如果将整个圆周划分为两个2个弧,则w_{2}^{1}的位置实际就是现在w_{4}^{2} 的位置,因此该引理成立。
    3. 消去定理:w_{k}^{n+k/2} = -w_{k}^{n},这个定理可以由上图中看出,复根转了半圈正好变成了-1。

    现在我们将单位复根带入上述的公式中代替x的值,则原来的公式可以表示为:

                                         F(w_{k}^{n}) = f(w_{k}^{2n})+w_{k}g(w_{k}^{2n})                                                                              公式9

    由于需要对n进行分类讨论,因为涉及到奇偶次项的运算,当0 <n <k/2 -1时 ,此时根据之前提到的复根的折半引理,我们可以将该公式推导为:

                                         F(w_{k}^{n}) = f(w_{k/2}^{n})+w_{k}g(w_{k/2}^{n})                                                                           公式10

    当k/2<n +k/2<k -1时,上述的公式又可以变为

                                         F(w_{k}^{n+k/2}) = f(w_{k}^{2n+k})+w_{k}^{n+k/2}g(w_{k}^{2n+k})                                                        公式11

    根据之前的消去定理以及折半定理,我们可以将公式优化为:

                                         F(w_{k}^{n+k/2}) = f(w_{k/2}^{n})-(w_{k/2}^{n})g(w_{k/2}^{n})                                                              公式12

    所以,fft的计算公式可以总结为两个区域内的值表示,即0 <n <k/2 -1以及k/2<n +k/2<k -1的区间范围内所有Fx 的值都可以表示,另外,可以看出fx 以及 gx 就是 Fx 的一半,因此在程序计算过程中可以按照子问题的方式来递归求解。

    以下即为根据上述推导处的最后两个公式来进行计算的fft代码表示。代码中涉及到的子函数均为复数间的计算。

    void fft(complex *a,int n,int dft)//n表示我的多项位数
    {
    	int  i = 0, j = 0, k = 0;
    	int step = 0;
    	for(i=0;i<n;i++) if(i<rev[i]) Swap(a[i],a[rev[i]]);
    	for(step=1;step<n;step<<=1)//模拟一个合并的过程
    	{
    		complex wn;
    		Wn_i(n,1,&wn,dft);//计算当前单位复根
    		for(j=0;j<n;j+=step<<1)
    		{
    			complex wnk;
    			Wn_i(n,1,&wnk,dft);//计算当前单位复根
    			for(k=j;k<j+step;k++)
    			{//蝴蝶操作
    				complex x=a[k];
    				complex y;
    				c_mul(a[k+step],wnk,&y);
    				c_plus(x,y,&a[k]);
    				c_sub(x,y,&a[k+step]);//后半个“step”中的ω一定和“前半个”中的成相反数
    				c_mul(wnk,wn,&wnk);
    			}
    		}
    	}
    }
    

    为了得到蝶形计算的参数序号,在进行fft计算之前先要进行参数重新排序,该函数的目的就是将每一位颠倒。如果暴力按位反转,总归不够优雅。所以,我们用一个类似DP动态规划的方法来实现这个功能。代码如下所示:

    void get_rev(int bit)//bit表示二进制的位数
    {  
        for(int i=0;i<(1<<bit);i++)//我么要对1~2^bit-1中的所有数做长度为bit的二进制翻转
            rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));//?!! SMG ?!!
    }
    

    根据dp的思想,每一个问题都可以由其子问题的解来进行求解。所以我们可以把一个二进制数看成两部分,它的前bit-1位是一部分,它的最后一位是一部分。全部bit位的数据求解看成是总问题,则前bit-1位可以看成是一个子问题。所以,要求解所有位数据的反转,我们可以直接利用前bit-1位数据的反转结果。因此,任意一个数的二进制反转就相当于是把它的最后一位当成首位,然后在后面接上它前bit-1位的二进制反转。而且在这个循环中我们能保证,在计算i的二进制反转之前,1 ~ i-1中的所有数的二进制反转都已经完成。 i的前bit-1位的数值其实就是i >>1的值,直接调用 i >>1的二进制反转的结果就相当于调用了i 的前bit-1位二进制反转的结果。

    其实i >>1的反转与i的前bit-1位的反转是有一点出入的,因为我们的二进制反转始终以bit位为标准,所以i >>1会比i的前bit-1位多出一个前导零,而反转之后就会多出一个后缀零,所以i的前bit-1位的反转要去掉那个后缀零,此处我们通过将结果向右移位来实现,也就是rev[i>>1]>>1。

    因此,我们只要把末尾乘上2^(bit-1)变成首位,此时该数据除了最高位有效之外,其余所有数位全都是向左移位产生的0,所以,再按位或(|)上rev[ i >>1]>>1就是我们要的答案了。

    关于快速傅里叶变换,我的学习过程属于比较坎坷的一类,大学期间曾经学习过一段时间,但那时对于这些概念没有深入的学习,所以压根没有理解。即使后来再次遇到这些概念及公式也是一头雾水。现在由于工作过程中需要用到这些知识,所以便重新回来翻看。快速傅里叶变换作为工程上的一种工具,通过很巧妙的手段将公式重组简化,大大提高了多项式乘法以及离散傅里叶变换的计算速度。学习期间上网查阅过很多前辈总结的学习笔记,在此向各位提供学习心得的前辈表示衷心的感谢!

     

     

    参考文献

    https://blog.csdn.net/WADuan2/article/details/79529900

    https://blog.csdn.net/tf18269639242/article/details/53024276

    https://blog.csdn.net/f_zyj/article/details/76037583

    https://wenku.baidu.com/view/5cacb2b8bd64783e09122b9a.html

    https://blog.csdn.net/chenyujing1234/article/details/7419863

    https://www.cnblogs.com/luoqingyu/p/5930181.html

    https://blog.csdn.net/ggn_2015/article/details/68922404

    https://blog.csdn.net/egean/article/details/53039248

    https://blog.csdn.net/ggn_2015/article/details/68922404

    https://blog.csdn.net/linwanglian1/article/details/56020221

    https://www.cnblogs.com/RabbitHu/p/FFT.html

    https://www.cnblogs.com/Lyush/articles/3219196.html

    https://blog.csdn.net/zhaopeizhaopeipei/article/details/53908238

    https://blog.csdn.net/shenziheng1/article/details/52891807

    展开全文
  • 快速傅里叶变换FFT

    2019-02-12 14:33:15
    // 快速傅里 叶变换FFT的C语言算法...// 快速傅里叶变换(Fast Fourier Transform)是离散傅里叶变换的一种快速算法,简称FFT,通过FFT可以将一个信号从时域变换到频域。 // 模拟信号经过A/D转换变为数字信号的过程...

    // 快速傅里 叶变换FFT的C语言算法彻底研究
    // LED音乐频谱显示的核心算法就是快速傅里叶变换,FFT的理解和编程还是比较难的,特地撰写此文分享一下研究成果。
    // 一、彻底理解傅里叶变换
    // 快速傅里叶变换(Fast Fourier Transform)是离散傅里叶变换的一种快速算法,简称FFT,通过FFT可以将一个信号从时域变换到频域。
    // 模拟信号经过A/D转换变为数字信号的过程称为采样。为保证采样后信号的频谱形状不失真,采样频率必须大于信号中最高频率成分的2倍,这称之为采样定理。
    // 假设采样频率为fs,采样点数为N,那么FFT结果就是一个N点的复数,每一个点就对应着一个频率点,某一点n(n从1开始)表示的频率为:fn=(n-1)*fs/N。
    // 举例说明:用1kHz的采样频率采样128点,则FFT结果的128个数据即对应的频率点分别是0,1k/128,2k/128,3k/128,…,127k/128 Hz。
    // 这个频率点的幅值为:该点复数的模值除以N/2(n=1时是直流分量,其幅值是该点的模值除以N)。
    // 二、傅里叶变换的C语言编程
    // 1、对于快速傅里叶变换FFT,第一个要解决的问题就是码位倒序。
    // 假设一个N点的输入序列,那么它的序号二进制数位数就是t=log2N.
    // 码位倒序要解决两个问题:①将t位二进制数倒序;②将倒序后的两个存储单元进行交换。

    // ①将t=3位二进制数倒序

    // ②将倒序后的两个存储单元进行交换
    // 如果输入序列的自然顺序号i用二进制数表示,例如若最大序号为15,即用4位就可表示n3n2n1n0,则其倒序后j对应的二进制数就是n0n1n2n3,那么怎样才能实现倒序呢?利用C语言的移位功能!
    // 程序如下,我不多说,看不懂者智商一定在180以下!
    // 复数类型定义及其运算
    #define N 64 //64点
    #define log2N 6 //log2N=6
    /复数类型/
    typedef struct
    {
    float real;
    float img;
    }complex;
    complex xdata x[N]; //输入序列
    /复数加法/
    complex add(complex a,complex b)
    {
    complex c;
    c.real=a.real+b.real;
    c.img=a.img+b.img;
    return c;
    }
    /复数减法/
    complex sub(complex a,complex b)
    {
    complex c;
    c.real=a.real-b.real;
    c.img=a.img-b.img;
    return c;
    }
    /复数乘法/
    complex mul(complex a,complex b)
    {
    complex c;
    c.real=a.realb.real - a.imgb.img;
    c.img=a.realb.img + a.imgb.real;
    return c;
    }
    /码位倒序函数/
    void Reverse(void)
    {
    unsigned int i,j,k;
    unsigned int t;
    complex temp;//临时交换变量
    for(i=0;i<N;i++)//从第0个序号到第N-1个序号
    {
    k=i;//当前第i个序号
    j=0;//存储倒序后的序号,先初始化为0
    for(t=0;t<log2N;t++)//共移位t次,其中log2N是事先宏定义算好的
    {
    j<<=1;
    j|=(k&1);//j左移一位然后加上k的最低位
    k>>=1;//k右移一位,次低位变为最低位
    }
    if(j>i)//如果倒序后大于原序数,就将两个存储单元进行交换(判断j>i是为了防止重复交换)
    {
    temp=x[ i];
    x[ i]=x[j];
    x[j]=temp;
    }
    }
    }
    2、第二个要解决的问题就是蝶形运算

    ①第1级(第1列)每个蝶形的两节点“距离”为1,第2级每个蝶形的两节点“距离”为2,第3级每个蝶形的两节点“距离”为4,第4级每个蝶形的两节点“距离”为8。由此推得,
    第m级蝶形运算,每个蝶形的两节点“距离”L=2m-1。
    ②对于16点的FFT,第1级有16组蝶形,每组有1个蝶形;第2级有4组蝶形,每组有2个蝶形;第3级有2组蝶形,每组有4个蝶形;第4级有1组蝶形,每组有8个蝶形。由此可推出,
    对于N点的FFT,第m级有N/2L组蝶形,每组有L=2m-1个蝶形。
    ③旋转因子 的确定
    以16点FFT为例,第m级第k个旋转因子为 ,其中k=0~2m-1-1,即第m级共有2m-1个旋转因子,根据旋转因子的可约性, ,所以第m级第k个旋转因子为 ,其中k=0~2m-1-1。
    为提高FFT的运算速度,我们可以事先建立一个旋转因子数组,然后通过查表法来实现。
    complex code WN[N]=//旋转因子数组
    { //为节省CPU计算时间,旋转因子采用查表处理
    //★根据实际FFT的点数N,该表数据需自行修改
    //以下结果通过Excel自动生成
    // WN[k].real=cos(2PI/Nk);
    // WN[k].img=-sin(2PI/Nk);
    {1.00000,0.00000},{0.99518,-0.09802},{0.98079,-0.19509},{0.95694,-0.29028},
    {0.92388,-0.38268},{0.88192,-0.47140},{0.83147,-0.55557},{0.77301,-0.63439},
    {0.70711,-0.70711},{0.63439,-0.77301},{0.55557,-0.83147},{0.47140,-0.88192},
    {0.38268,-0.92388},{0.29028,-0.95694},{0.19509,-0.98079},{0.09802,-0.99518},
    {0.00000,-1.00000},{-0.09802,-0.99518},{-0.19509,-0.98079},{-0.29028,-0.95694},
    {-0.38268,-0.92388},{-0.47140,-0.88192},{-0.55557,-0.83147},{-0.63439,-0.77301},
    {-0.70711,-0.70711},{-0.77301,-0.63439},{-0.83147,-0.55557},{-0.88192,-0.47140},
    {-0.92388,-0.38268},{-0.95694,-0.29028},{-0.98079,-0.19509},{-0.99518,-0.09802},
    {-1.00000,0.00000},{-0.99518,0.09802},{-0.98079,0.19509},{-0.95694,0.29028},
    {-0.92388,0.38268},{-0.88192,0.47140},{-0.83147,0.55557},{-0.77301,0.63439},
    {-0.70711,0.70711},{-0.63439,0.77301},{-0.55557,0.83147},{-0.47140,0.88192},
    {-0.38268,0.92388},{-0.29028,0.95694},{-0.19509,0.98079},{-0.09802,0.99518},
    {0.00000,1.00000},{0.09802,0.99518},{0.19509,0.98079},{0.29028,0.95694},
    {0.38268,0.92388},{0.47140,0.88192},{0.55557,0.83147},{0.63439,0.77301},
    {0.70711,0.70711},{0.77301,0.63439},{0.83147,0.55557},{0.88192,0.47140},
    {0.92388,0.38268},{0.95694,0.29028},{0.98079,0.19509},{0.99518,0.09802}
    };
    3、算法实现
    //我们已经知道,N点FFT从左到右共有log2N级蝶形,每级有N/2L组,每组有L个。
    //所以FFT的C语言编程只需用3层循环即可实现:最外层循环完成每一级的蝶形运算(整个FFT共log2N级),
    //中间层循环完成每一组的蝶形运算(每一级有N/2L组),最内层循环完成单独1个蝶形运算(每一组有L个)。
    /***【快速傅里叶变换】*/
    void FFT(void)
    {
    unsigned int i,j,k,l;
    complex top,bottom,xW;
    Reverse(); //码位倒序
    for(i=0;i<log2N;i++) /共log2N级/
    { //一级蝶形运算
    l=1<<i;//l等于2的i次方
    for(j=0;j<N;j+=2
    l) /每L个蝶形是一组,每级有N/2L组/
    { //一组蝶形运算
    for(k=0;k<l;k++) /每组有L个/
    { //一个蝶形运算
    xW=mul(x[j+k+l],WN[N/(2
    l)*k]); //碟间距为l
    top=add(x[j+k],xW); //每组的第k个蝶形
    bottom=sub(x[j+k],xW);
    x[j+k]=top;
    x[j+k+l]=bottom;
    }
    }
    }
    }
    三、FFT计算结果验证
    随便输入一个64点序列,例如
    x[N]={{1,0},{3,0},{2,0},{5,0},{8,0},{4,0},{1,0},{3,0},{2,0},{5,0},{8,0},{4,0},{1,0},{3,0},{2,0},{5,0},{8,0},{4,0},{1,0},{3,0},{2,0},{5,0},{8,0},{4,0},{1,0},{3,0},{2,0},{5,0},{8,0},{4,0},{1,0},{3,0},{2,0},{5,0},{8,0},{4,0},{1,0},{3,0},{2,0},{5,0},{8,0},{4,0},{1,0},{3,0},{2,0},{5,0},{8,0},{4,0},{1,0},{3,0},{2,0},{5,0},{8,0},{4,0},{1,0},{3,0},{2,0},{5,0},{8,0},{4,0},{1,0},{3,0},{2,0},{5,0}};
    在Keil中Debug查看数组变量x的FFT计算结果并与MATLAB计算结果进行比对,可以发现非常准确,说明程序编写正确!

    假设采样频率为 Fs,信号频率 F,采样点数为 N。那么 FFT 之后结果就是一个为 N 点的复数。每一个点就对应着一个频率点。这个点的模值,就是该频率值下的幅度特性。具体跟原始信号的幅度有什么关
    系呢?假设原始信号的峰值为 A,那么 FFT 的结果的每个点(除了第一个点直流分量之外)的模值就是 A的 N/2 倍。 而第一个点就是直流分量,它的模值就是直流分量的 N 倍。而每个点的相位呢,就是在该频率下的信号的相位。第一个点表示直流分量(即 0Hz),而最后一个点 N 的再下一个点(实际上这个点是不存在的,这里是假设的第 N+1 个点,可以看做是将第一个点分做两半分,另一半移到最后)则表示采样频率 Fs,这中间被 N-1 个点平均分成 N 等份,每个点的频率依次增加。例如某点 n 所表示的频率为:F n =(n − 1)xF s
    根据 FFT 结果以及上面的分析计算,我们就可以写出信号的表达式了,它就是我们开始提供的信号。总的来说,这个过程就是这样:假设采样频率为 Fs,采样点数为 N,做 FFT 之后,某一点 n(n 从 1开始)表示的频率为:Fn=(n-1)*Fs/N;该点的模值除以 N/2 就是对应该频率下的信号的幅度(对于直流信号是除以 N);该点的相位即是对应该频率下的信号的相位。相位的计算可用函数 atan2(b,a)计算。atan2(b,a)是求坐标为(a,b)点的角度值,范围从-pi 到 pi。要精确到 xHz,则需要采样长度为 1/x 秒的信号,并做 FFT。要提高频率分辨率,就需要增加采样点数,这在一些实际的应用中是不现实的,需要在较短的时间内完成分析。解决这个问题的方法有频率细分法,比较简单的方法是采样比较短时间的信号,然后在后面补充一定数量的 0,使其长度达到需要的点数,再做 FFT,这在一定程度上能够提高频率分辨力。具体的频率细分法大家可参考相关文献。
    频谱图像显示的就是信号的组成正弦波的峰峰值(即模值)和各自组成信号的频率。
    以下图片是方波的粗略频谱。
    在这里插入图片描述
    ThinkPadW530的STM32傅里叶函数.c文件路径D:\keil5\ARM\Pack\ARM\CMSIS\4.3.0\CMSIS\DSP_Lib\Examples
    已经调试成功的傅里叶变换程序代码如下:
    *uint32_t input[1024], output[1024], Mag[1024]; / 输入,输出和幅值 /
    /


    • 函 数 名: PowerMag
    • 功能说明: 求模值
    • 形 参:_usFFTPoints FFT点数
    • 返 回 值: 无

    /
    void PowerMag(uint16_t _usFFTPoints)
    {
    int16_t lX,lY;
    uint16_t i;
    float32_t mag;
    /
    计算幅值 /
    for (i=0; i < _usFFTPoints/2; i++)
    {
    lX= (output[i]<<16)>>16; /
    实部*/
    lY= (output[i]>> 16); /* 虚部 /
    {
    float X = _usFFTPoints
    ((float)lX)/32768;
    float Y = _usFFTPoints*((float)lY)/32768;
    mag = sqrt(XX+ YY)/_usFFTPoints; /* 求模 /
    Mag[i]=(u32)(mag
    65536); /* 求模后乘以2才是实际模值,直流分量不需要乘2 /
    }
    }
    /
    由于上面多乘了2,所以这里直流分量要除以2 /
    Mag[0] = Mag[0]/2;
    }
    /


    • 函 数 名: DSP_FFT1024
    • 功能说明: 1024点FFT实现
    • 形 参:无
    • 返 回 值: 无

    /
    //void PowerMag(uint16_t _usFFTPoints);
    void DSP_FFT1024(void)
    {
    uint16_t i;
    /
    获得1024个采样点 /
    for (i = 0; i < 1024; i++)
    {
    // input[i] = 0;
    /
    波形是由直流分量,50Hz正弦波和20Hz正弦波组成,波形采样率1KHz /
    input[i] = 1024 + 1024
    sin(23.1415926f50i/1000) + 512sin(23.1415926f20i/1000)+ 2048sin(23.1415926f100i/1000) ;
    }
    /
    计算1024点FFT
    output:输出结果,高16位是虚部,低16位是实部。
    input :输入数据,高16位是虚部,低16位是实部。
    第三个参数必须是1024。
    /
    cr4_fft_1024_stm32(output, input, 1024);
    /
    求幅值 /
    PowerMag(1024);
    /
    打印输出结果 /
    for (i = 0; i < 1024; i++)
    {
    printf("%4d, %.2f %10d\n",i,(((float)i
    1024/1024)-1),Mag[i]);
    }
    //(((float)i1024/1024)-1)该项为频率计算,用i采样频率(1024)/(采样点数)
    }**
    找到以上代码的网址:https://wenku.baidu.com/view/08ccee0984868762cbaed532.html

    展开全文
  • 傅里叶变换C语言.zip

    2020-04-13 09:28:33
    Opencv中使用的是dft函数,但是在很多场合需要纯C的代码,此程序完成了dft的函数功能,是纯C语言版本,只用了最基础的库。文件中有一幅lena的图像,将其归一化为32*32的大小,并将其像素值作为输入变量,输出结果为...
  • 即原始k点重排后位置: 即时域信号,x(n),重排序号perm_num = mod([1:n]*sigma,n)+1,则对应重排后的傅里叶变换,频谱顺序与原信号频谱X,经过重排序号perm_num1 = mod([1:n]*inv_sigma,n)+1,位置始终相差1(数论...

    作者:桂。

    时间:2018-01-06  14:00:25

    前言

    对于数字接收来讲,射频域随着带宽的增加,AD、微波、FPGA资源的需求越来越高,但频域开的越宽并不意味着频谱越宽,有限信号内可认为信号在宽开频域稀疏分布,最近较为流行的稀疏FFT(SFFT)是在传统FFT的基础上,利用了信号的稀疏特性,使得计算性能优于FFT。本文简单记录自己的理解。

    一、稀疏FFT

    主要是12年MIT的论文:Simple and Practical Algorithm for Sparse Fourier Transform。

    核心思想:

    SFT 作为这样一种“输出感知”算法,其核心思路是按照一定规则 Γ ( • )将信号频点投入到一组“筐”中(数量为 B,通过滤波器实现 ) . 因频域是稀疏的,各大值点将依很高的概率在各自的“筐”中孤立存在 . 将各“筐”中频点叠加,使 N 点长序列转换为 B点的短序列并作 FFT 运算,根据计算结果,忽略所有不含大值点的“筐”,最后根据对应分“筐”规则,设计重构算法 Γ-1 ( • )恢复出 N 点原始信号频谱。

    e2baacb3973b153cf014bea7220d2ccbc53.jpg

    算法流程:

    c463d820a6b0c9b5a8fb0640d3f7670a56b.jpg

    步骤一:选定一个sigma,实现数据频域重排。

    频域重排主要是因为FFT之后,频域大值集中在一起,需要将这一伙打散,保证频域的稀疏性(sparse)。打散之后就能稀疏,依据定理(可见n越大,打散的可能性越大,从这里看,sigma与B还是有关系的,sigma体现了相邻频点的最小间隔,而B决定了每个bucket的宽度):

    37eeaefbe24bd8a6a2dfbd27229f0590d7c.jpg

    这里是按一定概率(概率性)将频谱重排,MIT重排思路:

    ce9ec8097f94889f00aaca15cf230b0c27f.jpg

    对应代码:

    fs = 1000;

    f0 = 70;

    N = 256;

    t = [0:N-1]/fs;

    x = exp(1j*2*pi*t*f0) ;

    %%*************Step1:频谱随机重排**************

    sigma = 19; %inv(sigma) = 27

    tao = 3;

    %permutation

    perm_num = mod([1:N]*sigma+tao,N)+1;

    pn = x(perm_num);

    当然也有强制(确定性)将数据重排的思路,思路类似,只是实现方式不同:

    4ec7739135a5aeb4a03d2931f9325435405.jpg

    sigma的选择主要利用性质:

    0923f151a2e8796e0ecdd0cabc365d14ff5.jpg

    这里sigma^-1是sigma关于模N的逆元(数论倒数)。该点主要说明:变化前后的完备性(信号可重建)。

    步骤二:加窗。

    这里根据筐的多少(B),平分2pi频域,即带宽2pi/B,理想窗函数为矩形窗,但时域为无限长的sinc函数,需要加窗截断,可选择gausswin。

    即win = sinc.*gausswin:

    d40a3423513557ea07f6cc1d9d6206ecdea.jpg

    这里不局限于gausswin,满足给定约束的窗函数均可:

    7a2e328f54815992f2b7b9da70a65bc3820.jpg

    步骤三:频域抽取并作FFT

    加窗之后,保证了频谱不至于展宽严重,进一步保证了稀疏性。频域降采样:

    0247de5113af5bbc03afc335a2c1c5fab40.jpg

    等价于时域的混叠的傅里叶变换:

    e203ad63f0c70c2a5f97130cd945e204ac8.jpg

    故直接在时域进行处理。处理完成后进行FFT运算。

    该操作的理论基础为:

    db08ba4f8b265d24f446eef41f7843b2bab.jpg

    不谈加窗操作,x->p->y,可以看出x与y存在映射关系,而y的∑操作可以转化为并行,这样一来可以用多个低速率AD实现一个高速率AD的功能,前提是多个AD需要完全同步。

    与上述降速率思想等价的是:如果各AD可做好同步,则多个现有AD的能力,可以做出现有AD难以完成的事。

    步骤四:哈希映射

    哈希映射的线索为:最终观察的数据Y(k)【即y(n)】->P(k)【即p(n)】->X(k)【即x(n)】:

    第一步(y -> p)转化的理论依据:

    31b44f99eee9215005d66902550ae1efc46.jpg

    第二步(p -> x)转化的理论依据:

    序列重排后的频域变换为:

    d4a83789441fa7d84cb3c1cc9717af734c1.jpg

    这两步解释了算法step4的参数定义:

    4a527694064b56b9ebebe4742c649128652.jpg

    但实际中并非第一步提到的理想情况,实际情况是:

    5e98f441d97301c261650bde8706ec9dd93.jpg

    因此存在一个频谱重建的成功概率问题:

    1b4d33ebbc1dcd565d7149ec52493ae9cd8.jpg

    4章节的后半部分主要在证明这个概率问题。

    步骤五~六的主要目的,引用原文的说法:

    Here are two versions of the inner loop: location loops and estimation loops. Location loops are given a parameter d, and output a set I ⊂ [n] of dkn/B  coordinates that contains each large coefficient with“good” probability. Estimation loops are given a set  I ⊂ [n] and estimate x I such that each coordinate is  estimated well with “good” probability.

    步骤五:定位循环

    d是一个参数,存在约束

    37b0e0f5c9fe4d603d7b5d63fa6ba93cfa5.jpg

    原文取值为:

    b74ade2d409aec34cdd0773e8e1b3dbd2fe.jpg

    该步骤的主要操作为:

    将 Z ( k )中 dK 个较大值(从大到小依次排列)的坐标( k)归入集合 J 中,通过哈希反映射得到 J 的原像:

    2b5b901dc4d42fdf0ceeeae2223af9e7ab6.jpg

    这样便得到包含原始频谱坐标的集合,迭代L次:

    a8d787fcf0f7f13596c16a4a2c568a7cd12.jpg

    迭代的目的?

    步骤六:估值循环

    对于每个k∈Ir,计算频率信息:

    85de7ea88c3105ba01a0c281748091bfac9.jpg

    步骤5~6主要操作:

    57217e06f444ba73dc2656a729fad2e1266.jpg

    至此完成了稀疏FFT(sparse FFT)的整个运算过程,记作sfft_v01。

    改进版都是依次大框架进行,不同点主要有三个方面:1)重排的实现思路;2)频谱的重建思路。不再一一展开。

    原文示例:

    5570a844553badddad6fc1486d615e5f2ac.jpg

    该示例给出了步骤5~6的直观解释:

    ee2fba3cae55316cb09b6fe6d7e3b847235.jpg

    二、问题记录

    仿真验证:n = 256点频信号,sigma = 19,则inv_sigma = 27,假设生成点频信号:

    de4b1f8ce3449de3efcb759b1652ba816a9.jpg

    图1为重排的信号,图2为重排加窗(此处窗不够理想,看到长尾,论文中强调加窗,作用在于把尾巴剁掉。),图3为原始信号频谱,图4为降采样之后的频谱。可以看出重排容易引入谐波:以sigma为周期。

    原始频谱位置为k=10-1 = 9(下标从0开始),重排后对应频谱位置为mod(sigma*k,n) = 171 = 172-1,与理论分析一致。即原始k点重排后位置:

    4f8809a5a1f92c15f15c1aed2a7e953ff72.jpg

    即时域信号,x(n),重排序号perm_num = mod([1:n]*sigma,n)+1,则对应重排后的傅里叶变换,频谱顺序与原信号频谱X,经过重排序号perm_num1 =  mod([1:n]*inv_sigma,n)+1,位置始终相差1(数论倒数的性质决定):mod(sigma*inv_sigma,n)=1

    展开全文
  • 程序完成傅里叶变换中图像的含义,详见维基百科:https://en.wikipedia.org/wiki/File:Fourier_series_square_wave_circles_animation.gif 程序中,circle控制圆的绘制,curve控制曲线的绘制,rotate控制圆的旋转。...
  • Numpy模块提供了傅里叶变换功能,Numpy模块中的fft2()函数可以实现图像的傅里叶变换。本节介绍如何用Numpy模块实现图像的傅里叶变换,以及在频域内过滤图像的低频信息,保留高频信息,实现高通滤波。 14.2.1 实现...
  • #include #include /*********************************************************************快速傅立叶变换函数简介:此函数是通用的快速傅里叶变换C 函数C 语言函数,移植性强,以下部分不依赖硬件。此函数采用...
  • 本文是对斯坦福大学公开课-傅里叶变换及其应用的一些学习总结 对应的课程视频链接为:课程链接 课程用到的讲义下载地址:讲义链接 傅里叶变换的内容对应课程5-8节,讲义第二章。 由傅里叶级数到傅里叶变换 在...
  • 图像处理傅里叶变换图像变化What do Fourier Transforms do? What do the Fourier modes represent? Why are Fourier Transforms notoriously popular for data compression? These are the questions this article ...
  • C++ 傅里叶变换 推导

    2021-09-10 06:22:57
    傅里叶变换   在自己对傅里叶变换的不断学习中,逐渐对其有了一些新的理解,新的想法。故在本文中将首先简要介绍一下傅里叶变换的作用,之后对傅里叶变换过程给出自己角度的理解。 1 傅里叶变换的作用   所谓...
  • DSP-傅里叶变换

    2021-03-24 11:06:57
    DSP-傅里叶变换时域、频域功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个...
  • opencv-python 傅里叶变换

    千次阅读 2020-05-05 08:37:49
    目标: ...对于图像,2D离散傅里叶变换(DFT)用于找到频域。称为快速傅里叶变换(FFT)的快速算法用于计算DFT。有关这些的详细信息可以在任何图像处理或信号处理教科书中找到。 对于正弦信号,x(t...
  • 这不,无聊的假期里,我用它做了一个音频的频率计,通过电脑上的声卡采集声音,用傅里叶变换完成时域-频域的转换,最后确定声音的主频率。用这个简陋的频率计来给吉他定调,比专业的定音器还好玩。
  • 写了一上午,然后浏览器卡了,触发了自动刷新功能,87%的都没有了。 然后一怒之下删掉了。 从多项式说起 多项式的表示法 系数表示法 f(x)⁡=a0x0+a1x1+a2x2+⋯+anxn \large\operatorname{f(x)}=a_0x^0+a_1x^1...
  • 大概能明白傅里叶变换是干吗的了 但是还是不能明白为什么用傅里叶变换来算多项式求和 在多项式中,DFT就是系数表式转换成点值表示的过程。 我们熟知的是多项式的系数表示法,通过给定一组来确定一个唯一的...
  • 傅里叶变换应该是上大二的时候《信号与系统》课上学过,上研后在《数字信号处理》课上又学了一遍。当初一直在想傅里叶变换到底有什么用呢?什么时候能用上呢?时间如梭,没想到毕业四年后,一个小项目要用到傅里叶...
  • 数据分析-傅里叶变换

    2019-01-23 08:56:02
    傅里叶变换的过程即是把这条周期曲线拆解成多个光滑正弦曲线的过程. 傅里叶变换的目的是将时域(时间域)上的信号转变为频域(频率域信号), 随着域的不同, 对一个事物的了解角度也会随之改变.因此某些在时域中不好处的...
  • 快速傅里叶变换FFT的C语言算法彻底研究 LED音乐频谱显示的核心算法就是快速傅里叶变换,FFT的理解和编程还是比较难的,特地撰写此文分享一下研究成果。  一、彻底理解傅里叶变换 快速傅里叶变换(Fast Fourier...
  • [Python图像处理六] :Opencv图像傅里叶变换傅里叶变换原理及实现 一、傅里叶变换 1、傅里叶变换原理 2、自定义傅里叶变换功能函数 3、OpenCV库函数实现傅里叶变换 二、傅里叶变换 1、傅里叶变换原理 2、...
  • 接触了图像的傅里叶变换,数学原理依旧不是很懂,因此不敢在这里妄言。下午用Opencv代码实现了这一变换,有一些经验心得 二、关键函数解析 2.1copyMakeBorder() 扩展图片尺寸 傅里叶变换的计算对图像的尺寸有一定...
  • 并行快速傅里叶变换 mpi4py-fft

    千次阅读 2018-11-06 20:26:05
    本文从本人简书博客同步过来 在上一篇中我们介绍了一个使用 mpi...快速傅里叶变换(Fast Fourier Transform, FFT),是快速计算序列的离散傅里叶变换(DFT)或其逆变换的方法。傅里叶分析将信号从原始域(通常是时间...
  • 傅里叶变换的理解

    2020-01-14 16:01:23
    这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、...
  • 目标: ...对于图像,2D离散傅里叶变换(DFT)用于找到频域。称为快速傅里叶变换(FFT)的快速算法用于计算DFT。有关这些的详细信息可以在任何图像处理或信号处理教科书中找到。 对于正弦信号,x(...
  • 图像处理一般分为空间域处理和频率域处理。空间域处理是直接对图像额内部的...傅里叶变换是应用最广的一种频域变换,它能够将图像从空间域变换到频率域,同样,逆傅里叶变换则可以将频率域的信息变换到空间域内。 ...
  • matlab离散傅里叶变换平滑代码ECE 438:具有应用程序的数字信号处理 课程说明:本课程分为三个单元。 基础:连续时间和离散时间信号的回顾,以及频谱分析; 有限冲激响应和无限冲激响应数字滤波器的设计; 处理随机...
  • OpenCV(七)之直方图与傅里叶变换

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,505
精华内容 1,402
关键字:

傅里叶变换完成的功能