傅里叶变换算法和Python代码实现

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
实时数仓Hologres,5000CU*H 100GB 3个月
简介: 傅立叶变换是物理学家、数学家、工程师和计算机科学家常用的最有用的工具之一。本篇文章我们将使用Python来实现一个连续函数的傅立叶变换。

我们使用以下定义来表示傅立叶变换及其逆变换。

设 f: ℝ → ℂ 是一个既可积又可平方积分的复值函数。那么它的傅立叶变换,记为 f̂,是由以下复值函数给出:

同样地,对于一个复值函数 ĝ,我们定义其逆傅立叶变换(记为 g)为

这些积分进行数值计算是可行的,但通常是棘手的——特别是在更高维度上。所以必须采用某种离散化的方法。

在Numpy文档中关于傅立叶变换如下,实现这一点的关键是离散傅立叶变换(DFT):

 当函数及其傅立叶变换都被离散化的对应物所取代时,这被称为离散傅立叶变换(DFT)。离散傅立叶变换由于计算它的一种非常快速的算法而成为数值计算的重要工具,这个算法被称为快速傅立叶变换(FFT),这个算法最早由高斯(1805年)发现,我们现在使用的形式是由Cooley和Tukey公开的

根据Numpy文档,一个具有 n 个元素的序列 a₀, …, aₙ₋₁ 的 DFT 计算如下:

我们将积分分解为黎曼和。在 n 个不同且均匀间隔的点 xₘ = x₀ + m Δx 处对 x 进行采样,其中 m 的范围从 0 到 n-1,x₀ 是任意选择的最左侧点。然后就可以近似表示积分为

现在对变量 k 进行离散化,在 n 个均匀间隔的点 kₗ = l Δk 处对其进行采样。然后积分变为:

这使得我们可以用类似于 DFT 的形式来计算函数的傅立叶变换。这与DFT的计算形式非常相似,这让我们可以使用FFT算法来高效计算傅立叶变换的近似值。

最后一点是将Δx和Δk联系起来,以便指数项变为-2π I ml/n,这是Numpy的实现方法;

这就是不确定性原理,所以我们得到了最终的方程

我们可以对逆变换做同样的处理。在Numpy中,它被定义为

1/n是归一化因子:

概念和公式我们已经通过Numpy的文档进行了解了,下面开始我们自己的Python实现

 importnumpyasnp
 importmatplotlib.pyplotasplt


 deffourier_transform_1d(func, x, sort_results=False):

     """
     Computes the continuous Fourier transform of function `func`, following the physicist's convention
     Grid x must be evenly spaced.

     Parameters
     ----------

     - func (callable): function of one argument to be Fourier transformed
     - x (numpy array) evenly spaced points to sample the function
     - sort_results (bool): reorders the final results so that the x-axis vector is sorted in a natural order.
         Warning: setting it to True makes the output not transformable back via Inverse Fourier transform

     Returns
     --------
     - k (numpy array): evenly spaced x-axis on Fourier domain. Not sorted from low to high, unless `sort_results` is set to True
     - g (numpy array): Fourier transform values calculated at coordinate k
     """
     x0, dx=x[0], x[1] -x[0]
     f=func(x)

     g=np.fft.fft(f) # DFT calculation

     # frequency normalization factor is 2*np.pi/dt
     w=np.fft.fftfreq(f.size)*2*np.pi/dx

     # Multiply by external factor
     g*=dx*np.exp(-complex(0,1)*w*x0) 

     ifsort_results:    
         zipped_lists=zip(w, g)
         sorted_pairs=sorted(zipped_lists)
         sorted_list1, sorted_list2=zip(*sorted_pairs)
         w=np.array(list(sorted_list1))
         g=np.array(list(sorted_list2))

     returnw, g


 definverse_fourier_transform_1d(func, k, sort_results=False):
     """
     Computes the inverse Fourier transform of function `func`, following the physicist's convention
     Grid x must be evenly spaced.

     Parameters
     ----------

     - func (callable): function of one argument to be inverse Fourier transformed
     - k (numpy array) evenly spaced points in Fourier space to sample the function
     - sort_results (bool): reorders the final results so that the x-axis vector is sorted in a natural order.
         Warning: setting it to True makes the output not transformable back via Fourier transform

     Returns
     --------
     - y (numpy array): evenly spaced x-axis. Not sorted from low to high, unless `sort_results` is set to True
     - h (numpy array): inverse Fourier transform values calculated at coordinate x
     """
     dk=k[1] -k[0]

     f=np.fft.ifft(func) *len(k) *dk/(2*np.pi)
     x=np.fft.fftfreq(f.size)*2*np.pi/dk

     ifsort_results:    
         zipped_lists=zip(x, f)
         sorted_pairs=sorted(zipped_lists)
         sorted_list1, sorted_list2=zip(*sorted_pairs)
         x=np.array(list(sorted_list1))
         f=np.array(list(sorted_list2))
     returnx, f

我们来通过一些例子看看我们自己实现是否正确。

第一个例子:阶跃函数

函数在-1/2和1/2之间是1,在其他地方是0。它的傅里叶变换是

 N = 2048

 # Define the function f(x)
 f = lambda x: np.where((x >= -0.5) & (x <= 0.5), 1, 0)
 x = np.linspace(-1, 1, N) 
 plt.plot(x, f(x));

画出傅里叶变换,以及在k的采样值和整个连续体上计算的解析解:

 k, g = fourier_transform_1d(f, x, sort_results=True) # make it easier to plot
 kk = np.linspace(-30,30, 100)

 plt.plot(k, np.real(g), label='Numerical'); 
 plt.plot(k, np.sin(k/2)/(k/2), linestyle='-.', label='Analytic (samples)')
 plt.plot(kk, np.sin(kk/2)/(kk/2), linestyle='--', label='Analytic (full)')
 plt.xlim(-30, 30)
 plt.legend();

看起来是没问题的,然后我们把它转换回来:

 k, g = fourier_transform_1d(f, x)
 y, h = inverse_fourier_transform_1d(g, k, sort_results=True)

 plt.plot(y, np.real(h), label='Numerical transform')
 plt.plot(x, f(x), linestyle='--', label='Analytical')
 plt.legend();

我们可以清楚地看到不连续边缘处的 Gibbs 现象——这是傅里叶变换的一个预期特征。

第二个例子:高斯PDF

傅里叶变换

下面,我们绘制数值傅里叶变换和解析值:

以及傅里叶逆变换与原函数的对比

可以看到,我们的实现没有任何问题

最后,如果你对机器学习的基础计算和算法比较感兴趣,可以多多关注Numpy和SK-learn的文档(还有scipy但是这个更复杂),这两个库不仅有很多方法的实现,还有这些方法的详细解释,这对于我们学习是非常有帮助的。

例如本文的一些数学的公式和概念就是来自于Numpy的文档,有兴趣的可以直接看看

https://avoid.overfit.cn/post/546692942b9144a5a56d734c5a007099

作者:Alessandro Morita Gagliardi

目录
相关文章
|
7天前
|
开发者 Python
探索Python中的装饰器:简化代码,增强功能
【10月更文挑战第22天】在Python的世界里,装饰器是一个强大的工具,它能够让我们以简洁的方式修改函数的行为,增加额外的功能而不需要重写原有代码。本文将带你了解装饰器的基本概念,并通过实例展示如何一步步构建自己的装饰器,从而让你的代码更加高效、易于维护。
|
4天前
|
算法 测试技术 开发者
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗;代码审查通过检查源代码发现潜在问题,提高代码质量和团队协作效率。本文介绍了一些实用的技巧和工具,帮助开发者提升开发效率。
10 3
|
3天前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
9天前
|
开发框架 Python
探索Python中的装饰器:简化代码,增强功能
【10月更文挑战第20天】在编程的海洋中,简洁与强大是航行的双桨。Python的装饰器,这一高级特性,恰似海风助力,让代码更优雅、功能更强大。本文将带你领略装饰器的奥秘,从基础概念到实际应用,一步步深入其内涵与意义。
|
7天前
|
机器学习/深度学习 缓存 数据挖掘
Python性能优化:提升你的代码效率
【10月更文挑战第22天】 Python性能优化:提升你的代码效率
9 1
|
7天前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
21 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
|
10天前
|
机器人 Shell Linux
【Azure Bot Service】部署Python ChatBot代码到App Service中
本文介绍了使用Python编写的ChatBot在部署到Azure App Service时遇到的问题及解决方案。主要问题是应用启动失败,错误信息为“Failed to find attribute &#39;app&#39; in &#39;app&#39;”。解决步骤包括:1) 修改`app.py`文件,添加`init_func`函数;2) 配置`config.py`,添加与Azure Bot Service认证相关的配置项;3) 设置App Service的启动命令为`python3 -m aiohttp.web -H 0.0.0.0 -P 8000 app:init_func`。
|
7天前
|
缓存 算法 数据处理
Python性能优化:提升代码效率与速度的秘诀
【10月更文挑战第22天】Python性能优化:提升代码效率与速度的秘诀
8 0
|
9天前
|
缓存 分布式计算 监控
优化算法和代码需要注意什么
【10月更文挑战第20天】优化算法和代码需要注意什么
14 0
|
25天前
|
机器学习/深度学习 算法 搜索推荐
从理论到实践,Python算法复杂度分析一站式教程,助你轻松驾驭大数据挑战!
【10月更文挑战第4天】在大数据时代,算法效率至关重要。本文从理论入手,介绍时间复杂度和空间复杂度两个核心概念,并通过冒泡排序和快速排序的Python实现详细分析其复杂度。冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1);快速排序平均时间复杂度为O(n log n),空间复杂度为O(log n)。文章还介绍了算法选择、分而治之及空间换时间等优化策略,帮助你在大数据挑战中游刃有余。
50 4