Skip to main content

Function reference

All 33 functions are under system.signal, with SciPy 1.18.1's names, parameters and defaults; positional and keyword calls both work. Signals are lists of numbers, evenly sampled; None, NaN and infinity raise ValueError. Where a function differs from SciPy, its entry says so; the full list is on Differences from SciPy.

Groups: Detrending and windows · Filter design · Filter order selection · Frequency response · Filtering · Smoothing · Peak finding · Spectral analysis · Resampling

Detrending and windows​

detrend​

system.signal.detrend(data, axis=-1, type='linear', bp=0, overwrite_data=False)

Removes a linear or constant trend from a signal.

ParameterDescription
dataThe signal, a list of numbers.
axis-1 (default) or 0. Signals are 1-D, so both mean the same.
type'linear' (default) subtracts a least-squares line; 'constant' subtracts the mean. 'l' and 'c' also work.
bpBreakpoints for 'linear': sample indices where a new, independent line starts. An integer or a list. An empty list means none.
overwrite_dataAccepted for compatibility; the input is never modified.

Returns: the detrended signal, a list of floats.

get_window​

system.signal.get_window(window, Nx, fftbins=True)

Returns a window of Nx points: hann, hamming, blackman, blackmanharris, nuttall, flattop, boxcar, triang, bartlett, parzen, bohman, barthann, cosine, lanczos, tukey, kaiser, kaiser_bessel_derived, gaussian, general_gaussian, general_hamming, general_cosine, exponential, taylor and chebwin.

ParameterDescription
windowA name such as 'hann', a tuple or list with parameters such as ('kaiser', 8.6) or ('tukey', 0.25), or a number (a Kaiser beta). A name ending in _symmetric or _periodic overrides fftbins.
NxNumber of points, a positive integer.
fftbinsTrue (default): periodic window, for spectral analysis. False: symmetric window, for filter design.

Returns: the window, a list of floats. The dpss window is not available.

Filter design​

Five classic IIR designs, each returning (b, a), (z, p, k) or second-order sections. Use output='sos' for filtering: sections stay accurate at high orders and low cutoffs, where (b, a) coefficients lose precision.

FunctionCharacterExtra parameters
butter(N, Wn, ...)Butterworth: maximally flat passbandnone
cheby1(N, rp, Wn, ...)Chebyshev type I: ripple in the passband, steeper roll-offrp: passband ripple, dB
cheby2(N, rs, Wn, ...)Chebyshev type II: ripple in the stopbandrs: minimum stopband attenuation, dB
ellip(N, rp, rs, Wn, ...)Elliptic (Cauer): the sharpest transition for its orderrp and rs
bessel(N, Wn, ..., norm='phase')Bessel: flattest group delay, least overshoot on stepsnorm: 'phase' (default), 'delay' or 'mag', what Wn means

All five also take these parameters, after Wn:

ParameterDescription
NFilter order, a whole number. Up to 500 (Bessel: 100).
WnCritical frequency: a number for low-pass and high-pass, [low, high] for band-pass and band-stop. Normalized to 0..1 (1 = Nyquist) unless fs is given, then in the units of fs. For cheby2, the frequency where the attenuation first reaches rs.
btype'lowpass' (default; the signature's 'low' means the same), 'highpass', 'bandpass' or 'bandstop'. SciPy's short forms, such as 'lp', 'hp', 'bp' and 'bs', also work.
analogTrue for an analog filter (Wn in rad/s). Default False.
output'ba' (default), 'zpk' or 'sos'.
fsSampling frequency, in the units of Wn. Default None (Wn normalized).

Returns: (b, a), (z, p, k) or a list of sections, each [b0, b1, b2, 1, a1, a2], depending on output. Zeros and poles are Python complex numbers; the gain k is a float.

sos = system.signal.butter(4, 2.0, fs=50.0, output="sos") # 2 Hz low-pass at 50 samples/s
sos = system.signal.ellip(6, 0.5, 60, [0.1, 0.3], "bandpass", output="sos")

butter​

system.signal.butter(N, Wn, btype='low', analog=False, output='ba', fs=None)

cheby1​

system.signal.cheby1(N, rp, Wn, btype='low', analog=False, output='ba', fs=None)

cheby2​

system.signal.cheby2(N, rs, Wn, btype='low', analog=False, output='ba', fs=None)

ellip​

system.signal.ellip(N, rp, rs, Wn, btype='low', analog=False, output='ba', fs=None)

bessel​

system.signal.bessel(N, Wn, btype='low', analog=False, output='ba', norm='phase', fs=None)

Filter order selection​

Each finds the lowest order that meets a specification, and the critical frequency to design with: buttord for butter, cheb1ord for cheby1, cheb2ord for cheby2, ellipord for ellip. All four take the same parameters:

ParameterDescription
wpPassband edge: a number for low-pass and high-pass, [low, high] for band filters. Normalized to 0..1 (1 = Nyquist) unless fs is given, then in the units of fs.
wsStopband edge, in the same form and units as wp.
gpassMaximum loss in the passband, in dB.
gstopMinimum attenuation in the stopband, in dB.
analogTrue for an analog filter (frequencies in rad/s). Default False.
fsSampling frequency, in the units of wp and ws. Default None.

Returns: (N, Wn): the order, an int, and the critical frequency, a number or [low, high], ready to pass on.

N, Wn = system.signal.buttord(0.2, 1.0, 1, 40, fs=10.0) # pass 0.2 Hz within 1 dB, stop 1 Hz by 40 dB
sos = system.signal.butter(N, Wn, fs=10.0, output="sos")

buttord​

system.signal.buttord(wp, ws, gpass, gstop, analog=False, fs=None)

cheb1ord​

system.signal.cheb1ord(wp, ws, gpass, gstop, analog=False, fs=None)

cheb2ord​

system.signal.cheb2ord(wp, ws, gpass, gstop, analog=False, fs=None)

ellipord​

system.signal.ellipord(wp, ws, gpass, gstop, analog=False, fs=None)

Frequency response​

freqz​

system.signal.freqz(b, a=1, worN=512, whole=False, plot=None, fs=2*pi, include_nyquist=False)

Frequency response of a filter given as (b, a).

ParameterDescription
b, aNumerator and denominator coefficients. a defaults to 1.
worNNumber of frequencies (default 512), or a list of frequencies to evaluate, in the units of fs.
wholeTrue to cover 0 to fs instead of 0 to fs/2.
plotMust be None: plot w and h from the result instead.
fsSampling frequency; the default 2π gives frequencies in rad/sample.
include_nyquistTrue to end on fs/2 when worN is a count.

Returns: (w, h): frequencies, and the complex response at each. abs(h[i]) is the gain.

freqz_sos and sosfreqz​

system.signal.freqz_sos(sos, worN=512, whole=False, fs=2*pi)
system.signal.sosfreqz(sos, worN=512, whole=False, fs=2*pi)

Frequency response of a filter given as second-order sections, with the same worN, whole and fs as freqz. sosfreqz is SciPy's older name for the same function and takes the same arguments.

Returns: (w, h), as for freqz.

f, h = system.signal.freqz_sos(sos, worN=[0.2, 1.0], fs=10.0)
gains_db = [20 * math.log10(abs(v)) for v in h] # import math first

Filtering​

FunctionUse
sosfiltfilt(sos, x, ...)Zero-lag filtering with sections: the way to clean history without delay
filtfilt(b, a, x, ...)Zero-lag filtering with (b, a) coefficients
sosfilt(sos, x, zi=None)Causal (real-time) filtering with sections
lfilter(b, a, x, zi=None)Causal filtering with (b, a) coefficients
sosfilt_zi(sos), lfilter_zi(b, a)Initial state that starts a causal filter in steady state

sosfiltfilt and filtfilt​

system.signal.sosfiltfilt(sos, x, axis=-1, padtype='odd', padlen=None)
system.signal.filtfilt(b, a, x, axis=-1, padtype='odd', padlen=None, method='pad', irlen=None)

Filter forwards, then backwards, so the result has no lag: peaks and steps stay where they happened.

ParameterDescription
sos or b, aThe filter. a[0] must not be 0.
xThe signal. It must be longer than padlen.
padtypeEdge extension before filtering: 'odd' (default), 'even', 'constant' or None.
padlenSamples to extend at each end. Default: 3 times the number of filter taps.
methodfiltfilt only: 'pad' (default). 'gust' is not supported.
irlenfiltfilt only: used by 'gust'; accepted for compatibility.

Returns: the filtered signal, a list of floats, in step with the input.

sosfilt and lfilter​

system.signal.sosfilt(sos, x, axis=-1, zi=None)
system.signal.lfilter(b, a, x, axis=-1, zi=None)

Causal filtering: each output uses only the samples before it, so it works in real time and lags the input.

ParameterDescription
sos or b, aThe filter. a may be a number; a[0] must not be 0.
xThe signal (one sample, for live use).
ziThe filter's state: one [z0, z1] row per section for sosfilt, max(len(a), len(b)) - 1 numbers for lfilter. Default None: start from rest.

Returns: the filtered signal; with zi, a tuple (y, zf), where zf is the state to pass as zi next time. Filtering in pieces this way gives exactly the same result as filtering all at once.

sosfilt_zi and lfilter_zi​

system.signal.sosfilt_zi(sos)
system.signal.lfilter_zi(b, a)

The state that starts a causal filter in steady state for a unit step. Multiply it by the first sample to start on a signal without a start-up transient.

Returns: one [z0, z1] row per section (sosfilt_zi), or a list of max(len(a), len(b)) - 1 floats (lfilter_zi).

Smoothing​

savgol_filter​

system.signal.savgol_filter(x, window_length, polyorder, deriv=0, delta=1.0, axis=-1, mode='interp', cval=0.0)

Savitzky-Golay smoothing: fits a polynomial to the samples around each point by least squares and takes its value (or derivative) there. It keeps peak heights and shapes better than a moving average, and gives a smooth rate of change directly.

ParameterDescription
xThe signal.
window_lengthSamples in each fit window, an integer greater than polyorder (at most len(x) in mode 'interp').
polyorderDegree of the fitted polynomial, usually 2 to 4.
deriv0 (default) smooths; 1 gives the rate of change; 2 the curvature.
deltaSample spacing, which scales derivatives into real units: with 2-second samples, delta=2.0 gives units per second.
modeEnds of the signal: 'interp' (default) fits the first and last windows; 'mirror', 'nearest', 'constant' (pads with cval) or 'wrap' (periodic data only).
cvalValue beyond the ends for mode='constant'.

Returns: the smoothed signal, or its derivative, a list of floats. The fits are solved exactly, so results stay correct at high orders where SciPy's lose accuracy.

savgol_coeffs​

system.signal.savgol_coeffs(window_length, polyorder, deriv=0, delta=1.0, pos=None, use='conv')

The Savitzky-Golay weights themselves, to apply yourself: for example, live end-point smoothing of the latest samples.

ParameterDescription
window_length, polyorder, deriv, deltaAs for savgol_filter.
posWhere in the window the polynomial is evaluated. Default: the center. window_length - 1 is the newest sample, for live use.
use'conv' (default): convolution order, newest sample first. 'dot': multiply a window directly, oldest sample first.

Returns: window_length coefficients, correctly rounded. For window 5, order 2 they are -3/35, 12/35, 17/35, 12/35, -3/35.

c = system.signal.savgol_coeffs(21, 2, pos=20, use="dot")
now_smoothed = sum(ci * xi for ci, xi in zip(c, x[-21:])) # x[-21:] oldest to newest

medfilt​

system.signal.medfilt(volume, kernel_size=None)

Median filter: replaces each sample with the median of its window. It removes single-sample spikes and keeps real steps sharp.

ParameterDescription
volumeThe signal. Integers in give integers out.
kernel_sizeWindow length, an odd integer. Default 3. Beyond its ends the signal is padded with zeros, so the first and last kernel_size // 2 samples are pulled toward 0.

Returns: the filtered signal: integers if the input was all integers, otherwise floats.

Peak finding​

find_peaks​

system.signal.find_peaks(x, height=None, threshold=None, distance=None, prominence=None, width=None, wlen=None, rel_height=0.5, plateau_size=None)

Finds local maxima (the middle sample of a flat top), filtered by the conditions given. Each condition is a minimum, or a (min, max) pair in which either may be None.

ParameterDescription
xThe signal.
heightRequired peak height.
thresholdRequired rise above both neighboring samples.
distanceMinimum samples between peaks (1 or more); lower peaks within it are removed first. Equal-height peaks are ranked by position, the later kept.
prominenceRequired prominence: how far a peak stands out from the signal around it. Usually the most useful condition.
widthRequired width in samples, measured at rel_height.
wlenWindow, in samples, for the prominence search. Default None: the whole signal.
rel_heightWhere widths are measured, as a fraction of prominence below the peak. Default 0.5.
plateau_sizeRequired flat-top length, in samples.

Returns: a tuple (peaks, properties): peaks is a list of sample indices; properties is a dict of lists, one entry per peak, holding the measures the conditions needed, such as 'peak_heights', 'prominences', 'left_bases', 'right_bases', 'widths', 'width_heights', 'left_ips' and 'right_ips'.

peaks, props = system.signal.find_peaks(clean, prominence=2.0, distance=300)
for i, p in enumerate(peaks):
print p, clean[p], props["prominences"][i]

peak_prominences​

system.signal.peak_prominences(x, peaks, wlen=None)

How far each peak stands out from its surroundings.

ParameterDescription
xThe signal.
peaksSample indices of the peaks, a list of integers (as find_peaks returns).
wlenSearch window in samples. Default None: the whole signal.

Returns: a tuple (prominences, left_bases, right_bases).

peak_widths​

system.signal.peak_widths(x, peaks, rel_height=0.5, prominence_data=None, wlen=None)

The width of each peak at a height relative to its prominence.

ParameterDescription
x, peaksAs for peak_prominences.
rel_heightHeight to measure at, as a fraction of prominence below the peak. 0.5 (default) gives the width at half prominence; 1.0 at the base.
prominence_dataOptional: the tuple peak_prominences returned, to avoid computing it again.
wlenAs for peak_prominences.

Returns: a tuple (widths, width_heights, left_ips, right_ips); the ips are interpolated sample positions where each width is measured.

Spectral analysis​

welch​

system.signal.welch(x, fs=1.0, window='hann_periodic', nperseg=None, noverlap=None, nfft=None, detrend='constant', return_onesided=True, scaling='density', axis=-1, average='mean')

Power spectral density by Welch's method: the signal is cut into overlapping segments, each windowed and transformed, and their spectra averaged.

ParameterDescription
xThe signal.
fsSampling frequency, in samples per second; must be positive. Frequencies come out in the same unit.
windowA window name such as 'hann', a (name, parameter) tuple, or a list of window values of length nperseg.
npersegSamples per segment. Default 256, or the signal length if shorter. Longer segments give finer frequency resolution.
noverlapSamples shared by neighboring segments. Default: half a segment.
nfftFFT length, at least nperseg; extra length zero-pads, placing a peak between coarse bins. Default nperseg.
detrendPer segment: 'constant' (default), 'linear', or False.
return_onesidedTrue (default): frequencies from 0 to fs/2.
scaling'density' (default: power per Hz) or 'spectrum' (power).
average'mean' (default) or 'median', which resists bursts.

Returns: a tuple (f, Pxx): frequencies and power spectral density, lists of floats.

periodogram​

system.signal.periodogram(x, fs=1.0, window='boxcar', nfft=None, detrend='constant', return_onesided=True, scaling='density', axis=-1)

Power spectral density of the whole signal as one segment. Parameters as for welch, except nfft: by default the signal's length; a larger value zero-pads, a smaller one uses only the first nfft samples.

Returns: a tuple (f, Pxx).

spectrogram​

system.signal.spectrogram(x, fs=1.0, window=('tukey_periodic', 0.25), nperseg=None, noverlap=None, nfft=None, detrend='constant', return_onesided=True, scaling='density', axis=-1, mode='psd')

The spectrum over time: one spectrum per segment. Parameters as for welch, except that noverlap defaults to an eighth of a segment, and:

ParameterDescription
mode'psd' (default), 'complex', 'magnitude', 'angle' or 'phase' (angle unwrapped along frequency).

Returns: a tuple (f, t, Sxx): frequencies, segment center times, and Sxx with one row per frequency and one column per time; complex numbers for mode='complex'.

hilbert​

system.signal.hilbert(x, N=None, axis=-1)

The analytic signal; its absolute value is the amplitude envelope.

ParameterDescription
xThe signal.
NTransform length. Default len(x); a different value truncates or zero-pads the signal.

Returns: a list of complex numbers. [abs(z) for z in result] is the envelope.

Resampling​

resample_poly​

system.signal.resample_poly(x, up, down, axis=0, window=('kaiser', 5.0), padtype='constant', cval=None)

Resamples by the ratio up / down with a polyphase FIR filter. The best general choice for non-periodic signals such as historian data.

ParameterDescription
xThe signal.
up, downUp- and downsampling factors, whole numbers of 1 or more.
windowThe FIR design window, default ('kaiser', 5.0); or the filter's taps as a list of numbers.
padtypeEdge handling: 'constant' (default), 'edge', 'symmetric', 'reflect', 'wrap', 'smooth', 'line', 'antisymmetric', 'antireflect'; or 'mean', 'median', 'minimum', 'maximum', which subtract that value, resample, and add it back.
cvalValue beyond the ends, with padtype='constant' only. Default 0.

Returns: ceil(len(x) * up / down) samples, a list of floats.

decimate​

system.signal.decimate(x, q, n=None, ftype='iir', axis=-1, zero_phase=True)

Applies an anti-aliasing low-pass filter, then keeps every q-th sample.

ParameterDescription
xThe signal.
qThe factor, a whole number. With the IIR filter, keep it at 13 or below and decimate in stages for more (6 then 10, rather than 60).
nFilter order. Default 8 for 'iir', 20 * q for 'fir'.
ftype'iir' (default: Chebyshev type I) or 'fir' (Hamming-windowed).
zero_phaseTrue (default): filter both ways, so there is no lag.

Returns: ceil(len(x) / q) samples, a list of floats.

resample​

system.signal.resample(x, num, t=None, axis=0, window=None, domain='time')

Resamples to num samples using the FFT. It treats the signal as periodic, so it suits periodic data; for other signals use resample_poly.

ParameterDescription
xThe signal.
numNumber of samples in the result, a whole number.
tOptional sample times; only the first two are used. With t, the new times are returned too.
windowOptional spectral window: a name, a (name, parameter) tuple, or a list of len(x) values.
domain'time' (default): x is a signal. 'freq': x is a spectrum in FFT order.

Returns: the resampled signal, a list of floats (complex numbers for domain='freq'); with t, a tuple (signal, new_times).