measuring pulse width (not position) with best resolution?

JBeale

Well-known member
I'm wondering if there is some example Teensy 4 code that demonstrates how to measure a positive-going pulse width (as distinct from either pulse position, or frequency) with the best available accuracy, which I presume would mean hardware input capture to avoid uncertain interrupt latencies. In my limited understanding, the PulsePosition library https://github.com/PaulStoffregen/PulsePosition measures time interval from a rising edge to the next rising edge. I want to measure positive pulse width, that is between adjacent rising and falling edges.
AIUI this is simply the Arduino pulseIn(pin, HIGH) functionality, except that I am hoping for better than 1 microsecond resolution, and the ability to capture even very short pulses of approximately 1 usec in length. My pulses are raw sensor output and not part of a defined communication protocol, and they may be any length from about 1 usec to about 200 usec and there is no hard limit to the minimum or maximum time interval between successive pulses. If I need to come up with brand-new code, so be it, I just thought the problem might be common enough to have been encountered before.
 
You can measure period, high time, or low time with the FreqMeasureMulti library. Most of the examples measure total period, but you just need to specify an argument in the constructor to measure high time or low time. It uses the terms SPACE and MARK, and I can never remember which of this is high and which is low. It's a great library, though. The timer frequency is 150 MHz, so you would get a value of 150 for a 1 us pulse. You can get a little more resolution by over-clocking the T4, as timer frequency is F_CPU/4.
 
You're welcome. Be aware that an interrupt occurs on each measurement, so you can run into trouble if the frequency is high. In that case, you can use a timer feature to accumulate over multiple periods (or high or low times). You would only know the average high time over N periods. That feature is not yet in Paul's library, but I have added it and can share it with you if you need it.
 
I'm wondering if you might comment on what I'm seeing. I have pulses typically around 5 microseconds in length, on average about 20 of them per second, but each one arrives at a truly random time (this is a gamma scintillator, timing is random like a geiger counter). My code nominally works as expected, giving me measurements of a few hundred counts per pulse, but occasionally I see big numbers like 4 million which I do not think is possible from my hardware. What happens if two pulses are very close, like 50 nanoseconds apart? Is there a problem when a pulse arrives during the interrupt routine? I have a T4.1 board around somewhere but can't find it, so at the moment I'm running this on an old Teensy 3.2 board.

Code:
#include <FreqMeasureMulti.h>

FreqMeasureMulti freq1;
#define MEASURE_PIN 5
#define MEASURE_TYPE FREQMEASUREMULTI_MARK_ONLY

void setup() {
  Serial.begin(115200);
  while (!Serial) ; // wait for Arduino Serial Monitor
  delay(10);
  freq1.begin(MEASURE_PIN, MEASURE_TYPE);
}

void loop() {
  uint32_t pulses = freq1.available();  // return value is number of captures in buffer
  for (uint8_t i = 0; i < pulses; i++) {
    uint32_t t = freq1.read();
    if (t > 5000) Serial.print("0,");  // values this large unlikely to be real
    Serial.println(t);
  }
}

example output, with mostly the typical numbers but including the rare occurrance of a very large value:
Code:
251
139
256
300
256
182
275
0,4084398
149
265
 
In case of interest, here's a histogram of pulse lengths captured by the above code. In this case, pulse length is some function of gamma ray energy, and the rightmost peak around 580 counts on the horizontal axis is due to a small Cs-137 test source emitting gammas near my detector. The isolated column at 0 in this case corresponds to these huge numbers mentioned above, a situation I speculate might be caused when pairs of pulses happen to occur too close in time to each other.
 

Attachments

  • 2024-01-07_GammaScint_A.png
    2024-01-07_GammaScint_A.png
    16.5 KB · Views: 34
Last edited:
Update: I found my T4.1 board and ran the same code on it, with the same source signal of pulses. The T4.1 has higher resolution by counting a faster-running clock. It still has the too-large-number glitches described above, but they are far more rare; only two cases out of over 30000 samples. When they do occur, they are enormous numbers, like 4 billion.
Code:
0,4294951842
0,4294953093
This makes me think of 32-bit overflow, because 2^32 is about 4.295 billion. So it's like an interval got swapped and instead of computing a duration as (T2-T1) it's instead finding (T1-T2), but the result is an unsigned type so instead of a small negative number, the result is a huge positive number near 2^32.
 
Update: I found my T4.1 board and ran the same code on it, with the same source signal of pulses. The T4.1 has higher resolution by counting a faster-running clock. It still has the too-large-number glitches described above, but they are far more rare; only two cases out of over 30000 samples. When they do occur, they are enormous numbers, like 4 billion.
Code:
0,4294951842
0,4294953093
This makes me think of 32-bit overflow, because 2^32 is about 4.295 billion. So it's like an interval got swapped and instead of computing a duration as (T2-T1) it's instead finding (T1-T2), but the result is an unsigned type so instead of a small negative number, the result is a huge positive number near 2^32.
Yes, I think that could happen if intervals are too close together. The value that is captured on the interrupt is a running 32-bit timer, and the ISR computes the delta (period/high/low) and writes that to a queue, so if periods were too close together, there must be a mixup in the "current" and "previous" values. I'd have to review the ISR in the FreqMeasureMulti to be any more specific, but maybe that's not important, since you can work around it? I don't know why the T3.2 would have a value of around 4M in these situations instead of also being around 4B.
 
I don't know why the T3.2 would have a value of around 4M in these situations instead of also being around 4B.
On the T3.2, the large numbers near 4M would make sense if instead of + pulse width, it was counting - pulse width (duration from falling edge to next rising edge). It works out to be about right for the typical interval between pulses, which often come about 10 to 20 per second.
 
Back
Top