GSL中的快速傅里叶变换(FFTS)

快速傅里叶变换(FFTS)

    本章描述了执行快速傅里叶变换(FFTs)的函数。库中包含了radix-2例程(长度为2的幂)和混合基数例程(长度不限)。为了提高效率,对于真实数据和复杂数据,有不同版本的例程。混合基数例程是对Paul Swarztrauber的FFTPACK库的重新实现。FFTPACK的Fortran代码在Netlib上是可用的(FFTPACK也包括一些用于正弦和余弦变换的例程,但这些例程目前在GSL中不可用)。有关底层算法的详细信息和派生,请参阅文档“GSL FFT算法”(参见参考资料和进一步阅读)。

16.1 数学定义

    快速傅里叶变换是计算离散傅里叶变换(DFT)的有效算法,

    当函数在空间或时间上以离散间隔采样时,DFT通常是连续傅里叶变换的近似值。离散傅立叶变换的简单评估是矩阵向量乘积Wz

一般的矩阵向量乘法对n个数据点进行O(n2)次运算。快速傅里叶变换算法使用分治策略将矩阵W分解成更小的子矩阵,这些子矩阵对应于长度n的整数因子。如果n可以分解成整数积f1f2…fm,然后在O(nfi)运算中计算DFT。对于基数为2 的FFT,运算次数为O(nlog2 n)。

基于相同的数学定义,所有FFT函数都提供三种类型的转换:正向、逆向和反向。反向傅里叶变换x = FFT(z)的定义是,

傅里叶逆变换x = IFFT(z)的定义是

 因子1/n使得它是一个真正的逆矩阵。例如,调用gsl_fft_complex_forward()然后调用gsl_fft_complex_inverse()应该返回原始数据(在数值错误内)。

    一般来说,对于变换/逆变换对中的指数符号有两种可能的选择。GSL遵循与FFTPACK相同的约定,使用负指数进行正向转换。这种惯例的优点是,逆变换用简单的傅里叶综合法重建了原来的函数。数值方法使用相反的约定,正指数在正向变换。

反向FFT只是我们对逆FFT的无标度版本的术语,

当结果的整体比例不重要时,使用反向FFT而不是逆通常会很方便,以节省不必要的除法。

16.2 复数FFTs概述

复FFT例程的输入和输出是浮点数的压缩数组。在一个压缩数组中,每个复数的实部和虚部都位于相邻的备用元素中。例如,以下对长度为6的打包数组的定义:

double x[3*2];

gsl_complex_packed_array data = x;

可以通过以下方式用于保存三个复数z [3]的数组:

data[0] = Re(z[0])

data[1] = Im(z[0])

data[2] = Re(z[1])

data[3] = Im(z[1])

data[4] = Re(z[2])

data[5] = Im(z[2])

    数据的数组索引具有与DFT定义相同的顺序,即没有数据的索引转换或排列。

    stride参数允许用户对元素z[stride*i]代替z[i]执行转换。一个大于1的步长可以用来代替矩阵列的位置FFT。步长为1时访问数组,元素之间不需要任何额外的间距。

    要对向量参数(例如gsl_vector_complex * v)执行FFT,请在调用本章中介绍的函数时使用以下定义(或其等效项):

gsl_complex_packed_array data = v->data;

size_t stride = v->stride;

size_t n = v->size;

    对于物理应用程序,重要的是要记住,DFT中出现的索引并不直接对应于物理频率。如果DFT的时间步长为∆,则频率域包括正频率和负频率,范围为- 1/(2∆)到0 ~ +1/(2∆)。正频率从数组的开头一直存储到中间,负频率从数组的末尾向后存储。

下面的表格展示了数组数据的布局,以及时域数据z和频域数据x之间的对应关系:

index        z                         x = FFT(z)

0               z(t = 0)               x(f = 0)

1               z(t = 1)              x(f = 1/(n Delta))

2               z(t = 2)              x(f = 2/(n Delta))

. .               .......                   ..................

n/2           z(t = n/2)          x(f = +1/(2 Delta),

                                        -1/(2 Delta))

.                ........                  ..................

n-3          z(t = n-3)          x(f = -3/(n Delta))

n-2          z(t = n-2)          x(f = -2/(n Delta))

n-1          z(t = n-1)          x(f = -1/(n Delta)

    当n为偶数时,位置n/2包含的正、负频率(+1/(2∆),-1/(2∆))最大,且相等。如果n是奇数,那么上面表的一般结构仍然适用,但是n/2没有出现。

GSL(GNU Scientific Library)是一个开源的科学计算库,其包含了许多常用的数学函数算法。其就包括小波变换函数。小波变换是一种能够将信号分解成不同频率的技术。在信号处理、数据压缩、图像处理等领域被广泛应用。 GSL 的小波变换函数可以用来进行一维和二维的小波变换。一维小波变换可以用来处理一维信号,例如时间序列数据。而二维小波变换则可以用来处理二维图像数据。 下面是一个使用 GSL 进行一维小波变换的简单示例代码: ```c #include <stdio.h> #include <gsl/gsl_wavelet.h> int main() { const gsl_wavelet *w = gsl_wavelet_alloc(gsl_wavelet_haar, 2); gsl_wavelet_workspace *work = gsl_wavelet_workspace_alloc(1024); double data[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0}; gsl_wavelet_transform(w, data, 1, 8, work); for (int i = 0; i < 8; i++) { printf("%f ", data[i]); } printf("\n"); gsl_wavelet_free(w); gsl_wavelet_workspace_free(work); return 0; } ``` 这个例子使用了 Haar 小波作为小波基函数,对一个长度为 8 的一维数据进行了小波变换。具体来说,它将这个数据分成了 4 个长度为 2 的子序列,对每个子序列分别进行了变换,得到了一个长度为 8 的小波系数序列。最后输出了变换后的结果。 二维小波变换的代码类似,只需要将一维数据改为二维数据即可。需要注意的是,二维小波变换通常需要使用更复杂的小波基函数,例如 Daubechies 小波。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值