假设您正在分析的信号是幅度为的正弦波:A
x=asin2πf0t
然后,它的幅度 RMS 值是:,正如您在代码中注意到的那样。在执行 DFT 之前,最好对信号进行窗口化,因为它可以减少泄漏等。a2–√
将此信号转换到频域后,您将获得一个双边频谱。然后我们必须取这些复数值的大小。可能你会注意到它们都非常高。那是因为能量没有标准化。标准化可以通过将幅度值除以窗口的能量来完成。由于人们倾向于“按原样”获取信号(这等于应用矩形窗口),因此频谱会除以样本数。对于不同类型的窗口,这个因子等于所有窗口样本的总和。N
此外,我们只对频谱的一半感兴趣,因此所有样本的幅度必须乘以以补偿能量损失,除了 DC 分量(仅出现一次)和 Nyquist bin(如果存在)。2
最后,当您要分析信号的 RMS 时,您必须了解以下内容。单面谱的所有值都是高度,等于,其中是第i 个频率分量的 RMS 幅度幅度。将其转换为您获得的 Python 代码:A2i2(Ai2–√)2Ai2–√
import numpy as np
import matplotlib.pyplot as plt
fs = 5e5 # Sampling frequency [Hz]
duration = 10 # Duration of the test signal [s]
N = int(fs * duration)
t = np.arange(N, dtype=float) / fs
f = 1000 # Frequency of the test signal [Hz]
sensitivity = 0.004 # Sensitivity of the microphone [mV/Pa]
p_ref = 2e-5 # Reference acoustic pressure [Pa]
amp = sensitivity * np.sqrt(2) # Amplitude of sinusoidal signal with RMS of 4 mV (94 dB SPL)
signal = amp * np.sin(2 * np.pi * f * duration * t) # Signal [V]
# Calculate the level from time domain signal
rms_time = np.sqrt(np.mean(signal**2))
db_time = 20 * np.log10(rms_time / sensitivity / p_ref)
# Apply window to the signal
win = np.hamming(N)
signal = signal * win
# Get the spectrum and shift it so that DC is in the middle
spectrum = np.fft.fftshift( np.fft.fft(signal) )
freq = np.fft.fftshift( np.fft.fftfreq(N, 1 / fs) )
# Take only the positive frequencies
spectrum = spectrum[N//2:]
freq = freq[N//2:]
# Since we just removed the energy in negative frequencies, account for that
spectrum *= 2
# If there is even number of samples, do not normalize the Nyquist bin
if N % 2 == 0:
spectrum[-1] /= 2
# Scale the magnitude of FFT by window energy
spectrum_mag = np.abs(spectrum) / np.sum(win)
# To obtain RMS values, divide by sqrt(2)
spectrum_rms = spectrum_mag / np.sqrt(2)
# Do not scale the DC component
spectrum_rms[0] *= np.sqrt(2) / 2
# Convert to decibel scale
spectrum_db = 20 * np.log10(spectrum_rms / sensitivity / p_ref)
# Compare the outputs
print("Difference in levels: {} dB".format(db_time - spectrum_db.max()))
plt.semilogx(freq, spectrum_db)
plt.xlim( (1, fs/2) )
plt.ylim( (0, 120) )
plt.grid('on')
plt.xlabel("Frequency [Hz]")
plt.ylabel("SPL [dB]")
plt.show()
电平差异:-1.4210854715202004e-14 dB
如您所见,这为时域和频域产生了一致的结果。祝你好运!