buttap#
- scipy.signal.buttap(N, *, xp=None, device=None)[source]#
Return (z, p, k) for analog prototype of Nth-order Butterworth filter.
The filter will have an angular (e.g., rad/s) cutoff frequency of 1.
- Parameters:
- Nint
The order of the filter
- xparray_namespace, optional
Optional array namespace. Should be compatible with the array API standard, or supported by array-api-compat. Default:
numpy- deviceany
optional device specification for output. Should match one of the supported device specification in
xp.
- Returns:
- zndarray[float64]
Zeros of the transfer function. Is always an empty array.
- pndarray[complex128]
Poles of the transfer function as an
(N,)array.- kfloat
Gain of the transfer function, which is always one.
See also
butterFilter design function using this prototype
Notes
Here, a cutoff frequency of \(\omega_c = 1\,\)rad/s and a gain of \(k=1\) are assumed. The transfer function can be expressed as [1]
\[H(s) = k \prod_{l=0}^{N-1} \frac{\omega_c}{s - p_l} \quad\text{with poles}\quad p_l = -\omega_c\exp\!\left\{ j\pi\frac{2l+1-N}{2N} \right\} \,.\]Hence, this function returns no zeros and N poles. Note that the poles are ordered in a way so that the
l-th and(N-1-l)-th pole are complex conjugates of each other. Furthermore, if N is odd, then the(N//2)-th pole is always \(-1\).Array API Standard Support
buttaphas support for Python Array API Standard compatible backends in addition to NumPy. The following combinations of backend and device (or other capability) are supported.Library
CPU
GPU
NumPy
✅
n/a
CuPy
n/a
✅
PyTorch
✅
✅
JAX
✅
✅
Dask
✅
n/a
See Support for the array API standard for more information.
References
[1]“Butterworth filter”, Wikipedia, https://en.wikipedia.org/wiki/Butterworth_filter
Examples
Compute the zeros, poles, and gain of a 2nd-order Butterworth analog lowpass prototype with a cutoff frequency of 1 rad/s:
>>> from scipy.signal import buttap >>> z, p, k = buttap(2) >>> z array([], dtype=float64) >>> p array([-0.70710678+0.70710678j, -0.70710678-0.70710678j]) >>> k 1.0
Bode plot of the frequency response of a 3rd-order prototype:
>>> import numpy as np >>> import matplotlib.pyplot as plt >>> from scipy.signal import freqs_zpk, buttap ... >>> z, p, k = buttap(3) >>> f = np.geomspace(1e-1, 1e1, 200) >>> _, h = freqs_zpk(z, p, k, worN=f) >>> h_db, h_ph = 20 * np.log10(np.abs(h)), np.unwrap(np.angle(h)) ... >>> _, (ax0, ax1) = plt.subplots(2, 1, sharex='all', constrained_layout=True) >>> ax0.set(title='3rd-order Butterworth prototype', ylabel='Magnitude in dB', ... yticks=[-60, -40, -20, 0]) >>> ax0.semilogx(f, h_db, 'C0', label='Magnitude') >>> ax1.set(ylabel="Phase in radians", xlabel="Frequency in rad/s", ... yticks=np.pi*np.arange(-1.5, 0.5, 0.5), ylim=(-1.5*np.pi, 0), ... yticklabels=[r'-3$\pi$/2', r'-$\pi$', r'-$\pi$/2', '0'], ... xlim=(f[0], f[-1])) >>> ax1.semilogx(f, h_ph, 'C1', label='Phase') >>> for ax_ in (ax0, ax1): ... ax_.axvline(1.0, color='C2', ls='--', alpha=.5, label='Cutoff frequency') ... ax_.grid(True, which='both') ... ax_.legend() >>> plt.show()