4. 基于自适应滤波的时延估计

任务目标

本案例使用LMS自适应滤波器估计两路麦克风信号之间的相对时延。给定一路参考信号和一路延迟后的观测信号,通过自适应滤波器的权系数峰值位置确定时延值,并分析不同步长参数μ对收敛速度与稳态精度的影响。

实现原理

将参考信号x(n)经延迟后作为期望信号d(n),观测信号作为滤波器输入。LMS算法迭代更新长度为L的权向量w,使滤波输出y(n)逼近d(n)。当算法收敛后,权向量中最大值所在索引即为时延估计值(以采样点为单位)。步长μ越大收敛越快,但稳态失调增大;μ越小精度越高但收敛变慢。

完整代码

import numpy as np
import matplotlib.pyplot as plt

def generate_signals(true_delay, N, seed=42):
    """生成参考信号与延迟观测信号"""
    rng = np.random.default_rng(seed)
    x = rng.standard_normal(N)  # 参考信号(白噪声)
    d = np.zeros(N)
    if true_delay > 0:
        d[true_delay:] = x[:N - true_delay]  # 延迟后的期望信号
    else:
        d = x.copy()
    # 添加小幅噪声模拟实际采集
    d += 0.01 * rng.standard_normal(N)
    return x, d

def lms_delay_estimation(x, d, mu, filter_len, N):
    """LMS自适应时延估计,返回权系数历史与最终权向量"""
    w = np.zeros(filter_len)
    w_history = np.zeros((N, filter_len))
    for n in range(filter_len, N):
        x_block = x[n:n - filter_len:-1]  # 当前输入向量
        y = np.dot(w, x_block)
        e = d[n] - y
        w += 2 * mu * e * x_block
        w_history[n] = w
    return w, w_history

# 参数设置
true_delay = 20          # 真实时延(采样点)
N = 2000                 # 信号长度
filter_len = 64          # 滤波器长度(需大于最大时延)
mu_values = [0.001, 0.005, 0.01]  # 不同步长

# 生成信号
x, d = generate_signals(true_delay, N)

# 对不同步长进行估计
results = {}
for mu in mu_values:
    w_final, w_hist = lms_delay_estimation(x, d, mu, filter_len, N)
    est_delay = np.argmax(np.abs(w_final))
    results[mu] = {'w_final': w_final, 'w_hist': w_hist, 'est_delay': est_delay}
    print(f"μ={mu:.3f}: 估计时延={est_delay}点, 真实时延={true_delay}点")

# 绘制权系数收敛过程(以μ=0.005为例)
mu_plot = 0.005
w_hist = results[mu_plot]['w_hist']
peak_idx_over_time = np.argmax(np.abs(w_hist[filter_len:]), axis=1)

fig, axes = plt.subplots(2, 1, figsize=(10, 6))

# 上图:最终权系数
axes[0].stem(np.abs(results[mu_plot]['w_final']))
axes[0].set_title(f'最终权系数值 (μ={mu_plot})')
axes[0].set_xlabel('滤波器抽头索引')
axes[0].set_ylabel('|w|')
axes[0].axvline(true_delay, color='r', linestyle='--', label='真实时延')
axes[0].legend()

# 下图:峰值位置随迭代变化
axes[1].plot(peak_idx_over_time)
axes[1].axhline(true_delay, color='r', linestyle='--', label='真实时延')
axes[1].set_title('权系数峰值位置随迭代变化')
axes[1].set_xlabel('迭代次数')
axes[1].set_ylabel('峰值索引')
axes[1].set_ylim(0, filter_len)
axes[1].legend()

plt.tight_layout()
plt.savefig('delay_estimation_result.png', dpi=100)
plt.show()

运行方式

  1. 安装依赖:pip install numpy matplotlib
  2. 将代码保存为 lms_delay_est.py 并运行:python lms_delay_est.py

验证方法与判定标准

  • 时延估计正确性:程序输出的估计时延应等于真实时延20(或偏差不超过±1个采样点)。
  • 步长影响观察:运行后应看到μ=0.01时峰值位置最早稳定在20附近但波动较大;μ=0.001时收敛最慢但稳定后波动最小。
  • 可视化确认:生成的图中,最终权系数应在索引20处出现明显峰值;峰值位置曲线应最终收敛到20附近。

关键参数说明

  • 滤波器长度:需大于最大可能时延,本案例设为64,保证时延20在覆盖范围内。
  • 输入信号:使用白噪声作为参考信号,其平坦频谱保证各时延分量可辨识。
  • 收敛判据:权系数峰值位置在连续多次迭代中不再跳变,视为收敛。

常见问题

  • 估计时延始终为0:检查滤波器长度是否大于真实时延,或步长过大导致算法发散。
  • 收敛过慢:适当增大μ,但需保证μ < 1/λ_max(λ_max为输入相关矩阵最大特征值),白噪声场景下约需μ < 0.1。
  • 峰值不明显:增加信号长度N或降低观测噪声幅度。