I want to use a low pass Butterworth filter on my data but on applying the filter I don't get the intended signal. Here is the dummy code:

Signal A:

import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
a = np.linspace(0,1,1000)
signala = np.sin(2*np.pi*100*a) # with frequency of 100

Signal B:

signalb = np.sin(2*np.pi*20*a) # frequency 20

Let's combine signal A and B now to get signal C

signalc = signala + signalb

The resultant signal C looks like this

enter image description here

Let's now apply the filter:

b, a = signal.butter(5, 30, 'low', analog = True) #first parameter is signal order and the second one refers to frequenc limit. I set limit 30 so that I can see only below 30 frequency signal component
output = signal.filtfilt(b, a, signalc)

On applying above butter filter, I get an empty plot as

enter image description here

I don't understand where I am doing wrong? Any help will be appreciated.

  • $\begingroup$ I'd just like to point out, that if anyone is unsure about how to normalize properly the frequency of cutoff just by reading the doc (like me), you can just pass the sampling frequency fs as an argument in the butter function and it will take care of the normalization for you : scipy.signal.butter(N, Wn, btype='low', analog=False, output='ba', fs=None) $\endgroup$
    – Johncowk
    Mar 6, 2019 at 12:10

3 Answers 3


You should not be using the analog filter - use a digital filter instead. You want the filter to be defined in Z-domain, not S-domain. Also, you should define the time vector with known sampling frequency to avoid any confusion.

The design of the digital filter requires cut-off frequency to be normalized by fs/2.

Here is a working example:

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

fs = 1000  # Sampling frequency
# Generate the time vector properly
t = np.arange(1000) / fs
signala = np.sin(2*np.pi*100*t) # with frequency of 100
plt.plot(t, signala, label='a')

signalb = np.sin(2*np.pi*20*t) # frequency 20
plt.plot(t, signalb, label='b')

signalc = signala + signalb
plt.plot(t, signalc, label='c')

fc = 30  # Cut-off frequency of the filter
w = fc / (fs / 2) # Normalize the frequency
b, a = signal.butter(5, w, 'low')
output = signal.filtfilt(b, a, signalc)
plt.plot(t, output, label='filtered')

enter image description here

  • $\begingroup$ Could you please suggest how I can do this on the list of xy coordinates? $\endgroup$ Jun 10, 2020 at 8:21

As stated by jojek, Normalization of frequency values by the Nyquist frequency ( f = f / (fs/2) ) is needed as well as 'analog = False' option in the signal.butter function. i.e.,

`b, a = signal.butter(5, 30/(fs/2), 'low', analog = False) `

Here is how I apply a low pass Butterworth filter in Python, but form a first signal and then by providing a cutoff frequency and an order (the order acts somehow like cutoff "sharpness"):

def butter_lowpass(cutoff, nyq_freq, order=4):
    normal_cutoff = float(cutoff) / nyq_freq
    b, a = signal.butter(order, normal_cutoff, btype='lowpass')
    return b, a

def butter_lowpass_filter(data, cutoff_freq, nyq_freq, order=4):
    # Source: https://github.com/guillaume-chevalier/filtering-stft-and-laplace-transform
    b, a = butter_lowpass(cutoff_freq, nyq_freq, order=order)
    y = signal.filtfilt(b, a, data)
    return y

Source: https://github.com/guillaume-chevalier/filtering-stft-and-laplace-transform


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.