How to calculate the duty cycle of a time signal in a for loop?

Hi All,
I have multiple time signals and like to compute their duty cycles automatically within a "for loop". For example the duty cycle of the following signal is 74.29%. The signal is attached and the sample rate is 15360000.
Assume I have a bunch of these signals. How can I calculate the ratio of the pulse width (duration of the on state) to the pulse period (the total duration of an on-and-off state) for each signal in a for loop?
Thanks in advance!

 Risposta accettata

load waveform
wr = real(waveform);
wi = imag(waveform);
subplot(2,1,1); plot(wr); ylabel('real');
subplot(2,1,2); plot(wi); ylabel('imag');
mr = movmedian(wr, 5);
mi = movmedian(wi, 5);
mean(abs(mr)<0.01) * 100
ans = 74.2301
mean(abs(mi)<0.01) * 100
ans = 74.4255

9 Commenti

Susan
Susan il 15 Mar 2023
Modificato: Susan il 15 Mar 2023
@Walter Roberson Thank you so much for your response. It works well. Just a quick question, I noticed that the duty cycle depends pretty much on the "k" value in the movmedian(w,k). How do you choose this value, and how should I find the best "k" for each signal within a loop? For example, for the attached signal, I expect to get an 85.68% duty cycle; however, if I don't change the "k", I get the ~72.4% duty cycle.
And, one more question, How can I compute the representative rate, i.e., 1KHz for the attached signal?
To be honest, I guessed.
I tried without the movmedian() first, but got values around 54%, which I realized was because the data just happens to have a lot of zero-ish values.
Oh wait, I calculate the wrong thing, don't I? You should not be interested in the portion that is near 0, you should be interested in the portion that is not near 0 -- abs(mr)>0.01 rather than abs(mr)<0.01
The basic idea was that the signal is changing rapidly, and that putting it through a filter should remove a bunch of values that happen to be near 0 in the rapidly changing regions. But I realize now that can be flawed depending on how you happen to do the filtering, especially if the data just happens to be fairly symmetrical.
So maybe movmax() would be better... no, that is still only about 54%
load waveform
wr = real(waveform);
wi = imag(waveform);
mr = abs(wr(3:end) - wr(1:end-2)) > 0.001;
mi = abs(wi(3:end) - wi(1:end-2)) > 0.001;
mean(mr) * 100
ans = 72.0809
mean(mi) * 100
ans = 72.0698
Ah, that works with your original file. I will try your newer file in a moment.
%newer file -- still not what you were hoping for though
load waveform
wr = real(waveform);
wi = imag(waveform);
mr = abs(wr(3:end) - wr(1:end-2)) > 0.001;
mi = abs(wi(3:end) - wi(1:end-2)) > 0.001;
mean(mr) * 100
ans = 77.2289
mean(mi) * 100
ans = 77.2764
%newer file
load waveform
wr = real(waveform(:).');
wi = imag(waveform(:).');
maskr = abs(wr) < 1e-3;
startsr = strfind([0 maskr], [0 1 1]);
stopsr = strfind([maskr 0], [1 1 0]) + 2;
(1 - sum(stopsr - startsr) / numel(wr)) * 100
ans = 79.5306
maski = abs(wr) < 1e-3;
startsi = strfind([0 maski], [0 1 1]);
stopsi = strfind([maski 0], [1 1 0]) + 2;
(1 - sum(stopsi - startsi) / numel(wi)) * 100
ans = 79.5306
This counts any place with two or more consequative almost-0 as being out of the duty cycle. Using wr == 0 instead of testing for < 1e-3 makes only a small difference in the fraction.
I do not see any way you could say that the duty cycle is near 85% for this signal.
@Walter Roberson thank you so much for the response. I compute the duty cycle as follow
(30721-17560)/(32920-17560)
ans =
0.8568
That's what I think the DC is near 85% for this signal. Any thoughts?
My code assumes that the initial burst is part of the signal whose duty-cycle is to be calculated.
@Walter Roberson I see. Do you think there is any way to consider the repeatable part of the signal and ignore any initialization at the beginning?
We can tell from the graphs that the only part of the signal this is "repeatable" is the zeros.
You can do things like
%newer file
load waveform
wr = real(waveform(:).');
wi = imag(waveform(:).');
maskr = abs(wr) < 1e-3;
stopsr = strfind([maskr 0], [1 1 0]) + 2;
mean(~maskr(stopsr(2):stopsr(end-1)-1)) * 100
ans = 77.2091
maski = abs(wr) < 1e-3;
stopsi = strfind([maski 0], [1 1 0]) + 2;
mean(~maski(stopsi(2):stopsi(end-1)-1)) * 100
ans = 77.2091
This measures for the signal starting from end of the second stretch of zeros (so skipping the first pulse). But you can see it made little difference (gave a lower duty cycle in fact.)
To go much beyond that you would need a more explicit definition of what should be skipped.
@Walter Roberson I see. Thanks again for your help. Appreciate it.

Accedi per commentare.

Più risposte (0)

Community Treasure Hunt

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

Start Hunting!

Translated by