Zero-crossing calculation
13 views (last 30 days)
Show older comments
Jayanta Deb
on 12 Aug 2017
Commented: GIULIA CISOTTO
on 3 Nov 2020
Hi all, I need a script which can calculate zero crossing of the signal. I have the value of x and y. The script should be able to calculate the exact position of zero crossing points. Help!
0 Comments
Accepted Answer
Star Strider
on 12 Aug 2017
This is reasonably robust:
function ZC = ZeroX(x,y)
zci = @(v) find(v(:).*circshift(v(:), [-1 0]) <= 0); % Returns Approximate Zero-Crossing Indices Of Argument Vector
zxidx = zci(y);
for k1 = 1:numel(zxidx)
idxrng = max([1 zxidx(k1)-1]):min([zxidx(k1)+1 numel(y)]);
xrng = x(idxrng);
yrng = y(idxrng);
ZC(k1) = interp1( yrng(:), xrng(:), 0, 'linear', 'extrap' );
end
end
x = linspace(0, 11*pi, 42); % Create Data
y = sin(x); % Create Data
ZC = ZeroX(x,y);
figure(1)
plot(x, y, '-r')
hold on
plot(ZC, zeros(size(ZC)), 'pg')
hold off
grid
5 Comments
Ike Brown
on 19 Oct 2019
Thanks for posting this Star Strider! I found this very helpful. Here is a slight modification in order to avoid the following error "grid vectors not strictly monotonic increasing". This modification is based off of a forum answer by Jos (10584)
% ZeroX has been modified so as to avoid the following error "Error using griddedInterpolant
% The grid vectors are not strictly monotonic increasing."
%
% The following modifications are based off of this MatLab forum answer:
% https://www.mathworks.com/matlabcentral/answers/283718-grid-vectors-not-strictly-monotonic-increasing
function ZC = ZeroX(x,y)
zci = @(v) find(v(:).*circshift(v(:), [-1 0]) <= 0); % Returns Approximate Zero-Crossing Indices Of Argument Vector
zxidx = zci(y);
for k1 = 1:numel(zxidx)
idxrng = max([1 zxidx(k1)-1]):min([zxidx(k1)+1 numel(y)]);
xrng = x(idxrng);
yrng = y(idxrng);
% Beginning of ZeroX2 modifications. The naming conventions follow
% those in the referenced MatLab forum, except that "X" is "yrng" and
% "Y" is "xrng".
[yrng2, ~, jyrng] = unique(yrng); %yrng is a new array containing the unique values of yrng. jyrng contains the indices in yrng that correspond to the original vector. yrng = yrng2(jyrng)
xrng2 = accumarray(jyrng, xrng, [], @mean); %This function creates a new array "xrng2" by applying the function "@mean" to all elements in "xrng" that have identical indices in "jyrng". Any elements with identical X values will have identical indices in jyrng. Thus, this function creates a new array by averaging values with identical X values in the original array.
ZC(k1) = interp1( yrng2(:), xrng2(:), 0, 'linear', 'extrap' );
end
end
GIULIA CISOTTO
on 3 Nov 2020
Dear Ike Brown,
thank you for sharing your code. However, I would like to let you know that it seems to incorrectly detect ZC points.
To test the difference between ZeroX and myZC, you can run a modified version of your toy example as follows:
rng(shuffle)
x = linspace(0, 11*pi, 42); % Create Data
y = sin(x); % Create Data
n = 1 + 2.*randn(1,length(y)); % add Gaussian noise
y = y+n;
% myZC
[myZC, myZCx, myZCy, ys] = myZC(x,y);
% Comparison with ZeroX
ZC = ZeroX(x,y);
% Print ZC values
[length(myZC), length(ZC)]
% Plot figure
figure, hold all
plot(x,y,'k'), xlabel('No. samples'), ylabel('Amplitude [A.U.]')
plot(x,ys,'b:')
plot(x(myZC), zeros(size(myZC)), 'bs', 'markerface', 'b')
plot(myZCx, myZCy, 'cd', 'markerface', 'c')
plot(ZC, zeros(size(ZC)), 'pr'), grigrid on, legend('y', 'ys', 'myZC', 'myZC-refined', 'ZC')
In attach, you can also find a representative plot: you can notice that ZeroX can mostly correctly detect the zero-crossigs, but sometimes it misses one (between sample no.17 and sample no.18) or it detects a false one (at sample 27).
ZeroX returns a correct number of zero-crossings, but when plotted, they are mismatched to the raw signal, while myZC can correctly compute the number of zero-crossing and precisely get their locations.
More Answers (1)
MSP
on 12 Aug 2017
zeroindex=find(y==0)
x(zeroindex)
3 Comments
Shubhashree Bal
on 2 Jul 2019
It is not necessary that there is sample at amplitude equal to 0.
Example:
x = [ 1 2 3 4 5];
y = [1 -1 -2 -3 -4];
k= find (y==0);
Conclusion: Instead of having zero crossing it will not return any index. Thus, we can check sign change for finding zero crossing accurately.
Thanks!
GIULIA CISOTTO
on 3 Nov 2020
Dear Shubhashree, this is not actually true: zero-crossing is defined as the number of times a signal changes its sign. If you apply your computation, then you might have an incorrect number of ZC. Let's consider a signal with a number of consecutive samples set to zero: then, you will add all of them to the ZC counter. However, you would be wrong in that. Please, check my answer above for the correct computation of ZC.
See Also
Categories
Find more on Logical in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!