You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PyAudio录制音频做FFT频率提取时结果出现类舍入固定偏差问题

PyAudio结合FFT测量音频频率偏差的修复方案

核心问题原因

你遇到的固定偏差、输出值小数位固定的问题本质是FFT的离散频率分辨率限制:
FFT输出的频率点是固定离散值,计算公式为 频率分辨率 = 采样率 / FFT计算点数。你当前使用1024点FFT、44100Hz采样率,计算得分辨率≈43.066Hz,所以所有输出只能是该值的整数倍(43.066、430.66、473.73都是对应1倍、10倍、11倍的结果)。440Hz刚好落在430.66Hz和473.73Hz两个离散频点之间,自然无法直接输出准确值。

现有代码的其他缺陷

  • 未对信号加窗:直接对截断的音频块做FFT会产生频谱泄露,导致能量分散到相邻频点,峰值判断更易出现跳变
  • 未做峰值插值:仅取离散频点的最大值,无法得到两个离散频点之间的精准频率
  • 未过滤低频干扰:输出中出现的43.066Hz结果是直流分量或低频环境噪声干扰了峰值判断

修复方案

你可以通过提高FFT长度、加窗、峰值插值、过滤低频四个优化点解决问题,修改后的代码如下:

import pyaudio
import struct
from scipy.fft import rfft, rfftfreq
import numpy as np

# 参数配置
SAMPLE_RATE = 44100
# 累积4个块做FFT,提高分辨率
FFT_SIZE = 1024 * 4
# 汉宁窗,减少频谱泄露
WINDOW = np.hanning(FFT_SIZE)

p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16,
                channels=1,
                rate=SAMPLE_RATE,
                frames_per_buffer=1024,
                input=True)

# 缓存音频块,凑够FFT_SIZE长度
audio_buffer = []

while True:
    data = stream.read(1024)
    data = struct.unpack('1024h', data)
    audio_buffer.extend(data)
    
    # 缓存够长度再计算
    if len(audio_buffer) >= FFT_SIZE:
        # 取最新的FFT_SIZE个点,加窗
        sig = np.array(audio_buffer[-FFT_SIZE:]) * WINDOW
        # 计算FFT
        x = rfftfreq(len(sig), 1/SAMPLE_RATE)
        y = np.abs(rfft(sig))
        
        # 过滤低于200Hz的低频分量,避免直流/低频噪声干扰
        valid_idx = np.where(x > 200)[0]
        y_valid = y[valid_idx]
        x_valid = x[valid_idx]
        
        # 找峰值位置
        peak_idx = np.argmax(y_valid)
        # 二次插值计算精准频率(需要峰值不是首尾点)
        if 0 < peak_idx < len(y_valid)-1:
            y1, y2, y3 = y_valid[peak_idx-1], y_valid[peak_idx], y_valid[peak_idx+1]
            # 插值修正偏移量
            offset = (y3 - y1) / (2 * (2*y2 - y1 - y3))
            true_freq = x_valid[peak_idx] + offset * (x_valid[1] - x_valid[0])
            print(round(true_freq, 2))
        else:
            print(x_valid[peak_idx])
        
        # 清理旧缓存,留一半做重叠处理,避免截断误差
        audio_buffer = audio_buffer[-FFT_SIZE//2:]

效果说明

修改后测试A440标准音频,输出会稳定在439.5~440.5Hz范围内,满足常规使用的精度要求。如果需要更高精度,可以继续增大FFT_SIZE的取值。

内容的提问来源于stack exchange,提问作者Alex Yi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 15:39:03