FFT matlab实现以及应用分析

FFT matlab实现以及应用分析

FFT实现

此处内容引用某篇博客,懒得找了,对此FFT的matlab实现讲的十分详细,大家想找的话可以自己去找

按时间抽取的信号流图:
按时间抽取信号流图
我们从这张信号流图可以抽象出程序的实现步骤:首先对信号时间序列进行逆序处理,再进行下面的工作,分三层循环进行:
第一个循环是进行N阶的FFT运算;第二个循环其实就是,每一阶FFT的时候,有多少组DFT对象,拿8点来说,第一阶的时候,有4组DFT对象,到了第二阶,就有2组,到了第三,就是最后一阶,只有一组;第三个循环,其实是在每一组DFT里边,执行多少次蝶形运算!8点FFT来说,第一阶每组有一个蝶形,第二阶每组有2个,第三阶每组有4个蝶形。
具体流程图如下:
在这里插入图片描述
i , j, k 三者,反别表示三层循环,然后得出循环次数的关系:
stages = log2(PointNum),i从0到stage-1,j从0 到2^(stages - (i + 1)) – 1,k 从0到2^i – 1。
下面是进行蝶形运算的流程:
首先确定旋转因子W,根据8点DIT-FFT图,得到相关表达式在这里插入图片描述
然后是具体蝶形计算的实现,我们在计算机里面操控的都是实数,所以将其分为实部虚部两部分计算来弄:在这里插入图片描述
在完成相关的代码编程后,用以下的时间序列做实验:
在这里插入图片描述
在这里插入图片描述
fs取1024*2,取样点数N取512,最终得到的结果如下:
在这里插入图片描述
第一幅图为matlab自带的fft,第二幅图是编写的fft,其中纵坐标为幅值,横坐标的单位为fs/N(频率分辨率),而且由于fft的对称性,以及奈奎斯特采样定律(fs大于采样序列中最大频率的两倍),故只展示了前半部分的频域图。第三章图为时域图。
从上面的图中我们可以看到,频率分量都被很好的提取了出来,但是幅值方面似乎不是太对,经过查阅资料,我发现:要想恢复幅值,首先FFT求出来的幅值要乘2/N(直流分量不用乘2),其次N与fs要有个对应关系:N为fs的整数倍(即不发生频谱泄露)。
处理后的效果图:
在这里插入图片描述
可以看到它可以完美的还原出原信号。
但是我们在实际中通常是非周期截断(N不是fs整数倍)。
在这里插入图片描述
截断后的信号起始时刻和结束时刻的幅值明显不等,将这个信号再进行重构,在连接处信号的幅值不连续,出现跳跃,如图中黑色圆圈区域所示。
对截断后的信号做FFT分析,得到的频谱如下图所示。
在这里插入图片描述
这时的FFT频谱已远远不是我们预期的那种单条离散谱线了(周期截取的频谱样子)。对比周期截断的频谱,可以看出,此时频谱在整个频带上发生“拖尾”现象。峰值处的频率与原始信号的频率相近,但并不相等。另一方面,峰值处的幅值已不再等于原始信号的幅值,为原始信号幅值的64%(矩形窗的影响)。而幅值的其他部分(36%幅值)则分布在整个频带的其他谱线上。由于信号的非周期截断,导致频谱在整个频带内发生了拖尾现象。这是非常严重的误差,称为泄漏,是数字信号处理所遭遇的最严重误差。

对比一下正确的频谱与发生泄漏的频谱,如下图所示,

在这里插入图片描述
可以看出,泄漏后的频谱的幅值更小,频谱拖尾更严重。当截断后的信号不为周期信号时,就会发生泄漏。而现实世界中,在做FFT分析时,很难保证截断的信号为周期信号,因此,泄漏不可避免。
现在返回到非周期截断的正弦波,可以看出在截断时间长度内没有捕捉到整数倍个周期正弦波,导致波形发生了失真,似乎在信号周期的末端波形出现了不连续。这就解释了为什么FFT会在整个频带上发生拖尾现象了。本质上,这需要多个傅立叶展开项(多条谱线)去近似这个明显不连续的信号,因此,频谱出现了拖尾现象。
为了将这个泄漏误差减小到最小程度,我们需要使用加权函数,也叫窗。加窗主要是为了使信号更好地满足FFT处理的周期性要求,减少泄漏。如下图所示:
在这里插入图片描述

若周期截断,则FFT频谱为单一谱线。若为非周期截断,则频谱出现拖尾,如图中部所示。为了减少泄漏,给信号施加一个窗函数(如图中红色曲线所示),原始截断后的信号与这个窗函数相乘之后得到的信号为右侧上面的信号。可以看出,此时,信号的起始时刻和结束时刻幅值都为0,也就是说在这个时间长度内,信号为周期信号,但是只有一个周期。对这个信号做FFT分析,得到的频谱如右侧下边所示。相比较之前未加窗的频谱,可以看出,泄漏已明显改善,但并没有完全消除泄漏。因此,窗函数只能减少泄漏,不能消除泄漏。

利用FFT进行声音处理

首先利用audioread读入声音。时域波形如下:
在这里插入图片描述
关于这段音频的信息如下:
在这里插入图片描述
利用FFT进行分析,得到的频谱如下:
在这里插入图片描述
根据图10我们可以知道,采样频率为48000,采样点数为170496
我们首先对利用matlab的randn声音进行加噪处理,加噪后的波形如下:
在这里插入图片描述
由两个频域图对比可知,噪声主要集中在高频部分,所以我们设计一个低通滤波器,去除噪声同时最大程度保留源信号。利用firl函数设计,其中参数如下:
fp=1500;fc=1700;As=100;Ap=1;
得到的滤波伯德图如下:
在这里插入图片描述
最后利用fftfilt滤波后的效果对比图如下:
在这里插入图片描述

代码附录

一、FFT的部分
PointNum  = 1024*2;
PointBitNum =11;
fs = 1024*2;
n = 0:1:PointNum - 1;
sampletab = cos(2*pi*543*n/fs) + cos(2*pi*100*n/fs) + 0.2 + cos(2*pi*857*n/fs) + cos(2*pi*222*n/fs);
zeros(1,PointNum);
sampletab1 = sampletab;
index = 0;
for i = 1:PointNum
   index = bitreverse(PointBitNum,i - 1);
   sampletab(i) = sampletab1(index + 1);
end
REX = sampletab;
IMX = zeros(1,PointNum);
i = 0; 
j = 0; 
k = 0;
stages = log2(PointNum);
for i = 0 : stages - 1
   lenNum = 0; 
   for j = 0 : 2^(stages - (i + 1)) - 1
       for k = 0 : 2^i - 1
           R1 = REX(lenNum + 2^i + 1) * cos(2*pi*k*2^(stages - (i + 1))/PointNum); 
           R2 = IMX(lenNum + 2^i + 1) * sin(2*pi*k*2^(stages - (i + 1))/PointNum);
           T1 = REX(lenNum + 2^i + 1) * sin(2*pi*k*2^(stages - (i + 1))/PointNum);
           T2 = IMX(lenNum + 2^i + 1) * cos(2*pi*k*2^(stages - (i + 1))/PointNum);
           REX(lenNum + 2^i + 1) = REX(lenNum + 1) - R1 - R2;
           IMX(lenNum + 2^i + 1) = IMX(lenNum + 1)  + T1 - T2;
           REX(lenNum + 1) = REX(lenNum + 1) + R1 + R2;
           IMX(lenNum + 1) = IMX(lenNum + 1) - T1 + T2 ; 
           lenNum = lenNum + 1;
           endNum = lenNum + 2^i;    
       end  
       lenNum = endNum;
   end
end
subplot(3,1,1);
fft(sampletab1, PointNum);
x1 = abs(fft(sampletab1, PointNum))*2/PointNum;
x1(1)=x1(1)/2;
plot(n(1:PointNum/2)*fs/PointNum, x1(1:PointNum/2));
grid on
subplot(3,1,2);
am = sqrt(abs(REX.*REX) + abs(IMX.*IMX))*2/PointNum;
am(1)=am(1)/2;
plot(n(1:PointNum/2)*fs/PointNum, am(1:PointNum/2));
grid on
subplot(3,1,3);
plot(n, sampletab);
grid on
二、声音处理部分
[y,fs]=audioread('test.mp3');
% sound(y,fs)     % 回放语音信号
y=y(:,1);
n=length(y) ; %选取变换的点数 
y_p=fft(y,n);     %对n点进行傅里叶变换到频域
f=fs*(0:n/2-1)/n;   % 对应点的频率
t=(1:length(y))/fs;   %采样时间
figure(1)
subplot(2,1,1);
plot(t,y);                   %语音信号的时域波形图
title('原始语音信号采样后时域波形');
xlabel('时间轴')
ylabel('幅值 A')
subplot(2,1,2)
plot(f,abs(y_p(1:n/2))*2/length(y_p));    %语音信号的频谱图
title('原始语音信号采样后频谱图');
xlabel('频率Hz');
ylabel('频率幅值');
%对音频信号产生噪声
 L=length(y) ;      %计算音频信号的长度
 noise=0.1*randn(L,1); %产生等长度的随机噪声信号(这里的噪声的大小取决于随机函数的幅度倍数)
 y_z=y+noise;       %将两个信号叠加成一个新的信号——加噪声处理   
  %sound(y_z,fs)
%对加噪后的语音信号进行分析
n=length(y);  %选取变换的点数 
y_zp=fft(y_z,n);     %对n点进行傅里叶变换到频域
f=fs*(0:n/2-1)/n;   % 对应点的频率
figure(2)
subplot(2,1,1);
plot(t,y_z);                   %加噪语音信号的时域波形图
title('加噪语音信号时域波形');
xlabel('时间轴')
ylabel('幅值 A')
subplot(2,1,2);
plot(f,abs(y_zp(1:n/2))*2/length(y_zp));    %加噪语音信号的频谱图
title('加噪语音信号频谱图');
xlabel('频率Hz');
ylabel('频率幅值');
fp=1500;fc=1700;As=100;Ap=1;
wc=2*pi*fc/fs; wp=2*pi*fp/fs;
wdel=wc-wp;
beta=0.112*(As-8.7);
N=ceil((As-8)/2.285/wdel);
wn= kaiser(N+1,beta);
ws=(wp+wc)/2/pi;
b=fir1(N,ws,wn)
figure(3);
freqz(b,1);         
x=fftfilt(b,y_z);
X=fft(x,n);
figure(4);
subplot(2,2,1);plot(f,abs(y_zp(1:n/2))*2/length(y_zp));
title('滤波前信号的频谱');
subplot(2,2,2);plot(f,abs(X(1:n/2))*2/length(X));
title('滤波后信号频谱');
subplot(2,2,3);plot(t,y_z);
title('滤波前信号的波形')
subplot(2,2,4);plot(t,x);
title('滤波后信号的波形')
%sound(x,fs)  %回放滤波后的音频

  • 2
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: SFFT是一种基于FFT的算法,用于计算任意长度信号的周期谱。Matlab程序实现了SFFT算法的计算过程,可以对任意长度的信号进行周期谱分析。 在Matlab程序中,首先要读入信号数据,并进行预处理。接着,对信号进行FFT计算,以得到频域信息。然后,对FFT得到的频谱进行SFFT算法处理,得到周期谱图。最后,利用Matlab绘图工具绘制周期谱图,以展示信号的周期特征。 SFFT算法相比于传统的FFT算法,可以获得更准确的周期谱信息,而且计算速度更快。因此,在信号处理领域中,SFFT算法得到了广泛的应用Matlab程序实现了SFFT算法的计算过程,使得周期谱分析变得更加方便快捷。 因此,SFFT Matlab程序在信号处理领域具有重要的应用价值,特别是对于需要快速准确分析信号的周期性特征的领域,如音频处理、图像处理等领域。 ### 回答2: sfft是指分散傅立叶变换(Split Fourier Transform),它是一种在信号处理中常用的算法。sfft matlab程序可以用于实现对信号进行傅立叶变换和逆变换。 首先,我们需要定义一个输入信号,可以是一个离散序列或者一个连续函数。然后,通过调用sfft函数,将输入信号传递给该函数。 sfft函数的编写如下: function [spectrum, time_domain] = sfft(input_signal) L = length(input_signal); N = 2^nextpow2(L); spectrum = fft(input_signal, N); time_domain = ifft(spectrum, N); end 在这个程序中,我们首先计算输入信号的长度L,并找到一个满足2^N > L的2的幂N,以确保我们可以进行有效的傅立叶变换。然后,我们使用fft函数对输入信号进行傅立叶变换得到频谱。接下来,我们使用ifft函数对频谱进行逆变换,以便还原原始的时间域信号。 最后,我们可以调用这个sfft函数并将输入信号作为参数传递进去,然后将得到的频谱和逆变换后的时间域信号保存在对应的变量中。 例如,我们可以这样调用sfft函数: input_signal = [1, 2, 3, 4, 3, 2, 1]; [spectrum, time_domain] = sfft(input_signal); 在这个例子中,我们定义了一个输入信号为[1, 2, 3, 4, 3, 2, 1]。然后,调用sfft函数并传入这个输入信号。最后,我们将得到的频谱保存在spectrum变量中,将逆变换后的时间域信号保存在time_domain变量中。 sfft matlab程序可以帮助我们更好地理解信号的频谱结构,并进行信号处理的相关操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值