FFT之后那些事情2——如何得到正确的振幅

FFT之后那些事情2

n年前发过一篇文章,FFT之后那些事情,介绍了fft之后幅值要怎么处理的问题,这里对这个问题进行进一步详细介绍,实现一个完全正确的频谱,尤其是0频率和Nyquist频率分量(最后一个频率)要如何正确的处理,否则你做出来的频谱,总会和正确的频谱有一点点差距

首先一个完整的频谱(工程上使用的频谱)代码是这样的:

本文只讨论幅值谱的处理方式

下面就以这个频谱分析的函数,介绍为何要做那么多特殊处理

def spectrum_analysis(waveform, sampling_rate, fftsize=None):
    '''
    频谱分析

    :param waveform: 输入波形数据,可以是一维数组或列表  
    :param sampling_rate: 采样率  
    :param fftsize: FFT变换的窗口大小,默认为None,表示使用波形的长度  
    :return: 频谱分析结果,包含频率、振幅和相位三个部分  
    :rtype: 
    '''
    if fftsize is None:  
        fftsize = len(waveform)  # 如果没有指定fftsize或者fftsize为None,则使用波形的长度  
  
    # 如果fftsize大于波形长度,对波形进行补零  
    if fftsize > len(waveform):  
        waveform = np.pad(waveform, (0, fftsize - len(waveform)))  
    # 如果fftsize小于波形长度,截取波形  
    elif fftsize < len(waveform):  
        waveform = waveform[:fftsize]  
  
    # 对波形执行FFT变换  
    fft_values = np.fft.rfft(waveform)  
      
    # 获取FFT结果的频率值  
    freq = np.fft.rfftfreq(fftsize, 1.0 / sampling_rate)  
      
    # 计算频谱的振幅  
    amplitudes = np.abs(fft_values) / fftsize  # 先不进行乘以2的操作  
      
    # 对非直流分量和非Nyquist分量的振幅乘以2  
    # 直流分量是第一个元素,如果fftsize是偶数,Nyquist分量是最后一个元素  
    if fftsize % 2 == 0:  # 偶数个点  
        amplitudes[1:-1] *= 2  # 忽略直流分量和Nyquist分量  
    else:  # 奇数个点,没有Nyquist分量  
        amplitudes[1:] *= 2  # 只忽略直流分量  
        
    return freq,amplitudes

这里有两个地方说明:
1、fftsize这个参数,既然已经有波形了,为何还要设置一个fftsize?
2、幅值的特殊处理,为什么要取模乘以2再除以长度,以及对于直流分量(freq[0])和Nyquist频率分量为何要单独处理

fftsize有何用?波形长度难道不行吗

所有fft函数都可以指定一个fftsize参数,如NumPy的FFT模块中,np.fft.rfft 函数的 n 参数允许你指定FFT变换的点数。这个参数对于控制FFT的计算精度和性能是有用的,你可以设置比原来波形短,也可以设置比原来波形长,也可以和波形长度一样,它主要有如下作用:

1. 裁剪或补零输入:

当FFT长度小于输入波形长度时,裁剪输入可以减少FFT需要处理的数据量,从而提高计算速度。但这样做可能会丢失波形中的一些信息。
当FFT长度大于输入波形长度时,通过补零来增加数据点的数量。这样做通常不会增加频谱分辨率(因为实际的信号信息没有增加),但可以使频谱看起来更加平滑,并可能有助于在图形化展示时更清楚地识别出峰值。

2. 控制频率分辨率:

FFT将信号从时域转换到频域,结果是一系列表示不同频率分量的复数。这些复数的模表示该频率分量的幅度,而幅角表示相位。
FFT的长度(即点数n)决定了频率分量的数量。更长的FFT会产生更多的频率分量,从而提供更精细的频率分辨率。但要注意,增加FFT长度并不一定会增加频谱的精度或信息量,它只是将现有的频谱信息分布到更多的点上。

3. 性能优化:

许多FFT库(如FFTW、KissFFT等)都针对特定长度的FFT进行了优化,特别是当长度为2的幂时。在这些情况下,FFT算法可以利用分治策略(如Cooley-Tukey FFT算法)更高效地计算变换。

4. 避免频谱泄漏:

如果信号包含周期性成分(如正弦波),且FFT的长度恰好是该周期的整数倍,则FFT结果将在该频率处产生一个尖锐的峰值,而其他频率处的值将接近零。这有助于更准确地识别和测量信号中的周期性成分。
如果FFT长度不是信号周期的整数倍,则会导致频谱泄漏,即信号的能量会泄漏到其他频率上,使得频谱分析变得困难。选择合适的FFT长度(特别是与信号周期相匹配的长度)可以减少这种泄漏。

因此,上面的频谱分析函数提供了fftsize,可以根据需求来传入fftsize

幅值为什么要取模乘以2再除以长度,以及对于直流分量(freq[0])和Nyquist频率分量为何要单独处理

计算频谱的振幅时,使用rfft值取模、乘以二再除以fftsize的做法是基于FFT(快速傅里叶变换)的性质和信号处理的需要。

FFT返回的是复数数组,每个复数表示对应频率分量的幅度和相位。在计算频谱振幅时,通常只关心幅度信息,因此需要对每个复数取模(即计算复数的绝对值),这样得到的就是该频率分量的振幅。

为何要乘以2

对于实数信号的FFT分析,由于信号的对称性(实数信号的FFT结果是共轭对称的),我们通常只需要考虑正频率部分(对于np.fft.rfft来说,它只返回正频率部分的结果)。为了补偿由于只考虑正频率部分而丢失的能量,我们要将振幅乘以2(除了直流分量和Nyquist频率分量,它们不是成对出现的)。这样做是为了保证总能量在时域和频域之间保持一致。

直流分量(freq[0])和Nyquist频率分量为何要单独处理

在FFT(快速傅里叶变换)分析中,对于实数信号的频谱,通常只考虑正频率部分,因为实数信号的FFT结果是共轭对称的。然而,在振幅的计算中,需要特别注意两个特殊的频率分量:直流分量(DC分量,对应于频率为0的分量)和Nyquist分量(如果采样点数为偶数,则存在;对应于采样频率的一半)。为啥要特别注意呢,因为这两个不是对称的,就是因为不是对称,因此需要特殊处理

如果不进行特殊处理,直接将除了直流分量以外的所有振幅乘以2,那么直流分量和Nyquist分量的振幅将会被错误地加倍,从而导致频谱分析的结果不准确。

直流分量

直流分量是信号中的平均值或常数部分,在FFT结果中对应于频率为0的点。由于直流分量不是成对出现的(没有对应的负频率分量),因此在计算振幅时不需要将其振幅乘以2。

Nyquist频率分量

当采样点数为偶数时,FFT结果中会包含一个Nyquist分量,其频率为采样频率的一半。和直流分量一样,Nyquist分量也是独特的,没有对应的负频率分量。因此,在计算振幅时,同样不应该将其振幅乘以2。

Nyquist分量,也被称为Nyquist频率成分,是在进行数字信号处理时,特别是进行离散傅里叶变换(DFT)或快速傅里叶变换(FFT)时遇到的一个特殊频率成分。Nyquist分量是以美国电信工程师Harry Nyquist的名字命名的,他首先提出了采样定理,该定理说明了为了无失真地还原一个模拟信号,采样频率必须至少是信号中最高频率成分的两倍。这个两倍的频率就被称为Nyquist频率,说白了就是信号中接近或等于采样频率一半的成分。

在FFT分析中,如果采样点数为偶数,Nyquist分量会出现在FFT结果的最后一个点,其对应的频率正好是采样频率的一半,也就是Nyquist频率。这个分量代表了信号中接近或等于Nyquist频率的成分。由于FFT的周期性,Nyquist分量没有对应的负频率分量,因此在处理FFT结果时需要对它进行特殊处理。如果不正确处理,可能会导致频谱分析中的误差。

  • 35
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

尘中远

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值