I have to bandpass-filter a signal which has been sampled with 4000 Hz.
Only frequencies around 15 Hz shall remain after filtering (let's say in a band between 10 Hz and 20 Hz; the narrower the better).
I have several questions here:
- What is the recommended way to perform tasks like this?
What bandpass filter is suitable?
Do I need to downsample the signal before filtering. If yes, what type of additional low pass filter should I use to avoid aliasing?
In my case, it is important that the phase of the original signal will not be distorted or shifted in the whole process. Furthermore, the filter step response should have close to zero overshoot. The settling time could therefore be a little larger.
I do not want to perform a sophisticated filter design which delivers optimal results for exactly this specific signal. I am more interested in a general solution that delivers solid results using standard IIR or FIR filters (e. g. as available in Python's SciPy library) which could be reused afterwards for similar tasks.
After the answer of @MarcusMüller and the provided links, I basically tried every FIR filter design method available in Python's
SciPy library and deciced to go with
remez. I developed the following code which may be used for further discussion:
import math import matplotlib.pyplot as plt import numpy as np from scipy.signal import lfilter, remez F_test = 20.0 duration = 10.0 fs = 8000 samples = int(fs*duration) t = np.arange(samples) / fs signal_test = (5.0 * t * np.sin(2.0*np.pi*F_test*t)) + (0.5 * np.sin(2.0*np.pi*5.0*t)) + (0.5 * np.sin(2.0*np.pi*100.0*t)) #design filter ntaps = 5000 edges = [0, F_test - 5.0, F_test - 2.5, F_test + 2.5, F_test + 5.0, 0.5 * fs] taps = remez(ntaps, edges, [0, 1, 0], Hz=fs, maxiter=2500) #apply filter signal_test_filtered = lfilter(taps, 1, signal_test) #create plot fig = plt.figure() ax0 = fig.add_subplot(111) ax0.plot(t, signal_test_filtered, label='signal_test_filtered') ax0.set_xlabel("time [s]") ax0.legend() fig.show()