I am having a hard time figuring out how to employ a high pass filter to remove the DC offset of my data signal with the "scipy butter" function because my sample rate is quite high. The crux of my issue seems to be that my sample rate Fs is very high and my cut off frequency is very low (ideally just the DC offset component, but could be 1 to 10Hz with a sample rate of 125ksps).
Here is my example code:
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
# inital parameters
Fs = 125000 # sample rate (if changed to 125sps looks better)
n = 9 # filter order
Fc = 10 # cut off freq (Hz)
Nyq = Fs/2. # Nyquist freq (1/2 Fs)
Fcc = float(Fc)/float(Nyq) # normalized cut off freq
# find butterworth xfer functions
sos = signal.butter(n, Fcc, btype='hp', output='sos', analog=False)
# find freq/mag
w, h = signal.sosfreqz(sos, worN=1500, fs=Fs)
#convert to log scale
h_db = 20*np.log10(np.abs(h))
# plot filter response
fig1, ax1 = plt.subplots(1, 1)
ax1.plot(0.5*Fs*(w/np.pi), h_db)
ax1.set_title('db log')
plt.show()
I think this is working like it is supposed to because dropping the sample rate down to 125 instead of 125,000 yields a response that looks reasonable. I think I'm missing something fundamental here with the Fc vs Fs.
Here is the response plot:
Here is a screenshot of the data I'm trying to apply this filter to:
As you can see there is a DC offset I'd like to filter out of my data file with a high pass filter. Right now I'm just trying to get the filter response to behave so I'm not worried about processing the data yet - I just added the data file screenshot for reference. I don't need anything fancy. So my questions are the following:
- Why do I have ringing and such an aggressive response?
- How does the low cut off frequency and high sample rate affect the filter response?
- Why did Scipy go from the b,a approach in the butter() filter to the "sos"? I"m curious why they switch to this new sos appraoch. My understanding is that it is more accurate and/or prevents errors in the b,a approach. I'm unsure if this is just bolting second order transfer functions together though cascading simpler filters or what.
- Also, you can notice (if you print(w) to see my freq axis) that my frequencies seem to run from 0 to 2*pi. Is that normal or should it be from 0 to pi?
- If question #4 is is "yes this should be 0 to 2*pi" than should line #23 in script:
actually be
ax1.plot(0.5*Fs*(w/(2*np.pi)), h_db)
so that my frequency range in the final result/plot runs from 0 to 1/2*Fs?
Thanks for any help!