# 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

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)