WOLA(Weighted Overlap-Add)方法详解
在数字信号处理领域,信号的分析和重建是非常重要的任务。WOLA(Weighted Overlap-Add)是一种常用的技术,特别是在处理音频信号时。它通过将信号分成重叠的帧并对每一帧进行加窗处理,来实现信号的有效重建。
WOLA 方法概述
WOLA 方法的核心思想是将长信号分成多个短帧,并对每一帧应用窗函数。通过重叠相加这些帧,WOLA 能够有效地重建信号。该方法的主要步骤如下:
- 分帧: 将输入信号分成多个重叠的帧。
- 加窗: 对每一帧应用窗函数(如汉宁窗),以减少边缘效应。
- 重叠相加: 将处理后的帧重叠相加,重建完整信号。
首先将输入信号 x [ n ] x[n] x[n] 分成多个重叠的帧。假设信号的长度为 L L L,窗长度为 N N N,帧移为 H H H,则可以表示为:
x [ n ] = { x [ 0 ] , 0 ≤ n < L 0 , otherwise x[n] = \begin{cases}x[0], & 0 \leq n < L \\0, & \text{otherwise}\end{cases} x[n]={x[0],0,0≤n<Lotherwise
每一帧 x k [ n ] x_k[n] xk[n] 可以表示为:
x k [ n ] = x [ n − k H ] for n = 0 , 1 , … , N − 1 x_k[n] = x[n - kH] \quad \text{for } n = 0, 1, \ldots, N-1 xk[n]=x[n−kH]for n=0,1,…,N−1
其中 k k k是帧的索引, k = 0 , 1 , 2 , … , K k = 0, 1, 2, \ldots, K k=0,1,2,…,K, K K K是帧的总数。
对每一帧应用窗函数 ( w[n] ),通常使用汉宁窗或汉明窗。窗函数的定义为:
w [ n ] = 窗函数 ( n ) for n = 0 , 1 , … , N − 1 w[n] = \text{窗函数}(n) \quad \text{for } n = 0, 1, \ldots, N-1 w[n]=窗函数(n)for n=0,1,…,N−1
加窗后的帧 x k [ n ] x_k[n] xk[n] 可以表示为:
y k [ n ] = x k [ n ] ⋅ w [ n ] for n = 0 , 1 , … , N − 1 y_k[n] = x_k[n] \cdot w[n] \quad \text{for } n = 0, 1, \ldots, N-1 yk[n]=xk[n]⋅w[n]for n=0,1,…,N−1
重叠相加的公式可以表示为:
y [ n ] = ∑ k = 0 K y k [ n ] for n = 0 , 1 , … , L + N − 1 y[n] = \sum_{k=0}^{K} y_k[n] \quad \text{for } n = 0, 1, \ldots, L + N - 1 y[n]=k=0∑Kyk[n]for n=0,1,…,L+N−1
y [ n ] y[n] y[n] 是重建后的信号。由于帧之间的重叠,输出信号的幅度可能会增加,因此需要进行归一化处理。
在使用汉宁窗的情况下,最终的重建信号可以表示为:
Normalization Factor = N H × 2 \text{Normalization Factor} = \frac{N}{H \times 2} Normalization Factor=H×2N
N N N: 窗口长度(window_length
),表示每个帧的样本数。
H H H: 帧移(hop_size
),表示每次移动的样本数。
y [ n ] = 1 Normalization Factor ∑ k = 0 K y k [ n ] y[n] = \frac{1}{\text{Normalization Factor}} \sum_{k=0}^{K} y_k[n] y[n]=Normalization Factor1k=0∑Kyk[n]
Python 实现
下面是基于 WOLA 方法的 Python 实现示例。该示例生成一个随机信号,使用 WOLA 方法进行重建,并可视化原始信号、重建信号和分帧信号。
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import get_window# 生成随机信号
def generate_random_signal(duration, fs):num_samples = int(fs * duration)return np.random.randn(num_samples), np.linspace(0, duration, num_samples)# WOLA 实现
def wola(signal, window_length, hop_size):window = get_window('hann', window_length) # 使用汉宁窗num_frames = (len(signal) - window_length) // hop_size + 1output_length = hop_size * (num_frames - 1) + window_lengthoutput = np.zeros(output_length)# 计算归一化因子normalization_factor = window_length / (hop_size * 2)for k in range(num_frames):start = k * hop_sizeframe = signal[start:start + window_length] * window # 加窗output[start:start + window_length] += frame / normalization_factor # 重叠相加并归一化return output# 参数设置
fs = 16000 # 采样率
duration = 0.05 # 持续时间
window_length = 320 # 窗口长度
hop_size = 80 # 帧移# 生成随机信号
signal, t = generate_random_signal(duration, fs)# 1. 原始信号分帧加窗
window = get_window('hann', window_length)
num_frames = (len(signal) - window_length) // hop_size + 1
frames = np.array([signal[i * hop_size:i * hop_size + window_length] * window for i in range(num_frames)])# 4. 利用 WOLA 技术重建信号
wola_reconstructed_signal = wola(signal, window_length, hop_size)# 可视化原始信号和重建信号在一张大图中
plt.figure(figsize=(12, 8))# 原始信号
plt.subplot(2, 1, 1)
plt.plot(t, signal, label='Original Random Signal', color='blue')
plt.title('Original Random Signal')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.xlim(0, duration)
plt.grid()# 重建信号
plt.subplot(2, 1, 2)
plt.plot(np.linspace(0, duration, len(wola_reconstructed_signal)), wola_reconstructed_signal,label='Reconstructed Signal from WOLA', color='red')
plt.title('Reconstructed Signal from WOLA')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.xlim(0, duration)
plt.grid()plt.tight_layout()
plt.show()# 可视化分帧信号(每一帧单独子图)
plt.figure(figsize=(12, 8))
for i in range(num_frames):plt.subplot(num_frames, 1, i + 1) # 创建 num_frames 个子图plt.plot(np.linspace(i * hop_size / fs, (i * hop_size + window_length) / fs, window_length), frames[i],color='orange', alpha=0.5)plt.title(f'Windowed Frame {i + 1}')plt.xlabel('Time (s)')plt.ylabel('Amplitude')plt.xlim(0, duration) # 只显示原始信号的时间范围plt.grid()plt.tight_layout()
plt.show()
代码说明
- 生成随机信号: 使用
generate_random_signal
函数生成一个长度为 0.05 秒的随机信号,采样率为 16000 Hz。 - WOLA 实现:
wola
函数实现了 WOLA 方法,使用汉宁窗对信号进行加窗,并在重叠相加时进行归一化处理。 - 可视化: 原始信号和重建信号绘制在同一张图中,分帧信号在另一张图中,每一帧在单独的子图中显示。
- 归一化因子的计算逻辑
normalization_factor = window_length / (hop_size * 2)
在使用汉宁窗的情况下,重叠 2 次正好可以恢复原始信号幅度,如果重叠次数不为 2,需要计算归一化幅度。
上面重建的信号在首尾帧幅度降低。在实际操作中,为了消除加窗对信号首尾帧的影响,通常需要在信号的两端进行填充。这种填充可以确保在处理信号时,窗函数的边缘不会影响到信号的重建,特别是在信号的开始和结束部分。本文不赘述这部分,。