将音频信号转换为时序频率与音量列表的最简实现方法
问题描述
我有一组音频信号数据,格式如下:
input = [0, 0.1, 0.5, 2, 3, 4, 2, 0, ...]
需要将其转换成随时间变化的频率列表与对应音量列表的结构,示例输出如下:
output = [..., [[50, 100, 325, 950, 4000, ...], [0.1, 0.9, 4, 2, 0.3, ...]], ...]
之前试过signal.spectrogram()方法,但它返回的是按时间周期计算的频率平均值,不符合需求——我要的是每个时间点上频率和音量的明确映射关系。
解决方案
要实现逐时间点的频率-音量映射,你可以用希尔伯特变换计算瞬时频率,这能直接得到每个采样点对应的瞬时频率,搭配原信号的幅值作为音量,完全满足你的需求。
具体步骤与代码实现
- 用希尔伯特变换生成解析信号,提取瞬时相位
- 对相位做解缠绕处理,避免相位跳变导致的频率计算错误
- 对解缠绕后的相位求导,得到瞬时频率(需按采样率换算成实际赫兹值)
- 原信号的幅值(或做dB转换、平方处理)作为对应时间点的音量
import numpy as np from scipy.signal import hilbert # 假设音频参数:采样率sr,输入信号x sr = 44100 # 示例采样率,根据你的实际数据调整 x = np.array([0, 0.1, 0.5, 2, 3, 4, 2, 0, ...]) # 计算解析信号 analytic_signal = hilbert(x) # 提取瞬时幅值(即音量) instantaneous_amplitude = np.abs(analytic_signal) # 提取瞬时相位并解缠绕 instantaneous_phase = np.unwrap(np.angle(analytic_signal)) # 计算瞬时频率(弧度/秒转赫兹) instantaneous_frequency = (np.diff(instantaneous_phase) / (2.0 * np.pi)) * sr # 处理diff后频率数组长度短1的问题,这里补全第一个值做对齐 aligned_frequency = np.concatenate([[instantaneous_frequency[0]], instantaneous_frequency]) # 生成目标输出结构 output = [[aligned_frequency.tolist(), instantaneous_amplitude.tolist()]]
补充说明
- 如果你的信号是多成分的(同时包含多个频率),希尔伯特变换只能提取主导频率,这种情况可以用**变分模态分解(VMD)或者经验模态分解(EMD)**先把信号分解成单成分IMF,再对每个IMF计算瞬时频率和幅值,最后合并成多频率-音量的映射。
- 瞬时频率对噪声比较敏感,如果信号有噪声,建议先做低通滤波处理。
内容的提问来源于stack exchange,提问作者Lerian Acosenossa
相关产品推荐
相关产品推荐

