Thanks to visit codestin.com
Credit goes to github.com

Skip to content

bugfix: scaling of windows with negative coefficients #22828

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

lucasisonline
Copy link

PR Summary

The magnitude scaling is incorrect for windows with negative coefficients.

For proper scaling of the magnitude a division by the sum
of all window elements is needed.
To be able to handle complex window coefficients an abs()
was introduced in 76c4d84
which falsifies the scaling for windows with negative
coefficients. Most prominently the flattop window.

A proper type check is introduced to handle both cases
correctly.

PR Checklist

Tests and Styling

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (install flake8-docstrings and run flake8 --docstring-convention=all).

Documentation

  • New features are documented, with examples if plot related.
  • New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).

For proper scaling of the magnitude a division by the sum
of all window elements is needed.
To be able to handle complex window coefficients an abs()
was introduced in a622508
which falsifies the scaling for windows with negative
coefficients. Most prominently the flattop window.

A proper type check is introduced to handle both cases
correctly.
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for opening your first PR into Matplotlib!

If you have not heard from us in a while, please feel free to ping @matplotlib/developers or anyone who has commented on the PR. Most of our reviewers are volunteers and sometimes things fall through the cracks.

You can also join us on gitter for real-time discussion.

For details on testing, writing docs, and our review process, please see the developer guide

We strive to be a welcoming and open project. Please follow our Code of Conduct.

@oscargus
Copy link
Member

oscargus commented Apr 11, 2022

Thanks! Makes sense!

It would be good with a test for this so that it is not reintroduced. (Maybe it is a good idea to use the tests introduced in #8582, but not remove the ticklabels so that one actually see the effect of normalizing correctly.)

@tacaswell
Copy link
Member

@oscargus Can you please be in charge of final approval on this one? My biggest concern is that this is the correct (from a domain expect point of view) thing to do.

@tacaswell tacaswell added this to the v3.6.0 milestone Apr 11, 2022
@lucasisonline
Copy link
Author

Hello @oscargus,
while running the test from #8582 I noticed an inconcitenciy in the scaling for onesided/twosided. Only for the "psd" mode a proper physical scaling is done for "onesided". For all other modes, like "magnitude", it is not.
For PSD it correctly converts V -> Vrms², but for magnitude it converst V->V/2 in the "onesided" mode.
It is also contrary to the behaviour of numpy.fft.rfft which might be confusing to some.
What is best practice here? To open a issue to discuss this topic? More changes to the code will be required.

@jklymak
Copy link
Member

jklymak commented Apr 12, 2022

This needs a test, preferable for the flattop window. I don't fully parse the second point other than to note that one-sided spectra should definitely have twice the amplitude of the one side to account for the implied variance of the y shown negative side.

As noted a few times Matplotlib should spin power spectra functionality out to a separate project and deprecate as a main library. It's pretty orthogonal to plotting and complicated enough that it deserves its own proper sets of docs and testing.

@jklymak
Copy link
Member

jklymak commented Apr 12, 2022

Btw, yes, open a separate issue for the magnitude related issue.

@oscargus
Copy link
Member

Here is my take on the window aspect. The reason for scaling the window should be that the gain in the passband should be one. This is obtained by normalizing with abs(sum(window taps)), assuming that it is a "lowpass" window (as we set the DC gain to be one). Hence, I would even claim that the complex values windows should be normalized in this way. Unless, of course, the reason to use a complex window is that it is not "lowpass" anymore.

Regarding PSD, I do not have that strong opinions/knowledge, so I do not have much to add there. I can see both arguments being relevant. So better to open a new issue for that.

@jklymak
Copy link
Member

jklymak commented Apr 12, 2022

The window in spectral analysis is multiplied by the whole data block. It is not convolved with the data like a filter. The variance of the data block before and after should be the same if the underlying process variance is not changing with time (stationary).

I don't understand who uses complex windows or why. You likely would not use it for a single power spectra and I'm not sure what the convention should be.

@QuLogic QuLogic modified the milestones: v3.6.0, v3.7.0 Aug 24, 2022
@tacaswell tacaswell modified the milestones: v3.7.0, v3.8.0 Dec 21, 2022
@tacaswell
Copy link
Member

@oscargus I've pushed this to 3.8, please push back to 3.7 if you think this should go in.

@jklymak
Copy link
Member

jklymak commented Jan 26, 2023

I think this fix is OK for a magnitude spectrum, but definitely not for power spectral density. At least according to the script implementation. But unless I'm reading it wrong our psd option is wildly incorrect. This whole functionality should be removed, and I don't think it should wait for a package to replace it - it is verifiably wrong and there are existing libraries (scipy) that do the work.

@jklymak
Copy link
Member

jklymak commented Jan 30, 2023

I checked this, and so far as I can tell in #24821 the window including flattop is being applied correctly. Moving to draft until further clarification...

@jklymak jklymak marked this pull request as draft January 30, 2023 23:15
Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the same error occurs in the psd code.

The source of the idea you can have a complex window would be interesting - I suspect this was just an error that was not caught because most windows are >0.

This all definitely needs tests. I would suggest simple mean of the spectra of Gaussian random numbers for different windows, including flattop.

@@ -395,7 +395,11 @@ def _spectral_helper(x, y=None, NFFT=None, Fs=None, detrend_func=None,
elif mode == 'psd':
result = np.conj(result) * result
elif mode == 'magnitude':
result = np.abs(result) / np.abs(window).sum()
result = np.abs(result)
if np.iscomplexobj(window):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need to check for complex windows here.

@melissawm
Copy link
Member

👋🏻 Hi @lucasisonline ! Can we help you move this forward? If you have questions, feel free to ping. Thanks!

@ksunden ksunden modified the milestones: v3.8.0, future releases Aug 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Waiting for author
Development

Successfully merging this pull request may close these issues.

7 participants