如何在 python 中的段上 implement/perform DFT?

How to implement/perform DFT on a segment in python?

我正在尝试在 python 中编写一个简单的程序来计算和显示 1 段的 DFT 输出。

我的信号长 3 秒,我想为每 10 毫秒长的片段计算 DFT。采样率是44100。所以一段是441个样本长。

因为我正处于测试这个阶段并且原始程序要大得多(语音识别),所以这里是一个用于测试目的的孤立部分,不幸的是它表现得很奇怪。要么是我对这个问题缺乏了解。

  1. 我在某处读到 DFT 输入应四舍五入为 2 的幂,所以我将数组排列为 512 而不是 441。这是真的吗?

  2. 如果我以 44100 的速率采样,我最多可以达到 22050Hz 的频率,对于长度为 512(~441) 的样本,至少可以达到 100Hz ?

  3. 如果 2. 为真,那么我可以在 10ms 段中拥有 100hz 和 22050hz 之间的所有频率,但段的长度仅为 512(441) 个样本,fft 的输出 returns 256(220) 个值的数组,它们不能包含所有 21950 个频率,可以吗?

  4. 我的第一个猜测是 fft 的输出值应该乘以 100,因为 10 毫秒是 100 秒。这个推理好吗?

以下程序针对两个给定频率 1000 和 2000 returns 在输出数组中的位置 24 和 48 以及图形上的 ~2071 和 ~4156 处有两个尖峰。由于数字比例没问题 (2000:1000 = 48:24) 我想知道我是否应该忽略 fft 输出的某些起始部分?

import matplotlib.pyplot as plt
import numpy as np

t = np.arange(0, 1, 1/512.0)  # We create 512 long array

# We calculate here two sinusoids together at 1000hz and 2000hz
y = np.sin(2*np.pi*1000*t) + np.sin(2*np.pi*2000*t)
n = len(y)
k = np.arange(n)

# Problematic part is around here, I am not quite sure what
# should be on the horizontal line
T = n/44100.0
frq = k/T
frq = frq[range(n/2)]


Y = fft(y)  
Y = Y[range(n/2)]
# Convert from complex numbers to magnitudes
iY = []
for f in Y:
    iY.append(np.sqrt(f.imag * f.imag + f.real * f.real))


plt.plot(frq, iY,  'r')
plt.xlabel('freq (HZ)')
plt.show()

1) I read somewhere that DFT input should be rounded to power of 2 so I aranged my array to 512 instead 441. Is this true?

是的,DFT 长度应该是 2 的幂。只需用零填充输入即可匹配 512。

2) If I am sampling at a rate of 44100, at most I can reach frequency of 22050hz and for sample of length 512(~441) at least 100hz ?

是的,您可以获得的最高频率是采样率的一半,称为奈奎斯特频率。

不,您得到的最低频率仓(DFT 的第一个仓)称为直流分量,它标记了信号的平均值。在您的情况下,下一个最低的频率仓是 22050 / 256 = 86Hz,然后是 172Hz、258Hz,依此类推,直到 22050Hz。 您可以使用 numpy.fftfreq() 函数获取此频率。

3) If 2) is true, then I can have all frequencies between 100hz and 22050hz in that 10ms segments, but the length of segment is 512(441) samples only, output of fft returns array of 256(220) values, they cannot contain all 21950 frequencies in there, can they?

DFT不会丢失原始信号的数据,但当DFT尺寸较小时会缺乏准确性。您可以对其进行零填充以使 DFT 大小更大,例如 1024 或 2048。

DFT bin指的是以N个输出中的每一个为中心的频率范围 点。 bin的宽度为sample rate/2, 它从:中心频率 -(sample rate/N)/2 延伸到中心 频率 +(样本 rate/N)/2。换句话说,垃圾箱的一半延伸 在 N 个输出点中的每一个下方,以及在其上方的一半。

4) My first guess is that the values in output of fft should be multiplied by 100, since 10ms is 100th of a second. Is this good reasoning?

不,如果要保持幅度,则不应乘以该值。

The following program for two given frequencies 1000 and 2000 returns two spikes on graph at positions 24 and 48 in the output array and ~2071 and ~4156 on the graph. Since ratio of numbers is okay (2000:1000 = 48:24) I wonder if I should ignore some starting part of the fft output?

DFT 结果反映在实际输入中。换句话说,你的频率将是这样的:

n  0   1   2   3    4   ... 255   256   257   ... 511 512
Hz DC  86  172 258  344 ... 21964 22050 21964 ... 86  0
  1. I read somewhere that the DFT input should be rounded to power of 2 so I arranged my array to 512 instead 441. Is this true?

DFT 是为所有尺寸定义的。然而,对于可以分解为小素数的大小,DFT 的实现(例如 FFT)通常要高效得多。一些库实现有限制,不支持除 2 的幂以外的大小,但 numpy.

不是这种情况。
  1. If I am sampling at a rate of 44100, at most I can reach frequency of 22050Hz and for sample of length 512(~441) at least 100Hz?

正如您正确指出的那样,即使大小的 DFT 的最高频率将是 44100/2 = 22050Hz。请注意,对于奇数大小的 DFT,最高频率仓将对应于略低于奈奎斯特频率的频率。至于最低频率,它永远是0Hz。下一个非零频率将是 44100.0/N,其中 N 是样本中的 DFT 长度(如果您使用的 DFT 长度为 441 个样本,则为 100Hz,而 DFT 长度为 512 个样本,则为 ~86Hz) .

  1. If 2) is true, then I can have all frequencies between 100Hz and 22050Hz in that 10ms segments, but the length of segment is 512(441) samples only, output of fft returns array of 256(220) values, they cannot contain all 21950 frequencies in there, can they?

首先,在 100Hz 和 22050Hz 之间没有 21950 个频率,因为频率是连续的并且不限于整数频率。也就是说,您意识到 DFT 的输出将被限制在一组更小的频率上是正确的。更具体地说,DFT 表示离散频率步长的频谱:0,44100/N2*44100/N,...

  1. My first guess is that the values in output of FFT should be multiplied by 100, since 10ms is 100th of a second. Is this good reasoning?

不需要将 FFT 输出乘以 100。但是如果您的意思是 100Hz 的倍数,DFT 长度为 441,采样率为 44100Hz,那么您的猜测会是正确的。

The following program for two given frequencies 1000 and 2000 returns two spikes on graph at positions 24 and 48 in the output array and ~2071 and ~4156 on the graph. Since ratio of numbers is okay (2000:1000 = 48:24) I wonder if I should ignore some starting part of the fft output?

这里问题比较严重。当你声明数组时

t = np.arange(0, 1, 1/512.0)  # We create 512 long array

您实际上是在表示采样率为 512Hz 而不是 44100Hz 的信号。结果,您生成的音调严重混叠(分别为 24Hz 和 48Hz)。您随后使用 44100Hz 的采样率进行频率轴转换这一事实进一步加剧了这种情况。这就是峰值未出现在预期的 1000Hz 和 2000Hz 频率的原因。

要表示以 44100Hz 的采样率采样的信号的 512 个样本,您应该改用

t = np.arange(0, 511.0/44100, 1/44100.0)

此时您用于频率轴的公式将是正确的(因为它基于相同的 44100Hz 采样率)。然后,您应该能够在预期的 1000Hz 和 2000Hz 附近看到峰值(峰值的最接近频率区间在 ~1033Hz 和 1981Hz)。