在 3D 频谱图中正确找到 MATLAB 中的峰值

Properly finding peaks in MATLAB in 3D spectrogram

我正在尝试对一首歌进行频谱图分析。目前我有大约 10 秒的歌曲片段,我正在尝试找到局部峰值。

我真正想要的是有一个散点图显示一些 NxN 邻域值的振幅内的局部最大值

[y,fs] = audioread('audio_file.wav');
window = hamming(512);
num_overlap = 256;
nfft = 1024;
[S,F,T,P] = spectrogram(y(:,1), window, num_overlap, nfft, fs, 'yaxis');
surf(T,F,10*log10(P), 'edgecolor', 'none'); axis tight; view(0, 90); colormap hot;

结果如下图:

其中x轴当然是时间[0,~10],y轴是频率[0,22.5 KHz],z轴是振幅

现在我想做的是在这个海浪上创建一个 3D 散点图以显示峰值的位置。 S、F、T、P的维度是
S: 513 x 1770 complex double
F: 513 x 1 double
T: 1 x 1770 double
P: 513 x 1770 double

现在这是我很确定我做错了什么或者没有完全理解 MATLAB 的地方。

msk = true(3,3,3);
msk(2,2,2) = false;
dil = imdilate(10*log10(P), msk);
M = 10*log10(P) > dil;

我的理解是 1 无论我的本地峰值在哪里

现在我们只说 amp = 10*log10(P),我希望能够像调用 surf 一样调用 scatter3,如下所示:

scatter3(T, F, amp(M))

但我当然得到 X, Y and Z must be vectors of the same length. 我想这对我来说很有意义,所以我决定重复这些值,因为它们需要重复多次以使轴相等。

Tr = repelem(T, 513)';
Fr = repelem(F, 1770);
Zr = reshape(amp, [908010, 1]);
[pks, locs] = findpeaks(Zr);
scatter3(Tr(locs), Fr(locs), Zr(locs));

这会产生如下所示的 3D 散点图:

这绝对是不对的,因为在整个显示的振幅中应该有许多局部峰值。我不太确定我做错了什么,但我也几乎肯定有一种更简单的方法可以实现我想要的。我真正想要的是有一个散点图显示一些 NxN 邻域值的振幅内的局部最大值

如果我理解你想要的,你有一个带有局部峰值的矩阵 M 并且你想在峰值的位置绘制散点图。您可以使用 find 获得每个峰的 row\col 并使用 sub2ind:

获得线性索引
[Fi,Ti] = find(10*log10(P) > dil);
Pi = sub2ind(size(P),Fi,Ti);

scatter3(T(Ti),F(Fi),amp(Pi));