Python rising/falling edge oscilloscope-like trigger
Question:
I’m trying to detect rising and/or falling edges in a numpy vector, based on a trigger value. This is kinda like how oscilloscope triggering works.
The numpy vector contains floating point values. The trigger itself is a floating point value. I would expect this to work as such:
import numpy as np
data = np.array([-1, -0.5, 0, 0.5, 1, 1.5, 2])
trigger = rising_edge(data, 0.3)
print(trigger)
[3]
In other words, it would work like np.where
, returning a vector containing the positions where the condition is true.
I know i can simply iterate over the vector and get the same result (which is what i’m doing), but it isn’t ideal, as you can imagine. Is there some functionality built into numpy that can do this using optimized C code? Or maybe in some other library?
Thank you.
Answers:
We could slice one-off
and compare against the trigger for smaller than and greater than, like so –
In [41]: data = np.array([-1, -0.5, 0, 0.5, 1, 1.5, 2, 0, 0.5])
In [43]: trigger_val = 0.3
In [44]: np.flatnonzero((data[:-1] < trigger_val) & (data[1:] > trigger_val))+1
Out[44]: array([3, 8])
If you would like to include equality as well, i.e. <=
or >=
, simply add that into the comparison.
To include for both rising and falling edges, add the comparison the other way –
In [75]: data = np.array([-1, -0.5, 0, 0.5, 1, 1.5, 2, 0.5, 0])
In [76]: trigger_val = 0.3
In [77]: mask1 = (data[:-1] < trigger_val) & (data[1:] > trigger_val)
In [78]: mask2 = (data[:-1] > trigger_val) & (data[1:] < trigger_val)
In [79]: np.flatnonzero(mask1 | mask2)+1
Out[79]: array([3, 8])
So I was just watching the latest 3Blue1Brown video on convolution when I realized a new way of doing this:
def rising_edge(data, thresh):
sign = data >= thresh
pos = np.where(np.convolve(sign, [1, -1]) == 1)
return pos
So, get all the positions where the data is larger or equal to the threshold, do a convolution over it with [1, -1]
, and then just find where the convolution returns a 1 for a rising edge. Want a falling edge? Look for -1 instead.
Pretty neat, if I do say so myself. And it’s about 5-10% faster.
I’m trying to detect rising and/or falling edges in a numpy vector, based on a trigger value. This is kinda like how oscilloscope triggering works.
The numpy vector contains floating point values. The trigger itself is a floating point value. I would expect this to work as such:
import numpy as np
data = np.array([-1, -0.5, 0, 0.5, 1, 1.5, 2])
trigger = rising_edge(data, 0.3)
print(trigger)
[3]
In other words, it would work like np.where
, returning a vector containing the positions where the condition is true.
I know i can simply iterate over the vector and get the same result (which is what i’m doing), but it isn’t ideal, as you can imagine. Is there some functionality built into numpy that can do this using optimized C code? Or maybe in some other library?
Thank you.
We could slice one-off
and compare against the trigger for smaller than and greater than, like so –
In [41]: data = np.array([-1, -0.5, 0, 0.5, 1, 1.5, 2, 0, 0.5])
In [43]: trigger_val = 0.3
In [44]: np.flatnonzero((data[:-1] < trigger_val) & (data[1:] > trigger_val))+1
Out[44]: array([3, 8])
If you would like to include equality as well, i.e. <=
or >=
, simply add that into the comparison.
To include for both rising and falling edges, add the comparison the other way –
In [75]: data = np.array([-1, -0.5, 0, 0.5, 1, 1.5, 2, 0.5, 0])
In [76]: trigger_val = 0.3
In [77]: mask1 = (data[:-1] < trigger_val) & (data[1:] > trigger_val)
In [78]: mask2 = (data[:-1] > trigger_val) & (data[1:] < trigger_val)
In [79]: np.flatnonzero(mask1 | mask2)+1
Out[79]: array([3, 8])
So I was just watching the latest 3Blue1Brown video on convolution when I realized a new way of doing this:
def rising_edge(data, thresh):
sign = data >= thresh
pos = np.where(np.convolve(sign, [1, -1]) == 1)
return pos
So, get all the positions where the data is larger or equal to the threshold, do a convolution over it with [1, -1]
, and then just find where the convolution returns a 1 for a rising edge. Want a falling edge? Look for -1 instead.
Pretty neat, if I do say so myself. And it’s about 5-10% faster.