如何使用 FFT 确定频率相关幅度

问题描述 投票:0回答:1

我正在尝试通过简单地生成输入信号并通过频率扫描测量输出来测量和计算音频设备的频率响应。

这是我试图用伪代码实现的目标:

for each frequency f in (10-20k):
    generate reference signal s with frequency f
    async play s and record result r
    determine amplitude a of r using FFT
    add tuple (f,a) to result

在Python中:

import numpy as np
from matplotlib import pyplot as plt
import sounddevice as sd
import wave
from math import log10, ceil
from scipy.fft import fft, rfft, rfftfreq, fftfreq

SAMPLE_RATE = 44100     # Hertz
DURATION = 3            # Seconds

def generate_sine_wave(freq, sample_rate, duration):
    x = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
    frequencies = x * freq
    y = np.sin((2 * np.pi) * frequencies)
    return x, y

def main():
    # info about our device
    print(sd.query_devices(device="Studio 24c"))

    # default device settings
    sd.default.device = 'Studio 24c'
    sd.default.samplerate = SAMPLE_RATE

    f_start = 10
    f_end = 20000
    samples_per_decade = 10
    ndecades = ceil(log10(f_end) - log10(f_start))
    npoints = ndecades * samples_per_decade
    freqs = np.logspace(log10(f_start), log10(f_end), num=npoints, endpoint=True, base=10)
    
    measure_duration = 0.25 # seconds
    peaks = []
    for f in freqs:
        _, y = generate_sine_wave(f, SAMPLE_RATE, measure_duration)
        rec = sd.playrec(y, SAMPLE_RATE, input_mapping=[2], output_mapping=[2])
        sd.wait()
        yf = np.fft.rfft(rec, axis=0)
        yf_abs = 1 / rec.size * np.abs(yf)
        xf = np.fft.rfftfreq(rec.size, d=1./SAMPLE_RATE)
        peaks.append(np.max(yf_abs))

    plt.xscale("log")
    plt.scatter(freqs,peaks)
    plt.grid()
    plt.show()

if __name__ == "__main__":
    main()

在测量实际设备之前,我只是将输出信号循环到音频接口的输入,以基本上“校准”我正在做的事情。我期望所有频率的幅度都相等。然而,这就是我得到的:

为什么生成的正弦波相同,但幅度却到处都是?在扫描测量阶段,我没有更改音频接口上的任何内容。

python numpy matplotlib fft
1个回答
0
投票

这些差异对我来说似乎相对较小(~1.0E-6 分钟,1.6E-6 最大)。在频率范围的上限,您也非常接近 22.05 kHz 的奈奎斯特频率,因此我想每个正弦波周期只有大约 2 个样本必然会导致傅立叶变换不准确。

我知道您正在寻找一个音频系统,其中 44.1 kHz 是常见的采样频率(例如 CD),但您可以尝试将采样频率提高到 500 kHz 作为测试,看看这是否可以提供更一致的速率。这会更痛苦,但您也可以尝试对每个频率的 n 个完整周期进行采样。 IE。对于 10 Hz,采样 1 秒以获得 10 个周期;对于 1000 Hz,采样 10 毫秒以获得 10 个周期。我认为这将有助于你的基频排列,这样你就只能得到傅立叶变换的虚部,这样你就可以进行更多的同类比较。否则,在许多情况下,您将在周期中削波正弦波并引入余弦分量。此外,由于您没有使用任何加窗,您将获得超出预期频率的频率分量。我知道你正在取绝对值,所以这不应该使不完美的正弦波周期计数成为问题,但也许只是在测试时尝试一下,看看为什么你没有得到像你期望的那样平坦的频率响应。

© www.soinside.com 2019 - 2024. All rights reserved.