GSL 学习笔记(快速傅立叶变换)

GSL 学习笔记(快速傅立叶变换)

GNU Scientific Library (GSL)是一个开源的科学计算的函数库,里面实现了大量的数学函数,还提供了方程求解、傅立叶变换等多种功能。

GSL FFT 的定义如下,

正变换(forward):

逆变换(inverse):

还有一个叫做反向变换:

反变换(backward):

复数FFT,长度为2^N

这是最简单的一种。C89标准中没有定义复数类型,不过gsl 倒是给了个gsl_complex 类型。我们可以使用这个类型,或者直接实部虚部交替着放置。

下面是三个计算函数,都是在原位进行FFT计算,也就是计算结果仍然在 data 所指向的数据区。

int gsl_fft_complex_radix2_forward (gsl complex packed array data, size t stride, size t n)
int gsl_fft_complex_radix2_backward (gsl complex packed array data, size t stride, size t n)
int gsl_fft_complex_radix2_inverse (gsl complex packed array data, size t stride, size t n)

还有一个既可以算正变换,也可以算逆变换。用法也很简单。

int gsl_fft_complex_radix2_transform (gsl complex packed array data, size t stride, size t n, gsl fft direction sign)

因为用法非常简单,就不多说了,下面是个简单的算例。

#include <stdio.h>
#include <math.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_fft_complex.h>

#define REAL(z,i) ((z)[2*(i)])
#define IMAG(z,i) ((z)[2*(i)+1])

int
main (void)
{
    int i;
    double data[2*128];

    for (i = 0; i < 128; i++)
    {
        REAL(data,i) = 0.0;
        IMAG(data,i) = 0.0;
    }

    REAL(data,0) = 1.0;

    for (i = 1; i <= 10; i++)
    {
        REAL(data,i) = REAL(data,128-i) = 1.0;
    }

    for (i = 0; i < 128; i++)
    {
        printf ("%d %e %e\n", i,
                REAL(data,i), IMAG(data,i));
    }
    printf ("\n");

    gsl_fft_complex_radix2_forward (data, 1, 128);

    for (i = 0; i < 128; i++)
    {
        printf ("%d %e %e\n", i,
                REAL(data,i)/sqrt(128),
                IMAG(data,i)/sqrt(128));
    }

    return 0;
}

复数FFT,任意长度

用法也很简单。比如我们要计算N点的FFT。首先要先生成一个 wavetable

gsl_fft_complex_wavetable *wavetable = gsl_fft_complex_wavetable_alloc (N);

然后还要分配workspace

gsl_fft_complex_workspace * workspace = gsl_fft_complex_workspace_alloc (N);

之后就可以具体的计算工作了。计算的结果还是原位存放。

gsl_fft_complex_forward (data, stride, N, wavetable, workspace );
gsl_fft_complex_transform (data, stride, N, wavetable, workspace, sign);
gsl_fft_complex_backward  (data, stride, N, wavetable, workspace );
gsl_fft_complex_inverse  (data, stride, N, wavetable, workspace );

算完之后记得释放分配的空间。

gsl_fft_complex_workspace_free (workspace);
gsl_fft_complex_wavetable_free (wavetable);
 

下面还是一个简单的例子:

#include <stdio.h>
#include <math.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_fft_complex.h>

#define REAL(z,i) ((z)[2*(i)])
#define IMAG(z,i) ((z)[2*(i)+1])

int main (void)
{
    int i;
    const int n = 630;
    double data[2*n];
    gsl_fft_complex_wavetable * wavetable;
    gsl_fft_complex_workspace * workspace;

    for (i = 0; i < n; i++)
    {
        REAL(data,i) = 0.0;
        IMAG(data,i) = 0.0;
    }
    data[0] = 1.0;

    for (i = 1; i <= 10; i++)
    {
        REAL(data,i) = REAL(data,n-i) = 1.0;
    }

    for (i = 0; i < n; i++)
    {
        printf ("%d: %e %e\n", i, REAL(data,i), IMAG(data,i));
    }
    printf ("\n");

    wavetable = gsl_fft_complex_wavetable_alloc (n);
    workspace = gsl_fft_complex_workspace_alloc (n);

    for (i = 0; i < wavetable->nf; i++)
    {
        printf ("# factor %d: %d\n", i,
                wavetable->factor[i]);
    }
    gsl_fft_complex_forward (data, 1, n, wavetable, workspace);
    for (i = 0; i < n; i++)
    {
        printf ("%d: %e %e\n", i, REAL(data,i), IMAG(data,i));
    }

    gsl_fft_complex_wavetable_free (wavetable);
    gsl_fft_complex_workspace_free (workspace);
    return 0;

}

实数FFT,长度为2^M

长度为2^M的实数向量的FFT得到是长度为2^M的共轭对称复数向量。由于是共轭对称的,因此理论上只需要2^M 个存储空间就可以存下。 所谓共轭对称指的是:

所以变换后,N元素只要知道前 N/2个元素的值就可以得到后面N/2个元素的值。

 

GSL 中采用的存储方式如下:

设数组长度为N,变换后,数据按照如下方式存放。

 

位置

输出数据

0

complex[0].real

1

complex[1].real

2

complex[2].real

...

...

N/2

complex[N/2].real

N/2+1

-complex[N/2+1].imag

...

...

N-2

-complex[N-2].imag

N-1

-complex[N-1].imag

 

反变换时数据必须也按照这种方式存放。

int gsl_fft_real_radix2_transform (double data[], size_t stride, size_t n)
int gsl_fft_halfcomplex_radix2_inverse (double data[], size_t stride, size_t n)
int gsl_fft_halfcomplex_radix2_backward (double data[], size_t stride, size_t n)

实数FFT,任意长度

当数据长度为任意长度时,GSL 库采用另外一种方式存储变换后的结果。这种存储方式与Paul Swarztrauber编写的fftpack 相同。

N为偶数时,

complex[0].img = 0

complex[N/2].img = 0

 

还是用个表格来说明:

位置

输出数据

0

complex[0].real

1

complex[1].real

2

complex[1].imag

3

complex[2].real

4

complex[2].imag

...

...

N-2

complex[N/2-1].real

N-1

complex[N/2-1].imag

 

N为奇数时,complex[0].img = 0

位置

输出数据

0

complex[0].real

1

complex[1].real

2

complex[1].imag

3

complex[2].real

4

complex[2].imag

...

...

N-3

complex[(N-1)/2].real

N-2

complex[(N-1)/2].imag

N-1

complex[(N+1)/2].real

 

上面的表格还是挺复杂的,GSL 还提供了两个辅助函数,帮我们转换数据格式。

int gsl_fft_real_unpack (const double real_coefficient[], gsl_complex_packed_array complex_coefficient[], size_t stride, size_t n)

这个函数可以把实数数组转换为复数数组。之后就可以用复数fft 函数来计算了。

int gsl_fft_halfcomplex_unpack (const double halfcomplex_coefficient[], gsl_complex_packed_array complex_coefficient, size_t stride, size_t n)

这个函数可以把 gsl_fft_real_transform 函数计算出的 half-complex 数组扩充为正常的复数数组。

不过GSL 没有提供将 gsl_fft_real_radix2_transform 计算结果展开的函数。如果需要,只能自己实现。

 

具体计算时与复数的fft 类似,正变换时按如下的顺序调用。

gsl_fft_real_wavetable * gsl_fft_real_wavetable_alloc (size_t n);
gsl_fft_real_workspace * gsl_fft_real_workspace_alloc (size_t n);

int gsl_fft_real_transform (double data[], size_t stride, size_t n, const gsl_fft_real_wavetable * wavetable, gsl_fft_real_workspace * work);

void gsl_fft_real_workspace_free (gsl_fft_real_workspace * workspace);
gsl_fft_real_wavetable_free (gsl_fft_real_wavetable * wavetable);

逆变换时按如下的顺序调用。

gsl_fft_halfcomplex_wavetable * gsl_fft_halfcomplex_wavetable_alloc (size_t n);
gsl_fft_real_workspace * gsl_fft_real_workspace_alloc (size_t n);

int gsl_fft_halfcomplex_transform (double data[], size_t stride, size_t n, const gsl_fft_halfcomplex_wavetable * wavetable, gsl_fft_real_workspace * work);

void gsl_fft_real_workspace_free (gsl_fft_real_workspace * workspace);
gsl_fft_halfcomplex_wavetable_free (gsl_fft_halfcomplex_wavetable * wavetable);


  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
GSL 开源 科学计算库 学习笔记(分享部分译稿) GSL是GNU Scientific Libary的简写,是一组专门为数值科学计算而设计的程序库。该程序库用C语言写就,C程序员提供了API。不过 可以对其使用swig工具进行封装,以便能被更高级的语言使用,比如C#,java等。读者可以在网上找到很多swig的例子。 GSL原码是以GPL协议发布的,获取与使用都非常地方便,这也是我们之所以选取GSL学习的根本原因。 GSL库涵盖了数值计算领域的方方面面,主要包括下面的计算领域,还有一些新的程序代码会不断纳入到GSL中。 Complex Numbers 复数; Roots of Polynomials 多项式求根; Special Functions 特殊函数; Vectors and Matrices 向量与距阵; Permutations 排列; Combinations 组合; Sorting 排序; BLAS Support 基础线性代数程序集(向量间运算,向量距阵运算,距阵间运算); Linear Algebra CBLAS Library 线性代数库; Fast Fourier Transforms 快速傅利叶变换; Eigensystems 特征值; Random Numbers 随机数; Quadrature 积分; Random Distributions 随机分布; Quasi-Random Sequences 近似随机分布序列; Histograms 直方图; Statistics 统计; Monte Carlo Integration Monte Carlo积分; N-Tuples N元组; Differential Equations 微分方程; Simulated Annealing 模拟退火算法; Numerical Differentiation 数值差分; Interpolation 拟合与插值; Series Acceleration; Chebyshev Approximations Chebyshev逼近; Root-Finding 求根; Discrete Hankel Transforms 离散Hankel转换; Least-Squares Fitting 最小二乘算法拟合; Minimization 最小值; IEEE Floating-Point IEEE浮点运输; Physical Constants 物理常量; Basis Splines 基本样条曲线; Wavelets 小波变换。
GSL是GNU科学库(GNU Scientific Library)的缩写,它是一个开源的数值计算库,提供了许多数学函数和算法。其中包括二维小波变换的实现。 二维小波变换(2D Wavelet Transform)是一种信号处理技术,它可以将二维信号分解为多个子频带,每个子频带包含不同尺度和方向的信息。它广泛应用于图像处理、视频压缩等领域。 在GSL中,二维小波变换可以通过以下步骤实现: 1. 定义输入信号和输出信号的数组。 2. 使用gsl_wavelet_workspace_alloc函数创建小波变换的工作空间。 3. 使用gsl_wavelet2d_transform_forward函数进行正向变换,或使用gsl_wavelet2d_transform_inverse函数进行逆向变换。 4. 使用gsl_wavelet_workspace_free函数释放工作空间。 下面是一个简单的示例程序,演示如何使用GSL进行二维小波变换: ```c #include <stdio.h> #include <gsl/gsl_wavelet2d.h> #define N 256 int main(void) { double in[N][N], out[N][N]; gsl_wavelet2d_workspace *ws; gsl_wavelet2d *wavelet; int i, j; /* 初始化输入信号 */ for(i = 0; i < N; i++) for(j = 0; j < N; j++) in[i][j] = i + j; /* 创建小波变换的工作空间 */ wavelet = gsl_wavelet2d_alloc(gsl_wavelet2d_daubechies, 4, 4); ws = gsl_wavelet2d_workspace_alloc(N, N); /* 进行正向变换 */ gsl_wavelet2d_transform_forward(wavelet, in, N, N, out, ws); /* 输出结果 */ for(i = 0; i < N; i++) { for(j = 0; j < N; j++) printf("%g ", out[i][j]); printf("\n"); } /* 释放工作空间 */ gsl_wavelet2d_workspace_free(ws); gsl_wavelet2d_free(wavelet); return 0; } ``` 在上面的示例中,我们使用了Daubechies小波、4级分解和4个线程进行了二维小波变换。输出结果是一个256×256的矩阵,包含了分解后的子频带信息。 需要注意的是,GSL中的二维小波变换只支持正方形输入信号,如果输入信号不是正方形,需要将其补齐或者裁剪为正方形。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值