如何找到滞后过零点?

时间:2014-04-25 10:03:56

标签: python numpy debouncing

在numpy中,我想检测信号从(先前已经)低于某个阈值的点到高于某个其他阈值。这是用于去抖动,或者在存在噪声的情况下准确的过零点等。

像这样:

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 个答案:

答案 0 :(得分:10)

这可以这样做:

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,因此您需要使用where函数将相应的输出设置为初始值。

信用:这是我在一些Matlab论坛上old post找到的一个技巧,我将其转换为Numpy。这段代码有点难以理解,还需要分配各种中间数组。如果Numpy包含一个专用函数会更好,类似于你的简单for循环,但是用C实现了速度。

快速测试:

x = np.linspace(0,20, 1000)
y = np.sin(x)
h1 = hyst(y, -0.5, 0.5)
h2 = hyst(y, -0.5, 0.5, True)
plt.plot(x, y, x, -0.5 + h1, x, -0.5 + h2)
plt.legend(('input', 'output, start=0', 'output, start=1'))
plt.title('Thresholding with hysteresis')
plt.show()

结果: enter image description here

答案 1 :(得分:1)

我必须根据Bas Swinckels的上述答案对我的工作进行修改,以便在使用标准和反转阈值时检测阈值交叉。

我对命名很难感到高兴,也许现在应该阅读th_hi2loth_lo2hi而不是th_loth_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()

Sine with two different settings for hysteresis.