Как найти нулевые пересечения с гистерезисом?
в numpy я хотел бы определить точки, в которых сигнал пересекает от (ранее) ниже определенного порога до выше определенного другого порога. Это для таких вещей, как debouncing или точные нулевые пересечения при наличии шума и т. д.
такой:
import numpy
# set up little test problem
N = 1000
values = numpy.sin(numpy.linspace(0, 20, N))
values += 0.4 * numpy.random.random(N) - 0.2
v_high = 0.3
v_low = -0.3
# find transitions from below v_low to above v_high
transitions = numpy.zeros_like(values, dtype=numpy.bool)
state = "high"
for i in range(N):
if values[i] > v_high:
# previous state was low, this is a low-to-high transition
if state == "low":
transitions[i] = True
state = "high"
if values[i] < v_low:
state = "low"
Я хотел бы сделать это без явного зацикливания на массиве: но я не могу придумать никакого способа, так как каждое значение состояния зависит от предыдущего состояния. Это можно обойтись без цикла?
2 ответов
это можно сделать так:
def hyst(x, th_lo, th_hi, initial = False):
hi = x >= th_hi
lo_or_hi = (x <= th_lo) | hi
ind = np.nonzero(lo_or_hi)[0]
if not ind.size: # prevent index error if ind is empty
return np.zeros_like(x, dtype=bool) | initial
cnt = np.cumsum(lo_or_hi) # from 0 to len(x)
return np.where(cnt, hi[ind[cnt-1]], initial)
объяснение: ind
- индексы всех выборок, где сигнал находится ниже нижнего или выше верхнего порога, и для которых положение "переключателя", таким образом, четко определено. С cumsum
, вы делаете какой-то счетчик, который указывает на индекс последнего четко определенного образца. Если начало входного вектора находится между двумя порогами, cnt
будет 0, поэтому вам нужно установить соответствующий выход на начальное значение с помощью
модификации, которые я должен был сделать для своей работы, Все на основе ответа выше Bas Swinckels, разрешить обнаружение порог-пересечения при использовании стандарта, а также отменено пороги.
Я не доволен называя жестким, может быть, теперь он должен читать th_hi2lo
и th_lo2hi
вместо th_lo
и th_hi
? Используя исходные значения, поведение является таким же жестким.
def hyst(x, th_lo, th_hi, initial = False):
"""
x : Numpy Array
Series to apply hysteresis to.
th_lo : float or int
Below this threshold the value of hyst will be False (0).
th_hi : float or int
Above this threshold the value of hyst will be True (1).
"""
if th_lo > th_hi: # If thresholds are reversed, x must be reversed as well
x = x[::-1]
th_lo, th_hi = th_hi, th_lo
rev = True
else:
rev = False
hi = x >= th_hi
lo_or_hi = (x <= th_lo) | hi
ind = np.nonzero(lo_or_hi)[0] # Index für alle darunter oder darüber
if not ind.size: # prevent index error if ind is empty
x_hyst = np.zeros_like(x, dtype=bool) | initial
else:
cnt = np.cumsum(lo_or_hi) # from 0 to len(x)
x_hyst = np.where(cnt, hi[ind[cnt-1]], initial)
if rev:
x_hyst = x_hyst[::-1]
return x_hyst
и как выше тест код, чтобы увидеть, что это делает:
x = np.linspace(0,20, 1000)
y = np.sin(x)
h1 = hyst(y, -0.2, 0.2)
h2 = hyst(y, +0.5, -0.5)
plt.plot(x, y, x, -0.2 + h1*0.4, x, -0.5 + h2)
plt.legend(('input', 'output, classic, hyst(y, -0.2, +0.2)',
'output, reversed, hyst(y, +0.5, -0.5)'))
plt.title('Thresholding with hysteresis')
plt.show()