如何使用numpy.fft.fft从100个样本中提取LFO信号频率?
从100个音频样本中提取7Hz LFO频率的NumPy实现方案
核心前提说明
100个样本对应的时长约为 100/11025 ≈ 0.009秒,而7Hz信号的周期约为 1/7 ≈ 0.14秒,样本量不足以覆盖一个完整的LFO周期。直接使用FFT会因频率分辨率不足(11025/100 = 110.25Hz,远大于7Hz)无法精准检测,因此自相关法是更可靠的选择。
步骤1:样本数据预处理
将原始16位有符号样本转换为NumPy数组,并归一化到[-1, 1]范围,避免数值运算溢出:
import numpy as np # 假设samples是包含100个16位有符号整数的输入列表 samples = [你的样本数据] # 转换为16位有符号数组 x = np.array(samples, dtype=np.int16) # 归一化到[-1, 1] x_normalized = x / 32768.0
步骤2:计算自相关函数
自相关函数能捕捉信号的重复周期特征,通过计算信号与自身延迟版本的相关性,找到周期对应的延迟样本数:
# 计算完整自相关序列 autocorr = np.correlate(x_normalized, x_normalized, mode='full') # 截取正延迟部分(自相关的后半段) autocorr = autocorr[len(autocorr)//2:]
步骤3:定位周期峰值并计算频率
自相关序列中,跳过延迟为0的峰值(自身相关性最强),第一个有效峰值对应的延迟样本数即为LFO的周期长度,进而计算频率:
# 寻找自相关序列的峰值点(二阶导数由正转负的位置) peak_indices = np.where(np.diff(np.sign(np.diff(autocorr))) == -2)[0] + 1 if len(peak_indices) == 0: print("未检测到有效LFO周期,可能样本量不足或信号被干扰") else: # 取第一个有效峰值对应的周期样本数 period_samples = peak_indices[0] # 频率 = 采样率 / 周期样本数 detected_frequency = 11025 / period_samples # 四舍五入到整数,匹配目标7Hz detected_frequency_rounded = round(detected_frequency) print(f"检测到的LFO频率:{detected_frequency_rounded}Hz")
补充:FFT方法的局限性与尝试
若必须使用FFT,可通过零填充提高频率分辨率,但在样本不足一个周期时误差较大:
# 零填充到1024点,提升频率分辨率 n_fft = 1024 fft_vals = np.fft.fft(x_normalized, n=n_fft) fft_amps = np.abs(fft_vals) # 生成频率轴 freq_axis = np.fft.fftfreq(n_fft, 1/11025) # 筛选正频率部分 positive_mask = freq_axis >= 0 freq_pos = freq_axis[positive_mask] amps_pos = fft_amps[positive_mask] # 找到幅度最大的频率点 max_amp_idx = np.argmax(amps_pos) detected_freq_fft = freq_pos[max_amp_idx] print(f"FFT检测频率(近似):{round(detected_freq_fft)}Hz")
内容的提问来源于stack exchange,提问作者coderodde
相关产品推荐
相关产品推荐

