【问题标题】:Analyze audio using Fast Fourier Transform使用快速傅里叶变换分析音频
【发布时间】:2010-10-10 21:45:18
【问题描述】:

我正在尝试在 python 中创建图形频谱分析仪。

我目前正在读取 16 位双通道 44​​,100 Hz 采样率音频流的 1024 字节,并将 2 个通道的幅度平均在一起。所以现在我有一系列 256 条签名短裤。我现在想在该阵列上执行 fft,使用像 numpy 这样的模块,并使用结果创建图形频谱分析仪,开始时只有 32 条。

我已阅读有关快速傅里叶变换和离散傅里叶变换的维基百科文章,但我仍然不清楚结果数组代表什么。这是我使用 numpy 在数组上执行 fft 后数组的样子:

   [ -3.37260500e+05 +0.00000000e+00j   7.11787022e+05 +1.70667403e+04j
   4.10040193e+05 +3.28653370e+05j   9.90933073e+04 +1.60555003e+05j
   2.28787050e+05 +3.24141951e+05j   2.09781047e+04 +2.31063376e+05j
  -2.15941453e+05 +1.63773851e+05j  -7.07833051e+04 +1.52467334e+05j
  -1.37440802e+05 +6.28107674e+04j  -7.07536614e+03 +5.55634993e+03j
  -4.31009964e+04 -1.74891657e+05j   1.39384348e+05 +1.95956947e+04j
   1.73613033e+05 +1.16883207e+05j   1.15610357e+05 -2.62619884e+04j
  -2.05469722e+05 +1.71343186e+05j  -1.56779748e+04 +1.51258101e+05j
  -2.08639913e+05 +6.07372799e+04j  -2.90623668e+05 -2.79550838e+05j
  -1.68112214e+05 +4.47877871e+04j  -1.21289916e+03 +1.18397979e+05j
  -1.55779104e+05 +5.06852464e+04j   1.95309737e+05 +1.93876325e+04j
  -2.80400414e+05 +6.90079265e+04j   1.25892113e+04 -1.39293422e+05j
   3.10709174e+04 -1.35248953e+05j   1.31003438e+05 +1.90799303e+05j...

我想知道这些数字究竟代表什么,以及如何将这些数字转换为 32 个条形中每个条形的高度百分比。另外,我应该将 2 个通道一起平均吗?

【问题讨论】:

    标签: python audio signal-processing fft spectrum


    【解决方案1】:

    FFT 返回 N 个复数值,你们中的哪一个可以计算 module=sqrt(real_part^2+imaginary_part^2)。要获得每个频段的值,您必须对频段内所有谐波的模块求和。您可以在下面看到一个关于 10 条频谱分析仪的示例。必须包装 c 代码才能获得 pyd python 模块。

    float *samples_vett;
    float *out_filters_vett;
    int Nsamples;
    float band_power = 0.0;
    float harmonic_amplitude=0.0;
    int i, out_index;
    
    out_index=0;
    
    
    for (i = 0; i < Nsamples / 2 + 1; i++)       
            {
                if (i == 1 || i == 2 || i == 4 || i == 8 || i == 17 || i == 33 || i == 66 || i == 132 || i == 264 || i == 511)
                {
                    out_filters_vett[out_index] = band_power; 
                    band_power = 0; 
                    out_index++;  
                }
    
                harmonic_amplitude = sqrt(pow(ttfr_out_vett[i].r, 2) + pow(ttfr_out_vett[i].i, 2));
                band_power += harmonic_amplitude;
    
            }
    

    我用 Python 设计并制作了一个完整的 10 LED 条形频谱分析仪。取而代之的是使用 nunmpy 库(太大且无法仅获取 FFT),而是创建了一个 python pyd 模块(仅 27KB)来获取 FFT 并将整个音频频谱拆分为频段。

    此外,为了读取输出音频,创建了一个环回 WASapi portaudio pyd 模块。您可以在图像中看到项目(框图) 10BarsSpectrumAnalyzerWithWASapi.jpg

    刚刚在我的 YouTube 频道上添加了一个教程视频:how to design and make a very smart Python Spectrum Analyzer 10 Led Bar

    【讨论】:

      【解决方案2】:

      您所拥有的是一个样本,其时间长度为 256/44100 = 0.00580499 秒。这意味着您的频率分辨率为 1 / 0.00580499 = 172 Hz。从 Python 中得到的 256 个值基本上对应于频率,从 86 Hz 到 255*172+86 Hz = 43946 Hz。你得到的数字是复数(因此每个数字末尾都有“j”)。

      已编辑:修正错误信息

      您需要通过计算 sqrt(i2 + j2) 将复数转换为幅度,其中 i 和 j 分别是实部和虚部。

      如果你想要 32 根柱线,据我所知,你应该取四个连续振幅的平均值,得到 256 / 4 = 32 根柱线。

      【讨论】:

      • 请注意,如果 c 是复数,则 sqrt(c.real2 + c.imag2) == abs(c)
      【解决方案3】:

      虽然这个帖子已有多年历史,但我发现它非常有帮助。我只是想将我的意见提供给任何发现此内容并尝试创建类似内容的人。

      至于分成条形,这不应该像 antti 建议的那样,通过根据条形数平均划分数据来完成。最有用的是将数据分成倍频程部分,每个倍频程的频率是前一个倍频程的两倍。 (即100hz是50hz以上的一个八度音程,即25hz以上的一个八度音程)。

      根据您想要的小节数,您可以将整个范围划分为 1/X 倍频程范围。 根据条上 A 的给定中心频率,您可以从以下位置获得条的上限和下限:

      upper limit = A * 2 ^ ( 1 / 2X )
      lower limit = A / 2 ^ ( 1 / 2X )
      

      要计算下一个相邻的中心频率,您可以使用类似的计算:

      next lower =  A / 2 ^ ( 1 / X )
      next higher = A * 2 ^ ( 1 / X )
      

      然后,您对适合这些范围的数据进行平均,以获得每个条的幅度。

      例如: 我们想分成 1/3 倍频程范围,我们从 1khz 的中心频率开始。

      Upper limit = 1000 * 2 ^ ( 1 / ( 2 * 3 ) ) = 1122.5
      Lower limit = 1000 / 2 ^ ( 1 / ( 2 * 3 ) ) =  890.9
      

      给定 44100hz 和 1024 个样本(每个数据点之间为 43hz),我们应该对 21 到 26 的值进行平均。(890.9 / 43 = 20.72 ~ 21 和 1122.5 / 43 = 26.10 ~ 26)

      (1/3 个八度小节可以让您在 ~40hz 和 ~20khz 之间获得大约 30 个小节)。 正如您现在所知道的那样,随着我们走得更高,我们将平均更大范围的数字。低条通常仅包含 1 个或少量数据点。而较高的条形可以是数百个点的平均值。原因是 86hz 比 43hz 高一个八度……而 10086hz 听起来和 10043hz 几乎一样。

      【讨论】:

        【解决方案4】:

        您显示的数组是音频信号的傅立叶变换系数。这些系数可用于获取音频的频率内容。 FFT 是为复值输入函数定义的,因此即使您的输入都是实数值,您得到的系数也将是虚数。为了获得每个频率的功率量,您需要计算每个频率的 FFT 系数的大小。这只是系数的实部,您需要计算其实部和虚部的平方和的平方根。也就是说,如果你的系数是a + b*j,那么它的大小是sqrt(a^2 + b^2)。

        计算出每个 FFT 系数的幅度后,您需要弄清楚每个 FFT 系数属于哪个音频频率。 N 点 FFT 将为您提供从 0 开始的 N 个等距频率处的信号频率内容。因为您的采样频率为 44100 个样本/秒。 FFT 中的点数为 256,频率间隔为 44100 / 256 = 172 Hz(大约)

        数组中的第一个系数将是 0 频率系数。这基本上是所有频率的平均功率水平。其余系数将从 0 以 172 Hz 的倍数递增,直到达到 128。在 FFT 中,您只能测量最多一半采样点的频率。阅读Nyquist FrequencyNyquist-Shannon Sampling Theorem 上的这些链接,如果您喜欢惩罚并且需要知道原因,但基本结果是您的较低频率将被复制或aliased 在较高频率桶中。所以频率将从 0 开始,每个系数增加 172 Hz,直到 N/2 系数,然后减少 172 Hz,直到 N - 1 系数。

        这应该足以让您入门。如果您想要比 Wikipedia 上更容易理解的 FFT 介绍,您可以尝试 Understanding Digital Signal Processing: 2nd Ed.。这对我很有帮助。

        这就是这些数字所代表的。可以通过将每个频率分量幅度按所有分量幅度之和缩放来转换为高度百分比。虽然,这只会为您提供相对频率分布的表示,而不是每个频率的实际功率。您可以尝试按频率分量可能的最大幅度进行缩放,但我不确定这会显示得很好。找到可行比例因子的最快方法是对响亮和柔和的音频信号进行试验以找到正确的设置。

        最后,如果您想将整个音频信号的频率内容显示为一个整体,您应该将两个通道一起平均。您正在将立体声音频混合成单声道音频并显示组合频率。如果您想要两个单独的左右频率显示,则需要分别对每个通道执行傅里叶变换。

        【讨论】:

        • 我大多只能在网上找到过于复杂的 FFT 解释,这是对采样点数如何影响 FFT 结果的一个伟大而简单的解释。谢谢你!
        猜你喜欢
        • 1970-01-01
        • 2011-07-12
        • 2015-02-10
        • 1970-01-01
        • 2017-09-14
        • 2011-10-01
        • 2012-12-10
        • 2010-12-13
        • 2013-03-31
        相关资源
        最近更新 更多