如何将匹配滤波输出信号归一化至与输入信号相同电平
预期实现目标
假设已获取图中所示的输入信号(原始数据),需要将其传入匹配滤波器,理想输出效果如图中滤波后数据所示:滤波后数据与原始数据处于同一电平量级。
实际实现情况
目前采用scipy.signal.lfilter()实现匹配滤波,核心实现代码如下:
# 模板函数 def template(t, a=1, tau=0.02, c=0, t0=0): return a * np.exp(-(t - t0) / tau) + c # 生成模板信号 t = np.arange(0, 0.05, 1e-4) signal = template(t) # 匹配滤波处理 # raw_without_dc:原始数据去除直流分量后的结果,实现方式为减去原始数据均值 mf = sp.lfilter(signal[::-1], 1, raw_without_dc)**2 # 绘制滤波结果 fig = plt.figure(figsize=(12, 5)) plt.plot(times/1e6, raw_data, alpha=0.5, label='原始数据') plt.plot(times[:-500]/1e6, mf[500:], color='r',label='滤波后数据') plt.xlim(0,60) plt.xlabel('时间 (s)') plt.legend()
代码运行后绘制的原始数据、滤波数据效果分别见对应配图:

待解决问题
是否存在规范通用的正式方法,可将匹配滤波后的输出信号归一化至与输入信号相同的电平量级?
解决方案
匹配滤波输出量级和输入不对齐,核心原因有两点:一是模板未做能量归一化,二是代码中额外增加的平方操作改变了量纲。规范的归一化处理流程如下:
- 对匹配模板做单位能量归一化
匹配滤波器的冲激响应是时间反转的模板信号,要保证和模板完全匹配、幅值为A的输入信号经过滤波后峰值等于A,必须先将模板的L2能量归一化到1:
signal = template(t) # 单位能量归一化 signal = signal / np.linalg.norm(signal)
- 修正平方操作带来的量纲偏移
代码末尾的**2属于包络提取步骤,会把原始的电压/幅值量纲转换为功率量纲,直接放大会导致量级不匹配,根据需求选择处理方式:
- 如果需要线性幅值输出:直接去掉平方操作,用归一化模板做滤波即可,输出峰值会直接对齐输入信号的幅值量级
- 如果需要包络输出:实信号可以对滤波结果取绝对值,复信号取模值即可得到和输入同量纲的包络;如果必须保留平方包络的形式,需要先做一次标定:输入一段和目标信号形状一致、幅值与原始数据典型目标幅值相等的标定信号,记录其经过滤波、平方后的峰值作为归一化因子,实际处理时将滤波平方后的结果除以该因子,再乘以标定信号的峰值,即可对齐量级。
注意代码中对滤波结果做500点切片的操作是正确的——lfilter是因果滤波,输出峰值会延迟一个模板长度的位置(当前模板长度刚好是500点),该操作不会引入幅值误差。
修正后的核心滤波代码参考:
# 生成并归一化模板 t = np.arange(0, 0.05, 1e-4) signal = template(t) signal = signal / np.linalg.norm(signal) # 线性输出(直接对齐输入量级) mf_linear = sp.lfilter(signal[::-1], 1, raw_without_dc) # 包络输出(同量级) mf_envelope = np.abs(mf_linear) # 若要使用平方包络,先做标定 # cal_amp = 1 # 替换为原始数据中目标信号的典型幅值 # cal_signal = template(t, a=cal_amp) # 生成同形状等幅值的标定信号 # cal_output = sp.lfilter(signal[::-1], 1, cal_signal) # cal_peak = np.max(cal_output**2) # mf_sq_envelope = np.sqrt( (mf_linear**2) / cal_peak * cal_amp**2 )
内容的提问来源于stack exchange,提问作者Inm
相关产品推荐
相关产品推荐

