New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Doc mention cutoff frequency correction for signal.filtfilt #9371
Comments
Incidently, I think there is a mistake in the In the source, the low-pass filter is defined with the cutoff frequency Here is a minimal example demonstrating the difference: import numpy as np
import scipy.signal
import matplotlib.pyplot as plt
x = np.linspace(0, 100, 1001)
fs = 1/(x[1] - x[0]) # sampling frequency
f1 = 0.001*fs
y = 2*np.sin(2*np.pi*f1 * x) # sine with 1000 points per cycle
y += 0.5*np.sin(2*np.pi*10*f1 * x) # sine with 100 points per cycle
## Minimal scipy.signal.decimate
def good_dec(x, q, n=8):
filtered = scipy.signal.filtfilt(*scipy.signal.cheby1(n, 0.05, 1 / (0.8 * q)), x)
return filtered[::q]
def bad_dec(x, q, n=8):
filtered = scipy.signal.filtfilt(*scipy.signal.cheby1(n, 0.05, 0.8 / q), x)
return filtered[::q]
## Decimate
fact = 100 # only the first sine will survive
xd = x[::fact]
yc = good_dec(y, fact)
yb = bad_dec(y, fact)
fig,ax = plt.subplots(figsize=(16,12))
ax.plot(x, y, label="raw", linestyle="-", linewidth=2)
ax.plot(xd, yc, label="f0/0.8: r={}".format(fact), linestyle=":", linewidth=3)
ax.plot(xd, yb, label="f0*0.8: r={}".format(fact), linestyle="--", linewidth=3)
ax.set_xlabel("time")
ax.legend()
ax.set_xlim(0,100) The decimation process with the correct frequency cutoff seems to give a better result than the current implementation. I could not find any reference for the choice of |
Please notice that the 0.8 correction is valid only for a Butterworth filter. Other filters should use different correction values. |
I see two possibilities. One is that it's a typo. The other is that it's not related to the One option to move forward would be to open a PR and see if any existing tests break. Then extend the existing demos here to show that using the reciprocal of the correct value works better. While we're at it, I'm not sure why we bother going through And really we should probably use |
@larsoner You can find a reference to the 0.8 correction factor in page 69 of this book: This is a screenshot of the relevant paragraph: Section 2.6 of this paper also discuss the effects of filtfilt (how one should report its use, etc.). Perhaps the documentation should point to this paper. |
This site mention the correction factor also (but use it like this c_butter = 1/C ). And reference to this paper. All references I seen is for lowpass filters (f_c_low = f_wanted / C). Now my quest is what about highpass filters? I have tested and found that by inverting C I get an rather good response (f_c_high = f_wanted * C), but is this correct? Thanks for det book reference @aweinstein, does it state anything about highpass filters? |
For a Butterworth high-pass filter, the correction factor would be f_c_low = C*f_wanted . For |
I dug some deeper into this cutoff correction, and realised that the correction factor should NOT be applied directly on the cutoff frequency, i.e. f_c_low = f_wanted / C is incorrect. I find this so interesting that i wrote an article on codeproject to highlight this issue. |
@Xurotash So the CORRECT corrected cutoff frequency is: |
This issue is related to #9402 on signal attenuation in |
@piecot that one has to do with the DC component being affected by the Chebychev ripple, whereas this issue has to do with a frequency correction term for low-pass filter design when you know you will do two-pass filtering. So to summarize the bugs:
If someone can find the correction term for Chebychev filters, we can at least take care of points 1-3. |
The IIR filter parameters in As noted in #5392, Matlab's decimate offers only To the original bug report: to design a cheby1 filter for |
The
filtfilt
function runs two filters to cancel the phase shift. Hence to compensate for the twice -3dB attenuation, one should define a higher cutoff frequency equal tof_c = f_wanted / 0.8
. See explanations in https://nbviewer.jupyter.org/github/demotu/BMC/blob/master/notebooks/DataFiltering.ipynb, Cell[8]This should be mentioned in the doc and the examples changed appropriately for filtfilt and lfilter
Simple example:
The amplitude of the single pass
lfilter
(yellow) is comparable to thefiltfilt
with the corrected cutofff0/0.8
(red).On python3.7, Scipy 1.1
The text was updated successfully, but these errors were encountered: