How to find zero crossings with hysteresis?

前端 未结 2 1906
半阙折子戏
半阙折子戏 2020-12-09 05:42

In numpy, I would like to detect the points at which the signal crosses from (having been previously) below a certain threshold, to being above a certain other threshold. T

2条回答
  •  一生所求
    2020-12-09 06:15

    This can be done like so:

    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)
    

    Explanation: ind are the indices of all the samples where the signal is below the lower or above the upper threshold, and for which the position of the 'switch' is thus well-defined. With cumsum, you make some sort of counter which points to the index of the last well-defined sample. If the start of the input vector is between the two thresholds, cnt will be 0, so you need to set the the corresponding output to the initial value using the where function.

    Credit: this is a trick I found in an old post on some Matlab forum, which I translated to Numpy. This code is a bit hard to understand and also needs to allocate various intermediate arrays. It would be better if Numpy would include a dedicated function, similar to your simple for-loop, but implemented in C for speed.

    Quick test:

    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()
    

    Result: enter image description here

提交回复
热议问题