傅丽叶变换(二)
——(java)算法实现
离散傅里叶变换
离散傅里叶变换使得数学方法与计算机技术建立了联系,这就为傅里叶变换这样一个数学工具在实用中开辟了一条宽阔的道路。因此,它不仅仅有理论价值,而且在某种意义上说它也有了更重要的实用价值。
离散傅里叶变换的定义
如果x(n)为一数字序列,则其离散傅里叶正变换定义由下式来表示
傅里叶反变换定义由下式来表示
由(1)和(2)式可见,离散傅里叶变换是直接处理离散时间信号的傅里叶变换。如果要对一个连续信号进行计算机数字处理,那么就必须经过离散化处理。这样,对连续信号进行的傅里叶变换的积分过程就会自然地蜕变为求和过程。
快速傅里叶变换(FFT)
快速傅里叶变换并不是一种新的变换,它是离散傅里叶变换的一种算法。这种方法是在分析离散傅里叶变换中的多余运算的基础上,进而消除这些重复工作的思想指导下得到的,所以在运算中大大节省了工作量,达到了快速运算的目的。扩大了傅里叶变换的使用范围。下面我们从基本定义入手,讨论其原理。
对于一个有限长序列{x(n)}(0<=n<N-1),它的傅里叶变换由下式表示
令
因此,傅里叶变换对可写成下式
将正变换式(4)展开可得到如下算式
上面的方程式(6)可以用矩阵来表示
从上面的运算显然可以看出,要得到每一个频率分量,需进行N次乘法和N-1次加法运算。要完成整个变换需要N2次乘法和N(N-1)次加法运算。当序列较长时,必然要花费大量的时间。
观察上述系数矩阵,发现Wmn是以为N周期的,即
例如,当N=8时,其周期性如图3—6所示。由于exp(iθ)=cosθ+isinθ,即exp(-iθ)=cos(-θ)+isin(-θ)=cosθ-isinθ,所以
当N=8时,可得:
图1,N=8时Wmn的周期性和对称性
快速傅里叶变换简称FFT。算法根据分解的特点一般有两类,一类是按时间分解,一类是按频率分解。下面介绍一下FFT的基本形式及运算蝶式流程图。
把x(n)分成偶数点和奇数点,即:
由此,离散傅丽叶变换可写成如下的形式:
(10)
这种算法的流程图如图2所示:图(a)输入为顺序的,运算结果是乱序的;图(b)输入为乱序的,运算结果是顺序的。
图2,FFT蝶式运算流程图(按时间分解)
用计算机实现快速付傅里叶变换
利用FFT蝶式流程图算法在计算机上实现快速傅里叶变换必须解决如下问题:
1)、迭代次数r的确定;
由蝶式流程图可见,迭代次数r与N有关。值可由下式确定
int r = (int)(Math.log10(n)/Math.log10(2)); //求迭代次数r
式中N是变换序列的长度。对于前述基数2的蝶式流程图是2的整数次幂。例如,序列长度为8则要三次迭代,序列长度为16时就要4次迭代等等。
2)、对偶节点的计算;
在流程图中把标有xl(k)的点称为节点。其中下标l为列数,也就是第几次迭代,例如,xl(k)则说明它是第一次迭代的结果。k代表流程图中的行数,也就是序列的序号数。其中每一节点的值均是用前一节点对计算得来的。例如,x1(0)和x1(4)均是x(0)和x(4)计算得来的。在蝶式流程图中,把具有相同来源的一对节点叫做对偶节点。
如:x1(0)和x1(4)就是一对对偶节点,因为它们均来源于x(0)和x(4)。对偶节点的计算也就是求出在每次迭代中对偶节点的间隔或者节距。由流程图可见,第一次迭代的节距为N/2,第二次迭代的节距为N//22,第三次迭代的节距为N//23等等。由以上分析可得到如下对偶节点的计算方法。
如果某一节点为xl(k),那么,它的对偶节点为
xl(k+N/2l) (12)
if(k < n/Math.pow(2, l)) {
x1 = k;
x2 = x1 + (int)(n/Math.pow(2, l));
} else {
x2 = k;
x1 = x2 - (int)(n/Math.pow(2, l));
}
式中l是表明第几次迭代的数字,k是序列的序号数,N是序列长度。
例:如果序列长度N=8,求x2(1)的对偶节点。
xl(k+N/2l)=x2((1+8/22)=x2(3)
x2((1)=x1((1)+W80x1(3)
x2((3)=x1((1)+W84x1(3)
3)、加权系数WNP的计算;
WNP的计算主要是确定p值。p值可用下述方法求得。
(1)把k值写成r位的二进制数(k是序列的序号数,r是迭代次数);
(2)把这个二进制数右移r-l位,并把左边的空位补零(结果仍为r位);
(3)把这个右移后的二进制数进行比特倒转;
(4)把这比特倒转后的二进制数翻成十进制数就得到p值。
例:求x2(2)的加权系数W8P。
(1)因为k=2,所以写成二进制数为010;
(2)r-l=3-2=1,把010右移一位得到001;
(3)把001做位序颠倒,即做比特倒转,得到100;
(4)把100译成十进制数,得到4,所以p=4,x2(2)的加权值为WNP。
结合对偶节点的计算,可以看出WNP具有下述规律:如果某一节点上的加权系数为WNP,则其对偶节点的加权系数必然是WNp+N/2,而且WNP=
-WNp+N/2,所以一对对偶节点可用下式计算
/**
* 求加权系数
* 1.将数k写成r位的二进制数;2.将该二进制数向右移r-l位;3.将r位的二进制数比特倒转;4.求出倒置后的二进制数代表的十进制数;
* @param k 要倒转的十进制数
* @param l 下标值
* @param r 二进制的位数
* @return 加权系数
*/
private int getWeight(int k, int l, int r) {
int d = r-l; //位移量
k = k>>d;
return reverseRatio(k, r);
}
4)、重新排序问题。
由蝶式流程图可见,如果序列x(n)是按顺序排列的,经过蝶式运算后,其变换序列X(m)是非顺序排列的,即乱序的;反之,如果x(n)是乱序的,那么,就是顺序的。因此,为了便于输出使用,最好加入重新排序程序,以便保证x(n)与它的变换系数X(m)的对应关系。具体排序方法如下:
(1)将最后一次迭代结果xl(k)中的序号数k写成二进制数;
(2)将r位的二进制数比特倒转:
(3)求出倒置后的二进制数代表的十进制数,就可以得到与x(k)相对应的X(m)的序号数。
例如:
N=8的最后迭代结果:
x3(0)→000→倒置→000→十进制(0)
x3(1)→001→倒置→100→十进制(4)
x3(2)→010→倒置→010→十进制(2)
x3(3)→011→倒置→110→十进制(6)
x3(4)→100→倒置→001→十进制(1)
x3(5)→101→倒置→101→十进制(5)
x3(6)→110→倒置→011→十进制(3)
x3(7)→111→倒置→111→十进制(7)
/**
* 将数进行二进制倒转, 如0101倒转至1010
* 1.将数k写成r位的二进制数;2.将r位的二进制数比特倒转;3.求出倒置后的二进制数代表的十进制数;
* @param k 要倒转的十进制数
* @param r 二进制的位数
* @return 倒转后的十进制数
*/
private int reverseRatio(int k, int r) {
int n = 0;
StringBuilder sb = new StringBuilder(Integer.toBinaryString(k));
StringBuilder sb2 = new StringBuilder("");
if(sb.length()<r) {
n = r-sb.length();
for(int i=0; i<n; i++) {
sb.insert(0, "0");
}
}
for(int i=0; i<sb.length(); i++) {
sb2.append(sb.charAt(sb.length()-i-1));
}
return Integer.parseInt(sb2.toString(), 2);
}
一维傅丽叶变换的源码实现
里面用到了复数的计算,关于复数的计算的源码实现,请参考《
》
/**
* 一维快速傅里叶变换
* @param values 一维复数集数组
* @return 傅里叶变换后的数组集
*/
public Complex[] fft(Complex[] values) {
int n = values.length;
int r = (int)(Math.log10(n)/Math.log10(2)); //求迭代次数r
Complex[][] temp = new Complex[r+1][n]; //计算过程的临时矩阵
Complex w = new Complex(); //权系数
temp[0] = values;
int x1, x2; //一对对偶结点的下标值
int p, t; //p表示加权系数Wpn的p值, t是重新排序后对应的序数值
for(int l=1; l<=r; l++) {
if(l != r) {
for(int k=0; k<n; k++) {
if(k < n/Math.pow(2, l)) {
x1 = k;
x2 = x1 + (int)(n/Math.pow(2, l));
} else {
x2 = k;
x1 = x2 - (int)(n/Math.pow(2, l));
}
p = getWeight(k, l, r);
//xi(j) = temp[i-1][x1] + Wpn* temp[i-1][x2];
w.setA(Math.cos(-2*Math.PI*p/n));
w.setB(Math.sin(-2*Math.PI*p/n));
temp[l][k] = Complex.add(temp[l-1][x1] , Complex.multiply(w, temp[l-1][x2]) );
}
} else {
for(int k=0; k<n/2; k++) {
x1 = 2*k;
x2 = 2*k+1;
//System.out.println("x1:" + x1 + " x2:" + x2);
t = reverseRatio(2*k, r);
p = t;
w.setA(Math.cos(-2*Math.PI*p/n));
w.setB(Math.sin(-2*Math.PI*p/n));
temp[l][t] = Complex.add(temp[l-1][x1] , Complex.multiply(w, temp[l-1][x2]) );
t = reverseRatio(2*k+1, r);
p = t;
w.setA(Math.cos(-2*Math.PI*p/n));
w.setB(Math.sin(-2*Math.PI*p/n));
temp[l][t] = Complex.add(temp[l-1][x1] , Complex.multiply(w, temp[l-1][x2]) );
}
}
}
return temp[r];
}
二维傅丽叶变换的源码实现
/**
* 一维快速傅里叶变换
* @param matrix 二维复数集数组
* @param w 图像的宽
* @param h 图像的高
* @return 傅里叶变换后的数组集
*/
public Complex[][] fft(Complex matrix[][], int w, int h) {
double r1 = Math.log10(w)/Math.log10(2.0) - (int)(Math.log10(w)/Math.log10(2.0));
double r2 = Math.log10(h)/Math.log10(2.0) - (int)(Math.log10(w)/Math.log10(2.0));
if(r1 != 0.0 || r2 != 0.0) {
System.err.println("输入的参数w或h不是2的n次幂!");
return null;
}
int r = 0;
r = (int)(Math.log10(w)/Math.log10(2));
//进行行傅里叶变换
for(int i=0; i<h; i++) {
matrix[i] = fft(matrix[i]);
}
//进行列傅里叶变换
int n = h;
r = (int)(Math.log10(n)/Math.log10(2)); //求迭代次数r
Complex tempCom[] = new Complex[h];
for(int j=0; j<w; j++) {
for(int i=0; i<h; i++) {
tempCom[i] = matrix[i][j];
}
tempCom = fft(tempCom);
for(int i=0; i<h; i++) {
matrix[i][j] = tempCom[i];
}
}
return matrix;
}
分享到:
相关推荐
#### 二、傅立叶变换的基本思想 傅立叶变换的核心思想在于将一个复杂的周期信号分解为其组成成分——正弦波。这一过程有助于简化信号分析,因为它揭示了信号的频谱特性。例如,在音频信号处理中,通过傅立叶变换...
二、傅立叶反变换的原理 傅立叶反变换是将信号从频域转换到时域的数学工具。傅立叶反变换的原理是将频谱分解成不同的频率分量,然后将这些频率分量组合成时域信号。 三、快速傅立叶变换(FFT) 快速傅立叶变换...
在计算机科学和工程领域,处理信号和图像分析时,傅立叶变换(FT)和快速傅立叶变换(FFT)是不可或缺的工具。它们提供了从时域到频域转换的途径,让我们能够分析信号的频率成分。本文将探讨傅立叶变换和快速傅立叶...
分数阶傅立叶变换(Fractional Fourier Transform, FRFT)是一种信号处理技术,它将信号从时域转换到频域,但不同于传统的傅立叶变换,FRFT 使用了分数幂形式的傅立叶变换。该技术可以用于信号处理、图像处理、 ...
傅立叶变换是一种数学工具,它能够将一个在时间域或空间域中的函数转换为其在频率域或谱域中的表示。这一变换的核心在于将复杂的信号分解为简单的正弦和余弦函数的组合,这些基本频率成分反映了信号的构成要素。傅立...
本文将详细探讨标题中的四个关键概念:正交变换、一维傅立叶变换、二维离散余弦变换以及沃尔什变换,并结合VS2017这一编程环境,讲解它们的应用及实现。 首先,**正交变换** 是一类特殊的线性变换,它保持了向量间...
二维离散傅立叶变换程序设计 一、实验目的与要求 本实验的目的是通过学习傅立叶变换原理,掌握并编程验证二维离散傅立叶变换,理解二维傅立叶变换的主要性质。 二、知识点 1. 数字图像傅立叶变换的目的 数字...
二、傅立叶变换 1. 定义:傅立叶变换是一种将信号从时域表示转换到频域表示的方法。它能够揭示信号的频率成分,即信号由哪些不同频率的正弦波合成。 2. 概念:傅立叶变换把一个在时间上变化的信号(时域信号)转换...
二维离散傅立叶变换(2D DFT)是数字信号处理中的一个重要概念,它扩展了一维离散傅立叶变换(DFT)到多维空间,尤其在图像处理和频谱分析中有着广泛的应用。二维DFT可以将一个二维离散信号转换为其频率域表示,从而...
在IT领域,傅立叶变换是一种非常重要的数学工具,它在图像处理、信号处理和通信等领域有着广泛应用。本文将深入探讨C++实现傅立叶变换的过程,并以对图片进行傅立叶转换为例,来阐述这一技术的具体应用。 傅立叶...
傅立叶变换是数字信号处理领域中的一个核心概念,它在图像处理、音频处理、通信工程等诸多领域都有着广泛的应用。本教程将详细讲解傅立叶变换滤波的原理及其在实际中的演示。 傅立叶变换是一种数学工具,它可以将一...
1. **源代码文件**:这些可能是C#类库或控制台应用程序,实现了二维傅立叶变换的算法,可能包括预处理步骤(如将RGB图像转换为灰度图像)、执行FFT以及后处理步骤(如计算幅度谱、对结果进行反变换)。 2. **测试...
"傅立叶变换基础(包括基本公式)" 傅立叶变换是信号处理中的一种基本变换方法,它将时域信号转换为频域信号,从而方便了信号的分析和处理。傅立叶变换的基础知识包括傅立叶级数、傅立叶变换的基本公式、卷积公式等...
在这个"YangBen.rar_傅立叶_傅立叶变换_傅立叶变换 Matlab"压缩包中,包含的资源主要是关于傅立叶变换的Matlab源代码,用于实现这一转换过程。 Matlab作为一种强大的数值计算和可视化软件,是实现傅立叶变换的理想...
图像本质上是二维离散信号,可以应用二维离散傅立叶变换(2D DFT)。变换后的频谱图可以揭示图像的频率特征,例如边缘和高频细节。通过比较原始图像和其频谱图,可以观察到低频成分(对应图像的整体结构)和高频成分...
快速傅立叶变换(FFT)是数字信号处理领域中一种至关重要的算法,它极大地提高了离散傅立叶变换(DFT)的计算效率。DFT是连续傅立叶变换在离散时间序列上的应用,然而,由于DFT的计算复杂度为O(N^2),对于大数据量的...
与一维傅立叶变换类似,二维傅立叶变换的幅度谱和相位谱如下式: $$FRI(ω)=|F(ω)|eiφ(ω)$$ 其中,$|F(ω)|$是幅度谱,$φ(ω)$是相位谱。 傅立叶变换在图像处理中的应用非常广泛,例如图像增强、图像复原、...
"数学与傅立叶变换" 傅立叶变换是数学中一种基本的变换技术,用于将信号从时域转换到频域。傅立叶变换可以将信号分解成多个频率分量,方便信号的分析和处理。 1. 傅立叶级数 傅立叶级数是指将周期信号表示为多个...