知识点:重点讲解正弦函数和欧拉公式的关系,以及它们在傅里叶变换中的作用,附加:傅里叶变换和卷积公式
这是我第二次学习傅里叶变换,其实第一次就已经懂了时域和频域的关系,也知道一维傅里叶变换就是将一个函数转化为很多频率不同的正弦函数的和,二维图片傅里叶中的频率指的是图像中像素的梯度。频率高的代表图像的变换,频率低表示图像温和。
但是我还是不会自己编写代码,最让我不理解的就是为什么DFT的求解方程式就是 Xk=∑N−1n=0xn e−i 2π k n/N ,IDFT就是 xn=1N∑N−1k=0Xk ei 2π k n/N ??而且说好的正弦函数作为基呢!引入 e−it 是个什么鬼??而且当我输入的原函数f是正弦函数是,DFT分解后,并不是我想想中的,对应频率的正弦函数是一个振幅1,而其余频率的正弦函数函数振幅是0的结果??而且还有就是图像的频率, 一维傅里叶变换中,很多资料都给出一个函数具体怎么由其它基函数(正弦函数)组成的,每一个基长什么样子都可以看到,可是当讲到二维图像的时候,从来没人画出二维图像的基函数的图像??
下面是关于傅里叶一些资料,本文重点不是讲解傅里叶的直观上原理,而是帮助理解如何编程DFT。
傅里叶:
http://blog.jobbole.com/70549/
http://www.xuebuyuan.com/2052774.html
https://wenku.baidu.com/view/9687303f10661ed9ad51f3b6.html
快速傅里叶:
http://www.cnblogs.com/callback-w/p/4457507.html
https://www.zhihu.com/question/20456490
http://blog.jobbole.com/58246/
图像傅里叶:
http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/OWENS/LECT4/node2.html
http://cns-alumni.bu.edu/~slehar/fourier/fourier.html#filtering
http://blog.csdn.net/abcjennifer/article/details/7622228
http://blog.163.com/zwg_1314@126/blog/static/35333246201041113154728/
这里说的正弦函数是指一类函数,就像 3x 和 (12)x 和 ex 都是指数函数、 log2x 和 logex 都是对数函数一样,只要符合 f(x)=Asin(Bx+C) 形式的函数都是正弦函数,其中 A 表示振幅, B 表示周期、频率, C 表示相位,是正弦函数的三要素。
cos(x)=sin(x−3π2) ,余弦函数也是正弦函数的一种。
asin(x)+bcos(x)=a2+b2−−−−−−√sin(x+y) ,其中 tan(y)=ba 。也是一种正弦函数。
正弦函数的一个理解就是一个点围绕原点做圆周运动,它的y轴分量的时候岁时间变化的曲线,如下图所示,这里和上面的公式对应有三个要素,就是振幅 A 对应圆周半径,周期 B 对应圆周运动的角速度,相位 C 对应圆周运动的起始位置(即时间为0的时候,点所在的位置)。
也就是确定了圆周运动的三要素后,对任给x,正弦函数给出,对应x时刻的点的y轴的坐标值。
我之前一直看不懂欧拉公式,不明白这是什么意思,我觉得最关键的错误就是试图去理解 e 的 i 次方是什么意思。这里我们简简单单的将 eix 看做一种映射,一种函数,即 fEuler(x)=eix 给定 x ,函数 f 输出一个复数结果,函数 f 将实数 x 映射到复数空间,且这些复数点都在一个圆上。就好像知道一个函数 fEuler(x) ,你不用管 fEuler(x) 具体是什么,只知道可以将实数映射到复数空间。而且进一步我们知道这种映射关系的计算方式: fEuler(x)=cos(x)+isin(x) 。反正我们不用思考 e 的 i 次方是什么意思了,起码对我来说,将它看做是实数空间到复数空间的一种映射,而不去思考 e 的 i 次方,会更容易让我接受,把 e 的 i 次方当做是一种记号,一种规定的书写形式而已。(其实输入是x,一维的,输出虽然是复数,但其实也是一维的,不过是一条旋转的曲线,而输入x是一条直线)
我的理解是正弦函数和欧拉公式都是在描述圆周运动。前面讲过一个圆周运动有三个要素:半径、角速度和初始位置。这都很容易对应到正弦函数,而欧拉公式也是可以。我们这里说的欧拉公式为: fEuler(x)=Aei(Bx+C)=Acos(Bx+C)+iAsin(Bx+C) 。注意 Aei(Bx+C) 和 ei(Bx+C)+a 和 ea∗ei(Bx+C) 是一样的,因为总可以找到 a 来使得 A=ea (负数的振幅 A 应该是不被允许的)。如下所示:
欧拉公式也是在描述一种特定的圆周运动,而欧拉公式的返回值是x时刻的点的位置,用复数来表示,不同于正弦函数(它返回的是x时刻的点的有坐标值)。从描述圆周运动的角度,它们是一致的,它们都是根据时间x返回圆周运动上的点的一个指标上的值。复数和实数都是数,更或者说是信息的一种编码形式。欧拉公式返回的复数的实部表示点在x轴的坐标值,虚部表示点在y轴上的坐标值。
上图是wikipedia上关于欧拉公式的图,不过我修改了些部分。图中绿色线所标注的x轴,像时间在流失一样,一直往前走。y和z组成了一个平面空间,点就在这个平面空间上转动。欧拉公式中的自变量x是对应x轴上的时间点。欧拉公式返回的复数结果,对应点在yz平面上的坐标。随着自变量x的增大,点的移动轨迹就像红色的线所标注的一样,围绕x轴做螺旋圆周运动,如果映射到yz平面上就是做圆周运动。欧拉公式和正弦函数都是在描述这样一种运动,或者说映射规律,只不过欧拉公式根据x,输出的是点映射到yz平面上的坐标,用复数的形式来表示。而正弦函数将红色的点的运动轨迹映射到y轴上,如图中紫色的线所示,因为x轴信息已知,只需要输出y轴坐标即可。
eix 和 e−ix 的关系是点做圆周运动的方向不同,从x正半轴向负半轴看下去, eix 做逆时针旋转, e−ix 做顺时针旋转。所以 sin(x)=eix−e−ix2i , cos(x)=eix+e−ix2 。
欧拉函数的一个优点是,正弦函数一个周期内会输出重复的函数值,而欧拉公式在一个周期内不会输出重复的函数值。
总结一下,正弦函数和欧拉公式都是描述圆周运动随时间x变化的性质,都是一种映射,都是一种函数。欧拉公式更像是正弦函数的加强版,因为它返回了更多的信息。不要在意返回的是实数还是复数,因为都是数,都有完备的加减乘数运算。最原始的欧拉公式 eix 是在描述半径为1,周期为 2π ,初始点在 x 正半轴上的圆周运动。
最后说一下欧拉公式的编程实现。因为上面已知在强调欧拉公式就是一种映射,返回的是一个复数而已,而复数的实部和虚部的计算方式都给出来了,只要不在意 e 的 i 次方就行。python代码如下:
import numpy as np
def my_exp(x):
if x is complex:
res_real = np.exp(x.real)
res_imaginary = ( np.cos(x.imag) + 1j*np.sin(x.imag) )
return res_real * res_imaginary
else:
return np.exp(x)
x = 0.5
print np.exp(1+1j*x),my_exp(1+1j*x)
print np.exp(1+1j*x)==my_exp(1+1j*x)
最后再说下正弦函数和欧拉公式的正交性。
频率不相同的两个三角函数相乘,在它们两个共同的周期上积分为0。
离散的情况,当在它们共同周期内等间隔均匀采样的离散值求和也为0,例如:
很多文章都是从频域和正余弦函数来讲解傅里叶变换,可是DFT的编程公式里面偏偏出现了一个欧拉公式,让我费解好久。DFT: Xk=∑N−1n=0xn e−i 2π k n/N ,IDFT: xn=1N∑N−1k=0Xk ei 2π k n/N 。
这里假设需要进行离散傅里叶变换的信号是 X=(x0,x1,x2,x3) ,其DFT后的值为 Y=(y0,y1,y2,y3) 。从DFT和IDFT的公式中可以看出,就是向量内积的运算。
M−2π/4 和 M2π/4 分别描述的是振幅相同、相位相同、转速相同、但旋转方向相反的两种圆周运动。根据上一节欧拉公式的正交性可以容易计算出 M−2π/4×M2π/4=M2π/4×M−2π/4=4∗I ,如下所示:
也就是说 M−2π/4和M2π/4/4 互为逆矩阵。
最初我们希望 X 可以分解为多个频域的向量相加,也就是 X=(1/N)M2π/N⋅Y ,那么等式两边乘以 (1/N)M2π/N的逆矩阵,也就是M−2π/N ,即可得到Y的求解方程: M−2π/N⋅X=Y 。
矩阵可以看做是一种变换器,乘以一个矩阵相当于对数据进行对应的变换。我们首先用矩阵 M−2π/N 对 X 进行转变得到 Y=M−2π/N⋅X ,接着可以用 M−2π/N 的逆变换,也就是 (1/N)M2π/N 对 Y 操作在得到 X ,即: X=(1/N)M2π/N⋅Y=(1/N)M2π/N⋅M−2π/N⋅X=X 。
由 X=(1/N)M2π/N⋅Y 可知,我们选取频率的基向量 M2π/N=[f{2π∗1/N},f{2π∗2/N},⋯,f{2π∗(N−1)/N}] 来分解 X 。为什么选取 (1/N)M2π/N 为频率的基向量,我想有一个原因应该是它的逆矩阵很容易求。DFT和IDFT的代码:
# 当然实际生活中用到的是快速傅里叶变换FFT
def my_DFT(x):
'一维离散傅里叶变换'
x = np.asarray(x,dtype=complex)
N = x.shape[0]
n = np.arange(N)
k = n.reshape((N,1))
M = np.exp(-2j*np.pi*k*n/N)
return np.dot(M,x)
def my_IDFT(y):
'一维逆离散傅里叶变换'
y = np.asarray(y,dtype=complex)
N = y.shape[0]
n = np.arange(N)
k = n.reshape((N,1))
M = np.exp(2j*np.pi*k*n/N)
print M
return np.dot(M,y)/N
简单的例子 X=(1/4)M2π/4⋅Y 如下: