Skip to main content
`Ctrl`+`K`
scipy.signal.

# bilinear_zpk

scipy.signal.bilinear_zpk(z, p, k, fs)

  Return a digital IIR filter from an analog one using a bilinear transform.

  Transform a set of poles and zeros from the analog s-plane to the digital z-plane using Tustin’s method, which substitutes `2*fs*(z-1) / (z+1)` for `s`, maintaining the shape of the frequency response.

  Parameters:
    z array_like

      Zeros of the analog filter transfer function.

    p array_like

      Poles of the analog filter transfer function.

    k float

      System gain of the analog filter transfer function.

    fs float

      Sample rate, as ordinary frequency (e.g., hertz). No prewarping is done in this function.

  Returns:
    z ndarray

      Zeros of the transformed digital filter transfer function.

    p ndarray

      Poles of the transformed digital filter transfer function.

    k float

      System gain of the transformed digital filter.

  See also

  `lp2lp_zpk`, `lp2hp_zpk`, `lp2bp_zpk`, `lp2bs_zpk`
  `bilinear`

  Notes

  Added in version 1.1.0.

  Array API Standard Support

  `bilinear_zpk` has experimental support for Python Array API Standard compatible backends in addition to NumPy. Please consider testing these features by setting an environment variable `SCIPY_ARRAY_API=1` and providing CuPy, PyTorch, JAX, or Dask arrays as array arguments. The following combinations of backend and device (or other capability) are supported.

  Library | CPU | GPU
  --- | --- | ---
  NumPy | ✅ | n/a
  CuPy | n/a | ✅
  PyTorch | ✅ | ✅
  JAX | ⚠️ no JIT | ⛔
  Dask | ⚠️ computes graph | n/a

  > See Support for the array API standard for more information.

  Examples

      >>> import numpy as np
      >>> from scipy import signal
      >>> import matplotlib.pyplot as plt

      >>> fs = 100
      >>> bf = 2 * np.pi * np.array([7, 13])
      >>> filts = signal.lti(*signal.butter(4, bf, btype='bandpass', analog=True,
      ...                                   output='zpk'))
      >>> filtz = signal.lti(*signal.bilinear_zpk(filts.zeros, filts.poles,
      ...                                         filts.gain, fs))
      >>> wz, hz = signal.freqz_zpk(filtz.zeros, filtz.poles, filtz.gain)
      >>> ws, hs = signal.freqs_zpk(filts.zeros, filts.poles, filts.gain,
      ...                           worN=fs*wz)
      >>> plt.semilogx(wz*fs/(2*np.pi), 20*np.log10(np.abs(hz).clip(1e-15)),
      ...              label=r'$|H_z(e^{j \omega})|$')
      >>> plt.semilogx(wz*fs/(2*np.pi), 20*np.log10(np.abs(hs).clip(1e-15)),
      ...              label=r'$|H(j \omega)|$')
      >>> plt.legend()
      >>> plt.xlabel('Frequency [Hz]')
      >>> plt.ylabel('Amplitude [dB]')
      >>> plt.grid(True)