Matlab Spectrogram函数问题:无法获取图中对应dB值
Matlab频谱图P矩阵与图中dB/Hz刻度不符的问题
问题描述
运行Matlab程序读取音频文件并显示功率谱图,需要获取指定时间和频率对应的dB/Hz值。目前图上能看到合理的x(频率)、y(时间)、z(dB/Hz)刻度值,但调用[S, F, T, P, Fc, Tc] = spectrogram(...)后,得到的P矩阵数值在0.0000至0.0002之间,和图中-80到-100的dB/Hz刻度不符,不清楚P的含义,也不知道如何获取对应图中刻度的矩阵。
原代码如下:
clicky = audioread('ChamberTesting_Feb13.wav'); %normalized quiet_n = audioread('quiet60_normalized.wav'); %normalized %spectrogram(clicky(:,1),1000,500,1000,Fs); %channel 1 spectrogram spectrogram(quiet_n(:,1),1000,500,1000,Fs); %channel 1 spectrogram view(90,90) %s = spectrogram(clicky(:,1),1000,500,1000,Fs); s = spectrogram(quiet_n(:,1),1000,500,1000,Fs); C = get(gca, 'children'); X = get(C, 'Xdata'); Y = get(C, 'Ydata'); Z = get(C, 'Zdata'); delta = 1; %change in time from peak diff = 10; differences_count = 0; for j = 1:5 for i = 1:40 num_init = Z(i,j) num_comp = Z(i, j+delta) if abs(num_init-num_comp)>diff & differences_count<10 differences_count = differences_count+1; end end end if(differences_count>5) disp("CLICKY!") end
解决方案
1. P矩阵的含义
spectrogram函数返回的P是线性刻度的功率谱密度(PSD),单位与输入信号幅值相关(你的音频是归一化到[-1,1]的,所以P的单位为1/Hz)。而绘图时Matlab会自动将线性PSD转换为对数刻度的dB/Hz值,转换公式为:
P_dB = 10 * log10(P);
你看到的0.00000.0002的线性值是显示精度问题,真实数值更小(比如1e-81e-10),转换后正好对应图中-80~-100的dB/Hz刻度。
2. 获取对应图中刻度的矩阵
直接对P进行dB转换即可得到与图中Z轴刻度一致的矩阵,为避免log10(0)的计算错误,可添加机器精度eps:
P_dB = 10 * log10(P + eps);
3. 优化后的代码
无需从图形对象中提取Zdata,直接用转换后的P_dB矩阵计算更可靠高效:
% 读取音频时同时获取采样率Fs [clicky, Fs] = audioread('ChamberTesting_Feb13.wav'); %normalized [quiet_n, Fs] = audioread('quiet60_normalized.wav'); %normalized % 绘制频谱图(可选,用于可视化) spectrogram(quiet_n(:,1),1000,500,1000,Fs); view(90,90) % 获取线性PSD及对应频率、时间轴 [S, F, T, P] = spectrogram(quiet_n(:,1),1000,500,1000,Fs); % 转换为dB/Hz刻度,添加eps避免计算错误 P_dB = 10 * log10(P + eps); delta = 1; % 时间步长 diff = 10; % dB差值阈值 differences_count = 0; % 循环时避免索引越界,P_dB的行对应频率,列对应时间 time_len = size(P_dB, 2); for j = 1:(time_len - delta) for i = 1:size(P_dB, 1) num_init = P_dB(i,j); num_comp = P_dB(i, j+delta); if abs(num_init - num_comp) > diff && differences_count < 10 differences_count = differences_count + 1; end end end if differences_count > 5 disp("CLICKY!") end
补充说明
你之前通过get(gca, 'children')获取的Zdata是已经转换后的dB值,但这种方式依赖图形对象结构,不如直接计算P_dB稳定。另外,P矩阵维度为[频率点数, 时间帧数],对应图中的X(频率)和Y(时间)轴,循环时需注意索引对应关系。
内容的提问来源于stack exchange,提问作者jukebox41188
相关产品推荐
相关产品推荐

