我目前正在开发自己的音频库,并已实现了短时傅立叶变换(STFT)及其逆信号处理流水线的一部分。然而,我注意到STFT及其逆运算似乎导致了大量数据丢失,导致音频质量非常差。
首先,我将音频信号划分为重叠的帧,并且对于每一帧,我应用窗函数来减少频谱泄漏。然后,我对每一帧进行傅里叶变换,以获得频域表示。
然后,作为测试,我执行相反的操作以获取音频。我把这些结果绘制在下面,你可以看到退化。
以下是函数:
class AudioLib:
'''Library of audio processing functions.'''
def __init__(self, blocksize=1024 * 2):
self.blocksize = blocksize
self.window = np.hanning(blocksize)
def stft(self, audio):
'''Compute the short-time Fourier transform of the audio.'''
# Split the audio into overlapping blocks
num_blocks = len(audio) // self.blocksize
blocks = np.reshape(audio[:num_blocks * self.blocksize], (num_blocks, self.blocksize))
# Apply the windowing function to each block
windowed_blocks = blocks * self.window[np.newaxis, :]
# Compute the Fourier transform of each block
spectrum = np.fft.fft(windowed_blocks, axis=1)
return spectrum
def istft(self, spectrum):
'''Compute the inverse short-time Fourier transform of the spectrum.'''
# Compute the inverse Fourier transform of each block
windowed_blocks = np.fft.ifft(spectrum, axis=1).real
# Apply overlap-and-add to reconstruct the output signal
output = np.zeros(len(spectrum) * self.blocksize)
for i, block in enumerate(windowed_blocks):
output[i * self.blocksize : (i + 1) * self.blocksize] += block
return output
我已经尝试改变块的大小,虽然减少大小改善了音频有些,它仍然不完美,我觉得好像我的实现是不正确的。任何关于这方面的帮助将不胜感激!
1条答案
按热度按时间gzjq41n41#
正如Christoph拉克维茨所说,这种STFT实现的问题在于块是不重叠的。对于可逆性,您希望每个块与下一个块有50%的重叠。
这里是用于提取和重叠相加块的可能的简单实现:
如果你想更有效地完成这个任务,请查看numpy stride_tricks。
另一个细节:为了精确的可逆性,窗口应该是这样的,即添加50%重叠的翻译副本产生1.0。要做到这一点,
np.hanning
需要一个小的修正。将self.window = np.hanning(blocksize)
更改为此图显示
blocksize = 32
的差异。粗线是窗口的总和。请注意,对于np.hanning(blocksize)
,粗线是摆动的,但对于np.hanning(blocksize + 1)[:blocksize]
,粗线完全平坦,等于1.0。