% ZCROSS ( MatLinks) Find the zero crossings of an arbitrary function.
%
% ZCROSS(X) finds the zero crossings in the given data vector X.
%
% ZCROSS(X,W) ignores multiple (noisy) zero crossings occurring within
% a moving window of length W. The default value for W=1.
%
% ZCROSS(...,'exact') linearly interpolates the data to yield the "exact"
% zero crossings. In this case the result will contain non-integer "indices"
% into the data X which correspond to the interpolated zero crossing points.
% Applying ROUND(ZCROSS(*)) will subsequently yield the integer-valued
% indices of X closest to the actual zero crossings.
%
% ZCROSS(...) plots X and marks the zero crossings. I = ZCROSS(...) returns
% the indices I closest to each zero crossing. LENGTH(I) will thus equal the
% total number of zero crossings.
%
% [I,D]=ZCROSS(...) also returns the mean deviation from true zero at the
% "zero" crossings. If [I,D]=ZCROSS(...) is used with the 'exact' parameter,
% D will yield the mean deviation from the interpolated zero crossing points.
%
% When no zero crossings are found, I=0 is returned.
%
% See also FINDPEAK.
%
% Type HELP MATLINKS for a full listing of all MatLinks ToolChest functions.
%
function [I, D] = zcross(data, w, exact)
%===============================================================================
% Copyright 1998,2000 Julian Andrew de Marchi, Ph.D. (julian@matlinks.net)
% Use & distribution covered by GNU General Public License (www.gnu.org)
%===============================================================================
%------------------
% parse the inputs
%------------------
if (nargin==0), error('No data vector X supplied.');
elseif (nargin<2), w=1; exact=0;
elseif (nargin==2), exact=num2str(w);
if (exact(1)>='0' & exact(1)<='9'), w=str2num(exact); exact=0;
else w=1; exact=1; end;
elseif (exact~='exact')
error('"exact" is the only valid interpolation.');
else exact=1;
end;
if (w~=fix(w) | w<=0),
error('The window length W must be a positive integer.');
elseif (length(data)<w+1)
error('Not enough data in X--zero crossing detection would be senseless.');
end;
%---------------------------
% locate the zero crossings
%---------------------------
ii=0; II=1; I(1) = 0;
for ix=2:length(data),
if (sign(data(ix))~=sign(data(ix-1)) & sign(data(ix))~=0),
if (ix-II>=w | II<w), ii=ii+1;
if (exact), I(ii)=data(ix-1)/(data(ix-1)-data(ix))+ix-1;
else II=ix-1; [dummy inx]=min(abs(data(II:ix))); I(ii)=II+inx-1; end;
end;
end;
end;
if (exact), D=zeros(1,ii);
for ix=2:ii,
II=abs((data(round(I(ix)))-data(round(I(ix-1))))*(I(ix)-floor(I(ix)))+data(round(I(ix-1))))/(ii-1);
D(ix-1)=D(ix-1)+II; D(ix)=D(ix)+II;
end;
D(1)=2*D(1); D(ii)=2*D(ii); D=D./2;
else
P = mean(abs(data(I)));
end;
%-------------------------------------------------------
% plot the zero crossings if there's no output variable
%-------------------------------------------------------
if (nargout==0),
hold off, plot(data), hold on, plot(1:length(data), data, 'c.');
if (exact), plot(I, D(1:ii), 'mo'), title(['Interpolated zero crossings (w=' num2str(w) ')']);
else plot(I, data(I), 'mo'), title(['Zero crossings (w=' num2str(w) ')']); end;
if (exact),
plot(1:length(data), ones(1,length(data))' * [max(D) min(D)], 'c:'), xlabel('i'), ylabel('x(i)');
end;
zoom on;
end;
%===============================================================================
% End-of-File
%===============================================================================