# zero crossings with interpolation

89 views (last 30 days)
Mohamed Jamal on 13 Jul 2020
Commented: Sanders A. on 6 Jan 2023
Hi guys!
I have Ac singal as what Im attaching here(see photo down) , ofcourse , my AC signal ofcourse it's implicitly vector sized as 1X32000 samples. (vectors that its values are samples). Im trying to do zero crossing in matlab in order to detect where I have edges! , I's preferable to do that and find the approximated point on the edge that I have the zero crossings by interpolation(if there's another good way and it's optimal approximation to find the point at which there's the zero crossing would be accepted .. but to be assure Im dealing with AC signal this means analog "continues values" and not discrete .. so interpolation is very good for me to find zero crossings), once again it's right that my ac signal is a vector of samples but I take time (x-axis) into consideration .. so it's continues .. and it's suitable and better in my case to detect zero crossings by interpolation!
Any help please how can I do zero crossings by interpolation in matlab? really appreciated for any help.
lets assume that my ac signal (vector of samples) is variable b, also I want to plot the zero crossings as returned values and to show on the same ac signal(my input) the zero cossings like dots/marks when there's zero crossings.
why I need to do interpolation method for zero crossings in my case? because my signal is about samples that I sampled .. attaching down a photo of what I mean :

KSSV on 13 Jul 2020
Mohamed Jamal on 13 Jul 2020
Hi , he doesn't use interpolation method for zero crossings!!!!! your link is not helping me .. thanks anyway

neil jerome on 13 Jul 2020
LOTS of ways to do this!
i've 'over-commented' this code to show the logic - this is deliberately not the fastest or most compact way, but should be understandable... :)
good luck!
% commented find zero crossings
%% set up arbitrary signal (sum of 2 sines for demo)
x = 0:0.01:4;
sin1 = 10*sin(10*x); sin2 = 42*sin(6*x);
signal = sin1+sin2;
% plot to show signal
figure;
plot(x, signal, 'bo-');
hold on;
plot(x, zeros(1,legth(x)), 'k:');
%% find next point after zero crossing
sigPos = logical(signal>0); % find all positive points
cross = sigPos - circshift(sigPos,1); % find changeover points
% add to plot
plot(x(logical(cross)), signal(logical(cross)), 'ko');
%% assume straight line approximation between adjacent points
crossInd = find(cross); % x indices of cross points
nCross = length(crossInd); % number of cross points found
x0 = NaN(1,nCross); % vector of x-values for cross points
for aa = 1:nCross
thisCross = crossInd(aa);
% interpolate to get x coordinate of approx 0
x1 = thisCross-1; % before-crossing x-value
x2 = thisCross; % after-crossing x-value
y1 = signal(thisCross-1); % before-crossing y-value
y2 = signal(thisCross); % after-crossing y-value
ratio = (0-y1) / (y2-y1); % interpolate between to find 0
x0(aa) = x(x1) + (ratio*(x(x2)-x(x1))); % estimate of x-value
end
% add to plot
plot(x0, zeros(1,nCross), 'ro');
neil jerome on 21 Jul 2021
hi ivy
i don't want to spend much time on this, but if i just copy and paste the code above (and correct 'legth' -> length), then it works. i hope that is the same for you.
i get the 'array indices...' message a lot in other stuff, and it means that you are trying to tell matlab to access an array using something other than a regular integer, and it can't do that (nobody can do that!). so if have an array [1 2 3 4], what is the "2.34"-th element? well, that doesn't have a meaning, so you get an error. its like asking "what is the first-and-a-half letter of your name"? doesn't work! :)
thisArray = [2 4 6 8 10];
a = thisArray(2); % no problem! a is second element, = 4
b = thisArray(3); % b = 6; all good :)
c = thisArray(2.21); % array indices error! because ther is no "2.21"th element
so you need to go through your code and find the line corresponding to where the error is created, and look for where you are doing this sort of thing - using a non-integer (most likely in a variable) as the index for an array.
thisArray = [2 4 6 8 10];
a = 2.21;
b = thisArray(a); % :(
hope that explains this error and why it comes about. try doing some basic debugging by running with a breakpoint on your error line, and just before you would get the error, hover over the variables and look for when you are trying to ask for an element of an array using something that isn't an integer. if you still can't see it, you need to start extracting individual pasrts (while still paused at the breakpoints) and running them separately to explore. this can be harder to see when you work with very large arrays, so you could also try taking small arrays as test data first, etc. all the usual tricks.
for this specific code, we were talking about zero crossing in a signal and there seemed to be some confusion as to what the x-axis values were. there is a distinction between your x-variable, which could well be non-integers (eg fractions of a second), and the x variable array, where you talk about each element of the array and each element is accessed by what number element of the array it is - and that has to be an integer, or you get the error as above..
x = 1:100; % just a list of numbers
here, the values in the array are the same as the element indices. i do this a lot for testing/examples, but it can cause confusion. so let's imagine i have a time signal being sampled at some random frequency, 240 Hz, and i want the x data to be the time of the samples (and starting from zero):
nSamples = 1000; % there are 1000 samples in my recording
freq = 240; % my sampling frequency
startTime = 0; % start recording at zero time
x = startTime + [1:nSamples]*(1/freq);
now, x is a list of times (in seconds), telling me when each sample was recorded, but i still acess & work with them based on their indices (which still have to be integers!).
so. run my code above with no edits, and see that:
x is a list of sample 'times', which are not integers.
crossInd are the indices (which must be integers) of the points where the signal seems to cross zero. if you want a list of the times that the signal seems to cross zero, you could access the values at those indices you found (which are close to the crossing) using crossTimes = x(crossInd). in the code, i do a simple interpolation between the two points at the crossing to get the time values, which i call x0.
good luck!
Sanders A. on 6 Jan 2023
I was able to fix the error mentioned by Mohamed and Ivy by making sure that there wasn't an erroneous zero crossing detected by having opposite signal(1) and signal (end) signs.
crossInd = find(cross); % x indices of cross points
if crossInd(1) == 1
crossInd(1) = [];
end
nCross = length(crossInd); % number of cross points found
For whomever may show up and find this very useful code later!