Librosa stft + istft - 了解我在不同窗口长度下的输出(看起来总是太完美)

信息处理 Python 窗函数 stft 音乐 优化
2022-02-13 18:44:13

我刚刚开始将 Python 与 Librosa 一起用于我将从事的 DSP 项目。我一直在尝试做的第一件事是确定 FFT 窗口大小和跳跃距离的首选参数。

领域是音乐,我的计划是尝试各种窗口大小和跳跃距离的值,对它们中的每一个,执行正向 STFT,然后执行反向 STFT,并将结果写回 wav 文件。然后,我将听取结果并根据我认为在输入中捕获信息的最佳值进行选择。

我的简单代码如下:

import librosa.core as lc
import numpy as np
import scipy

_n_fft=80
print(str(_n_fft))
_hop_length=_n_fft/4

data, sampleRate = lc.load("13_Hate_To_See_Your_Heart_Break.wav", sr=44100, duration=20, mono=True)

stftMat = lc.stft(data, n_fft=_n_fft, hop_length=_hop_length, center=True)
iStftMat = lc.istft(stftMat, hop_length=_hop_length)

scipy.io.wavfile.write("testOut.wav", 44100, iStftMat)

powerMat = np.abs(stftMat)
print("powerMat shape = " + str(powerMat.shape))

然而,我正在经历的行为并不是我所期望的。

当我使用非常短的窗口长度时(如上面的代码中所示) - 我的 FFT 长度和跳跃距离得到了正确数量的窗口帧:

powerMat shape = (41, 44101)

44101 窗口是有道理的,正如您所见,频率分辨率很低,只有 41 个频段。我希望得到的 testOut.wav 听起来很糟糕,因为频率分辨率太低了。当频率变化的细微之处被涂抹在一起时,我可以明显地看到对渲染频谱图的影响。然而,回想起来,生成的音轨听起来很棒——很像原始输入。

将此与更宽的窗口大小 44100 进行比较(1 个窗口 = 1 秒的音频,跳跃距离为 1/4*窗口大小):

powerMat shape = (22051, 81)

同样,这个输出是有意义的——在 20 秒的音频中,窗口长度为 1 秒,跳跃距离为 1/4 秒,大约有 80 个窗口帧。这是相当差的时间分辨率,但具有 22051 个频率箱的频率分辨率相当高。我再次希望得到的 testOut.wav 在时域中听起来很差。

生成的音轨再一次听起来很棒——很像原始输入。这些极值,以及介于两者之间的所有值,几乎都会产生相同的输出 testOut.wav,即使在实际功率谱上我可以在更改参数时明显看到差异。

我对 STFT 是否存在根本性的误解,并且是相反的?我只是不了解图书馆吗?

3个回答

由于可见频率分辨率差或可见时间分辨率差,您认为丢失的信息实际上仍包含在 FFT 序列中,但不是以易于可视化的形式,尤其是仅通过显示 FFT 幅度或频谱图时。那是因为信息被“隐藏”在 FFT 阶段结果中。

在短 FFT 窗口序列的情况下,一些频率分辨率信息表示为相邻或重叠窗口之间的相位差。在长 FFT 窗口的情况下,大部分时间局部性信息以绝对相位和附近 FFT 结果箱组内的相位差表示。这些在 FFT 幅度图或频谱图中都看不到;FFT 相位和相位增量图很难阅读。

但完全复数IFFT确实利用复数FFT结果的实部和虚部所包含的相位信息,因此可以准确、完整地再现时间和频率信息。

该相位信息可用于某些形式的 FFT 分析,以恢复一些“缺失”的分辨率。例如,相位声码器算法通过查看相邻或重叠 FFT 窗口之间的相位增量来推断或使用更高的频率分辨率。FT 的时移属性显示了当事件(AM 或“拍”调制等)旋转到 DFT 窗口内的不同位置时,DFT 结果箱之间的相位如何相对于彼此旋转。

您描述的行为是完全正常的。实际上,如果您首先计算时域信号的短期离散傅里叶 (STDFT) 变换,然后计算逆变换,则输出信号应该输入信号相同,而不仅仅是“几乎”相同。与块长度无关,时域信号的 STDFT 是一个完整的、可逆的表示,包含返回时域并获得原始信号所需的所有信息。

所以 - 回答你的两个问题 - 似乎对短期离散傅里叶变换及其逆工作的方式存在根本性的误解。您从librosa库中获得的输出非常好。

我建议您收集一些有关短期离散傅里叶变换的信息。也许采取逐步方法是个好主意:

  1. 阅读离散傅里叶变换,它是 STDFT 的基本构建块
  2. 阅读(加权)重叠相加(WOLA)方法
  3. 将两者结合以获得 STDFT

但是,您观察到 STDFT 域中表示的属性会因块长度和跳数大小而异,这是正确的。通常,当目标是在变换域中进行分析或处理时,选择这些参数是为了在时间频率分辨率之间获得令人满意的折衷。如果 STDFT 域中的值被某种处理算法修改,则行为通常会根据 STDFT 参数的特定选择而改变。然后,通过逆变换获得的时域信号也间接地依赖于这些参数值。

STFT 是属于时频变换的大型系列线性、冗余、可逆变换的一个实例。它们可以用冗余重叠滤波器组来表示(正向和逆变换) 。

对于经典的正交变换,通常只有一个逆变换。通过可逆冗余变换,将原始N信号样本M>N(复)系数,以这样一种方式,几个逆是可能的。

在最经典的版本中,对于特定的窗口类型,完美的反演被固定在几个跳跃距离上。