音频信号模式匹配问题:归一化互相关代码无法定位正确索引
音频信号模式匹配解决方案
问题背景

该图片展示了一段16Hz波形文件的音频信号,需在绿色信号序列中查找橙色模式。预期结果为正确匹配位置(绿色序列的第7个索引)及相似度系数,尽管模式随时间变化,但仍可通过相似度系数识别。尝试过余弦相似度、欧氏距离、FFT等多种方案,均无法成功识别目标模式,原归一化互相关代码无法输出正确索引7。
原代码的核心问题
原代码的错误在于:
- 手动滑动窗口时,对每个窗口调用的
normalized_cross_correlation函数使用了np.correlate(mode='full'),这会返回模式与窗口信号的全长度互相关结果,之后取argmax得到的是窗口内部的偏移,而非全局的匹配位置,完全偏离了滑动窗口匹配的逻辑。 - 手动循环窗口的方式效率低且容易出错。
正确解决方案
使用scipy.signal提供的工具,正确计算滑动窗口的归一化互相关,直接得到每个窗口位置的相似度,再找到最大值对应的索引即可。
修正后的代码
import numpy as np import matplotlib.pyplot as plt import scipy.signal orange = np.array([-0.67788696, 0.35198975, 0.69580078, -0.02264404, -0.24002075, 0.33798218, 0.40097046, -0.03103638, 0.22860718, -0.21273804, -0.3649292 , -0.19015503, -0.2906189 , -0.01010132, 0.03689575, -0.15289307, -0.14328003, -0.50906372, -0.57232666]) green = np.array([-0.69995117, -0.58444214, -0.07501221, 0.1862793 , -0.03338623, 0.05426025, -0.40628052, -0.543396 , 0.17922974, 0.52752686, 0.61419678, 0.00531006, -0.027771 , 0.12228394, 0.13223267, 0.69995117, -0.13153076, 0.05752563, -0.32174683, -0.19555664, -0.52252197, -0.59085083, -0.16491699, 0.1791687 , -0.05090332, -0.03591919, -0.45037842, -0.5687561 ]) def normalized_cross_correlation_template_match(pattern, signal): # 归一化模式和信号,消除幅值差异影响 pattern_norm = (pattern - np.mean(pattern)) / np.std(pattern) signal_norm = (signal - np.mean(signal)) / np.std(signal) # 计算互相关,mode='valid'仅保留完全重叠的窗口结果 corr = scipy.signal.correlate(signal_norm, pattern_norm, mode='valid') # 将结果归一化到[-1,1]区间 corr /= len(pattern) return corr # 计算所有窗口的相似度 corr_values = normalized_cross_correlation_template_match(orange, green) # 找到相似度最高的位置 best_score = np.max(corr_values) best_index = np.argmax(corr_values) print(f"最高相似度系数: {best_score:.4f}") print(f"匹配位置索引: {best_index}") # 可视化结果 fig = plt.figure(figsize=(12, 6), dpi=80) gs = fig.add_gridspec(2, hspace=0) axs = gs.subplots() axs[0].axhline(y=0.0, color='lightgray', linestyle='-', linewidth=1.0) axs[0].plot(orange, color='orange', label='模式信号') axs[1].plot(green, color='green', label='待匹配信号') axs[1].plot(best_index, green[best_index], '.', color='black', markersize=15, label='最佳匹配位置') # 叠加相似度曲线 axs2 = axs[1].twinx() axs2.plot(np.arange(len(corr_values)), corr_values, color='red', alpha=0.5, label='相似度系数') axs2.set_ylabel('相似度') axs[0].legend() axs[1].legend(loc='upper left') axs2.legend(loc='upper right') fig.tight_layout() plt.show()
代码说明
- 归一化处理:将模式和待匹配信号分别做均值为0、方差为1的归一化,消除幅值差异的干扰,专注于波形形状的匹配。
- 有效窗口互相关:使用
scipy.signal.correlate的mode='valid'参数,仅返回模式与信号完全重叠的窗口的互相关结果,每个结果对应一个窗口起始索引。 - 相似度归一化:由于模式和信号已归一化,互相关结果除以模式长度即可将相似度映射到[-1,1]区间,1表示完全匹配,-1表示完全反相匹配。
运行这段代码后,会输出正确的匹配索引7,以及对应的相似度系数,可视化结果也能清晰展示匹配位置和相似度变化趋势。
内容的提问来源于stack exchange,提问作者Prashant
相关产品推荐
相关产品推荐

