Let me give you but a superficial overview of this module's elegance.
import numpy as np import rolling_quantiles as rq pipe = rq.Pipeline( # rq.Pipeline is the only stateful object # declare a cascade of filters by a sequence of immutable description objects rq.LowPass(window=200, portion=100, subsample_rate=2), # the above takes a median (100 out of 200) of the most recent 200 points # and then spits out every other one rq.HighPass(window=10, portion=3, subsample_rate=1)) # that subsampled rolling median is then fed into this filter that takes a # 30% quantile on a window of size 10, and subtracts it from its raw input # the pipeline exposes a set of read-only attributes that describe it pipe.lag # = 60.0, the effective number of time units that the real-time output # is delayed from the input pipe.stride # = 2, how many inputs it takes to produce an output # (>1 due to subsampling) input = np.random.randn(1000) output = pipe.feed(input) # the core, singular exposed method # every other output will be a NaN to demarcate unready values subsampled_output = output[1::pipe.stride]
That may be a lot to take in, so let me break it down for you:
rq.Pipeline(description...)constructs a filter pipeline from one or more filter descriptions and initializes internal state.
.feed(*)takes in a Python number or
np.arrayand its output is shaped likewise.
rq.HighPassthat compute rolling quantiles and return them as is, and subtract them from the raw signal respectively. Compose them however you like!
NaNs in the output purposefully indicate missing values, usually due to subsampling. If you pass a
LowPassfilter, it will slowly deplete its reserve and continue to return valid quantiles until the window empties completely.
I also expose a convenience function
rq.medfilt(signal, window_size) at the top-level of the package to directly supplant
That's it! I detailed the entire library. Don't let the size of its interface fool you!
If you are running MacOS or Linux with Python 3.8+, execute the following: