# Apply Low pass Butterworth filter in Python

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
plt.plot(signala)


Signal B:

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


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

signalc = signala + signalb
plt.plot(signalc)


The resultant signal C looks like this 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)
plt.plot(output)


On applying above butter filter, I get an empty plot as I don't understand where I am doing wrong? Any help will be appreciated.

• 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) – Johncowk Mar 6 '19 at 12:10

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')
plt.legend()
plt.show() • Could you please suggest how I can do this on the list of xy coordinates? – user1241241 Jun 10 '20 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