[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Autocorrelation pitch detection



Hi Stuart,

For the second you can use simple parabolic interpolation based on the 3 samples nearest the peak.  It's practically as accurate as since.  Look at my simple implementation of yin below.  Interpolation is applied to the difference function, but it works as well for the autocorrelation.

For the first it is worth using a definition of autocorrelation that does not introduce bias (rather than correcting the bias of the standard definition).  See discussion in my 1993 YIN paper.

Alain

On 2 Aug 2012, at 19:33, Stuart Rosen wrote:

Paul Boersma points out in his article 'ACCURATE SHORT-TERM ANALYSIS OF THE FUNDAMENTAL FREQUENCY AND THE HARMONICS-TO-NOISE RATIO OF A SAMPLED SOUND' (http://www.fon.hum.uva.nl/paul/papers/Proceedings_1993.pdf) that there are two ways to improve the use of an autocorrelation method to track fundamental frequency in speech. One (correcting the autocorrelation for the effects of the window function) is simple, but the interpolations he suggests for best estimation of the lag and the height of that peak (especially the sin(x)/x one) is not!  Has anyone implemented these procedures in Matlab by any chance, and are willing to share their code?

Thanks!

Yours - Stuart

--

Stuart Rosen, PhD
Professor of Speech and Hearing Science
UCL Speech, Hearing and Phonetic Sciences
2 Wakefield Street
London WC1N 1PF, England

Telephone numbers:
  • Office: (+ 44 [0]20) 7679 4077
  • Admin: (+ 44 [0]20) 7679 4050
  • Internal: ext 24077
  • Fax: (+ 44 [0]20) 7679 4238
Email: stuart@xxxxxxxxxxxxxx
Home page: http://www.phon.ucl.ac.uk/home/stuart

Request an inspection copy of Signals and Systems for Speech and Hearing, 2nd edition by Stuart Rosen & Peter Howell
http://info.emeraldinsight.com/promo/signals.htm


function r=yin2(x,p);
% YIN2: a simple implementation of the yin period-estimation algorithm
%
%  yin2(x) : plot the period, power, and aperiodicity as a function of time
%
%  r=yin2(x,p): use parameters in p, return result in r:
%
%    r.prd: period 
%    r.ap: aperiodicity measure
%  
%    p.maxprd: samples, maximum of search range [default 100]
%    p.minprd: samples, minimum of search range [default 2]
%    p.wsize: samples, window size [default maxprd]
%    p.hop: samples, frame period [default wsize]
%    p.thresh: threshold for period minimum [default: 0.1]
%    p.smooth: samples, size of low-pass smoothing window [default: minprd/2]

 

if nargin>2; error('!'); end
if nargin<2; p=[]; end
if nargin<1; error('!'); end

 

% defaults
if ~isfield(p, 'maxprd'); p.maxprd=100; end
if ~isfield(p, 'minprd'); p.minprd=2; end
if ~isfield(p, 'wsize'); p.wsize=p.maxprd; end
if ~isfield(p, 'hop'); p.hop=p.wsize; end
if ~isfield(p, 'thresh'); p.thresh=0.1; end
if ~isfield(p, 'smooth'); p.smooth=p.minprd/2; end

 

if min(size(x)) ~= 1; error('data should be 1D'); end
x=x(:);
nsamples=numel(x);

 

nframes=floor((nsamples-p.maxprd-p.wsize)/p.hop);
pwr=zeros(1,nframes);
prd=zeros(1,nframes);
ap=zeros(1,nframes);

 

% shifted data
x=convmtx(x,p.maxprd+1);
x=x(p.maxprd:end-p.maxprd,:);

 

for k=1:nframes

   

    start=(k-1)*p.hop; % offset of frame
    xx=x(start+1:start+p.wsize,:);
    d=mean( (xx - repmat(xx(:,1),1,p.maxprd+1)).^2 )/2;     % squared difference function
    dd= d(2:end) ./ (cumsum(d(2:end)) ./ (1:(p.maxprd)));   % cumulative mean - normalized

    

    % parabolic interpolation of all triplets to refine local minima
    min_pos=1:numel(dd);    % nominal position of each sample
    x1=dd(1:end-2);
    x2=dd(2:end-1);
    x3=dd(3:end);
    a=(x1+x3-2*x2)/2;
    b=(x3-x1)/2;
    shift=-b./(2*a);        % offset of interpolated minimum re current sample
    val=x2-b.^2./(4*a);     % value of interpolated minimum

    

    % replace all local minima by their interpolated value, 
    idx= 1 + find(x2<x1 & x2<x3);
    dd(idx)=val(idx-1);
    min_pos(idx)=min_pos(idx-1)+shift(idx-1);

    

    % find index of first min below threshold
    a=dd<p.thresh;
    if isempty(find(a))
        [~,prd0]=min(dd); % none below threshold, take global min instead
    else
        b=min(find(a)); % left edge
        c=min(b*2,numel(a));
        [~,prd0]=min(dd(b:(c-1))); 
        prd0=b+prd0-1;
    end

    

    prd=min_pos(prd0)+1;

        

    if prd>2 & prd<numel(dd) & d(prd0)<d(prd0-1) & d(prd0)<d(prd0+1)

        

        % refine by parabolic interpolation of raw difference function 
        x1=d(prd-1);
        x2=d(prd);
        x3=d(prd+1);
        a=(x1+x3-2*x2)/2;
        b=(x3-x1)/2;
        shift=-b./(2*a);        % offset of interpolated minimum re current sample
        val=x2-b.^2./(4*a);     % value of interpolated minimum
        prd=prd+shift-1;
    end

 

    % aperiodicity
    frac=prd-floor(prd);
    if frac==0
        yy=xx(:,prd);
    else
        yy=(1-frac)*xx(:,floor(prd+1))+frac*xx(:,floor(prd+1)+1); % linear interpolation
    end
    pwr=(mean(xx(:,1).^2) + mean(yy.^2))/2; % average power over fixed and shifted windows
    res=mean(((xx(:,1) - yy)).^2) / 2;
    ap=res/pwr;

    

        

    r.prd(k)=prd;
    r.ap(k)=ap;

 

end

 

if nargout==0; 
    subplot 211; plot(r.prd); title('period'); xlabel('frame'); ylabel('samples');
    subplot 212; plot(r.ap); title('periodicity'); xlabel('frame');
    r=[]; 
end