一键搭建Linux环境(需要登录)>>
安装部署就是这么简单!!!
写在前面
不是科研狗,基础理论薄弱,写的很匆忙。如有任何误解,请理解并纠正我。
网上大佬写的傅里叶公式推导证明了很多(瑟瑟发抖)。我这里主要讲傅里叶的应用,不涉及公式的证明,而是直接使用公式。
由于自己获得的知识也是通过阅读大佬的博文获得的,所以有些图是别人的图,不过我附上了别人的链接。
阅读本文后,您可以获得:
1 傅里叶变换原理
2 傅里叶变换在音频中的应用
3 C语言代码及离散傅里叶变换处理音频的解释
背景
最近接触音视频处理比较多,遇到采集到的音频数据有噪音的情况。是否可以使用傅立叶变换来消除音频噪声?在此之前,关于傅里叶变换的概念,我只有一句话,“一种将时域转换为频域的东西”。如果我把音频的时域转换到频域,然后去掉噪声的频段,是不是就不能达到去噪的效果呢?好吧,试着去死。
嗯,折腾了几天,效果(上图是原始音频信号,下图是去除频域中的高频正交基后的音频信号)
综上所述:
1、有点效果傅里叶变换基本公式,但噪音只是降低,没有去除。使用了 DFT,这留下了改进的空间。
2.琢磨了一会,还是有很多地方没看懂。傅里叶变换是一门需要长期研究和深思熟虑的知识。把自己理解的知识点记下来,以后走图像处理的路子,再详细研究。
1.什么是傅里叶变换(分析)?
你可以参考这个
在回答这个问题时,我们首先要知道什么是转型?为什么要转型?
(1)什么是转换?
举一个常见的例子,两个向量 a 和 b 在一个坐标系中表示傅里叶变换基本公式,并且可以转换为一组坐标。
(2)为什么要转型?
比如要求c点的坐标,在图中是一个比较难处理的问题,但是经过变换,c=a+b=(2+1,1+2)=( 3、3),在数值上很容易处理。总之,当一个问题难以处理的时候,换个思路(变换),就可以解决了。嗯,有点像线性代数。
傅里叶变换的思想是时域和频域的相互变换。
两个时域和频域
时域和频域一一对应,频域可以转化为时域
傅里叶变换类型
傅里叶变换的种类很多,通常是不带前缀的连续傅里叶变换,而离散傅里叶变换则常用于计算机处理中。最重要的是,对算法进行了改进以降低时间复杂度,这被称为快速傅里叶变换。转换。
变换在时域中周期性且连续的函数称为傅里叶级数
在时域中变换非周期连续函数称为傅里叶变换
三傅里叶级数(Fourier Series)
所以啊,傅里叶提出了这句话:任何周期函数都是由多个不同的正弦波(sin和cos)叠加而成的(如果满足Dirichli条件的话)
如图,频域由若干个正弦波组成,时域的矩形波可以由多个正弦波叠加组成(当正弦波个数趋于无穷大时,近似为一个矩形波,这有点有限)
周期函数实际上指的是时域信号,多个不同的正弦波指的是频域信号。
当然,如上图所示,要确定一个正弦波,需要知道它的相位、幅值和角频率,所以将时域转换为频域,得到一系列初始相位、幅值和角频率频率。
傅立叶说写在公式中的这句话是
或者你可以写
这个公式应该怎么理解?这需要知道正弦波的正交性。
(1)正弦波的正交性
正弦波自身的内积为1,自身与他人的内积为0,即sin(nwt)、cos(nwt)为标准正交基,加上常数1,可以用任何周期函数. 三种表示。因此只需要在时域与各种标准正交基做f(t)的内积,等于0表示不存在这样的正弦波,否则分量存在。
什么是标准正交基
线性代数:在空间中找到一组向量,当它们的内积为0且模为1时,这组向量称为标准正交基,空间中的任何向量都可以由这些标准正交基组成。
什么是内积?
嗯,你需要学习到下午 2 点[手动搞笑]
三傅里叶变换公式
(1) 欧拉公式
但是上图中的f(t)并不是和各种正弦波做内积,而是和e^-iwt做内积。实际上,这是欧拉公式在正弦波和指数之间进行转换。本质上,图中的公式就是用各种正弦波做内积。现在让我们谈谈欧拉公式。
数制
复习初中知识
自然数:1、2、3、4。.
整数:-1、1、-2、2.。. .
有理数:-1、2、2/3、4/5.。.
无理数:根 2 等。
这些共同构成实数,如实数轴所示。
但是遇到x^2=-1这样的解时,不能用实数解,引入虚数。虚数+实数=复数,如图是复平面,任意点都可以用a+bi表示
在复平面上画一个圆。由三角公式可以得到点a为cosx+i *sinx。
复平面乘法的含义:
乘以 -1 逆时针旋转 180 度。乘-i,逆时针旋转90度,复数乘法如图
现在你可以想出欧拉公式
公式的推导是使用的泰勒公式。e、sin、cos都是泰勒展开式前十名,两边展开式相等。
让我们停在这里。总之,我们可以知道傅里叶变换公式e^iwt实际上是每个sin和cos的内积。有关欧拉公式的详细说明,请参阅此
欧拉公式解释
欧拉的身份
即当角度达到180度时,返回实轴
离散傅里叶变换 (DFT)
离散傅里叶变换可以参考这个
离散傅里叶变换解释
离散和连续的区别在于,连续是积分,离散是求和
原理,如下图,a和b是要检测的信号,c和d是3周期的正弦信号,很明显a图片包含一个正弦波,e=ac,加点e图片,很明显值为正,表示图片a包含频率为3的正弦波,f=bd,显然图片f中的点相加结果约等于0,说明图片b不包含周期为 3 的正弦波
在电脑上用这个公式会好一点
n和N是在一个正弦周期内采样N个点,采样间隔为2piN,n用于步进,一步为2piN,最后累加求和,X(k)
最终离散傅里叶变换完整代码
1、从文件中读取8000条音频数据。由于现实中的音频没有虚部,所以只设置了实部。
2.离散傅里叶变换的关键点
temp的re就是上图中公式对应的cos。同理,im就是上图对应的sin。每个 X[k] 被累加和求和。
for (int k = 0; k < N; k++){X[k].re = 0;X[k].im = 0;for (int n = 0; n < N; n++){temp.re = (float)cos(2 * pi*k*n / N);temp.im = -(float)sin(2 * pi*k*n / N);X[k] = complexadd(X[k], complexMult(x[n], temp));}}
3.离散傅里叶逆变换是X(k)乘以e^(j2tkn/N),即实部和虚部都是正的
temp.re = (float)cos(2 * pi*k*n / N);temp.im = (float)sin(2 * pi*k*n / N);x[k] = complexadd(x[k], complexMult(X[n], temp));
4、下图公式求幅值
在代码中表示
printf("%d ", int(2.0/N*sqrt(X[k].re*X[k].re + X[k].im*X[k].im)));//打印的为幅度
完整代码
#include #include #define pi 3.1415926struct complex{float re;float im;};complex complexadd(complex a, complex b) { //复数加complex rt;rt.re = a.re + b.re;rt.im = a.im + b.im;return rt;}complex complexMult(complex a, complex b) { //复数乘complex rt;rt.re = a.re*b.re - a.im*b.im;rt.im = a.im*b.re + a.re*b.im;return rt;}complex complexSet(complex *a, short *b, int N)//复数设置{for (int i = 0; i < N; i++){a[i].re = b[i];a[i].im = 0;}}//离散傅里叶变换//X[]标识变换后频域,x[]为时域采样信号void dft(complex X[], complex x[], int N){ complex temp;int k, n;for (int k = 0; k < N; k++){X[k].re = 0;X[k].im = 0;for (int n = 0; n < N; n++){temp.re = (float)cos(2 * pi*k*n / N);temp.im = -(float)sin(2 * pi*k*n / N);X[k] = complexadd(X[k], complexMult(x[n], temp));}printf("%d ", int(2.0/N*sqrt(X[k].re*X[k].re + X[k].im*X[k].im)));//打印的为幅度if (k >= 6000)//去除高频信号{X[k].re = 0.0;X[k].im = 0.0;}}}//离散傅里叶逆变换//X[]标识变换后频域,x[]为时域采样信号void idft(complex X[], complex x[], int N) {complex temp;//int k, n;for (int k = 0; k < N; k++){x[k].re = 0;x[k].im = 0;for (int n = 0; n < N; n++){temp.re = (float)cos(2 * pi*k*n / N);temp.im = (float)sin(2 * pi*k*n / N);x[k] = complexadd(x[k], complexMult(X[n], temp));}x[k].re /= N;x[k].im /= N;}}#define N 8000//采样率为8000int main() {complex samples[N], X[N], x[N]; //原始数据,变换后的频域数据,逆变换后的时域数据FILE *fp;FILE *fp2;short buf[N];int re=0;fp=fopen("./ttt.pcm", "rb");fp2 = fopen("./trans.pcm", "wb");if (!fp ||!fp2) {printf("I could not open file.n");return 1;}else{while (fread(buf, sizeof(short)*N,1 , fp) > 0)//末尾数据忽略{complexSet(samples, buf, N);dft(X, samples, N);idft(X, x, N);for (int i = 0; i < N; i++){buf[i] = x[i].re;}fwrite(buf, sizeof(short)*N,1 , fp2);}}fclose(fp);fclose(fp2);return 0;}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 欧资源网