1.208 views (last 30 days)

I am trying to find zero-crossings of a function in Matlab and plot the points where zero-crossing occurs. However, i am not able to find an easy way. I tried http://terpconnect.umd.edu/~toh/spectrum/PeakFindingandMeasurement.htm

and Matlab fnzeros, but i can't understand the spmak and x,y used in these function. The function for which i want to find zero crossing is Euclidean distance function. I will really appreciate if someone can tell me an easy way of doing this.

Star Strider
on 8 Feb 2016

Edited: Star Strider
on 8 Jul 2020

If your function is a vector of values, you can use this little function to approximate them:

zci = @(v) find(v(:).*circshift(v(:), [-1 0]) <= 0); % Returns Zero-Crossing Indices Of Argument Vector

It is also helpful if you want to use fzero or interp1 in a loop to get the exact values.

Note that it returns the indices of the zero-crossings, so you have to do the appropriate vector addressing to get the corresponding x and y coordinates of them.

EDIT — (7 Jul 2020 at 2:54)

Another way of defining ‘zci’ is:

zci = @(v) find(diff(sign(v)));

producing the same result.

Star Strider
on 9 Feb 2016

I would have to have your signal and experiment with it to see what the problem is. The first thing you need to do is to plot it to see if it even has zero-crossings.

This works:

t = [1:0.01:5]; % Time Vector

y = sin(2*pi*t); % Signal

zci = @(v) find(v(:).*circshift(v(:), [-1 0]) <= 0); % Returns Zero-Crossing Indices Of Argument Vector

zx = zci(y); % Approximate Zero-Crossing Indices

figure(1)

plot(t, y, '-r')

hold on

plot(t(zx), y(zx), 'bp')

hold off

grid

legend('Signal', 'Approximate Zero-Crossings')

Star Strider
on 9 Feb 2016

I have no idea what your signal is. It is possible that your signal has no zero crossings, and the paper is looking at the zero-crossings of something else (perhaps the derivative of the signal). If you want to find the peaks instead, and you have the Signal Processing Toolbox, see if the findpeaks function will work for you.

For example, in my illustration, if the original signal were a cosine, the zero-crossings of the sine curve (the negative derivative of the cosine signal) would be the peaks (and valleys) of the cosine signal.

xszm
on 10 Aug 2019

I think that you can interpolate your data. You can find my results as follow. Thanks for Star Strider, I found it for a long time.

NO interp

interp

Mohamed Jamal
on 15 Jul 2020

Im trying this code below in my matlab: (my signal is y1 -it's implicitly values of samples, my time (x's axis)=1:length(y1); )

but it doesn't work, could you please help me why and how could I correct it? thanks.

Iwl2=360:0.001:740; % interpolating to 0.001-nm resolution

loc_frequ1=0;

w1=1:length(y1);

for i=1:c

y = y1(:,i);

y2=interp1(wl,y,Iwl2); % interpolating to 0.001-nm resolution

zci = @(v) find(v(:).*circshift(v(:), [-1 0]) <= 0); % Returns Zero-Crossing Indices Of Argument Vector

zx = zci(y2); % Approximate Zero-Crossing Indices

loczeros1=round(Iwl2(zx));

locfrequ= ismember(Iwl2,loczeros1); % find same data from Iwl2

loc_frequ1=loc_frequ1+double(locfrequ);

end

Walter Roberson
on 15 Jul 2020

w1 should not be 1:length(y1) . You should be using wl (lower-case-L not digit 1), and it should be the time vector corresponding to your input signal. If you know your sampling rate, Fs, then

if size(y1,1) == 1; y1 = y1.'); end %ensure columns of signal

c = size(y1,2);

wl = (0:size(y1,1)-1) / Fs;

Iwl2=360:0.001:740; % interpolating to 0.001-nm resolution

loc_frequ1=0;

for i=1:c

y = y1(:,i);

y2=interp1(wl,y,Iwl2); % interpolating to 0.001-nm resolution

zx = zci(y2); % Approximate Zero-Crossing Indices

loczeros1=round(Iwl2(zx));

locfrequ= ismember(Iwl2,loczeros1); % find same data from Iwl2

loc_frequ1=loc_frequ1+double(locfrequ);

end

Mitch Lautigar
on 7 Jul 2020

Edited: Walter Roberson
on 7 Jul 2020

There are many ways to try and skin this problem, many people have tried and find varying different levels of success. Here's a function you can use that requires a sinusoidal waveform to approximate 0 intersections.

[out_array] = signal_manip(s_in)

sign_array = []; %predeclaration

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%Following for loop checks every spot to create the following numbers:

%For positive numbers, a "1" is placed in an array.

%For negative numbers, a "-1" is placed in an array.

%For a zero, a "0" is placed in an array.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

for i = 1:length(s_in)

if s_in(1,i) > 0

curr_sign = 1;

elseif s_in(1,i) < 0

curr_sign = -1;

else

curr_sign = 0;

end %end "if s_in > 0"

sign_array = [sign_array,curr_sign]; %gives an output array that shows you all negative and positive numbers

end %end for i = 1:length(s_in)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%following for loop looks for the change points and handles the spots where a 0 occurs.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

curr = sign_array(1,1); %Starting comparison Point

out_array = [] %Predeclaration of array

for i = 2:length(s_in)

if ( sign_array(1,i) ~= curr) %if number change detected, mark it.

out_array = [out_array,i];

elseif (sign_array(1,i) == 0) %if we have a zero on the graph, mark it and skip i forward by 1 so as to not have a false hit.

out_array = [out_array,i];

i = i + 1;

end

curr = sign_array(1,i);

end

Mohamed Jamal
on 15 Jul 2020

OOOPS didn't notice that there's keyword function, my bad, but whatever it still gives me bugs:

signal_manip(y1) %y1 is my signal (it's vector of values)

Index in position 2 exceeds array bounds (must not exceed 1).

Error in signal_manip (line 10)

if s_in(1,i) > 0

Walter Roberson
on 15 Jul 2020

The person who posted it left out the function keyword accidentally, so it is not surprising you missed it!

In order to get the error message you are seeing when you are passing in a vector of values, then you must have passed in a column vector of values -- but as I was careful to point out before, it expects a row vector of values.

Mohamed Jamal
on 15 Jul 2020

UMAIR RASOOL
on 13 Aug 2020

close all

clear all

clc

n=-10:10;

a=.9;

y=zeros(size(n));

for k=-5:5

temp=find(n-(2*k)==0); %find xaxis where it is zero(zero crossing)

y(temp)=1; %palce the value at the zero crossing

x=n.*(sum(a^k)*y);

end

plot(n,x)

xlabel('n')

ylabel('x(n)')

Maximum=max(x);

Nick Hunter
on 12 Apr 2020

Edited: Nick Hunter
on 16 Jul 2020

I have just worked out a quicker bug proof solution, I guess:

clear;

theta = [0:7:360*4,1440]; % Angle Vector (MUST BE a ROW VECTOR)

y = sind(theta); % Signal Vector (MUST BE a ROW VECTOR)

UpZCi = @(v) find(v(1:end-1) <= 0 & v(2:end) > 0); % Returns Up Zero-Crossing Indices

DownZCi = @(v) find(v(1:end-1) >= 0 & v(2:end) < 0); % Returns Down Zero-Crossing Indices

ZeroX = @(x0,y0,x1,y1) x0 - (y0.*(x0 - x1))./(y0 - y1); % Interpolated x value for Zero-Crossing

ZXi = sort([UpZCi(y),DownZCi(y)]);

ZX = ZeroX(theta(ZXi),y(ZXi),theta(ZXi+1),y(ZXi+1));

% === Checking for zero at the ignored value ===

if y(end)==0

ZX(end+1) = theta(end);

end

% ==============================================

figure(1)

plot(theta, y, '-b')

hold on;

plot(ZX,zeros(1,length(ZX)),'ro')

grid on;

legend('Signal', 'Interpolated Zero-Crossing')

Nick Hunter
on 15 Jul 2020

Walter Roberson
on 16 Jul 2020

Nick:

y = [1 0 1 0 1 0 -1].';

UpZCi = @(v) find(v(1:end-1) <= 0 & v(2:end) > 0); % Returns Up Zero-Crossing Indices

DownZCi = @(v) find(v(1:end-1) >= 0 & v(2:end) < 0); % Returns Down Zero-Crossing Indices

UpZCi(y),DownZCi(y)

ans =

2

4

ans =

6

However, you cannot [] together [2;4] and [6]

Your code is assuming that the result of UpZCi and DownZCi are row vectors, but that will not be the case if y is a column vector. You did not document an orientation requirement.

Nick Hunter
on 16 Jul 2020

Thank you so much, Walter. This is a good point. I added this condition in comments.

Mitch Lautigar
on 27 Jul 2020

So I took the code previously used and modified it to what I needed (finding zero point crossing for a sin/cos wave. The code is below

function [freq_val] = peakfind(dm_allow)

%Step 1: Load file and find zero crossings

load('s_m.mat','s_m2','t')

zci = @(v) find(v(:) .* circshift(v(:), [-1 0]) <= 0);

zx = zci(s_m2)';

rp_zx = [];

%Step 2: manipulate above values so as to find unique values.

zx2 = round(zx ./ max(zx),2);

for i = 1:length(zx2)-1

if round(zx2(1,i),3) ~= round(zx2(1,i+1),3)

rp_zx = [rp_zx,zx2(1,i+1)];

end

end

end_array = [1];

%Eliminate redundant numbers

for i = 1:length(rp_zx)

zeta = find(zx2 == rp_zx(1,i));

end_array = [end_array,zeta(1,1)];

end

actual_spots = zx(end_array);

t_val = [];

%convert above numbers to to time values.

for i = 1:length(end_array)-1

low_spot = actual_spots(1,i);

high_spot = actual_spots(1,i+1);

max_spot = max(s_m2(low_spot:high_spot));

min_spot = abs(min(s_m2(low_spot:high_spot)));

if max_spot > min_spot

beta = find(s_m2(low_spot:high_spot) == max_spot);

t_val = [t_val,t(beta+low_spot)];

elseif max_spot < min_spot

%do nothing

end

end

%convert time values to frequency values.

if length(t_val) > 1

freq_val = [];

for i = 1:length(t_val)-1

freq_val = [freq_val,1/(t_val(i+1)-t_val(i))];

end

else

error('Cycle time not long enough')

end

end

If you use my code, simply change the following:

zx = zci(s_m2)' %replace s_m2 with whatever signal you are wanting to find zero crossings for.

Opportunities for recent engineering grads.

Apply TodayFind the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!
## 2 Comments

## Direct link to this comment

https://la.mathworks.com/matlabcentral/answers/267222-easy-way-of-finding-zero-crossing-of-a-function#comment_341394

⋮## Direct link to this comment

https://la.mathworks.com/matlabcentral/answers/267222-easy-way-of-finding-zero-crossing-of-a-function#comment_341394

## Direct link to this comment

https://la.mathworks.com/matlabcentral/answers/267222-easy-way-of-finding-zero-crossing-of-a-function#comment_341517

⋮## Direct link to this comment

https://la.mathworks.com/matlabcentral/answers/267222-easy-way-of-finding-zero-crossing-of-a-function#comment_341517

Sign in to comment.