Python频谱图:识别音频信号中目标声音的起止时间点
音频频谱图的声音起止时间检测方案
需求说明
我正在绘制音频信号的频谱图,该图展示不同时间区间的频率信息。感兴趣区域已用红圈标记,这些时段麦克风记录到了未知频率的声音(当前暂不关注频率值)。希望找到方法,检测每个记录到的声音对应的起止时间(秒级)。
参考普通折线图的思路:初始阶段数值为0,约4秒后数值上升,可将第一个大于阈值的点作为起始点,最后一个后续值回落至阈值以下的点作为结束点,以此检测声音的时长。
当前实现代码
sampleRate = 44100 f, t, Sxx = signal.spectrogram(audio_original, sampleRate) plt.figure(1) plt.pcolormesh(t,f,Sxx,shading='gouraud') plt.ylabel('Frequency [Hz]') plt.xlabel('Time [sec]') plt.show()
数据维度说明
f、t、Sxx的长度分别为[129, 17072, 129],其中:
f:采样频率数组t:分段时间数组Sxx:音频的频谱图,默认最后一维对应分段时间
实现方案与代码
由于不关注具体频率,只需判断每个时间点是否存在有效声音,可先将频谱数据压缩为时间维度的能量序列,再通过阈值检测起止区间:
将频谱转换为时间维度的能量序列:
# 对每个时间点的所有频率能量求和,得到与t长度一致的一维数组 time_energy = Sxx.sum(axis=0) # 若声音集中在单一频率,也可用最大值替代求和 # time_energy = Sxx.max(axis=0)基于噪声段设置检测阈值:
# 假设前2秒为无声音的噪声基线,计算噪声平均能量 noise_mask = t < 2 noise_avg = time_energy[noise_mask].mean() # 设置阈值为噪声能量的2倍,可根据实际场景调整系数 threshold = noise_avg * 2检测声音事件的起止时间:
import numpy as np # 标记每个时间点是否超过阈值 above_threshold = time_energy > threshold # 通过差分找到连续超过阈值的区间索引 diff = np.diff(np.concatenate([[False], above_threshold, [False]])) event_indices = np.where(diff)[0].reshape(-1, 2) # 转换为实际秒级时间 event_times = [] for start_idx, end_idx in event_indices: start_time = t[start_idx] end_time = t[end_idx - 1] # end_idx是从有效到无效的切换点,对应最后一个有效时间点的下一位 event_times.append((start_time, end_time)) # 输出检测结果 for i, (start, end) in enumerate(event_times, 1): print(f"第{i}个声音事件:起始时间 {start:.2f} 秒,结束时间 {end:.2f} 秒")
注意事项
- 阈值是检测准确性的核心:若噪声波动大,可改用中位数计算噪声基线,或对
time_energy做滑动窗口平滑处理,减少误检 - 频谱图的时间分辨率由
spectrogram的nperseg参数决定,若需要更精确的时间,可结合原始音频波形的检测结果进行修正
内容的提问来源于stack exchange,提问作者Philipp
相关产品推荐
相关产品推荐

