I want to do exactly what this guy did:
Python - count sign changes
However I need to optimize it to run super fast. In brief I want to take a time series and tell every time it crosses crosses zero (changes sign). I want to record the time in between zero crossings. Since this is real data (32 bit float) I doubt I'll every have a number which is exactly zero, so that is not important. I currently have a timing program in place so I'll time your results to see who wins.
My solution gives (micro seconds):
open data 8384 sign data 8123 zcd data 415466
As you can see the zero-crossing detector is the slow part. Here's my code.
import numpy, datetime class timer(): def __init__(self): self.t0 = datetime.datetime.now() self.t = datetime.datetime.now() def __call__(self,text='unknown'): print text,'\t',(datetime.datetime.now()-self.t).microseconds self.t=datetime.datetime.now() def zcd(data,t): sign_array=numpy.sign(data) t('sign data') out=[] current = sign_array[0] count=0 for i in sign_array[1:]: if i!=current: out.append(count) current=i count=0 else: count+=1 t('zcd data') return out def main(): t = timer() data = numpy.fromfile('deci.dat',dtype=numpy.float32) t('open data') zcd(data,t) if __name__=='__main__': main()
What about:
import numpy a = [1, 2, 1, 1, -3, -4, 7, 8, 9, 10, -2, 1, -3, 5, 6, 7, -10] zero_crossings = numpy.where(numpy.diff(numpy.sign(a)))[0]
Output:
> zero_crossings array([ 3, 5, 9, 10, 11, 12, 15])
I.e., zero_crossings will contain the indices of elements before which a zero crossing occurs. If you want the elements after, just add 1 to that array.
As remarked by Jay Borseth the accepted answer does not handle arrays containing 0 correctly.
I propose using:
import numpy as np a = np.array([-2, -1, 0, 1, 2]) zero_crossings = np.where(np.diff(np.signbit(a)))[0] print(zero_crossings) # output: [1]
Since a) using numpy.signbit() is a little bit quicker than numpy.sign(), since it's implementation is simpler, I guess and b) it deals correctly with zeros in the input array.
However there is one drawback, maybe: If your input array starts and stops with zeros, it will find a zero crossing at the beginning, but not at the end...
import numpy as np a = np.array([0, -2, -1, 0, 1, 2, 0]) zero_crossings = np.where(np.diff(np.signbit(a)))[0] print(zero_crossings) # output: [0 2]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With