python - 相同长度音频剪辑的不同 FFT 信号长度

标签 python scikit-learn fft audio-processing librosa

目前,我正在开展一个项目,该项目要求我挑选出音频剪辑并根据 FFT 结果(即频谱图)对它们进行比较。我所有的音频剪辑都是 0.200 秒长,但是当我通过转换处理它们时,它们的长度不再相同。我用于转换的代码使用了 numpy 和 librosa 库:

def extractFFT(audioArr):
    fourierArr = []
    fourierComplex = []
    for x in range(len(audioArr)):
        y, sr = lb.load(audioArr[x])
        fourier = np.fft.fft(y)
        fourier = fourier.real
        fourierArr.append(fourier)
     return fourierArr

我只采用转换的实数部分,因为我还想通过不允许复数的 PCA 传递它。无论如何,我无法对这个 FFT 音频片段数组执行 LDA(线性判别分析)或 PCA,因为有些片段的长度不同。

我为 LDA 编写的代码如下,其中为长度为 4 的 frequencyArr 给出了标签:

def LDA(frequencyArr):
    splitMark = int(len(frequencyArr)*0.8)
    trainingData = frequencyArr[:splitMark]
    validationData = frequencyArr[splitMark:]
    labels = [1,1,2,2]

    lda = LinearDiscriminantAnalysis()
    lda.fit(trainingData,labels[:splitMark])

    print(f"prediction: {lda.predict(validationData)}")

这会引发以下值错误,来自 lda.fit(trainingData,labels[:splitMark]) 行:

ValueError:使用序列设置数组元素。

我知道这个错误源于数组不是一组二维形状,因为当 FFT 元素都等长并且代码按预期工作时我没有收到这个错误。

这与音频片段有关吗?转换后,一些音频片段的长度相等,而另一些则不同。如果有人能解释为什么这些相同长度的音频剪辑可以返回不同长度的 FFT,那就太好了!

请注意,它们通常只有几点不同,比如 3 个音频片段的 FFT 长度为 4410,而第 4 个片段的 FFT 长度为 4409。我知道我可以将长度缩减到组,但我更喜欢一种不会遗漏任何值的更简洁的方法。

最佳答案

首先:不要只取转换结果的实部。这对你没有任何好处。使用功率 (r^2+i^2) 或幅度 (sqrt(power)) 获取频率仓的信号强度。

Does this have something to do with the audio clips? After the transform, some audio clips are of equal lengths, others are not. If someone could explain why these same length audio clips can return different length FFT's, that would be great!

它们的长度根本不一样。我敢打赌你们剪辑的样本编号并不完全相同。

y, sr = lb.load(audioArr[x]) 之后执行 print('sample count = {}'.format(len(y)))并且您很可能会看到不同的值(您自己也说过很多)。

正如您已经指出的那样,您当然可以简单地在 min(len(y)) 处截断信号,然后将其输入 FFT。但通常情况下,你要做的是使用 discrete STFT 来解决这个问题。 ,它有一个固定的窗口大小。这确保了 FFT 的相同长度输入大小。您可以使用 librosa's implementation作为一个简单的起点。该文档还解释了如何获得幅度/功率。

所以代替:

y, sr = lb.load(audioArr[x])
fourier = np.fft.fft(y)
fourier = fourier.real
fourierArr.append(fourier)

你这样做:

y, sr = lb.load(audioArr[x])
# get the magnitudes
D = np.abs(librosa.stft(y, n_fft=4096))  # use 4096 as window length
fourierArr.append(D[0])                  # only use the first frame of the STFT

本质上,如果你对不同长度的输入使用傅里叶变换,你会得到不同长度的输出,这是 LDA 不能原谅的,当使用这个输出作为训练数据时。所以你必须确保你的输入具有相同的长度。最简单的方法是使用 STFT(或简单地将所有输入剪切到 min)。 IMO,这没有什么不干净的,如果您缺少几个样本,它不会对结果产生太大影响。

关于python - 相同长度音频剪辑的不同 FFT 信号长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57265244/

相关文章:

python - 使用python将特殊值粘贴到另一个多个excel文件

python - 在有障碍物的迷宫中找到路径的数量

python - 登录 Behave BDD 框架

python - sklearn 中的 pca.inverse_transform

scikit-learn - 我应该如何在 Scikit-learn 中使用 RandomizedLogisticRegression?

python - 如何解决由FFT驱动的微分程序中的移位和缩放错误?

python - FFTW 向后变换乘以 N

python - 像 -h 一样对待可选参数

machine-learning - 解决文本分类监督学习中的同义词问题

python - 在 Python 中计算单位的 n 次根