如何从 MATLAB 中的自相关数据中提取峰值?

发布于 2024-09-14 09:47:45 字数 1841 浏览 11 评论 0原文

我有关于音轨的信息(20,000 帧数据),我使用它自动关联:

[r,lags] = xcorr(XX,XX,'biased');

它看起来像这样:

替代文字

希望到目前为止一切顺利。理想情况下,我希望能够获取与第二个峰值的最高部分相对应的帧号。我已经阅读并尝试了很多不同的方法,但我似乎无法让它为我检索信息。

有人能够阐明我必须做什么吗?

非常感谢!


编辑1: 我尝试过使用 findpeaks,但它似乎对我不起作用。我不确定这是否是因为我使用了错误的数据。

edit2:我目前正在测试一种仅在该音轨上使用的方法,但很快我想扩展它,以便我可以在整个文件目录上执行此方法,所以我需要一个可以检测峰值而不是自己查找信息的脚本。

edit3:我的.M文件:

[y, fs, nb] = wavread('Three.wav');                 %# Load the signal into variable y

frameWidth = 441;                                   %# 10ms
numSamples = length(y);                             %# Number of samples in y
numFrames = floor(numSamples/frameWidth);           %# Number of full frames in y
energy = zeros(1,numFrames);                        %# Initialize energy
startSample = zeros(1,numFrames);                   %# Initialize start indices
endSample = zeros(1,numFrames);                     %# Initialize end indices

for frame = 1:numFrames                             %# Loop over frames
  startSample(frame) = (frame-1)*frameWidth+1;      %# Starting index of frame
  endSample(frame) = frame*frameWidth;              %# Ending index of frame
  frameIndex = startSample(frame):endSample(frame); %# Indices of frame samples
  energy(frame) = sum(y(frameIndex).^2);            %# Calculate frame energy
end                                                 %# End loop

XX = filtfilt(ones(1,10)/10, 1, energy);            %# Smooths signal

[r,lags] = xcorr(XX,XX,'biased');                   %# Auto-correlates the data
plot(lags,r), xlabel('lag'), ylabel('xcorr')        %# Plots data

I have information (20,000 frames of data) about an audio track that I have auto-correlated using:

[r,lags] = xcorr(XX,XX,'biased');

And it looks like this:

alt text

Which hopefully is so far so good. Ideally I would like to be able to take the frame number that corresponds to the highest part of the second peak. I've read around and tried a load of different methods but I just can't seem to get it to retrieve the information for me.

Would anybody be able to shed some light on what I have to do?

Many thanks!


edit1:
I have tried using findpeaks, but it doesn't seem to work for me. I'm not sure if that's because I'm using the wrong data or not.

edit2: I'm currently testing a method to use on just this audio track, but soon I want to expand it so that I can perform this method on a whole directory of files, so I kind of need a script that can detect peaks rather than finding the information myself.

edit3: My .M file:

[y, fs, nb] = wavread('Three.wav');                 %# Load the signal into variable y

frameWidth = 441;                                   %# 10ms
numSamples = length(y);                             %# Number of samples in y
numFrames = floor(numSamples/frameWidth);           %# Number of full frames in y
energy = zeros(1,numFrames);                        %# Initialize energy
startSample = zeros(1,numFrames);                   %# Initialize start indices
endSample = zeros(1,numFrames);                     %# Initialize end indices

for frame = 1:numFrames                             %# Loop over frames
  startSample(frame) = (frame-1)*frameWidth+1;      %# Starting index of frame
  endSample(frame) = frame*frameWidth;              %# Ending index of frame
  frameIndex = startSample(frame):endSample(frame); %# Indices of frame samples
  energy(frame) = sum(y(frameIndex).^2);            %# Calculate frame energy
end                                                 %# End loop

XX = filtfilt(ones(1,10)/10, 1, energy);            %# Smooths signal

[r,lags] = xcorr(XX,XX,'biased');                   %# Auto-correlates the data
plot(lags,r), xlabel('lag'), ylabel('xcorr')        %# Plots data

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

离鸿 2024-09-21 09:47:45

编辑

%# load the signal
[y, fs, nb] = wavread('Three.wav');
y = mean(y,2);                               %# stereo, take avrg of 2 channels

%# Calculate frame energy
fWidth = round(fs*10e-3);                    %# 10ms
numFrames = floor(length(y)/fWidth);
energy = zeros(1,numFrames);
for f=1:numFrames
  energy(f) = sum( y((f-1)*fWidth+1:f*fWidth).^2 );
end

%# smooth the signal (moving average with window size = 1% * length of data)
WINDOW_SIZE = round(length(energy) * 0.01);  %# 200
XX = filtfilt(ones(1,WINDOW_SIZE)/WINDOW_SIZE, 1, energy);

%# auto-correlation
[r,lags] = xcorr(XX, 'biased');

%# find extrema points
dr = diff(r);
eIdx = find(dr(1:end-1) .* dr(2:end) <= 0) + 1;

[~,loc] = sort(r(eIdx), 'descend');
loc = loc(1:min(3,end));                     %# take the highest 3 values

%# plot
plot(lags,r), hold on
plot(lags(eIdx), r(eIdx), 'g*')
plot(lags(eIdx(loc)), r(eIdx(loc)), 'ro')
hold off, xlabel('lag'), ylabel('xcorr')

alt text

以及与标记峰值相对应的滞后值:

>> lags( eIdx(loc) )
ans =
           0       -6316        6316

请注意,我们平滑了在计算自相关函数的导数之前计算信号,以便找到极值点

EDIT:

%# load the signal
[y, fs, nb] = wavread('Three.wav');
y = mean(y,2);                               %# stereo, take avrg of 2 channels

%# Calculate frame energy
fWidth = round(fs*10e-3);                    %# 10ms
numFrames = floor(length(y)/fWidth);
energy = zeros(1,numFrames);
for f=1:numFrames
  energy(f) = sum( y((f-1)*fWidth+1:f*fWidth).^2 );
end

%# smooth the signal (moving average with window size = 1% * length of data)
WINDOW_SIZE = round(length(energy) * 0.01);  %# 200
XX = filtfilt(ones(1,WINDOW_SIZE)/WINDOW_SIZE, 1, energy);

%# auto-correlation
[r,lags] = xcorr(XX, 'biased');

%# find extrema points
dr = diff(r);
eIdx = find(dr(1:end-1) .* dr(2:end) <= 0) + 1;

[~,loc] = sort(r(eIdx), 'descend');
loc = loc(1:min(3,end));                     %# take the highest 3 values

%# plot
plot(lags,r), hold on
plot(lags(eIdx), r(eIdx), 'g*')
plot(lags(eIdx(loc)), r(eIdx(loc)), 'ro')
hold off, xlabel('lag'), ylabel('xcorr')

alt text

and the lag values corresponding to the marked peaks:

>> lags( eIdx(loc) )
ans =
           0       -6316        6316

Note that we smoothed the signal prior to computing the derivative of the autocorrelation function in order to find the extrema points

烂人 2024-09-21 09:47:45
  1. 使用低通滤波器平滑数据(或对每个样本与多个周围样本进行平均)。
  2. 通过寻找最高样本值来找到中心的峰值。
  3. 通过搜索比其前一个值更高的第一个样本,找到峰值右侧的谷值。
  4. 通过搜索比其前一个值更小的第一个样本,找到谷右侧的峰值。
  1. Smooth the data using a lowpass filter (or average each sample with a number of surrounding samples).
  2. Find the peak in the center by looking for the highest sample value.
  3. find the valley to the right of the peak by searching for the first sample that has a higher value than its predecessor.
  4. Find the peak to the right of the valley by searching for the first sample to a smaller value than its predecessor.
合久必婚 2024-09-21 09:47:45

如果您有信号处理工具箱,我认为 findpeaks 函数应该可以为您完成这项工作。

类似于:

th = x //(some value that will overlook noise in the data. See the documentation)
[peaks locs] = findpeaks(a,'threshold',th)

http://www.mathworks.com/access /helpdesk/help/toolbox/signal/findpeaks.html

我习惯于在图像强度数据上使用它,图像强度数据的局部方差不如您的数据(那些看起来“厚”的部分)绘图只是许多快速上升和下降的数据点,对吧?)。您可能需要先对数据进行一些平滑处理才能使其正常工作。

If you have the signal processing toolbox, I think the findpeaks function should do the job for you.

Something like:

th = x //(some value that will overlook noise in the data. See the documentation)
[peaks locs] = findpeaks(a,'threshold',th)

http://www.mathworks.com/access/helpdesk/help/toolbox/signal/findpeaks.html

I'm used to using it on image intensity data, which doesn't have quite as much local variance as your data (Those "thick" looking sections of your plot are just many data points going up and down quickly, right?). You might need to smooth the data out a bit first to get it to work.

翻身的咸鱼 2024-09-21 09:47:45

第一步,您应该使用 xcorr 的第二个输出参数来使绘图上的单位正确:

Fs = length(data)./T; % or replace with whatever your sample frequency is (44.1 kHz?)
[a,lags] = xcorr(data,data,'biased');
plot(lags./Fs,a);

现在您可以使用您最喜欢的方法来获取第二个峰值的滞后;如果您只需要执行一次,则图中的数据浏览器按钮即可。如果您需要重复执行此操作,我看不出有任何方法可以避免陷入 findpeaks 或类似情况。

As a first step, you should use the second output argument of xcorr to get your units on the plot correct:

Fs = length(data)./T; % or replace with whatever your sample frequency is (44.1 kHz?)
[a,lags] = xcorr(data,data,'biased');
plot(lags./Fs,a);

Now you can use your favorite method to get the lag for the second peak; the data explorer button in the figure will do if you just need to do it once. If you need to do it repeatedly, I don't see any way to avoid getting into findpeaks or similar.

寒尘 2024-09-21 09:47:45

您可以使用 findpeaks 两次。首先获得峰值的初始估计,并使用该结果来微调第二次调用 findpeaks 的输入参数。从问题来看,您似乎想计算音高值。
代码如下:

maxlag = fs/50;
r = xcorr(x, maxlag, 'coeff');
r_slice = r(ceil(length(r)/2) : length(r));
[pksh,lcsh] = findpeaks(r_slice);

if length(lcsh) > 1
short = mean(diff(lcsh));
else
    short = lcsh(1)-1;
end

[pklg,lclg] = findpeaks(r_slice,'MinPeakDistance',ceil(short),'MinPeakheight',0.3);

if length(lclg) > 1
    long = mean(diff(lclg));
else
    if length(lclg) > 0
        long = lclg(1)-1;
    else
        long = -1;
    end
end

if long > 0
    pitch = fs / long; % fs is sample rate in Hertz

上面是此处给出的代码的修改版本。

You can use findpeaks twice. First to get an initial estimate of the peaks and use that results to fine tune the input parameters of the second call to findpeaks. From the question it seems that you want to calculate the pitch value.
Here is the code :

maxlag = fs/50;
r = xcorr(x, maxlag, 'coeff');
r_slice = r(ceil(length(r)/2) : length(r));
[pksh,lcsh] = findpeaks(r_slice);

if length(lcsh) > 1
short = mean(diff(lcsh));
else
    short = lcsh(1)-1;
end

[pklg,lclg] = findpeaks(r_slice,'MinPeakDistance',ceil(short),'MinPeakheight',0.3);

if length(lclg) > 1
    long = mean(diff(lclg));
else
    if length(lclg) > 0
        long = lclg(1)-1;
    else
        long = -1;
    end
end

if long > 0
    pitch = fs / long; % fs is sample rate in Hertz

The above is a modified version of the code given here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文