1+ from functools import cache
2+
13import numpy as np
24
5+ from astropy .timeseries .periodograms .lombscargle .utils import (
6+ compute_chi2_ref ,
7+ convert_normalization ,
8+ )
9+ from astropy .utils import minversion
310from astropy .utils .compat .optional_deps import HAS_SCIPY
411
512
6- def lombscargle_scipy (t , y , frequency , normalization = "standard" , center_data = True ):
13+ @cache
14+ def _scipy_supports_floating_mean ():
15+ # Deferred so that scipy is only imported and its version only probed when
16+ # the answer is needed; passing the module object lets minversion fall
17+ # back to scipy.__version__ when the distribution metadata is missing
18+ # (e.g. in some frozen applications).
19+ import scipy
20+
21+ return minversion (scipy , "1.15.0.dev0" )
22+
23+
24+ def lombscargle_scipy (
25+ t , y , frequency , normalization = "standard" , center_data = True , * , fit_mean = False
26+ ):
727 """Lomb-Scargle Periodogram.
828
929 This is a wrapper of ``scipy.signal.lombscargle`` for computation of the
@@ -23,6 +43,11 @@ def lombscargle_scipy(t, y, frequency, normalization="standard", center_data=Tru
2343 center_data : bool, optional
2444 If True, pre-center the data by subtracting the weighted mean
2545 of the input data.
46+ fit_mean : bool, optional, keyword-only
47+ If True, include a constant offset as part of the model at each
48+ frequency. This can lead to more accurate results, especially in the
49+ case of incomplete phase coverage. Requires Scipy 1.15 and corresponds
50+ to the ``floating_mean`` argument in `scipy.signal.lombscargle`.
2651
2752 Returns
2853 -------
@@ -41,6 +66,9 @@ def lombscargle_scipy(t, y, frequency, normalization="standard", center_data=Tru
4166
4267 from scipy import signal
4368
69+ if fit_mean and not _scipy_supports_floating_mean ():
70+ raise ValueError ("fit_mean=True requires scipy 1.15 or later" )
71+
4472 t , y = np .broadcast_arrays (t , y )
4573
4674 # Scipy requires floating-point input
@@ -56,17 +84,13 @@ def lombscargle_scipy(t, y, frequency, normalization="standard", center_data=Tru
5684 if center_data :
5785 y = y - y .mean ()
5886
59- # Note: scipy input accepts angular frequencies
60- p = signal .lombscargle (t , y , 2 * np .pi * frequency )
87+ kwargs = {"floating_mean" : True } if fit_mean else {}
88+
89+ # Note: scipy `freqs` input is in angular frequencies
90+ p = signal .lombscargle (t , y , 2 * np .pi * frequency , ** kwargs )
6191
6292 if normalization == "psd" :
63- pass
64- elif normalization == "standard" :
65- p *= 2 / (t .size * np .mean (y ** 2 ))
66- elif normalization == "log" :
67- p = - np .log (1 - 2 * p / (t .size * np .mean (y ** 2 )))
68- elif normalization == "model" :
69- p /= 0.5 * t .size * np .mean (y ** 2 ) - p
70- else :
71- raise ValueError (f"normalization='{ normalization } ' not recognized" )
72- return p
93+ return p
94+
95+ chi2_ref = compute_chi2_ref (y , center_data = center_data , fit_mean = fit_mean )
96+ return convert_normalization (p , t .size , "psd" , normalization , chi2_ref = chi2_ref )
0 commit comments