Skip to content

DynamicalPowerspectrum and DynamicalCrossspectrum cannot select the per-segment mean (use_common_mean) - #987

Open
bjricketts wants to merge 5 commits into
StingraySoftware:mainfrom
bjricketts:dyn_ps_mean_fix
Open

bjricketts wants to merge 5 commits into
StingraySoftware:mainfrom
bjricketts:dyn_ps_mean_fix

Conversation

@bjricketts

Copy link
Copy Markdown
Contributor

Relevant Issue(s)/PR(s)

Closes #986

Provide an overview of the implemented solution or the fix and elaborate on the modifications.

AveragedPowerspectrum and AveragedCrossspectrum already take use_common_mean. The dynamical classes build their matrix from those objects but never accepted or passed the flag, so every column was normalised by the mean count rate of the whole observation and the per-segment option was unreachable. This adds the argument to both classes and passes it through. The default is True, so existing behaviour is unchanged.

With norm="frac" and use_common_mean=False, each column is normalised by its own mean count rate, which is what you want when comparing the columns with each other: a change in count rate at constant fractional rms, as produced by a linear rms-flux relation, no longer rescales the matrix.

Changes:

  • DynamicalCrossspectrum.__init__ and DynamicalPowerspectrum.__init__ take use_common_mean=True and store it; _make_matrix passes it to the averaged spectrum.
  • Docstrings: use_common_mean is documented as a parameter and an attribute, and the norm entry now says which mean the normalisation uses.
  • unnorm_conversion is a per-segment array when use_common_mean=False. This factor converts normalised back to unnormalised powers and is used by compute_rms; with a per-segment mean it differs from segment to segment, so the previous np.nanmean(conv) over the whole matrix would have made compute_rms wrong. It is constant across frequency within a segment, so the mean over frequency is exact. The scalar is kept when use_common_mean=True.
  • compute_rms indexes that factor per segment, so its result is now independent of the flag (there is a test for this). rebin_time and rebin_by_n_intervals carry the array along so it stays the same length as the time axis.
  • DynamicalPowerspectrum.power_colors warns when use_common_mean=False and no poisson_power is given, because the default level is computed from meanrate, which is still the mean over the whole observation.

Any other comments?

A per-segment meanrate array and a poisson_level property or subtract_poisson_noise() would be relevant additions. Those would need avg_pds_from_iterables and avg_cs_from_iterables to keep the per-segment photon counts, and turning the existing scalar meanrate into an array would also break power_colors.

@Ved0019

Ved0019 commented Sep 19, 2026

Copy link
Copy Markdown

I checked the failing Docs checks / linkcheck (pull_request) run. It is failing because the Slack invite link in docs/contributing.rst is expired.

image

@bjricketts

Copy link
Copy Markdown
Contributor Author

I checked the failing Docs checks / linkcheck (pull_request) run. It is failing because the Slack invite link in docs/contributing.rst is expired.
image

image

I'm not convinced this is the case: clicking the links in my forked repository correctly invites. I suspect it's an issue with the workflow's interface being unable to query links correctly.

Looking at the actual details yields a number of failing links:
image

but clicking the first link in each of those correctly routes to the address. I wonder if this is linked to sites attempting to prevent accessing from bots more generally. The links check being broken isn't related to this PR anyway.

Comment thread stingray/crossspectrum.py Outdated
Comment thread stingray/powerspectrum.py Outdated

@matteobachetti matteobachetti left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @bjricketts !

My main concern here is the poisson level machinery. I think it should be calculated per-segment if use_common_mean is False.

Other minor comments below

Comment thread stingray/powerspectrum.py
)
conv = avg.cs_all / avg.unnorm_cs_all
self.unnorm_conversion = np.nanmean(conv)
conv = np.asarray(avg.cs_all) / np.asarray(avg.unnorm_cs_all)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Now that we are at it, maybe better to use np.asanyarray?

bjricketts and others added 2 commits September 23, 2026 10:32
Co-authored-by: Matteo Bachetti <matteo@matteobachetti.it>
Co-authored-by: Matteo Bachetti <matteo@matteobachetti.it>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DynamicalPowerspectrum and DynamicalCrossspectrum cannot select the per-segment mean (use_common_mean)

3 participants