🔥 🔥 🔥 背景:做某个项目(由于项目处于保密状态,只提供思路),需要求多帧的istft。但是手头只有单帧的istft代码(当然不能python代码,不然就直接调包)。
📣 问题1:torch.istft center=True和center=False的区别,通过选取center=False istft结果的[hop_length-1:n_fft+1]片段,就能和center=True istft结果的[:hop_length-1]片段对上。
📣 问题2:如何将两个单帧的torch.istft(out[:,0:1]和torch.istft(out[:,1:2])得到torch.istft(out[:,0:2])的结果。
👉问题1解答:
import torch
from matplotlib import pyplot as plt
x = torch.randn([1,254*4])
n_fft = 254
hop_length = 128
out = torch.stft(x,n_fft=n_fft,hop_length=hop_length,center=False,win_length=n_fft,window=torch.tensor(get_window(n_fft,0.5)), return_complex=True).squeeze()
out1 = torch.istft(out[:,0:1],n_fft=n_fft,center=False,hop_length=hop_length,win_length=n_fft,window=torch.hamming_window(window_length=n_fft, periodic=True), return_complex=False,length=n_fft)
out2 = torch.istft(out[:,0:1],n_fft=n_fft,center=True,hop_length=hop_length,win_length=n_fft,window=torch.hamming_window(window_length=n_fft, periodic=True), return_complex=False,length=n_fft)
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
plt.figure(figsize=(10,6))
plt.subplot(3,1,1)
plt.plot(out1,label="istft center=False")
plt.plot(out2,label="istft center=True")
plt.title("center=True和center=False的区别")
plt.legend()
plt.subplot(3,1,2)
plt.plot(out1,label="istft center=False")
plt.legend()
plt.subplot(3,1,3)
plt.plot(out2,label="istft center=True")
plt.legend()
plt.show()
plt.figure(figsize=(10,6))
plt.subplot(3,1,1)
plt.plot(out1[hop_length-1:n_fft+1],label="istft center=False")
plt.plot(out2[:hop_length-1],label="istft center=True")
plt.title("center=True和center=False的区别")
plt.legend()
plt.subplot(3,1,2)
plt.plot(out1[hop_length-1:n_fft+1],label="istft center=False")
plt.legend()
plt.subplot(3,1,3)
plt.plot(out2[:hop_length-1],label="istft center=True")
plt.legend()
plt.show()
👉问题2解答:
首先看一下torch.istft(out[:,0:1]),torch.istft(out[:,1:2])和torch.istft(out[:,0:2])的趋势图,通过两图发现两者是存在联系的,但是又不是1+1的关系,经过3天的不懈努力发现两个单帧的数据可以通过overlap重叠拼接在取片段得到。
torch.istft(out[:,0:1]),torch.istft(out[:,1:2])经过istft2overlap进行重叠拼接是能和torch.istft(out[:,0:2])对的上的,但是在使用随机数进行提取stft、istft,最终结果存在差异,本博客只提供个思路,具体还要结合业务去实践。
代码参考librosa.stft() 源码分析中的 istft函数
def istft2overlap(x1,x2,):
ifft_window = torch.hamming_window(window_length=n_fft, periodic=True).numpy()
n_frames = 2
expected_signal_len = n_fft + hop_length * (n_frames - 1)
y = np.zeros(expected_signal_len)
ifft_window_sum = np.zeros(expected_signal_len)
ifft_window_square = ifft_window * ifft_window
for i in range(n_frames):
sample = i * hop_length
if i==0:
y[sample:(sample + n_fft)] += x1
else:
y[sample:(sample + n_fft)] += x2
ifft_window_sum[sample:(sample + n_fft)] += ifft_window_square
# Normalize by sum of squared window # 1.1754944e-38
for i in range(expected_signal_len):
if ifft_window_sum[i] > 1.1754944e-38:
y[i] /= ifft_window_sum[i]
return y.tolist()
out33 = istft2overlap(out1.numpy(),out2.numpy())
plt.figure(figsize=(10,6))
plt.subplot(3,1,1)
plt.plot(out33[hop_length:n_fft],label="torch.istft(out[:,0:2])",color="r")
plt.plot(out3[hop_length:n_fft],label="torch.istft(out[:,0:1])和torch.istft(out[:,1:2]) istft2overlap",color="g")
plt.title("单帧torch.istft和多帧torch.istft的区别和联系")
plt.legend()
plt.subplot(3,1,2)
plt.plot(out33[hop_length:n_fft],label="torch.istft(out[:,0:2])",color="r")
plt.legend()
plt.subplot(3,1,3)
plt.plot(out3[hop_length:n_fft],label="torch.istft(out[:,0:1])和torch.istft(out[:,1:2]) istft2overlap",color="g")
plt.legend()
plt.show()