rms归一化_将FFT频谱幅度归一化为0dB

本文介绍了如何使用Python的scipy库来实现RMS归一化的FFT频谱分析,参照Audacity的Welch算法进行信号处理。通过设置合适的参数,如窗口大小、重叠和窗函数类型,计算并显示功率谱密度。归一化过程包括将最大振幅的正弦波作为参考,设置0dB,并将低于-90dB的频谱忽略不计。
部署运行你感兴趣的模型镜像

在对Audacity做了一些逆向工程后,这里给出了一些答案。首先,他们使用Welch algorithm来估计PSD。简而言之,它将信号分割成重叠段,应用一些窗口函数,应用FFT并对结果进行平均。主要是因为这有助于在存在噪声时获得更好的结果。总之,在提取了必要的参数后,这里的解决方案近似于Audacity的光谱图:import numpy as np

from scipy.io import wavfile

from scipy import signal

from matplotlib import pyplot as plt

segment_size = 512

fs, x = wavfile.read('sine3k6k.wav')

x = x / 32768.0 # scale signal to [-1.0 .. 1.0]

noverlap = segment_size / 2

f, Pxx = signal.welch(x, # signal

fs=fs, # sample rate

nperseg=segment_size, # segment size

window='hanning', # window type to use

nfft=segment_size, # num. of samples in FFT

detrend=False, # remove DC part

scaling='spectrum', # return power spectrum [V^2]

noverlap=noverlap) # overlap between segments

# set 0 dB to energy of sine wave with maximum amplitude

ref = (1/np.sqrt(2)**2) # simply 0.5 ;)

p = 10 * np.log10(Pxx/ref)

fill_to = -150 * (np.ones_like(p)) # anything below -150dB is irrelevant

plt.fill_between(f, p, fill_to )

plt.xlim([f[2], f[-1]])

plt.ylim([-90, 6])

# plt.xscale('log') # uncomment if you want log scale on x-axis

plt.xlabel('f, Hz')

plt.ylabel('Power spectrum, dB')

plt.grid(True)

plt.show()

有关参数的一些必要说明:波形文件读取为16位PCM,为了与Audacity兼容,应将其缩放为| A |<1.0

segment_size对应于Audacity的GUI中的Size。在

默认窗口类型为“Hanning”,如果需要,可以更改它。在

重叠是segment_size/2,就像在Audacity代码中一样。在

输出窗口被框住以遵循Audacity样式。他们扔掉第一个低频仓,把所有的东西都降低到-90分贝以下

What's physical meaning of the amplitude in the second picture?

它基本上是频率仓中的能量量。在How to normalize the amplitude to 0dB like the one in Audacity?

你需要选择一些参考点。以分贝为单位的图表总是与某些事物相关。当你选择最大能量箱作为参考,你的0db点就是最大能量(显然)。可以将最大振幅的正弦波设定为参考能量。请参见ref变量。正弦信号中的功率是RMS的平方,要得到RMS,只需将振幅除以sqrt(2)。所以比例因子是0.5。请注意,log10之前的系数是10而不是20,这是因为我们处理的是信号的功率而不是振幅。在Can I treat the amplitude below -90dB so low that it can be ignored?

是的,低于-40dB的东西通常被认为是可以忽略的

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

def analyze_wav(file_path, freq_max, Des_freq, Des_Freq_Width): """# 读取WAV文件 采样率和数据""" sample_rate, data = wav.read(file_path) """# 如果是多通道,取其中个通道(例如立体声转单声道)""" if len(data.shape) > 1: data = data[:, 0] maxVoiceV = 32767.0 if 8 == data.dtype: maxVoiceV = 127.0 else: if 16 == data.dtype: maxVoiceV = 32767.0 else: if 24 == data.dtype: maxVoiceV = 8388607.0 else: if 32 == data.dtype: maxVoiceV = 2147483647.0 """# 应用汉宁窗,减少频谱泄露""" window = np.hanning(len(data)) data_window = data * window """# 执行傅里叶变换(频谱)""" spectrum = np.fft.fft(data_window) frequencies = np.fft.fftfreq(len(data), d=1 / sample_rate) """# 只保留正频率部分(频谱是对称的)""" positive_frequencies = frequencies[:len(frequencies) // 2] positive_spectrum = spectrum[:len(data) // 2] """只取范围内""" min_idx = np.searchsorted(positive_frequencies, 50) max_idx = np.searchsorted(positive_frequencies, freq_max + 100) positive_frequencies = positive_frequencies[range(int(min_idx), int(max_idx))] positive_spectrum = positive_spectrum[range(int(min_idx), int(max_idx))] """# 计算幅度并转换为分贝(dB)""" magnitude = np.abs(positive_spectrum) """归一化幅值""" DataNum = (len(data) / 2) normalMag = magnitude / DataNum normalMag[0] /= 2 dB_values = 10 * np.log10(normalMag / maxVoiceV) """# 获取波峰F0大小 并获取其对应的频率""" max_db = compute_max(dB_values) max_db_idx = np.argmax(dB_values) max_freq = positive_frequencies[max_db_idx] """# 获取二次谐波响度 >=-25dB""" shg_freq = max_freq * 2 shg_dB = get_dB_at_freq(shg_freq, positive_frequencies, dB_values) """# 获取F0波谷的值""" right_valley_db, is_pass = get_right_valley(dB_values, max_db, max_db_idx) if not is_pass: right_valley_db = 0 """# 计算每个目标频域及谐波以内范围的RMS值""" in_rms_index = [] in_db_values = [] in_rms_values = [] freq = Des_freq while freq < freq_max: """# 当前起始""" freq_rangeS = freq - Des_Freq_Width freq_rangeE = freq + Des_Freq_Width """# 找到频率范围对应的索引""" start_idx = np.searchsorted(positive_frequencies, freq_rangeS) end_idx = np.searchsorted(positive_frequencies, freq_rangeE) dB_range = dB_values[start_idx:end_idx] in_db_values.append(compute_max(dB_range)) """# 计算该频域范围内的RMS值""" rms = compute_rms(dB_range) in_rms_index.append((freq_rangeS, freq_rangeE)) in_rms_values.append(rms) freq += Des_freq """# 计算每个目标频域及谐波以外范围的RMS值""" out_rms_index = [] out_rms_values = [] freq = 80 while freq < freq_max: """# 当前起始""" freq_rangeS = freq freq_rangeE = (freq // Des_freq + 1) * Des_freq - Des_Freq_Width; """# 找到频率范围对应的索引""" start_idx = np.searchsorted(positive_frequencies, freq_rangeS) end_idx = np.searchsorted(positive_frequencies, freq_rangeE) dB_range = dB_values[start_idx:end_idx] """# 计算该频域范围内的RMS值""" rms = compute_rms(dB_range) out_rms_index.append((freq_rangeS, freq_rangeE)) out_rms_values.append(rms) freq = (freq // Des_freq + 1) * Des_freq + Des_Freq_Width print(f"db最大值为:{max_db} 分贝最大值对应频率为:{max_freq}") print(f"二次谐波频率 {shg_freq} Hz 对应的dB值: {shg_dB:.2f} dB") # print(f"二次谐波频率 {shg_freq} Hz 对应的dB值: {shg_dB:.2f} dB") return positive_frequencies, dB_values, in_rms_index, in_rms_values, in_db_values, out_rms_index, out_rms_values, max_db, max_freq, shg_freq, shg_dB, right_valley_db 目前这个代码和专业的Audacity解析后最大的db值相差-1db,请你在这个代码的基础上优化,不要改变代码的原有返回参数。请给出可靠的改变后的代码。
最新发布
08-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值