StefanVR
StefanVR

Reputation: 67

Implementation of a threshold detection function in Python

I want to implement following trigger function in Python:

Input:

Output:

Function:

I would like to return tr_time which consists of the exact (preferred also interpolated which is not yet in code below) time values at which y is crossing tr (crossing means going from less then to greater then or the other way around). The different values in tr_time correspond to the tr_type vector: the elements of tr_type indicate the number of the crossing and if this is an upgoing or a downgoing crossing. For example 1 means first time y goes from less then tr to greater than tr, -3 means the third time y goes from greater then tr to less then tr (third time means along the time vector t)

For the moment I have next code:

import numpy as np
import matplotlib.pyplot as plt


def trigger(t, y, tr, tr_type):
    triggermarker = np.diff(1 * (y > tr))
    positiveindices = [i for i, x in enumerate(triggermarker) if x == 1]
    negativeindices = [i for i, x in enumerate(triggermarker) if x == -1]
    triggertime = []
    for i in tr_type:
        if i >= 0:
            triggertime.append(t[positiveindices[i - 1]])
        elif i < 0:
            triggertime.append(t[negativeindices[i - 1]])
    return triggertime


t = np.linspace(0, 20, 1000)
y = np.sin(t)
tr = 0.5
tr_type = [1, 2, -2]
print(trigger(t, y, tr, tr_type))
plt.plot(t, y)
plt.grid()

Now I'm pretty new to Python so I was wondering if there is a more Pythonic and more efficient way to implement this. For example without for loops or without the need to write separate code for upgoing or downgoing crossings.

Upvotes: 2

Views: 2817

Answers (1)

Tarifazo
Tarifazo

Reputation: 4343

You can use two masks: the first separates the value below and above the threshold, the second uses np.diff on the first mask: if the i and i+1 value are both below or above the threshold, np.diff yields 0:

import numpy as np
import matplotlib.pyplot as plt
t = np.linspace(0, 8 * np.pi, 400)
y = np.sin(t)
th = 0.5

mask = np.diff(1 * (y > th) != 0)
plt.plot(t, y, 'bx', markersize=3)
plt.plot(t[:-1][mask], y[:-1][mask], 'go', markersize=8)

output

Using the slice [:-1] will yield the index "immediately before" crossing the threshold (you can see that in the chart). if you want the index "immediately after" use [1:] instead of [:-1]

Upvotes: 5

Related Questions