Finding discrete logic levels in a waveform
Question: I have some waveforms that I'm trying to process with Python. I would like to
find discrete logic levels that these signals are displaying. I have a 1D
array of each waveform's x and y values.

The data looks something like this example staircase:

![example](http://i.imgur.com/u4Z92Qk.png)

How can I find the different levels? Here they might be around (1.8, 3.3),
(2.1, 3.0), (2.7, 2.6) and so on.

I have tried following the approach discussed in [this similar
question](http://stats.stackexchange.com/questions/36309/how-do-i-find-peaks-
in-a-dataset) relating to R. I implemented a LOWESS smoother (which is the
curve you see) with a tight fit to eliminate noise, since the real waveforms
have a non-trivial noise component, and then tried doing a rolling max with a
window over the data, but I can't get anything solid.


Answer: For your simple example, you can just define a skip size and plot a step
function,

    
    
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.signal import argrelmin, argrelmax
    
    #Generate some example signal
    res = 1000
    x = np.linspace(0,2*np.pi,res)
    y = np.sin(x)
    plt.plot(x,y)
    
    #Take a number of discrete steps
    Nsteps = 10
    skip = x.shape[0]/Nsteps
    xstep = x[::skip]; ystep = y[::skip]
    plt.plot(xstep,ystep,'o')
    
    #Plot the step graph
    plt.step(xstep, ystep)
    
    #Get max and min (only 2 in this simple case)
    plt.plot(x[argrelmax(y)[0]],y[argrelmax(y)[0]],'ro')
    plt.plot(x[argrelmin(y)[0]],y[argrelmin(y)[0]],'ro')
    plt.show()
    

which gives

![enter image description here](http://i.stack.imgur.com/PukQQ.png)

For the more complicated solution in the link, I think this will involve
building up the ystep by looking for local min/max in a given range, something
like:

    
    
    ystep =[]
    for rec in range(0,x.shape[0],skip):
        ystep.append(y[argrelmax(y[rec:rec+skip])[0]])
    

EDIT: complete example giving local min/max for a range

    
    
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.signal import argrelmin, argrelmax
    
    #Generate some example signal
    res = 1000
    x = np.linspace(0,2*np.pi,res)
    y = np.sin(x)
    plt.plot(x,y)
    
    #Take a number of discrete steps
    Nsteps = 10
    skip = x.shape[0]/Nsteps
    
    #Get local minimum and maximum in blocks for whole set of data
    xstep = []; ystep =[]
    for rec in range(0,x.shape[0],skip):
        srt = rec
        end = rec+skip-1
        if (y[srt] > y[end]):
            indx = argrelmax(y[srt:end],mode='wrap')[0]
        elif (y[srt] < y[end]):
            indx = argrelmin(y[srt:end],mode='wrap')[0]
    
        xstep.append(x[srt+indx])
        ystep.append(y[srt+indx])
    
    #Plot location of min/max
    plt.plot(xstep,ystep,'o')
    
    #Plot the step graph
    plt.step(xstep, ystep)
    
    plt.show()
    

