# Unexpected peaks in power density following downsampling and filtering

I first applied a 100 Hz lowpass filter to my data, which was recorded at 30000 Hz:

import numpy as np
from scipy import signal as ss
from scipy.signal import butter, lfilter, freqz
import matplotlib.pyplot as plt

def butter_lowpass(low_cutoff, fs, order=5):
nyq = 0.5 * fs
normal_low_cutoff = low_cutoff / nyq
b_low, a_low = butter(order, normal_low_cutoff, btype='lowpass', analog=False)
return b_low, a_low

def butter_lowpass_filter(data, low_cutoff, fs, order=5):
b_low, a_low = butter_lowpass(low_cutoff, fs, order=order)
y_low = ss.lfilter(b_low, a_low, data)
return y_low

# Filter requirements.
order = 5
fs = 30000      # sample rate, Hz
low_cutoff = 100 # desired cutoff frequency of the filter, Hz

print('Filtering data')
filtered_array = butter_lowpass_filter(array, low_cutoff, fs, order)


Then I down sampled my data from 30000 Hz to 250 Hz

updated_array=ss.decimate(filtered_array, 12, ftype = 'fir')
newarray = ss.decimate(updated_array,10, ftype = 'fir')


And then apply the decimated result to a spectrogram:

frequencies, time, Sxx = ss.spectrogram(newarray,sampling_rate, ss.get_window('hamming', bin_size), noverlap=0, nfft=sampling_rate*4)


However, the resulted plot showed some signal higher than 100Hz even though I already used a lowpass 100Hz filter earlier. For reference, this is the plot if the filter was not sed before decimation: Is there any explanation for this?

Thanks a lot!

• well the 2nd plot shows that the interference is in your original signal, so the filtering code has nothing to do with it, right? – endolith May 19 '18 at 0:44
• Seems to be the case. My main concern is to investigate whether the post-20 Hz spikes originate from my code. If filtering is not the source of the problem, can downsampling (by decimation) and spectrogram generate falsely high signals? It may also be the case of mains interferences but I just want to make sure that the code is working as intended – T.Tran May 19 '18 at 8:48
• isn't your last plot a spectrum of the original signal? what code did you use to plot it? if not, plot that first – endolith May 20 '18 at 12:29
• The last plot is the result of decimating the original signal and turn it into a spectrogram, without the filtering process at all. In essence, I just wish to find out what could lead to the generation of the false peaks observed at >20Hz frequencies. – T.Tran May 20 '18 at 13:20
• Well you have to figure out if they're in the original signal or if they're being generated by the decimation, so plot the spectrum of the original signal. plt.semilogx(20*log10(abs(scipy.fftpack.rfft(signal)))) – endolith May 21 '18 at 13:35

## 1 Answer

2 comments:

First, scipy signal decimate already low-pass filters the signal. It first filters the signal and then subsamples. So there is no need to pre-filter your signal before decimation. In your case, the signal is filtered at 125 Hz, which is half the resulting sampling frequency. (decimate doc here)

Second, a Butterworth filter is not an ideal filter. This filter will have a 3dB attenuation at the cutoff frequency, no matter the order of the filter. So you are expected to have components remaining between 100 Hz and 125 Hz.

If you want nothing detectable above 100 Hz, then design a filter with stop-band at 100 Hz and sufficient attenuation. This will result in a cutoff frequency below 100 Hz.

Depending on your requirements, an elliptic or Chebyshev filter will result in a narrower transition than a Butterworth of the same order.

• First of all, thanks a lot! I also want to take this chance to ask if any of the functions I used could generate false spikes? My data only supposed to have the spikes before 10 Hz; so all the spikes that you can see after 20 Hz are false. – T.Tran May 18 '18 at 19:02
• Spikes at 50 Hz and 100 Hz may be mains interference (depending on mains frequency on your country). Not knowing the nature of your signal nor your aquisition setup, it's difficult to explain those artifacts. – Juancho May 18 '18 at 19:31