【音频处理】离散傅里叶变换

前言

最近复现音乐驱动舞蹈的文章《Dancing-to-Music Character Animation》,用到了与傅里叶变换很相似的称为常Q变换的方法去分割音乐,所以对傅里叶变换做了一个小了解,本文不深入各种乱糟糟的理论,比如什么蝶形算法啥的,单纯讨论离散傅里叶变换(DFT),我们常见的是快速傅里叶变换(FFT),其实FFT是对DFT的一个计算优化,主要是剔除DFT里面有周期性之类的被冗余计算,但是FFT的算法有点小复杂,有兴趣深入理论的请移步如下几篇博文:

如何理解和掌握快速傅里叶变换的计算和概念?

如何通俗地解释什么是离散傅里叶变换?

傅里叶分析之掐死教程(完整版)更新于2014.06.06

傅里叶变换

快速傅里叶变换

第三章 离散傅里叶变换(DFT) 及其快速算法(FFT)

傅里叶级数和傅里叶变换是什么关系?

如何理解傅里叶变换公式?

An Introduction to the Fast Fourier Transform

FFT的详细解释,相信你看了就明白了

如果想仔细学习FFT,最好是看完上述推荐的博文并额外找资料,我是不想看了,因为我看着看着发现自己掉头发了o(╯□╰)o

#简介

傅里叶变换意思就是任何一个输入信号都可以使用多个余弦波叠加而成,简单的说就是把时序信号转换成频域信息。我们最终需要的就是找到这些余弦波的相关参数:幅值,相位。

复习一下三角函数的标准式:
y = A c o s ( w x + b ) + k y=Acos(wx+b)+k y=Acos(wx+b)+k
A A A代表振幅,函数周期是 2 π w \frac{2\pi}{w} w2π,频率是周期的倒数 w 2 π \frac{w}{2\pi} 2πw b b b是函数初相位, k k k在信号处理中称为直流分量。

在很多工具的实现中,余弦波的个数就是信号长度,但是在理论公式中会出现一个参数N,是采样点,通常称为N点FFT。
X ( k ) = ∑ n = 1 N x ( n ) ∗ exp ⁡ ( − − 1 ∗ 2 π ∗ ( k − 1 ) ∗ ( n − 1 ) / N ) , 1 < = k < = N . X(k) = \sum _{n=1}^N x(n)*\exp(-\sqrt{-1}*2\pi*(k-1)*(n-1)/N), 1 <= k <= N. X(k)=n=1Nx(n)exp(1 2π(k1)(n1)/N),1<=k<=N.
上述公式就是DFT的求解方法了,不考虑它的优化方法FFT,我们直接在matlab中码公式,最后与FFT的结果做对比即可验证写的算法对不对。

#实例

假设我们的输入信号是函数是
S = 0.2 + 0.7 ∗ cos ⁡ ( 2 π ∗ 50 t + 20 180 π ) + 0.2 ∗ cos ⁡ ( 2 π ∗ 100 t + 70 180 π ) S=0.2+0.7*\cos(2\pi *50t+\frac{20}{180}\pi) + 0.2*\cos(2\pi*100t+\frac{70}{180}\pi) S=0.2+0.7cos(2π50t+18020π)+0.2cos(2π100t+18070π)
可以发现直流分量是0.2,以及两个余弦函数的叠加,余弦函数的幅值分别为0.7和0.2,频率分别为50和100,初相位分别为20度和70度。

画出信号图:

Fs = 1000;            % Sampling frequency
T = 1/Fs;             % Sampling period
L = 1000;             % Length of signal
t = (0:L-1)*T;        % Time vector
S = 0.2+0.7*cos(2*pi*50*t+20/180*pi) + 0.2*cos(2*pi*100*t+70/180*pi) ;
plot(1000*t(1:50),S(1:50))
title('Signal Corrupted with Zero-Mean Random Noise')
xlabel('t (milliseconds)')
ylabel('X(t)')

这里写图片描述

FFT变换

先使用matlab默认的快速傅里叶变换函数FFT求解叠加余弦的各参数

Y = fft(S);
P2 = abs(Y/L);
P1 = P2(1:L/2+1);
P1(2:end-1) = 2*P1(2:end-1);

首先直接对原始信号进行傅里叶变换得到 Y Y Y,它包含实部与虚部,然后求解归一化后 Y Y Y各项的模得到 P 2 P2 P2,由于matlab求解的结果包含对称的两个频谱,称为双侧频谱,我们只需要取一半得到 P 1 P1 P1,此时只需要将除第一个元素外的元素乘以2即可得到幅值信息,其实求解的根本就是来源于 Y Y Y Y Y Y有多少项,就说明求解了多少个叠加的余弦波,接下来解释如何求解各参数:

  • 直流分量:就是Y的第一个值除以采样频率,一般来说是非复数
  • 频率: 采 样 频 率 采 样 长 度 ∗ ( 第 几 项 − 1 ) \frac{采样频率}{采样长度}*(第几项-1) (1),本例中采样频率是1000,长度也是1000,那么 Y Y Y的第二项频率就是1,第三项频率是2,其实最终情况下,我们选取频率不接近0的值。
  • 幅值: 2 ∗ a b s ( Y 各 项 采 样 长 度 ) 2*abs(\frac{Y各项}{采样长度}) 2abs(Y)
  • 初相位: a t a n 2 ( Y 的 虚 部 Y 的 实 部 ) atan2(\frac{Y的虚部}{Y的实部}) atan2(YY)转角度制表示

这里写图片描述

P 1 P1 P1的图中,我们很容易看出来幅值不接近0的位置分别是0,50,100附近,其实我们去看具体的位置发现是1,51,101,此三个位置的 Y Y Y值分别为:

>> Y(1)

ans =

  200.0000

>> Y(51)

ans =

   3.2889e+02 + 1.1971e+02i

>> Y(101)

ans =

  34.2020 +93.9693i

那么按照描述,我们得到:

  • 直流分量: Y ( 1 ) F s = 0.2 \frac{Y(1)}{Fs}=0.2 FsY(1)=0.2

  • 频率:第51项和101项的频率分别为50和100

  • 幅值: 2 ∗ a b s ( Y ( 51 ) L ) = 0.7 2*abs\left(\frac{Y(51)}{L}\right)=0.7 2abs(LY(51))=0.7 同理 2 ∗ a b s ( Y ( 101 ) L ) = 0.2 2*abs\left(\frac{Y(101)}{L}\right)=0.2 2abs(LY(101))=0.2

  • 初相位:

    >> rad2deg(atan2(imag(Y(51)),real(Y(51))))
    
    ans =
    
       20.0000
    
    >> rad2deg(atan2(imag(Y(101)),real(Y(101))))
    
    ans =
    
       70.0000
    

【注1】: 在实际应用中,一般让余弦波的的数量与信号长度相同,如果不相同,那就是理论中常说的N点FFT

【注2】:幅值是通过模求解的,但是模一般都是正数,如果叠加信号的幅值是复数呢?不要忘记了 − c o s ( x ) = c o s ( x − π ) -cos(x)=cos(x-\pi) cos(x)=cos(xπ),也就是说如果幅值是负数,那么只需要在正数幅值的基础上变化一初相位。比如把例子的函数换成:
S = 0.2 − 0.7 ∗ cos ⁡ ( 2 π ∗ 50 t + 20 180 π ) + 0.2 ∗ cos ⁡ ( 2 π ∗ 100 t + 70 180 π ) S=0.2-0.7*\cos(2\pi *50t+\frac{20}{180}\pi) + 0.2*\cos(2\pi*100t+\frac{70}{180}\pi) S=0.20.7cos(2π50t+18020π)+0.2cos(2π100t+18070π)
那么求解频率50对应余弦波的赋值为+0.7,初相位为-160

IFFT变换

顾名思义,IFFT就是逆傅里叶变换,用Y重构信号,其实我们通过Y都已经分析出了原始信号所需的余弦波的各参数,肯定能重构原始数据,这里还是做个实验吧,用IFFT函数:

figure
pred_X=ifft(Y);
plot(pred_X,'r-')
hold on
plot(S,'b*')

这里写图片描述

DFT变换

按照公式手撸DFT,看看计算得到 Y Y Ymatlab自带的FFT结果是否一致
X ( k ) = ∑ n = 1 N x ( n ) ∗ exp ⁡ ( − − 1 ∗ 2 π ∗ ( k − 1 ) ∗ ( n − 1 ) / N ) , 1 < = k < = N . X(k) = \sum _{n=1}^N x(n)*\exp(-\sqrt{-1}*2\pi*(k-1)*(n-1)/N), 1 <= k <= N. X(k)=n=1Nx(n)exp(1 2π(k1)(n1)/N),1<=k<=N.

%% DFT变换
%                    N
%      X(k) =       sum  x(n)*exp(-j*2*pi*(k-1)*(n-1)/N), 1 <= k <= N.
%                   n=1
DFT_X=zeros(1,L);
N=L;
for k=1:L
    for n=1:N
        DFT_X(k)=DFT_X(k)+S(n)*exp(-1j*2*pi*(k-1)*(n-1)/N);
    end
end
P2=abs(DFT_X/L);
P1 = 2*P2(1:L/2+1);
f = Fs*(0:(L/2))/L;
figure
plot(f,P1)
xlabel('频率')
ylabel('振幅')
title('DFT变换')

这里写图片描述
再计算与FFT求解的结果的误差

%% FFT变换
FFT_X=fft(S);
figure
plot(abs(FFT_X-DFT_X))
title('DFT和FFT误差')

这里写图片描述

IDFT

同样按照公式手撸逆离散傅里叶变换
x ( n ) = 1 N ∑ k = 1 N X ( k ) ∗ exp ⁡ ( − 1 ∗ 2 π ∗ ( k − 1 ) ∗ ( n − 1 ) / N ) , 1 < = n < = N . x(n) = \frac{1}{N}\sum _{k=1}^N X(k)*\exp(\sqrt{-1}*2\pi*(k-1)*(n-1)/N), 1 <= n <= N. x(n)=N1k=1NX(k)exp(1 2π(k1)(n1)/N),1<=n<=N.

%% IDFT变换
%                    N
%      x(n) = (1/N) sum  X(k)*exp( j*2*pi*(k-1)*(n-1)/N), 1 <= n <= N.
%                   k=1
DFT_rec_x=zeros(1,k);
for n=1:L
    for k=1:L
        DFT_rec_x(n)=DFT_rec_x(n)+DFT_X(k)*exp( 1j*2*pi*(k-1)*(n-1)/N);
    end
end
DFT_rec_x=DFT_rec_x./N;
rec_err=real(DFT_rec_x)-S;
figure
plot(rec_err)
title('IFFT数据重构误差')

这里写图片描述
IFFT的结果对比一下:

%% IFFT变换
FFT_rec_x=ifft(FFT_X);
figure
plot(abs(DFT_rec_x-FFT_rec_x))
title('IDFT和IFFT误差')

这里写图片描述

后记

折腾了这么多,其实就是为了一个字:懒。为了避免复杂的FFT的理论理解,我直接按照DFT的公式码代码,取得了与FFT一样的结果,对于不喜欢复杂理论的同志,可以在代码实现FFT的时候直接采用DFT的代码作为替代品,虽然时间复杂度增大很多,但是理论理解起来简单很多倍不是。

贴一下文章代码,此外还有一个FFT的手动实现:链接:https://pan.baidu.com/s/1mUdclEQ3tgQUvZQ4XffN3g 密码:08tg

等我不掉头发了,再去纠结FFT的蝶形算法_

博客已同步更新到微信公众号中,有兴趣可关注一波,微信公众号与博客同步更新个人的学习笔记
在这里插入图片描述

  • 18
    点赞
  • 99
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
离散傅立变换(Discrete Fourier Transform,DFT)是一种将时域上的离散信号转换为频域上的离散信号的算法。它在信号处理、图像处理音频处理等领域都有广泛的应用。 以下是离散傅立变换的一些应用: 1. 信号处理离散傅立变换可以将时域上的信号转换到频域上,从而可以对信号进行频域滤波、频谱分析等处理。例如,可以通过对音频信号进行离散傅立变换,得到音频信号的频域表示,从而可以实现音频降噪、音频增强等功能。 2. 图像处理离散傅立变换可以将图像从空间域转换到频域,从而可以进行频域滤波、频谱分析等处理。例如,可以通过对图像进行离散傅立变换,得到图像的频域表示,从而可以实现图像去噪、图像增强等功能。 3. 通信系统:离散傅立变换可以用于数字通信系统中的调制与解调、信道均衡等处理。例如,在 OFDM(Orthogonal Frequency Division Multiplexing,正交频分复用)系统中,离散傅立变换被广泛用于将多个子载波的信号转换到频域上进行处理。 4. 控制系统:离散傅立变换可以用于控制系统的频域分析与设计。例如,可以通过对控制系统进行离散傅立变换,得到系统的频域响应,从而可以进行控制器的设计与优化。 总之,离散傅立变换在信号处理、图像处理、通信系统、控制系统等领域都有广泛的应用,是一种非常重要的数学工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风翼冰舟

额~~~CSDN还能打赏了

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值