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.
| Parameter | Description |
|---|---|
data | The 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. |
bp | Breakpoints for 'linear': sample indices where a new, independent line starts. An integer or a list. An empty list means none. |
overwrite_data | Accepted 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.
| Parameter | Description |
|---|---|
window | A 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. |
Nx | Number of points, a positive integer. |
fftbins | True (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.
| Function | Character | Extra parameters |
|---|---|---|
butter(N, Wn, ...) | Butterworth: maximally flat passband | none |
cheby1(N, rp, Wn, ...) | Chebyshev type I: ripple in the passband, steeper roll-off | rp: passband ripple, dB |
cheby2(N, rs, Wn, ...) | Chebyshev type II: ripple in the stopband | rs: minimum stopband attenuation, dB |
ellip(N, rp, rs, Wn, ...) | Elliptic (Cauer): the sharpest transition for its order | rp and rs |
bessel(N, Wn, ..., norm='phase') | Bessel: flattest group delay, least overshoot on steps | norm: 'phase' (default), 'delay' or 'mag', what Wn means |
All five also take these parameters, after Wn:
| Parameter | Description |
|---|---|
N | Filter order, a whole number. Up to 500 (Bessel: 100). |
Wn | Critical 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. |
analog | True for an analog filter (Wn in rad/s). Default False. |
output | 'ba' (default), 'zpk' or 'sos'. |
fs | Sampling 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:
| Parameter | Description |
|---|---|
wp | Passband 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. |
ws | Stopband edge, in the same form and units as wp. |
gpass | Maximum loss in the passband, in dB. |
gstop | Minimum attenuation in the stopband, in dB. |
analog | True for an analog filter (frequencies in rad/s). Default False. |
fs | Sampling 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).
| Parameter | Description |
|---|---|
b, a | Numerator and denominator coefficients. a defaults to 1. |
worN | Number of frequencies (default 512), or a list of frequencies to evaluate, in the units of fs. |
whole | True to cover 0 to fs instead of 0 to fs/2. |
plot | Must be None: plot w and h from the result instead. |
fs | Sampling frequency; the default 2π gives frequencies in rad/sample. |
include_nyquist | True 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
| Function | Use |
|---|---|
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.
| Parameter | Description |
|---|---|
sos or b, a | The filter. a[0] must not be 0. |
x | The signal. It must be longer than padlen. |
padtype | Edge extension before filtering: 'odd' (default), 'even', 'constant' or None. |
padlen | Samples to extend at each end. Default: 3 times the number of filter taps. |
method | filtfilt only: 'pad' (default). 'gust' is not supported. |
irlen | filtfilt 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.
| Parameter | Description |
|---|---|
sos or b, a | The filter. a may be a number; a[0] must not be 0. |
x | The signal (one sample, for live use). |
zi | The 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.
| Parameter | Description |
|---|---|
x | The signal. |
window_length | Samples in each fit window, an integer greater than polyorder (at most len(x) in mode 'interp'). |
polyorder | Degree of the fitted polynomial, usually 2 to 4. |
deriv | 0 (default) smooths; 1 gives the rate of change; 2 the curvature. |
delta | Sample spacing, which scales derivatives into real units: with 2-second samples, delta=2.0 gives units per second. |
mode | Ends of the signal: 'interp' (default) fits the first and last windows; 'mirror', 'nearest', 'constant' (pads with cval) or 'wrap' (periodic data only). |
cval | Value 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.
| Parameter | Description |
|---|---|
window_length, polyorder, deriv, delta | As for savgol_filter. |
pos | Where 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.
| Parameter | Description |
|---|---|
volume | The signal. Integers in give integers out. |
kernel_size | Window 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.
| Parameter | Description |
|---|---|
x | The signal. |
height | Required peak height. |
threshold | Required rise above both neighboring samples. |
distance | Minimum samples between peaks (1 or more); lower peaks within it are removed first. Equal-height peaks are ranked by position, the later kept. |
prominence | Required prominence: how far a peak stands out from the signal around it. Usually the most useful condition. |
width | Required width in samples, measured at rel_height. |
wlen | Window, in samples, for the prominence search. Default None: the whole signal. |
rel_height | Where widths are measured, as a fraction of prominence below the peak. Default 0.5. |
plateau_size | Required 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.
| Parameter | Description |
|---|---|
x | The signal. |
peaks | Sample indices of the peaks, a list of integers (as find_peaks returns). |
wlen | Search 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.
| Parameter | Description |
|---|---|
x, peaks | As for peak_prominences. |
rel_height | Height 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_data | Optional: the tuple peak_prominences returned, to avoid computing it again. |
wlen | As 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.
| Parameter | Description |
|---|---|
x | The signal. |
fs | Sampling frequency, in samples per second; must be positive. Frequencies come out in the same unit. |
window | A window name such as 'hann', a (name, parameter) tuple, or a list of window values of length nperseg. |
nperseg | Samples per segment. Default 256, or the signal length if shorter. Longer segments give finer frequency resolution. |
noverlap | Samples shared by neighboring segments. Default: half a segment. |
nfft | FFT length, at least nperseg; extra length zero-pads, placing a peak between coarse bins. Default nperseg. |
detrend | Per segment: 'constant' (default), 'linear', or False. |
return_onesided | True (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:
| Parameter | Description |
|---|---|
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.
| Parameter | Description |
|---|---|
x | The signal. |
N | Transform 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.
| Parameter | Description |
|---|---|
x | The signal. |
up, down | Up- and downsampling factors, whole numbers of 1 or more. |
window | The FIR design window, default ('kaiser', 5.0); or the filter's taps as a list of numbers. |
padtype | Edge 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. |
cval | Value 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.
| Parameter | Description |
|---|---|
x | The signal. |
q | The 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). |
n | Filter order. Default 8 for 'iir', 20 * q for 'fir'. |
ftype | 'iir' (default: Chebyshev type I) or 'fir' (Hamming-windowed). |
zero_phase | True (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.
| Parameter | Description |
|---|---|
x | The signal. |
num | Number of samples in the result, a whole number. |
t | Optional sample times; only the first two are used. With t, the new times are returned too. |
window | Optional 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).