zero crossings with interpolation
Mostra commenti meno recenti
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 :

Risposte (2)
neil jerome
il 13 Lug 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');
16 Commenti
Mohamed Jamal
il 13 Lug 2020
Mohamed Jamal
il 13 Lug 2020
Mohamed Jamal
il 13 Lug 2020
Mohamed Jamal
il 13 Lug 2020
Mohamed Jamal
il 13 Lug 2020
neil jerome
il 13 Lug 2020
did you run the code? it does exactly this. run the code, look at the plot, zoom in on the red circles. it looks remarkably like your drawing... :)

Mohamed Jamal
il 13 Lug 2020
Modificato: Mohamed Jamal
il 13 Lug 2020
neil jerome
il 13 Lug 2020
hi mohamed,
obvisouly, we can't write this precisely for you, the code i gave you just uses a dummy signal to show the manipulations. you will always ned to adjust the code provided to fit your variables. so, basically, you will need:
x variable. i have called mine x, you can call it whatever, but this is the time index of your signal (its your x-variable in the plot you showed!). so you can work it out in real time (each increment is your sampling time) if you care about that, or just give it something arbitrary (x = 1:32000, or however many samples you have. but it has to match, in length, to your...
y variable. i called mine 'signal', you can just give it 'a' - or, if you want to use the rest of my code as written (and i promise you there are probably better ways of doing the same thing, i'm no expert!), just get rid of
%% 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;
and instead specify:
signal = a;
x = 1:length(signal);
good luck!
n.
Mohamed Jamal
il 13 Lug 2020
Modificato: Mohamed Jamal
il 13 Lug 2020
neil jerome
il 13 Lug 2020
dude, call it what you want! what did you use for the plot you showed? its that variable!
i'm using x = 1:32000 because i don't know what you're using, its just the simplest version to sat that each signal sample has a 'sample number', given in the variable x, which is the same index of that sample value in the signal varible. so the x0 result gives you the 'sample location' (which is interpolated, so won't be a round number) for the crossing.
if you are sampling wth 2048 kHz and want to reflect that in x, fine, then your x will represent sample time and not sample index. but its still just a vector, right? each new sample point represents 1/2048000 seconds real time difference from the preceding point. so use that if you want, then your x0 result gives you the real-time of the crossing from the start of the signal (assuming it starts at zero) instead of just the 'signal sample number'.
but: they behave exactly the same :)
samplingFreq = 2048000;
samplingTime = 1/samplingFreq;
actualStartTimeInSeconds = 1234; % whatever; you might not know/care about this
numberOfSamples = 32000;
x = (1:numberOfSamples)*samplingTime + actualStartTimeInSeconds;
Mohamed Jamal
il 14 Lug 2020
Modificato: Mohamed Jamal
il 14 Lug 2020
Mohamed Jamal
il 15 Lug 2020
Mohamed Jamal
il 16 Lug 2020
Ivy Vun Jin Ying
il 17 Lug 2021
Ya same problem with me did you managed to solve the problem? I get this "Array indices must be positive integers or logical values" too
neil jerome
il 21 Lug 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.
il 6 Gen 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!
Categorie
Scopri di più su Multirate Signal Processing in Centro assistenza e File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!

