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

时间:2010-08-16 18:01:35

标签: matlab audio signal-processing correlation

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

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

它看起来像这样:

alt text http://a.imageshack.us/img809/3775/plot.jpg

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

是否有人能够阐明我必须做的事情?

非常感谢!


EDIT1: 我尝试过使用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

5 个答案:

答案 0 :(得分:5)

修改

%# 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

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

答案 1 :(得分:1)

  1. 使用低通滤波器平滑数据(或使用多个周围样本对每个样本求平均值)。
  2. 通过查找最高样本值找到中心的峰值。
  3. 通过搜索价值高于其前身的第一个样本,找到峰顶右侧的山谷。
  4. 通过搜索第一个样本到比其前身更小的值来找到山谷右侧的峰值。

答案 2 :(得分:1)

如果您有信号处理工具箱,我认为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

我习惯在图像强度数据上使用它,它没有像你的数据那么多的局部方差(那些“厚”的情节部分只是很多数据点快速上下移动,正确?)。您可能需要首先平滑数据以使其工作。

答案 3 :(得分:1)

作为第一步,您应该使用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或类似情况。

答案 4 :(得分:1)

你可以使用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

以上是给定here的代码的修改版本。