Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在MATLAB中从自相关数据中提取峰值?_Matlab_Audio_Signal Processing_Correlation - Fatal编程技术网

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

如何在MATLAB中从自相关数据中提取峰值?,matlab,audio,signal-processing,correlation,Matlab,Audio,Signal Processing,Correlation,我有关于音轨的信息(20000帧数据),我使用以下方法自动关联: [r,lags] = xcorr(XX,XX,'biased'); 看起来是这样的: 希望到目前为止一切都很好。理想情况下,我希望能够获取对应于第二个峰值最高部分的帧编号。我读了很多书,尝试了很多不同的方法,但我似乎无法让它为我检索信息 谁能告诉我该做什么 非常感谢 edit1: 我尝试过使用findpeaks,但它似乎对我不起作用。我不确定这是否是因为我使用了错误的数据 edit2:我目前正在测试一种仅用于此音频曲目的方

我有关于音轨的信息(20000帧数据),我使用以下方法自动关联:

[r,lags] = xcorr(XX,XX,'biased');
看起来是这样的:

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

谁能告诉我该做什么

非常感谢


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

edit2:我目前正在测试一种仅用于此音频曲目的方法,但很快我想扩展它,以便在整个文件目录中执行此方法,因此我需要一种能够检测峰值而不是自己查找信息的脚本

edit3:My.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
  • 使用低通滤波器平滑数据(或使用多个周围样本平均每个样本)
  • 通过查找最高采样值,找到中心的峰值
  • 通过搜索第一个比前一个样本的值更高的样本,找到峰值右侧的谷
  • 通过将第一个样本的值搜索到比前一个样本的值小的值,找到山谷右侧的峰值
    如果你有信号处理工具箱,我认为findpeaks函数应该可以帮你完成这项工作

    比如:

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


    我习惯于在图像强度数据上使用它,它没有你的数据那么多的局部方差(你的图中那些看起来“厚”的部分只是许多快速上下移动的数据点,对吧?)。您可能需要先将数据平滑一点,以使其正常工作。

    作为第一步,您应该使用
    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);
    
    现在,您可以使用您最喜欢的方法获得第二个峰值的滞后;如果只需要执行一次,图中的data explorer按钮就可以了。如果您需要重复执行此操作,我看不到任何方法可以避免进入
    FindPeak
    或类似程序。

    编辑

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

    请注意,在计算自相关函数的导数之前,我们对信号进行了平滑处理,以便找到

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

    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
    

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

    图上的单位是多少?自相关给出了单个集合与自身的相关性,第二个集合偏移了一定数量的样本(或“帧”)。你的图表(我认为)显示了作为偏移量(x轴)函数的相关性(y轴),因此第二个峰值不对应于单个帧。听起来你没有正确解释自相关性。它给出了信号在时间滞后tau时与自身的平均相关程度。如上所述,所有数据对[t_i,t_i-tau]对给定tau的最终自相关贡献相等。也许你在问如何找到对应于你指示的峰值的滞后值tau?@MusiGenesis“数据”包含了这张图片中显示的内容:-我假设Y轴是相关性,x轴是帧编号,其中“2”是零滞后点…@Matt Mizumi是的,在这种情况下,滞后值将是完美的,因为我可以将其转换为帧数。@马克·斯皮维:您也可以从上面上传“Three.wav”文件吗。您可以使用类似于宿主文件的东西..是的,当前findpeaks不想输出任何东西。即使您使用它时没有阈值选项?FindPeak返回什么错误/警告?xcorr返回的数据是什么格式?Findpeaks只适用于Nx1或1xN向量。是的,我尝试了各种不同的选项,但它只返回一个空白矩阵。在某些命令上,它表示输出参数太多。xcorr返回一个1x40081双精度。你能用你尝试过但没有成功的例子更新你的问题吗?我希望我可以使用某个命令,而不是制作一个低通滤波器。正如你可能知道的,我使用MATLAB的技术不是很熟练。这与我想要的很相似,这很好,但当然,对于你的信号,你看到的是一个单峰。正如我在第一篇文章中提到的,我正在努力确定右边第二个峰值周围的值——我只是不知道公式@马克·斯皮维:如果将移动平均窗口大小增加到200(即增加平滑效果)
    XX=filtfilt(one(1200)/200,1,energy)
    ,那么只需运行我上面发布的相同代码,即可正确标记峰值:为什么绘图上的y轴的最大xcorr值为1,而我的增加了500?那肯定不对?我还得到奇怪的“loc”数据,例如12、16、8。因此,我认为我又做错了。@Mark Spivey:这肯定是进行这种自动信号处理的困难之一,很难获得适用于所有输入数据的值。我需要重复使用它,因为我希望将来将其用作批处理脚本。但我仍然在努力使用FindPeak。
    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