【问题标题】:Different FFT signal lengths for same length audio clips相同长度音频剪辑的不同 FFT 信号长度
【发布时间】:2019-12-07 11:12:32
【问题描述】:

目前我正在开展一个项目,该项目需要我挑选音频片段并根据它们的 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: setting an array element with a sequence.

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

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

请注意,它们通常仅相差几个点,例如,对于 3 个音频剪辑,FFT 长度为 4410,但第 4 个为 4409。我知道我可能只是将长度修剪到最小长度组,但我更喜欢一种不会遗漏任何值的更简洁的方法。

【问题讨论】:

    标签: python scikit-learn fft audio-processing librosa


    【解决方案1】:

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

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

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

    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)。国际海事组织,这没有什么不干净的,如果您缺少几个样本,它不会对结果产生太大影响。

    【讨论】:

    • 感谢您澄清不同的音频长度以及如何解决这种情况。至于包括转换的虚部,您包含的代码是否这样做?然后我会训练音频剪辑的幅度/功率而不是 FFT 或 STFT 吗?还是实施 STFT 消除了虚数问题?抱歉,如果这个问题不清楚,我只是不明白在我将其切换到 STFT 后功率/幅度如何发挥作用。
    • 另一个问题/评论,当您加载音频时,n_fft=4096 是什么参数?我查看了 librosa.core.load 文档,找不到符合该标准的参数。
    • 我很抱歉。该参数应该进入stft 调用(docs)。我更新了代码示例。
    • 不用担心,感谢您的帮助/澄清!
    • D[0] 对应第一个窗口,即前 4096 个样本。 D[1] 对应于样本 1*hop_length1*hop_length+n_fft (hop_length=n_fft/2)。您也可以使用第二个值,事实上,如果它适合您,您可以计算每个 bin 的平均值(使用 np.mean 和右轴)或简单地将更多数据转储到 LDA 中。但是,前 4096 个样本中没有的任何内容都将被补零,因为您的信号很短,并且可能不会提高您想做的任何事情的质量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    • 2020-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多