-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
ENH: sosfreqz #6328
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
ENH: sosfreqz #6328
Conversation
Thanks for picking this up! I got sucked down a rabbit hole when trying to make this part of gh-6059, which I will now ramble on about: Basically, I was thinking it would be good if proper SOS and ZPK frequency responses could just live behind I.e., we specify the SOS arrays as arrays of shape All this is to say: we probably do indeed need this, and the more accurate |
Maybe just for now we do the SOS, and then someone else can make public the improved ZPK one?
Yeah I would like to see that, too, but I worry about holding this one up to wait on it. Are you okay going forward with |
Sorry for being unclear, this is what I was getting at. I agree that this PR should happen sooner rather than later. |
`scipy.signal` improvements | ||
--------------------------- | ||
|
||
The funtion `scipy.signal.sosfreqz` was added to compute the frequency |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function
Eric, thanks for picking this up. The changes look good; I made a few suggestions in the code. My PR was pretty close to ready. The main issue (which I agree with) was the API. I copied it from |
@WarrenWeckesser any idea how your changes could have broken some |
I removed the |
N = 500 | ||
order = 25 | ||
Wn = 0.15 | ||
mpmath.mp.dps = 80 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Eric89GXL: I think the test failure comes from increasing the dps here. mpmath
uses a global precision and running test_hyp0f1_gh5764
with a dps of 80 fails. IOW test_hyp0f1_gh5764
is bad... but at low precision mpmath happens to be bad in the same way.
I bet restoring the original precision at the end of test_sos_freqz_against_mp
will fix the problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh I tried to find some global setting but missed this. Thanks for finding it, I'll set it back
Wn = 0.15 | ||
old_dps = mpmath.mp.dps | ||
mpmath.mp.dps = 80 | ||
try: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW the mpmath.workdps
context manager is nice for doing this sort of thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, I'll put that in
Yes. One more or less is not going to make the difference, and this is functionality that is needed. |
a digital filter, compute the frequency response of the system function:: | ||
|
||
B0(z)*B1(z)*...*B{n-1}(z) | ||
H(z) = ------------------------- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about
B0(z) B1(z) B{n-1}(z)
H(z) = ----- * ----- * ... * ---------
A0(z) A1(z) A{n-1}(z)
to imply the stages being calculated separately and then combined?
Also would it be worth showing a higher-order filter that becomes garbled with freqz, showing them side-by-side to illustrate why sos is beneficial? |
>>> sos = signal.ellip(8, 0.5, 60, (0.2, 0.4), btype='bandpass', | ||
... output='sos') | ||
|
||
Compute the frequency response on a grid of 1500 points. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Compute the frequency response at 1500 points from DC to Nyquist.
?
Also would it make sense to have a parameter that makes it output the responses for each stage separately, so you can plot them individually? https://en.wikibooks.org/wiki/Signals_and_Systems/Second_Order_Transfer_Function#Amplitude_Responses You can break up the sos array and do it yourself, but a function would be more convenient. This looks fine to me otherwise. |
|
||
sos, n_sections = _validate_sos(sos) | ||
if n_sections == 0: | ||
raise ValueError('Cannot compute frequencies with no sections') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should freqz([], [], worN=10)
raise a ValueError
, too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps, but it might be a backward incompatible change...?
Suggested changes in endolith@b35fbc6 |
Mpmath computes the test values in `test_mpmath:test_hyp0f1_gh5764` correctly at small dps, incorrectly at medium dps, and then correctly again at large dps. This sets the dps to be high to avoid confusion. See scipy#6328 (comment).
Thanks @endolith cherry-picked and updated. Based on the comments I think this should be mergeable. If anyone else wants to look again (or wants me to wait) feel free, otherwise I'll put it in next week. |
For testing, you could generate some high-order filters as SOS and then check that sosfreqz is within bounds for what the filter should do, like the plots and tests for these:
|
@endolith commit added, see if you're happy now |
Mpmath computes the test values in `test_mpmath:test_hyp0f1_gh5764` correctly at small dps, incorrectly at medium dps, and then correctly again at large dps. This sets the dps to be high to avoid confusion. See scipy#6328 (comment).
I started modifying the test cases to make them more extreme (so that sosfreqz could handle them but freqz couldn't) but one of them fails, and I don't know if it's
equiripple should be below -150 dB, but it's more like -147: |
@endolith wrote:
That's also what |
anyway these are the checks I made:
|
Change equation format to clarify stages Italicize variables Clarify output complex format Remove obsolete plot= description Increase order of example filter to highlight benefits of SOS Add an example of same-order filter implemented as single stage
Thanks @endolith added your tests (after making the problematic If there are no other comments I'll merge in a couple of days. |
Thanks for the reviews |
I had no idea how close to mergeable @WarrenWeckesser's #4465 was. This should be ready for review/merge, I just rebased and tweaked the release notes.